Backport recent changes from mainline.
This includes all changes from59cae77e28
serial_stream_detect(): Make a code comment more generic. up toa7600dc5c7
Makefile.am: Install MIME info file in $(datadir)/mime/packages. This is possible since (almost) none of the changes above change or remove public API calls of the library.
This commit is contained in:
parent
1aba657270
commit
8cd15dd4ce
|
@ -12,6 +12,7 @@
|
||||||
# Editor/IDE cruft
|
# Editor/IDE cruft
|
||||||
*.kate-swp
|
*.kate-swp
|
||||||
*~
|
*~
|
||||||
|
.*.sw*
|
||||||
/*.kdev4
|
/*.kdev4
|
||||||
/Makefile.am.user
|
/Makefile.am.user
|
||||||
|
|
||||||
|
|
107
Makefile.am
107
Makefile.am
|
@ -50,6 +50,7 @@ lib_LTLIBRARIES = libsigrok.la
|
||||||
# Backend files
|
# Backend files
|
||||||
libsigrok_la_SOURCES = \
|
libsigrok_la_SOURCES = \
|
||||||
src/backend.c \
|
src/backend.c \
|
||||||
|
src/conversion.c \
|
||||||
src/device.c \
|
src/device.c \
|
||||||
src/session.c \
|
src/session.c \
|
||||||
src/session_file.c \
|
src/session_file.c \
|
||||||
|
@ -73,10 +74,12 @@ libsigrok_la_SOURCES += \
|
||||||
src/input/binary.c \
|
src/input/binary.c \
|
||||||
src/input/chronovu_la8.c \
|
src/input/chronovu_la8.c \
|
||||||
src/input/csv.c \
|
src/input/csv.c \
|
||||||
|
src/input/logicport.c \
|
||||||
src/input/raw_analog.c \
|
src/input/raw_analog.c \
|
||||||
src/input/trace32_ad.c \
|
src/input/trace32_ad.c \
|
||||||
src/input/vcd.c \
|
src/input/vcd.c \
|
||||||
src/input/wav.c
|
src/input/wav.c \
|
||||||
|
src/input/null.c
|
||||||
|
|
||||||
# Output modules
|
# Output modules
|
||||||
libsigrok_la_SOURCES += \
|
libsigrok_la_SOURCES += \
|
||||||
|
@ -91,7 +94,8 @@ libsigrok_la_SOURCES += \
|
||||||
src/output/hex.c \
|
src/output/hex.c \
|
||||||
src/output/ols.c \
|
src/output/ols.c \
|
||||||
src/output/srzip.c \
|
src/output/srzip.c \
|
||||||
src/output/vcd.c
|
src/output/vcd.c \
|
||||||
|
src/output/null.c
|
||||||
|
|
||||||
# Transform modules
|
# Transform modules
|
||||||
libsigrok_la_SOURCES += \
|
libsigrok_la_SOURCES += \
|
||||||
|
@ -104,7 +108,6 @@ libsigrok_la_SOURCES += \
|
||||||
libsigrok_la_SOURCES += \
|
libsigrok_la_SOURCES += \
|
||||||
src/scpi.h \
|
src/scpi.h \
|
||||||
src/scpi/scpi.c \
|
src/scpi/scpi.c \
|
||||||
src/scpi/helpers.c \
|
|
||||||
src/scpi/scpi_tcp.c
|
src/scpi/scpi_tcp.c
|
||||||
if NEED_RPC
|
if NEED_RPC
|
||||||
libsigrok_la_SOURCES += \
|
libsigrok_la_SOURCES += \
|
||||||
|
@ -143,18 +146,21 @@ endif
|
||||||
|
|
||||||
# Hardware (DMM chip parsers)
|
# Hardware (DMM chip parsers)
|
||||||
libsigrok_la_SOURCES += \
|
libsigrok_la_SOURCES += \
|
||||||
|
src/dmm/asycii.c \
|
||||||
|
src/dmm/bm25x.c \
|
||||||
|
src/dmm/dtm0660.c \
|
||||||
|
src/dmm/eev121gw.c \
|
||||||
src/dmm/es519xx.c \
|
src/dmm/es519xx.c \
|
||||||
src/dmm/fs9721.c \
|
src/dmm/fs9721.c \
|
||||||
src/dmm/fs9922.c \
|
src/dmm/fs9922.c \
|
||||||
src/dmm/m2110.c \
|
src/dmm/m2110.c \
|
||||||
src/dmm/metex14.c \
|
src/dmm/metex14.c \
|
||||||
src/dmm/asycii.c \
|
src/dmm/ms8250d.c \
|
||||||
src/dmm/rs9lcd.c \
|
src/dmm/rs9lcd.c \
|
||||||
src/dmm/bm25x.c \
|
|
||||||
src/dmm/ut71x.c \
|
|
||||||
src/dmm/ut372.c \
|
src/dmm/ut372.c \
|
||||||
|
src/dmm/ut71x.c \
|
||||||
src/dmm/vc870.c \
|
src/dmm/vc870.c \
|
||||||
src/dmm/dtm0660.c
|
src/dmm/vc96.c
|
||||||
|
|
||||||
# Hardware (LCR chip parsers)
|
# Hardware (LCR chip parsers)
|
||||||
if NEED_SERIAL
|
if NEED_SERIAL
|
||||||
|
@ -167,15 +173,22 @@ libsigrok_la_SOURCES += \
|
||||||
src/scale/kern.c
|
src/scale/kern.c
|
||||||
|
|
||||||
# Hardware drivers
|
# Hardware drivers
|
||||||
noinst_LTLIBRARIES = src/libdrivers.la
|
noinst_LTLIBRARIES = src/libdrivers.la \
|
||||||
|
src/libdrivers_head.la src/libdrivers_tail.la
|
||||||
|
|
||||||
src/libdrivers.o: src/libdrivers.la
|
src/libdrivers.o: src/libdrivers.la \
|
||||||
$(AM_V_CCLD)$(LINK) src/libdrivers.la
|
src/libdrivers_head.la src/libdrivers_tail.la
|
||||||
|
$(AM_V_CCLD)$(LINK) src/libdrivers_head.la src/libdrivers.la \
|
||||||
|
src/libdrivers_tail.la
|
||||||
src/libdrivers.lo: src/libdrivers.o
|
src/libdrivers.lo: src/libdrivers.o
|
||||||
$(AM_V_GEN)echo "# Generated by libtool" > $@
|
$(AM_V_GEN)echo "# Generated by libtool" > $@
|
||||||
$(AM_V_at)echo "pic_object='libdrivers.o'" >> $@
|
$(AM_V_at)echo "pic_object='libdrivers.o'" >> $@
|
||||||
$(AM_V_at)echo "non_pic_object='libdrivers.o'" >> $@
|
$(AM_V_at)echo "non_pic_object='libdrivers.o'" >> $@
|
||||||
|
|
||||||
|
src_libdrivers_head_la_SOURCES = src/driver_list_start.c
|
||||||
|
|
||||||
|
src_libdrivers_tail_la_SOURCES = src/driver_list_stop.c
|
||||||
|
|
||||||
src_libdrivers_la_SOURCES = src/drivers.c
|
src_libdrivers_la_SOURCES = src/drivers.c
|
||||||
|
|
||||||
if HW_AGILENT_DMM
|
if HW_AGILENT_DMM
|
||||||
|
@ -221,7 +234,9 @@ src_libdrivers_la_SOURCES += \
|
||||||
src/hardware/beaglelogic/beaglelogic.h \
|
src/hardware/beaglelogic/beaglelogic.h \
|
||||||
src/hardware/beaglelogic/protocol.h \
|
src/hardware/beaglelogic/protocol.h \
|
||||||
src/hardware/beaglelogic/protocol.c \
|
src/hardware/beaglelogic/protocol.c \
|
||||||
src/hardware/beaglelogic/api.c
|
src/hardware/beaglelogic/api.c \
|
||||||
|
src/hardware/beaglelogic/beaglelogic_native.c \
|
||||||
|
src/hardware/beaglelogic/beaglelogic_tcp.c
|
||||||
endif
|
endif
|
||||||
if HW_BRYMEN_BM86X
|
if HW_BRYMEN_BM86X
|
||||||
src_libdrivers_la_SOURCES += \
|
src_libdrivers_la_SOURCES += \
|
||||||
|
@ -272,6 +287,18 @@ src_libdrivers_la_SOURCES += \
|
||||||
src/hardware/demo/protocol.c \
|
src/hardware/demo/protocol.c \
|
||||||
src/hardware/demo/api.c
|
src/hardware/demo/api.c
|
||||||
endif
|
endif
|
||||||
|
if HW_DREAMSOURCELAB_DSLOGIC
|
||||||
|
src_libdrivers_la_SOURCES += \
|
||||||
|
src/hardware/dreamsourcelab-dslogic/protocol.h \
|
||||||
|
src/hardware/dreamsourcelab-dslogic/protocol.c \
|
||||||
|
src/hardware/dreamsourcelab-dslogic/api.c
|
||||||
|
endif
|
||||||
|
if HW_FLUKE_45
|
||||||
|
src_libdrivers_la_SOURCES += \
|
||||||
|
src/hardware/fluke-45/protocol.h \
|
||||||
|
src/hardware/fluke-45/protocol.c \
|
||||||
|
src/hardware/fluke-45/api.c
|
||||||
|
endif
|
||||||
if HW_FLUKE_DMM
|
if HW_FLUKE_DMM
|
||||||
src_libdrivers_la_SOURCES += \
|
src_libdrivers_la_SOURCES += \
|
||||||
src/hardware/fluke-dmm/protocol.h \
|
src/hardware/fluke-dmm/protocol.h \
|
||||||
|
@ -288,9 +315,7 @@ if HW_FX2LAFW
|
||||||
src_libdrivers_la_SOURCES += \
|
src_libdrivers_la_SOURCES += \
|
||||||
src/hardware/fx2lafw/protocol.h \
|
src/hardware/fx2lafw/protocol.h \
|
||||||
src/hardware/fx2lafw/protocol.c \
|
src/hardware/fx2lafw/protocol.c \
|
||||||
src/hardware/fx2lafw/api.c \
|
src/hardware/fx2lafw/api.c
|
||||||
src/hardware/fx2lafw/dslogic.c \
|
|
||||||
src/hardware/fx2lafw/dslogic.h
|
|
||||||
endif
|
endif
|
||||||
if HW_GMC_MH_1X_2X
|
if HW_GMC_MH_1X_2X
|
||||||
src_libdrivers_la_SOURCES += \
|
src_libdrivers_la_SOURCES += \
|
||||||
|
@ -304,12 +329,24 @@ src_libdrivers_la_SOURCES += \
|
||||||
src/hardware/gwinstek-gds-800/protocol.c \
|
src/hardware/gwinstek-gds-800/protocol.c \
|
||||||
src/hardware/gwinstek-gds-800/api.c
|
src/hardware/gwinstek-gds-800/api.c
|
||||||
endif
|
endif
|
||||||
|
if HW_GWINSTEK_GPD
|
||||||
|
src_libdrivers_la_SOURCES += \
|
||||||
|
src/hardware/gwinstek-gpd/protocol.h \
|
||||||
|
src/hardware/gwinstek-gpd/protocol.c \
|
||||||
|
src/hardware/gwinstek-gpd/api.c
|
||||||
|
endif
|
||||||
if HW_HAMEG_HMO
|
if HW_HAMEG_HMO
|
||||||
src_libdrivers_la_SOURCES += \
|
src_libdrivers_la_SOURCES += \
|
||||||
src/hardware/hameg-hmo/protocol.h \
|
src/hardware/hameg-hmo/protocol.h \
|
||||||
src/hardware/hameg-hmo/protocol.c \
|
src/hardware/hameg-hmo/protocol.c \
|
||||||
src/hardware/hameg-hmo/api.c
|
src/hardware/hameg-hmo/api.c
|
||||||
endif
|
endif
|
||||||
|
if HW_HANTEK_4032L
|
||||||
|
src_libdrivers_la_SOURCES += \
|
||||||
|
src/hardware/hantek-4032l/protocol.h \
|
||||||
|
src/hardware/hantek-4032l/protocol.c \
|
||||||
|
src/hardware/hantek-4032l/api.c
|
||||||
|
endif
|
||||||
if HW_HANTEK_6XXX
|
if HW_HANTEK_6XXX
|
||||||
src_libdrivers_la_SOURCES += \
|
src_libdrivers_la_SOURCES += \
|
||||||
src/hardware/hantek-6xxx/protocol.h \
|
src/hardware/hantek-6xxx/protocol.h \
|
||||||
|
@ -328,6 +365,12 @@ src_libdrivers_la_SOURCES += \
|
||||||
src/hardware/hp-3457a/protocol.c \
|
src/hardware/hp-3457a/protocol.c \
|
||||||
src/hardware/hp-3457a/api.c
|
src/hardware/hp-3457a/api.c
|
||||||
endif
|
endif
|
||||||
|
if HW_HP_3478A
|
||||||
|
src_libdrivers_la_SOURCES += \
|
||||||
|
src/hardware/hp-3478a/protocol.h \
|
||||||
|
src/hardware/hp-3478a/protocol.c \
|
||||||
|
src/hardware/hp-3478a/api.c
|
||||||
|
endif
|
||||||
if HW_HUNG_CHANG_DSO_2100
|
if HW_HUNG_CHANG_DSO_2100
|
||||||
src_libdrivers_la_SOURCES += \
|
src_libdrivers_la_SOURCES += \
|
||||||
src/hardware/hung-chang-dso-2100/protocol.h \
|
src/hardware/hung-chang-dso-2100/protocol.h \
|
||||||
|
@ -346,6 +389,12 @@ src_libdrivers_la_SOURCES += \
|
||||||
src/hardware/ikalogic-scanaplus/protocol.c \
|
src/hardware/ikalogic-scanaplus/protocol.c \
|
||||||
src/hardware/ikalogic-scanaplus/api.c
|
src/hardware/ikalogic-scanaplus/api.c
|
||||||
endif
|
endif
|
||||||
|
if HW_IPDBG_LA
|
||||||
|
src_libdrivers_la_SOURCES += \
|
||||||
|
src/hardware/ipdbg-la/protocol.h \
|
||||||
|
src/hardware/ipdbg-la/protocol.c \
|
||||||
|
src/hardware/ipdbg-la/api.c
|
||||||
|
endif
|
||||||
if HW_KECHENG_KC_330B
|
if HW_KECHENG_KC_330B
|
||||||
src_libdrivers_la_SOURCES += \
|
src_libdrivers_la_SOURCES += \
|
||||||
src/hardware/kecheng-kc-330b/protocol.h \
|
src/hardware/kecheng-kc-330b/protocol.h \
|
||||||
|
@ -430,6 +479,12 @@ src_libdrivers_la_SOURCES += \
|
||||||
src/hardware/pipistrello-ols/protocol.c \
|
src/hardware/pipistrello-ols/protocol.c \
|
||||||
src/hardware/pipistrello-ols/api.c
|
src/hardware/pipistrello-ols/api.c
|
||||||
endif
|
endif
|
||||||
|
if HW_RDTECH_DPS
|
||||||
|
src_libdrivers_la_SOURCES += \
|
||||||
|
src/hardware/rdtech-dps/protocol.h \
|
||||||
|
src/hardware/rdtech-dps/protocol.c \
|
||||||
|
src/hardware/rdtech-dps/api.c
|
||||||
|
endif
|
||||||
if HW_RIGOL_DS
|
if HW_RIGOL_DS
|
||||||
src_libdrivers_la_SOURCES += \
|
src_libdrivers_la_SOURCES += \
|
||||||
src/hardware/rigol-ds/protocol.h \
|
src/hardware/rigol-ds/protocol.h \
|
||||||
|
@ -448,6 +503,12 @@ src_libdrivers_la_SOURCES += \
|
||||||
src/hardware/saleae-logic16/protocol.c \
|
src/hardware/saleae-logic16/protocol.c \
|
||||||
src/hardware/saleae-logic16/api.c
|
src/hardware/saleae-logic16/api.c
|
||||||
endif
|
endif
|
||||||
|
if HW_SALEAE_LOGIC_PRO
|
||||||
|
src_libdrivers_la_SOURCES += \
|
||||||
|
src/hardware/saleae-logic-pro/protocol.h \
|
||||||
|
src/hardware/saleae-logic-pro/protocol.c \
|
||||||
|
src/hardware/saleae-logic-pro/api.c
|
||||||
|
endif
|
||||||
if HW_SCPI_PPS
|
if HW_SCPI_PPS
|
||||||
src_libdrivers_la_SOURCES += \
|
src_libdrivers_la_SOURCES += \
|
||||||
src/hardware/scpi-pps/protocol.h \
|
src/hardware/scpi-pps/protocol.h \
|
||||||
|
@ -465,6 +526,12 @@ if HW_SERIAL_LCR
|
||||||
src_libdrivers_la_SOURCES += \
|
src_libdrivers_la_SOURCES += \
|
||||||
src/hardware/serial-lcr/api.c
|
src/hardware/serial-lcr/api.c
|
||||||
endif
|
endif
|
||||||
|
if HW_SIGLENT_SDS
|
||||||
|
src_libdrivers_la_SOURCES += \
|
||||||
|
src/hardware/siglent-sds/protocol.h \
|
||||||
|
src/hardware/siglent-sds/protocol.c \
|
||||||
|
src/hardware/siglent-sds/api.c
|
||||||
|
endif
|
||||||
if HW_SYSCLK_LWLA
|
if HW_SYSCLK_LWLA
|
||||||
src_libdrivers_la_SOURCES += \
|
src_libdrivers_la_SOURCES += \
|
||||||
src/hardware/sysclk-lwla/lwla.h \
|
src/hardware/sysclk-lwla/lwla.h \
|
||||||
|
@ -529,6 +596,12 @@ src_libdrivers_la_SOURCES += \
|
||||||
src/hardware/zeroplus-logic-cube/protocol.c \
|
src/hardware/zeroplus-logic-cube/protocol.c \
|
||||||
src/hardware/zeroplus-logic-cube/api.c
|
src/hardware/zeroplus-logic-cube/api.c
|
||||||
endif
|
endif
|
||||||
|
if HW_ZKETECH_EBD_USB
|
||||||
|
src_libdrivers_la_SOURCES += \
|
||||||
|
src/hardware/zketech-ebd-usb/protocol.h \
|
||||||
|
src/hardware/zketech-ebd-usb/protocol.c \
|
||||||
|
src/hardware/zketech-ebd-usb/api.c
|
||||||
|
endif
|
||||||
|
|
||||||
libsigrok_la_LIBADD = src/libdrivers.lo $(SR_EXTRA_LIBS) $(LIBSIGROK_LIBS)
|
libsigrok_la_LIBADD = src/libdrivers.lo $(SR_EXTRA_LIBS) $(LIBSIGROK_LIBS)
|
||||||
libsigrok_la_LDFLAGS = -version-info $(SR_LIB_VERSION) -no-undefined
|
libsigrok_la_LDFLAGS = -version-info $(SR_LIB_VERSION) -no-undefined
|
||||||
|
@ -544,7 +617,7 @@ noinst_HEADERS = src/libsigrok-internal.h
|
||||||
pkgconfigdir = $(libdir)/pkgconfig
|
pkgconfigdir = $(libdir)/pkgconfig
|
||||||
pkgconfig_DATA = libsigrok.pc
|
pkgconfig_DATA = libsigrok.pc
|
||||||
|
|
||||||
mimeappdir = $(datadir)/mime/application
|
mimeappdir = $(datadir)/mime/packages
|
||||||
mimeapp_DATA = contrib/vnd.sigrok.session.xml
|
mimeapp_DATA = contrib/vnd.sigrok.session.xml
|
||||||
|
|
||||||
mimeicondir = $(datadir)/icons/hicolor/48x48/mimetypes
|
mimeicondir = $(datadir)/icons/hicolor/48x48/mimetypes
|
||||||
|
@ -581,7 +654,9 @@ EXTRA_DIST = \
|
||||||
contrib/libsigrok.png \
|
contrib/libsigrok.png \
|
||||||
contrib/libsigrok.svg \
|
contrib/libsigrok.svg \
|
||||||
contrib/vnd.sigrok.session.xml \
|
contrib/vnd.sigrok.session.xml \
|
||||||
contrib/z60_libsigrok.rules
|
contrib/60-libsigrok.rules \
|
||||||
|
contrib/61-libsigrok-plugdev.rules \
|
||||||
|
contrib/61-libsigrok-uaccess.rules
|
||||||
|
|
||||||
if HAVE_CHECK
|
if HAVE_CHECK
|
||||||
TESTS = tests/main
|
TESTS = tests/main
|
||||||
|
|
2
README
2
README
|
@ -41,7 +41,7 @@ Requirements for the C library:
|
||||||
- libserialport >= 0.1.1 (optional, used by some drivers)
|
- libserialport >= 0.1.1 (optional, used by some drivers)
|
||||||
- librevisa >= 0.0.20130412 (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)
|
- libusb-1.0 >= 1.0.16 (optional, used by some drivers)
|
||||||
- libftdi >= 0.16 or libftdi1 >= 1.0 (optional, used by some drivers)
|
- libftdi1 >= 1.0 (optional, used by some drivers)
|
||||||
- libgpib (optional, used by some drivers)
|
- libgpib (optional, used by some drivers)
|
||||||
- libieee1284 (optional, used by some drivers)
|
- libieee1284 (optional, used by some drivers)
|
||||||
- check >= 0.9.4 (optional, only needed to run unit tests)
|
- check >= 0.9.4 (optional, only needed to run unit tests)
|
||||||
|
|
|
@ -14,6 +14,7 @@ the device is connected to the PC (usually via USB), before it can be used.
|
||||||
|
|
||||||
The default locations where libsigrok expects the firmware files are:
|
The default locations where libsigrok expects the firmware files are:
|
||||||
|
|
||||||
|
$SIGROK_FIRMWARE_DIR (environment variable)
|
||||||
$HOME/.local/share/sigrok-firmware
|
$HOME/.local/share/sigrok-firmware
|
||||||
$prefix/share/sigrok-firmware
|
$prefix/share/sigrok-firmware
|
||||||
/usr/local/share/sigrok-firmware
|
/usr/local/share/sigrok-firmware
|
||||||
|
@ -114,6 +115,7 @@ The following drivers/devices do not need any firmware upload:
|
||||||
- scpi-pps
|
- scpi-pps
|
||||||
- serial-dmm (including all subdrivers)
|
- serial-dmm (including all subdrivers)
|
||||||
- serial-lcr (including all subdrivers)
|
- serial-lcr (including all subdrivers)
|
||||||
|
- siglent-sds
|
||||||
- teleinfo
|
- teleinfo
|
||||||
- testo
|
- testo
|
||||||
- tondaj-sl-814
|
- tondaj-sl-814
|
||||||
|
@ -138,7 +140,8 @@ Example:
|
||||||
|
|
||||||
$ sigrok-cli --driver <somedriver>:conn=/dev/ttyUSB0 ...
|
$ sigrok-cli --driver <somedriver>:conn=/dev/ttyUSB0 ...
|
||||||
|
|
||||||
The following drivers/devices require a serial port specification:
|
The following drivers/devices require a serial port specification. Some of
|
||||||
|
the drivers implement a default for the connection.
|
||||||
|
|
||||||
- agilent-dmm
|
- agilent-dmm
|
||||||
- appa-55ii
|
- appa-55ii
|
||||||
|
@ -183,6 +186,21 @@ The following drivers/devices do not require a serial port specification:
|
||||||
- yokogawa-dlm (USBTMC or TCP)
|
- yokogawa-dlm (USBTMC or TCP)
|
||||||
- zeroplus-logic-cube
|
- zeroplus-logic-cube
|
||||||
|
|
||||||
|
Beyond strict serial communication over COM ports (e.g. /dev/ttyUSB0), 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
|
||||||
|
|
||||||
|
|
||||||
Specifying serial port parameters
|
Specifying serial port parameters
|
||||||
---------------------------------
|
---------------------------------
|
||||||
|
@ -212,33 +230,39 @@ For USB-to-serial based devices, we recommended using our udev rules file
|
||||||
(see below for details).
|
(see below for details).
|
||||||
|
|
||||||
|
|
||||||
Permissions for USB devices (udev rules file)
|
Permissions for USB devices (udev rules files)
|
||||||
---------------------------------------------
|
----------------------------------------------
|
||||||
|
|
||||||
When using USB-based devices supported by libsigrok, the user running the
|
When using USB-based devices supported by libsigrok, the user running the
|
||||||
libsigrok frontend (e.g. sigrok-cli) has to have (read/write) permissions
|
libsigrok frontend (e.g. sigrok-cli) has to have (read/write) permissions
|
||||||
for the respective USB device.
|
for the respective USB device.
|
||||||
|
|
||||||
On Linux, this is accomplished using either 'chmod' (not recommended) or
|
On Linux, this is accomplished using udev rules. libsigrok ships a rules
|
||||||
using the udev rules file shipped with libsigrok (recommended).
|
file containing all supported devices which can be detected reliably
|
||||||
|
(generic USB-to-serial converters are omitted, as these are used for a wide
|
||||||
|
range of devices, e.g. GPS receivers, which are not handled by libsigrok).
|
||||||
|
|
||||||
The file is available in contrib/z60_libsigrok.rules. It contains entries
|
The file is available in contrib/60-libsigrok.rules. This file just contains
|
||||||
for all libsigrok-supported (USB-based) devices and changes their group
|
the list of devices and flags these devices with ID_SIGROK="1". Access is
|
||||||
to 'plugdev' and the permissions to '664'.
|
granted by the 61-libsigrok-plugdev.rules or 61-libsigrok-uaccess.rules files,
|
||||||
|
allowing access to members of the plugdev group or to currently logged in
|
||||||
|
users, respectively.
|
||||||
|
|
||||||
When using a libsigrok package from your favorite Linux distribution, the
|
When using a libsigrok package from your favorite Linux distribution, the
|
||||||
packager will have already taken care of properly installing the udev file
|
files should already be installed in /usr/lib/udev/rules.d/, i.e.
|
||||||
in the correct (distro-specific) place, and you don't have to do anything.
|
60-libsigrok.rules and one of the access granting rules files. Use of
|
||||||
The packager might also have adapted 'plugdev' and '664' as needed.
|
61-libsigrok-uaccess.rules is encouraged on systemd distributions.
|
||||||
|
|
||||||
|
The access policy can be locally overridden by placing appropriate rules in
|
||||||
|
/etc/udev/rules.d/, disabling or ammending the default policy. See the
|
||||||
|
udev documentation, e.g. man 7 udev, for details.
|
||||||
|
|
||||||
If you're building from source, you need to copy the file to the place
|
If you're building from source, you need to copy the file to the place
|
||||||
where your distro expects such files. This is beyond the scope of this README,
|
where udev will read these rules. Local rules should go to /etc/udev/rules.d.
|
||||||
but generally the location could be e.g. /etc/udev/rules.d, or maybe
|
Keep the file naming, otherwise interaction between the libsigrok rules and
|
||||||
/lib/udev/rules.d, or something else. Afterwards you might have to restart
|
rules shipped by the system will be broken.
|
||||||
udev, e.g. via '/etc/init.d/udev restart' or similar, and you'll have to
|
|
||||||
re-attach your device via USB.
|
|
||||||
|
|
||||||
Please consult the udev docs of your distro for details.
|
Please consult the udev docs for details.
|
||||||
|
|
||||||
|
|
||||||
Cypress FX2 based devices
|
Cypress FX2 based devices
|
||||||
|
@ -349,6 +373,9 @@ a short list for convenience:
|
||||||
'SI232 online' (28-29S) or 'SI232 store' (22-26x). The interface must
|
'SI232 online' (28-29S) or 'SI232 store' (22-26x). The interface must
|
||||||
be configured to the same baud rate as the host (default 9600).
|
be configured to the same baud rate as the host (default 9600).
|
||||||
Multimeter and interface must be configured to the same address.
|
Multimeter and interface must be configured to the same address.
|
||||||
|
- 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.
|
||||||
- Norma DM950: If the interface doesn't work (e.g. USB-RS232 converter), power
|
- Norma DM950: If the interface doesn't work (e.g. USB-RS232 converter), power
|
||||||
on the device with "FUNC" pressed (to power the interface from the DMM).
|
on the device with "FUNC" pressed (to power the interface from the DMM).
|
||||||
- PCE PCE-DM32: Briefly press the "RS232" button.
|
- PCE PCE-DM32: Briefly press the "RS232" button.
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
const DataType *ConfigKey::data_type() const
|
const DataType *ConfigKey::data_type() const
|
||||||
{
|
{
|
||||||
const struct sr_key_info *info = sr_key_info_get(SR_KEY_CONFIG, id());
|
const struct sr_key_info *info = sr_key_info_get(SR_KEY_CONFIG, id());
|
||||||
|
@ -30,8 +32,6 @@ const ConfigKey *ConfigKey::get_by_identifier(string identifier)
|
||||||
return get(info->key);
|
return get(info->key);
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <config.h>
|
|
||||||
|
|
||||||
#ifndef HAVE_STOI_STOD
|
#ifndef HAVE_STOI_STOD
|
||||||
|
|
||||||
/* Fallback implementation of stoi and stod */
|
/* Fallback implementation of stoi and stod */
|
||||||
|
@ -70,12 +70,12 @@ static inline double stod( const std::string& str )
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Glib::VariantBase ConfigKey::parse_string(string value) const
|
Glib::VariantBase ConfigKey::parse_string(string value, enum sr_datatype dt)
|
||||||
{
|
{
|
||||||
GVariant *variant;
|
GVariant *variant;
|
||||||
uint64_t p, q;
|
uint64_t p, q;
|
||||||
|
|
||||||
switch (data_type()->id())
|
switch (dt)
|
||||||
{
|
{
|
||||||
case SR_T_UINT64:
|
case SR_T_UINT64:
|
||||||
check(sr_parse_sizestring(value.c_str(), &p));
|
check(sr_parse_sizestring(value.c_str(), &p));
|
||||||
|
@ -90,7 +90,7 @@ Glib::VariantBase ConfigKey::parse_string(string value) const
|
||||||
case SR_T_FLOAT:
|
case SR_T_FLOAT:
|
||||||
try {
|
try {
|
||||||
variant = g_variant_new_double(stod(value));
|
variant = g_variant_new_double(stod(value));
|
||||||
} catch (invalid_argument) {
|
} catch (invalid_argument&) {
|
||||||
throw Error(SR_ERR_ARG);
|
throw Error(SR_ERR_ARG);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -105,7 +105,7 @@ Glib::VariantBase ConfigKey::parse_string(string value) const
|
||||||
case SR_T_INT32:
|
case SR_T_INT32:
|
||||||
try {
|
try {
|
||||||
variant = g_variant_new_int32(stoi(value));
|
variant = g_variant_new_int32(stoi(value));
|
||||||
} catch (invalid_argument) {
|
} catch (invalid_argument&) {
|
||||||
throw Error(SR_ERR_ARG);
|
throw Error(SR_ERR_ARG);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -116,3 +116,8 @@ Glib::VariantBase ConfigKey::parse_string(string value) const
|
||||||
return Glib::VariantBase(variant, false);
|
return Glib::VariantBase(variant, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Glib::VariantBase ConfigKey::parse_string(string value) const
|
||||||
|
{
|
||||||
|
enum sr_datatype dt = (enum sr_datatype)(data_type()->id());
|
||||||
|
return parse_string(value, dt);
|
||||||
|
}
|
||||||
|
|
|
@ -7,4 +7,5 @@
|
||||||
/** Get configuration key by string identifier. */
|
/** Get configuration key by string identifier. */
|
||||||
static const ConfigKey *get_by_identifier(string identifier);
|
static const ConfigKey *get_by_identifier(string identifier);
|
||||||
/** Parse a string argument into the appropriate type for this key. */
|
/** 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;
|
Glib::VariantBase parse_string(string value) const;
|
||||||
|
|
|
@ -18,8 +18,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Needed for isascii(), as used in the GNU libstdc++ headers */
|
/* Needed for isascii(), as used in the GNU libstdc++ headers */
|
||||||
|
/* Needed in strutil.c for POSIX.1-2008 locale functions */
|
||||||
#ifndef _XOPEN_SOURCE
|
#ifndef _XOPEN_SOURCE
|
||||||
#define _XOPEN_SOURCE 600
|
#define _XOPEN_SOURCE 700
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
@ -128,19 +129,19 @@ Context::Context() :
|
||||||
if (struct sr_dev_driver **driver_list = sr_driver_list(_structure))
|
if (struct sr_dev_driver **driver_list = sr_driver_list(_structure))
|
||||||
for (int i = 0; driver_list[i]; i++) {
|
for (int i = 0; driver_list[i]; i++) {
|
||||||
unique_ptr<Driver> driver {new Driver{driver_list[i]}};
|
unique_ptr<Driver> driver {new Driver{driver_list[i]}};
|
||||||
_drivers.insert(make_pair(driver->name(), move(driver)));
|
_drivers.emplace(driver->name(), move(driver));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const struct sr_input_module **input_list = sr_input_list())
|
if (const struct sr_input_module **input_list = sr_input_list())
|
||||||
for (int i = 0; input_list[i]; i++) {
|
for (int i = 0; input_list[i]; i++) {
|
||||||
unique_ptr<InputFormat> input {new InputFormat{input_list[i]}};
|
unique_ptr<InputFormat> input {new InputFormat{input_list[i]}};
|
||||||
_input_formats.insert(make_pair(input->name(), move(input)));
|
_input_formats.emplace(input->name(), move(input));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const struct sr_output_module **output_list = sr_output_list())
|
if (const struct sr_output_module **output_list = sr_output_list())
|
||||||
for (int i = 0; output_list[i]; i++) {
|
for (int i = 0; output_list[i]; i++) {
|
||||||
unique_ptr<OutputFormat> output {new OutputFormat{output_list[i]}};
|
unique_ptr<OutputFormat> output {new OutputFormat{output_list[i]}};
|
||||||
_output_formats.insert(make_pair(output->name(), move(output)));
|
_output_formats.emplace(output->name(), move(output));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,11 +158,10 @@ string Context::lib_version()
|
||||||
map<string, shared_ptr<Driver>> Context::drivers()
|
map<string, shared_ptr<Driver>> Context::drivers()
|
||||||
{
|
{
|
||||||
map<string, shared_ptr<Driver>> result;
|
map<string, shared_ptr<Driver>> result;
|
||||||
for (const auto &entry: _drivers)
|
for (const auto &entry: _drivers) {
|
||||||
{
|
|
||||||
const auto &name = entry.first;
|
const auto &name = entry.first;
|
||||||
const auto &driver = entry.second;
|
const auto &driver = entry.second;
|
||||||
result.insert({name, driver->share_owned_by(shared_from_this())});
|
result.emplace(name, driver->share_owned_by(shared_from_this()));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -169,23 +169,47 @@ map<string, shared_ptr<Driver>> Context::drivers()
|
||||||
map<string, shared_ptr<InputFormat>> Context::input_formats()
|
map<string, shared_ptr<InputFormat>> Context::input_formats()
|
||||||
{
|
{
|
||||||
map<string, shared_ptr<InputFormat>> result;
|
map<string, shared_ptr<InputFormat>> result;
|
||||||
for (const auto &entry: _input_formats)
|
for (const auto &entry: _input_formats) {
|
||||||
{
|
|
||||||
const auto &name = entry.first;
|
const auto &name = entry.first;
|
||||||
const auto &input_format = entry.second;
|
const auto &input_format = entry.second;
|
||||||
result.insert({name, input_format->share_owned_by(shared_from_this())});
|
result.emplace(name, input_format->share_owned_by(shared_from_this()));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shared_ptr<InputFormat> Context::input_format_match(string filename)
|
||||||
|
{
|
||||||
|
const struct sr_input *input;
|
||||||
|
const struct sr_input_module *imod;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Have the input module looked up for the specified file.
|
||||||
|
* Failed lookup (or "successful lookup" with an empty result)
|
||||||
|
* are non-fatal. Free the sr_input that was created by the
|
||||||
|
* lookup routine, but grab the input module kind and return an
|
||||||
|
* InputFormat instance to the application. This works because
|
||||||
|
* the application passes a filename, no input data got buffered
|
||||||
|
* in the sr_input that we release.
|
||||||
|
*/
|
||||||
|
input = NULL;
|
||||||
|
rc = sr_input_scan_file(filename.c_str(), &input);
|
||||||
|
if (rc != SR_OK)
|
||||||
|
return nullptr;
|
||||||
|
if (!input)
|
||||||
|
return nullptr;
|
||||||
|
imod = sr_input_module_get(input);
|
||||||
|
sr_input_free(input);
|
||||||
|
return shared_ptr<InputFormat>{new InputFormat{imod}, default_delete<InputFormat>{}};
|
||||||
|
}
|
||||||
|
|
||||||
map<string, shared_ptr<OutputFormat>> Context::output_formats()
|
map<string, shared_ptr<OutputFormat>> Context::output_formats()
|
||||||
{
|
{
|
||||||
map<string, shared_ptr<OutputFormat>> result;
|
map<string, shared_ptr<OutputFormat>> result;
|
||||||
for (const auto &entry: _output_formats)
|
for (const auto &entry: _output_formats) {
|
||||||
{
|
|
||||||
const auto &name = entry.first;
|
const auto &name = entry.first;
|
||||||
const auto &output_format = entry.second;
|
const auto &output_format = entry.second;
|
||||||
result.insert({name, output_format->share_owned_by(shared_from_this())});
|
result.emplace(name, output_format->share_owned_by(shared_from_this()));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -213,12 +237,9 @@ static int call_log_callback(void *cb_data, int loglevel,
|
||||||
|
|
||||||
auto *const callback = static_cast<LogCallbackFunction *>(cb_data);
|
auto *const callback = static_cast<LogCallbackFunction *>(cb_data);
|
||||||
|
|
||||||
try
|
try {
|
||||||
{
|
|
||||||
(*callback)(LogLevel::get(loglevel), message.get());
|
(*callback)(LogLevel::get(loglevel), message.get());
|
||||||
}
|
} catch (Error &e) {
|
||||||
catch (Error e)
|
|
||||||
{
|
|
||||||
return e.result;
|
return e.result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,8 +302,7 @@ shared_ptr<Packet> Context::create_meta_packet(
|
||||||
map<const ConfigKey *, Glib::VariantBase> config)
|
map<const ConfigKey *, Glib::VariantBase> config)
|
||||||
{
|
{
|
||||||
auto meta = g_new0(struct sr_datafeed_meta, 1);
|
auto meta = g_new0(struct sr_datafeed_meta, 1);
|
||||||
for (const auto &input : config)
|
for (const auto &input : config) {
|
||||||
{
|
|
||||||
const auto &key = input.first;
|
const auto &key = input.first;
|
||||||
const auto &value = input.second;
|
const auto &value = input.second;
|
||||||
auto *const output = g_new(struct sr_config, 1);
|
auto *const output = g_new(struct sr_config, 1);
|
||||||
|
@ -312,7 +332,7 @@ shared_ptr<Packet> Context::create_logic_packet(
|
||||||
|
|
||||||
shared_ptr<Packet> Context::create_analog_packet(
|
shared_ptr<Packet> Context::create_analog_packet(
|
||||||
vector<shared_ptr<Channel> > channels,
|
vector<shared_ptr<Channel> > channels,
|
||||||
float *data_pointer, unsigned int num_samples, const Quantity *mq,
|
const float *data_pointer, unsigned int num_samples, const Quantity *mq,
|
||||||
const Unit *unit, vector<const QuantityFlag *> mqflags)
|
const Unit *unit, vector<const QuantityFlag *> mqflags)
|
||||||
{
|
{
|
||||||
auto analog = g_new0(struct sr_datafeed_analog, 1);
|
auto analog = g_new0(struct sr_datafeed_analog, 1);
|
||||||
|
@ -350,7 +370,7 @@ shared_ptr<Packet> Context::create_analog_packet(
|
||||||
spec->spec_digits = 0;
|
spec->spec_digits = 0;
|
||||||
|
|
||||||
analog->num_samples = num_samples;
|
analog->num_samples = num_samples;
|
||||||
analog->data = data_pointer;
|
analog->data = (float*)data_pointer;
|
||||||
auto packet = g_new(struct sr_datafeed_packet, 1);
|
auto packet = g_new(struct sr_datafeed_packet, 1);
|
||||||
packet->type = SR_DF_ANALOG;
|
packet->type = SR_DF_ANALOG;
|
||||||
packet->payload = analog;
|
packet->payload = analog;
|
||||||
|
@ -446,16 +466,14 @@ vector<shared_ptr<HardwareDevice>> Driver::scan(
|
||||||
map<const ConfigKey *, Glib::VariantBase> options)
|
map<const ConfigKey *, Glib::VariantBase> options)
|
||||||
{
|
{
|
||||||
/* Initialise the driver if not yet done. */
|
/* Initialise the driver if not yet done. */
|
||||||
if (!_initialized)
|
if (!_initialized) {
|
||||||
{
|
|
||||||
check(sr_driver_init(_parent->_structure, _structure));
|
check(sr_driver_init(_parent->_structure, _structure));
|
||||||
_initialized = true;
|
_initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Translate scan options to GSList of struct sr_config pointers. */
|
/* Translate scan options to GSList of struct sr_config pointers. */
|
||||||
GSList *option_list = nullptr;
|
GSList *option_list = nullptr;
|
||||||
for (const auto &entry : options)
|
for (const auto &entry : options) {
|
||||||
{
|
|
||||||
const auto &key = entry.first;
|
const auto &key = entry.first;
|
||||||
const auto &value = entry.second;
|
const auto &value = entry.second;
|
||||||
auto *const config = g_new(struct sr_config, 1);
|
auto *const config = g_new(struct sr_config, 1);
|
||||||
|
@ -473,8 +491,7 @@ vector<shared_ptr<HardwareDevice>> Driver::scan(
|
||||||
|
|
||||||
/* Create device objects. */
|
/* Create device objects. */
|
||||||
vector<shared_ptr<HardwareDevice>> result;
|
vector<shared_ptr<HardwareDevice>> result;
|
||||||
for (GSList *device = device_list; device; device = device->next)
|
for (GSList *device = device_list; device; device = device->next) {
|
||||||
{
|
|
||||||
auto *const sdi = static_cast<struct sr_dev_inst *>(device->data);
|
auto *const sdi = static_cast<struct sr_dev_inst *>(device->data);
|
||||||
shared_ptr<HardwareDevice> hwdev {
|
shared_ptr<HardwareDevice> hwdev {
|
||||||
new HardwareDevice{shared_from_this(), sdi},
|
new HardwareDevice{shared_from_this(), sdi},
|
||||||
|
@ -570,23 +587,22 @@ Device::Device(struct sr_dev_inst *structure) :
|
||||||
Configurable(sr_dev_inst_driver_get(structure), structure, nullptr),
|
Configurable(sr_dev_inst_driver_get(structure), structure, nullptr),
|
||||||
_structure(structure)
|
_structure(structure)
|
||||||
{
|
{
|
||||||
for (GSList *entry = sr_dev_inst_channels_get(structure); entry; entry = entry->next)
|
for (GSList *entry = sr_dev_inst_channels_get(structure); entry; entry = entry->next) {
|
||||||
{
|
|
||||||
auto *const ch = static_cast<struct sr_channel *>(entry->data);
|
auto *const ch = static_cast<struct sr_channel *>(entry->data);
|
||||||
unique_ptr<Channel> channel {new Channel{ch}};
|
unique_ptr<Channel> channel {new Channel{ch}};
|
||||||
_channels.insert(make_pair(ch, move(channel)));
|
_channels.emplace(ch, move(channel));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (GSList *entry = sr_dev_inst_channel_groups_get(structure); entry; entry = entry->next)
|
for (GSList *entry = sr_dev_inst_channel_groups_get(structure); entry; entry = entry->next) {
|
||||||
{
|
|
||||||
auto *const cg = static_cast<struct sr_channel_group *>(entry->data);
|
auto *const cg = static_cast<struct sr_channel_group *>(entry->data);
|
||||||
unique_ptr<ChannelGroup> group {new ChannelGroup{this, cg}};
|
unique_ptr<ChannelGroup> group {new ChannelGroup{this, cg}};
|
||||||
_channel_groups.insert(make_pair(group->name(), move(group)));
|
_channel_groups.emplace(group->name(), move(group));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Device::~Device()
|
Device::~Device()
|
||||||
{}
|
{
|
||||||
|
}
|
||||||
|
|
||||||
string Device::vendor() const
|
string Device::vendor() const
|
||||||
{
|
{
|
||||||
|
@ -632,11 +648,10 @@ map<string, shared_ptr<ChannelGroup>>
|
||||||
Device::channel_groups()
|
Device::channel_groups()
|
||||||
{
|
{
|
||||||
map<string, shared_ptr<ChannelGroup>> result;
|
map<string, shared_ptr<ChannelGroup>> result;
|
||||||
for (const auto &entry: _channel_groups)
|
for (const auto &entry: _channel_groups) {
|
||||||
{
|
|
||||||
const auto &name = entry.first;
|
const auto &name = entry.first;
|
||||||
const auto &channel_group = entry.second;
|
const auto &channel_group = entry.second;
|
||||||
result.insert({name, channel_group->share_owned_by(get_shared_from_this())});
|
result.emplace(name, channel_group->share_owned_by(get_shared_from_this()));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -695,7 +710,7 @@ shared_ptr<Channel> UserDevice::add_channel(unsigned int index,
|
||||||
GSList *const last = g_slist_last(sr_dev_inst_channels_get(Device::_structure));
|
GSList *const last = g_slist_last(sr_dev_inst_channels_get(Device::_structure));
|
||||||
auto *const ch = static_cast<struct sr_channel *>(last->data);
|
auto *const ch = static_cast<struct sr_channel *>(last->data);
|
||||||
unique_ptr<Channel> channel {new Channel{ch}};
|
unique_ptr<Channel> channel {new Channel{ch}};
|
||||||
_channels.insert(make_pair(ch, move(channel)));
|
_channels.emplace(ch, move(channel));
|
||||||
return get_channel(ch);
|
return get_channel(ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -918,7 +933,7 @@ Session::Session(shared_ptr<Context> context, string filename) :
|
||||||
for (GSList *dev = dev_list; dev; dev = dev->next) {
|
for (GSList *dev = dev_list; dev; dev = dev->next) {
|
||||||
auto *const sdi = static_cast<struct sr_dev_inst *>(dev->data);
|
auto *const sdi = static_cast<struct sr_dev_inst *>(dev->data);
|
||||||
unique_ptr<SessionDevice> device {new SessionDevice{sdi}};
|
unique_ptr<SessionDevice> device {new SessionDevice{sdi}};
|
||||||
_owned_devices.insert(make_pair(sdi, move(device)));
|
_owned_devices.emplace(sdi, move(device));
|
||||||
}
|
}
|
||||||
_context->_session = this;
|
_context->_session = this;
|
||||||
}
|
}
|
||||||
|
@ -1299,6 +1314,48 @@ vector<const QuantityFlag *> Analog::mq_flags() const
|
||||||
return QuantityFlag::flags_from_mask(_structure->meaning->mqflags);
|
return QuantityFlag::flags_from_mask(_structure->meaning->mqflags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shared_ptr<Logic> Analog::get_logic_via_threshold(float threshold,
|
||||||
|
uint8_t *data_ptr) const
|
||||||
|
{
|
||||||
|
auto datafeed = g_new(struct sr_datafeed_logic, 1);
|
||||||
|
datafeed->length = num_samples();
|
||||||
|
datafeed->unitsize = 1;
|
||||||
|
|
||||||
|
if (data_ptr)
|
||||||
|
datafeed->data = data_ptr;
|
||||||
|
else
|
||||||
|
datafeed->data = g_malloc(datafeed->length);
|
||||||
|
|
||||||
|
shared_ptr<Logic> logic =
|
||||||
|
shared_ptr<Logic>{new Logic{datafeed}, default_delete<Logic>{}};
|
||||||
|
|
||||||
|
check(sr_a2l_threshold(_structure, threshold,
|
||||||
|
(uint8_t*)datafeed->data, datafeed->length));
|
||||||
|
|
||||||
|
return logic;
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_ptr<Logic> Analog::get_logic_via_schmitt_trigger(float lo_thr,
|
||||||
|
float hi_thr, uint8_t *state, uint8_t *data_ptr) const
|
||||||
|
{
|
||||||
|
auto datafeed = g_new(struct sr_datafeed_logic, 1);
|
||||||
|
datafeed->length = num_samples();
|
||||||
|
datafeed->unitsize = 1;
|
||||||
|
|
||||||
|
if (data_ptr)
|
||||||
|
datafeed->data = data_ptr;
|
||||||
|
else
|
||||||
|
datafeed->data = g_malloc(datafeed->length);
|
||||||
|
|
||||||
|
shared_ptr<Logic> logic =
|
||||||
|
shared_ptr<Logic>{new Logic{datafeed}, default_delete<Logic>{}};
|
||||||
|
|
||||||
|
check(sr_a2l_schmitt_trigger(_structure, lo_thr, hi_thr, state,
|
||||||
|
(uint8_t*)datafeed->data, datafeed->length));
|
||||||
|
|
||||||
|
return logic;
|
||||||
|
}
|
||||||
|
|
||||||
Rational::Rational(const struct sr_rational *structure) :
|
Rational::Rational(const struct sr_rational *structure) :
|
||||||
_structure(structure)
|
_structure(structure)
|
||||||
{
|
{
|
||||||
|
@ -1361,15 +1418,14 @@ map<string, shared_ptr<Option>> InputFormat::options()
|
||||||
{
|
{
|
||||||
map<string, shared_ptr<Option>> result;
|
map<string, shared_ptr<Option>> result;
|
||||||
|
|
||||||
if (const struct sr_option **options = sr_input_options_get(_structure))
|
if (const struct sr_option **options = sr_input_options_get(_structure)) {
|
||||||
{
|
|
||||||
shared_ptr<const struct sr_option *> option_array
|
shared_ptr<const struct sr_option *> option_array
|
||||||
{options, &sr_input_options_free};
|
{options, &sr_input_options_free};
|
||||||
for (int i = 0; options[i]; i++) {
|
for (int i = 0; options[i]; i++) {
|
||||||
shared_ptr<Option> opt {
|
shared_ptr<Option> opt {
|
||||||
new Option{options[i], option_array},
|
new Option{options[i], option_array},
|
||||||
default_delete<Option>{}};
|
default_delete<Option>{}};
|
||||||
result.insert({opt->id(), move(opt)});
|
result.emplace(opt->id(), move(opt));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -1392,8 +1448,7 @@ Input::Input(shared_ptr<Context> context, const struct sr_input *structure) :
|
||||||
|
|
||||||
shared_ptr<InputDevice> Input::device()
|
shared_ptr<InputDevice> Input::device()
|
||||||
{
|
{
|
||||||
if (!_device)
|
if (!_device) {
|
||||||
{
|
|
||||||
auto sdi = sr_input_dev_inst_get(_structure);
|
auto sdi = sr_input_dev_inst_get(_structure);
|
||||||
if (!sdi)
|
if (!sdi)
|
||||||
throw Error(SR_ERR_NA);
|
throw Error(SR_ERR_NA);
|
||||||
|
@ -1483,6 +1538,28 @@ vector<Glib::VariantBase> Option::values() const
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Glib::VariantBase Option::parse_string(string value)
|
||||||
|
{
|
||||||
|
enum sr_datatype dt;
|
||||||
|
Glib::VariantBase dflt = default_value();
|
||||||
|
GVariant *tmpl = dflt.gobj();
|
||||||
|
|
||||||
|
if (g_variant_is_of_type(tmpl, G_VARIANT_TYPE_UINT64)) {
|
||||||
|
dt = SR_T_UINT64;
|
||||||
|
} else if (g_variant_is_of_type(tmpl, G_VARIANT_TYPE_STRING)) {
|
||||||
|
dt = SR_T_STRING;
|
||||||
|
} else if (g_variant_is_of_type(tmpl, G_VARIANT_TYPE_BOOLEAN)) {
|
||||||
|
dt = SR_T_BOOL;
|
||||||
|
} else if (g_variant_is_of_type(tmpl, G_VARIANT_TYPE_DOUBLE)) {
|
||||||
|
dt = SR_T_FLOAT;
|
||||||
|
} else if (g_variant_is_of_type(tmpl, G_VARIANT_TYPE_INT32)) {
|
||||||
|
dt = SR_T_INT32;
|
||||||
|
} else {
|
||||||
|
throw Error(SR_ERR_BUG);
|
||||||
|
}
|
||||||
|
return ConfigKey::parse_string(value, dt);
|
||||||
|
}
|
||||||
|
|
||||||
OutputFormat::OutputFormat(const struct sr_output_module *structure) :
|
OutputFormat::OutputFormat(const struct sr_output_module *structure) :
|
||||||
_structure(structure)
|
_structure(structure)
|
||||||
{
|
{
|
||||||
|
@ -1515,15 +1592,14 @@ map<string, shared_ptr<Option>> OutputFormat::options()
|
||||||
{
|
{
|
||||||
map<string, shared_ptr<Option>> result;
|
map<string, shared_ptr<Option>> result;
|
||||||
|
|
||||||
if (const struct sr_option **options = sr_output_options_get(_structure))
|
if (const struct sr_option **options = sr_output_options_get(_structure)) {
|
||||||
{
|
|
||||||
shared_ptr<const struct sr_option *> option_array
|
shared_ptr<const struct sr_option *> option_array
|
||||||
{options, &sr_output_options_free};
|
{options, &sr_output_options_free};
|
||||||
for (int i = 0; options[i]; i++) {
|
for (int i = 0; options[i]; i++) {
|
||||||
shared_ptr<Option> opt {
|
shared_ptr<Option> opt {
|
||||||
new Option{options[i], option_array},
|
new Option{options[i], option_array},
|
||||||
default_delete<Option>{}};
|
default_delete<Option>{}};
|
||||||
result.insert({opt->id(), move(opt)});
|
result.emplace(opt->id(), move(opt));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -1579,14 +1655,11 @@ string Output::receive(shared_ptr<Packet> packet)
|
||||||
{
|
{
|
||||||
GString *out;
|
GString *out;
|
||||||
check(sr_output_send(_structure, packet->_structure, &out));
|
check(sr_output_send(_structure, packet->_structure, &out));
|
||||||
if (out)
|
if (out) {
|
||||||
{
|
|
||||||
auto result = string(out->str, out->str + out->len);
|
auto result = string(out->str, out->str + out->len);
|
||||||
g_string_free(out, true);
|
g_string_free(out, true);
|
||||||
return result;
|
return result;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
return string();
|
return string();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -252,6 +252,8 @@ public:
|
||||||
map<string, shared_ptr<Driver> > drivers();
|
map<string, shared_ptr<Driver> > drivers();
|
||||||
/** Available input formats, indexed by name. */
|
/** Available input formats, indexed by name. */
|
||||||
map<string, shared_ptr<InputFormat> > input_formats();
|
map<string, shared_ptr<InputFormat> > input_formats();
|
||||||
|
/** Lookup the responsible input module for an input file. */
|
||||||
|
shared_ptr<InputFormat> input_format_match(string filename);
|
||||||
/** Available output formats, indexed by name. */
|
/** Available output formats, indexed by name. */
|
||||||
map<string, shared_ptr<OutputFormat> > output_formats();
|
map<string, shared_ptr<OutputFormat> > output_formats();
|
||||||
/** Current log level. */
|
/** Current log level. */
|
||||||
|
@ -283,7 +285,7 @@ public:
|
||||||
/** Create an analog packet. */
|
/** Create an analog packet. */
|
||||||
shared_ptr<Packet> create_analog_packet(
|
shared_ptr<Packet> create_analog_packet(
|
||||||
vector<shared_ptr<Channel> > channels,
|
vector<shared_ptr<Channel> > channels,
|
||||||
float *data_pointer, unsigned int num_samples, const Quantity *mq,
|
const float *data_pointer, unsigned int num_samples, const Quantity *mq,
|
||||||
const Unit *unit, vector<const QuantityFlag *> mqflags);
|
const Unit *unit, vector<const QuantityFlag *> mqflags);
|
||||||
/** Load a saved session.
|
/** Load a saved session.
|
||||||
* @param filename File name string. */
|
* @param filename File name string. */
|
||||||
|
@ -758,6 +760,8 @@ private:
|
||||||
const struct sr_datafeed_logic *_structure;
|
const struct sr_datafeed_logic *_structure;
|
||||||
|
|
||||||
friend class Packet;
|
friend class Packet;
|
||||||
|
friend class Analog;
|
||||||
|
friend struct std::default_delete<Logic>;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Payload of a datafeed packet with analog data */
|
/** Payload of a datafeed packet with analog data */
|
||||||
|
@ -803,6 +807,34 @@ public:
|
||||||
const Unit *unit() const;
|
const Unit *unit() const;
|
||||||
/** Measurement flags associated with the samples in this packet. */
|
/** Measurement flags associated with the samples in this packet. */
|
||||||
vector<const QuantityFlag *> mq_flags() const;
|
vector<const QuantityFlag *> mq_flags() const;
|
||||||
|
/**
|
||||||
|
* Provides a Logic packet that contains a conversion of the analog
|
||||||
|
* data using a simple threshold.
|
||||||
|
*
|
||||||
|
* @param threshold Threshold to use.
|
||||||
|
* @param data_ptr Pointer to num_samples() bytes where the logic
|
||||||
|
* samples are stored. When nullptr, memory for
|
||||||
|
* logic->data_pointer() will be allocated and must
|
||||||
|
* be freed by the caller.
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
* data using a Schmitt-Trigger.
|
||||||
|
*
|
||||||
|
* @param lo_thr Low threshold to use (anything below this is low).
|
||||||
|
* @param hi_thr High threshold to use (anything above this is high).
|
||||||
|
* @param state Points to a byte that contains the current state of the
|
||||||
|
* converter. For best results, set to value of logic
|
||||||
|
* sample n-1.
|
||||||
|
* @param data_ptr Pointer to num_samples() bytes where the logic
|
||||||
|
* samples are stored. When nullptr, memory for
|
||||||
|
* logic->data_pointer() will be allocated and must be
|
||||||
|
* freed by the caller.
|
||||||
|
*/
|
||||||
|
shared_ptr<Logic> get_logic_via_schmitt_trigger(float lo_thr,
|
||||||
|
float hi_thr, uint8_t *state, uint8_t *data_ptr=nullptr) const;
|
||||||
private:
|
private:
|
||||||
explicit Analog(const struct sr_datafeed_analog *structure);
|
explicit Analog(const struct sr_datafeed_analog *structure);
|
||||||
~Analog();
|
~Analog();
|
||||||
|
@ -917,6 +949,8 @@ public:
|
||||||
Glib::VariantBase default_value() const;
|
Glib::VariantBase default_value() const;
|
||||||
/** Possible values for this option, if a limited set. */
|
/** Possible values for this option, if a limited set. */
|
||||||
vector<Glib::VariantBase> values() const;
|
vector<Glib::VariantBase> values() const;
|
||||||
|
/** Parse a string argument into the appropriate type for this option. */
|
||||||
|
Glib::VariantBase parse_string(string value);
|
||||||
private:
|
private:
|
||||||
Option(const struct sr_option *structure,
|
Option(const struct sr_option *structure,
|
||||||
shared_ptr<const struct sr_option *> structure_array);
|
shared_ptr<const struct sr_option *> structure_array);
|
||||||
|
|
|
@ -45,6 +45,8 @@ which provides access to the error code and description."
|
||||||
%module(docstring=DOCSTRING) classes
|
%module(docstring=DOCSTRING) classes
|
||||||
|
|
||||||
%{
|
%{
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <pygobject.h>
|
#include <pygobject.h>
|
||||||
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
|
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
|
||||||
|
@ -53,8 +55,6 @@ which provides access to the error code and description."
|
||||||
PyObject *PyGObject_lib;
|
PyObject *PyGObject_lib;
|
||||||
PyObject *GLib;
|
PyObject *GLib;
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#if PYGOBJECT_FLAGS_SIGNED
|
#if PYGOBJECT_FLAGS_SIGNED
|
||||||
typedef gint pyg_flags_type;
|
typedef gint pyg_flags_type;
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -41,10 +41,10 @@ which provides access to the error code and description."
|
||||||
%module(docstring=DOCSTRING) sigrok
|
%module(docstring=DOCSTRING) sigrok
|
||||||
|
|
||||||
%{
|
%{
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <glibmm.h>
|
#include <glibmm.h>
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
%include "../swig/templates.i"
|
%include "../swig/templates.i"
|
||||||
|
|
34
configure.ac
34
configure.ac
|
@ -99,8 +99,7 @@ SR_EXTRA_CXX_LIBS=
|
||||||
SR_ARG_OPT_PKG([libserialport], [LIBSERIALPORT], [NEED_SERIAL],
|
SR_ARG_OPT_PKG([libserialport], [LIBSERIALPORT], [NEED_SERIAL],
|
||||||
[libserialport >= 0.1.1])
|
[libserialport >= 0.1.1])
|
||||||
|
|
||||||
SR_ARG_OPT_PKG([libftdi], [LIBFTDI],,
|
SR_ARG_OPT_PKG([libftdi], [LIBFTDI], , [libftdi1 >= 1.0])
|
||||||
[libftdi1 >= 1.0], [libftdi >= 0.16])
|
|
||||||
|
|
||||||
# FreeBSD comes with an "integrated" libusb-1.0-style USB API.
|
# 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.
|
# This means libusb-1.0 is always available; no need to check for it.
|
||||||
|
@ -234,18 +233,24 @@ SR_DRIVER([ChronoVu LA], [chronovu-la], [libusb libftdi])
|
||||||
SR_DRIVER([Colead SLM], [colead-slm], [libserialport])
|
SR_DRIVER([Colead SLM], [colead-slm], [libserialport])
|
||||||
SR_DRIVER([Conrad DIGI 35 CPU], [conrad-digi-35-cpu], [libserialport])
|
SR_DRIVER([Conrad DIGI 35 CPU], [conrad-digi-35-cpu], [libserialport])
|
||||||
SR_DRIVER([demo], [demo])
|
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], [libserialport])
|
||||||
SR_DRIVER([FTDI LA], [ftdi-la], [libusb libftdi])
|
SR_DRIVER([FTDI LA], [ftdi-la], [libusb libftdi])
|
||||||
SR_DRIVER([fx2lafw], [fx2lafw], [libusb])
|
SR_DRIVER([fx2lafw], [fx2lafw], [libusb])
|
||||||
SR_DRIVER([GMC MH 1x/2x], [gmc-mh-1x-2x], [libserialport])
|
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 GDS-800], [gwinstek-gds-800], [libserialport])
|
||||||
|
SR_DRIVER([GW Instek GPD], [gwinstek-gpd], [libserialport])
|
||||||
SR_DRIVER([Hameg HMO], [hameg-hmo], [libserialport])
|
SR_DRIVER([Hameg HMO], [hameg-hmo], [libserialport])
|
||||||
|
SR_DRIVER([Hantek 4032L], [hantek-4032l], [libusb])
|
||||||
SR_DRIVER([Hantek 6xxx], [hantek-6xxx], [libusb])
|
SR_DRIVER([Hantek 6xxx], [hantek-6xxx], [libusb])
|
||||||
SR_DRIVER([Hantek DSO], [hantek-dso], [libusb])
|
SR_DRIVER([Hantek DSO], [hantek-dso], [libusb])
|
||||||
SR_DRIVER([HP 3457A], [hp-3457a])
|
SR_DRIVER([HP 3457A], [hp-3457a])
|
||||||
|
SR_DRIVER([HP 3478A], [hp-3478a], [libgpib])
|
||||||
SR_DRIVER([Hung-Chang DSO-2100], [hung-chang-dso-2100], [libieee1284])
|
SR_DRIVER([Hung-Chang DSO-2100], [hung-chang-dso-2100], [libieee1284])
|
||||||
SR_DRIVER([Ikalogic Scanalogic-2], [ikalogic-scanalogic2], [libusb])
|
SR_DRIVER([Ikalogic Scanalogic-2], [ikalogic-scanalogic2], [libusb])
|
||||||
SR_DRIVER([Ikalogic Scanaplus], [ikalogic-scanaplus], [libftdi])
|
SR_DRIVER([Ikalogic Scanaplus], [ikalogic-scanaplus], [libftdi])
|
||||||
|
SR_DRIVER([IPDBG LA], [ipdbg-la])
|
||||||
SR_DRIVER([Kecheng KC-330B], [kecheng-kc-330b], [libusb])
|
SR_DRIVER([Kecheng KC-330B], [kecheng-kc-330b], [libusb])
|
||||||
SR_DRIVER([KERN scale], [kern-scale], [libserialport])
|
SR_DRIVER([KERN scale], [kern-scale], [libserialport])
|
||||||
SR_DRIVER([Korad KAxxxxP], [korad-kaxxxxp], [libserialport])
|
SR_DRIVER([Korad KAxxxxP], [korad-kaxxxxp], [libserialport])
|
||||||
|
@ -260,12 +265,15 @@ SR_DRIVER([Norma DMM], [norma-dmm], [libserialport])
|
||||||
SR_DRIVER([OpenBench Logic Sniffer], [openbench-logic-sniffer], [libserialport])
|
SR_DRIVER([OpenBench Logic Sniffer], [openbench-logic-sniffer], [libserialport])
|
||||||
SR_DRIVER([PCE PCE-322A], [pce-322a], [libserialport])
|
SR_DRIVER([PCE PCE-322A], [pce-322a], [libserialport])
|
||||||
SR_DRIVER([Pipistrello-OLS], [pipistrello-ols], [libftdi])
|
SR_DRIVER([Pipistrello-OLS], [pipistrello-ols], [libftdi])
|
||||||
|
SR_DRIVER([RDTech DPSxxxx/DPHxxxx], [rdtech-dps], [libserialport])
|
||||||
SR_DRIVER([Rigol DS], [rigol-ds])
|
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], [libserialport])
|
||||||
SR_DRIVER([Saleae Logic16], [saleae-logic16], [libusb])
|
SR_DRIVER([Saleae Logic16], [saleae-logic16], [libusb])
|
||||||
|
SR_DRIVER([Saleae Logic Pro], [saleae-logic-pro], [libusb])
|
||||||
SR_DRIVER([SCPI PPS], [scpi-pps])
|
SR_DRIVER([SCPI PPS], [scpi-pps])
|
||||||
SR_DRIVER([serial DMM], [serial-dmm], [libserialport])
|
SR_DRIVER([serial DMM], [serial-dmm], [libserialport])
|
||||||
SR_DRIVER([serial LCR], [serial-lcr], [libserialport])
|
SR_DRIVER([serial LCR], [serial-lcr], [libserialport])
|
||||||
|
SR_DRIVER([Siglent SDS], [siglent-sds])
|
||||||
SR_DRIVER([Sysclk LWLA], [sysclk-lwla], [libusb])
|
SR_DRIVER([Sysclk LWLA], [sysclk-lwla], [libusb])
|
||||||
SR_DRIVER([Teleinfo], [teleinfo], [libserialport])
|
SR_DRIVER([Teleinfo], [teleinfo], [libserialport])
|
||||||
SR_DRIVER([Testo], [testo], [libusb])
|
SR_DRIVER([Testo], [testo], [libusb])
|
||||||
|
@ -275,6 +283,7 @@ SR_DRIVER([UNI-T UT32x], [uni-t-ut32x], [libusb])
|
||||||
SR_DRIVER([Victor DMM], [victor-dmm], [libusb])
|
SR_DRIVER([Victor DMM], [victor-dmm], [libusb])
|
||||||
SR_DRIVER([Yokogawa DL/DLM], [yokogawa-dlm])
|
SR_DRIVER([Yokogawa DL/DLM], [yokogawa-dlm])
|
||||||
SR_DRIVER([ZEROPLUS Logic Cube], [zeroplus-logic-cube], [libusb])
|
SR_DRIVER([ZEROPLUS Logic Cube], [zeroplus-logic-cube], [libusb])
|
||||||
|
SR_DRIVER([ZKETECH EBD-USB], [zketech-ebd-usb], [libserialport])
|
||||||
|
|
||||||
###############################
|
###############################
|
||||||
## Language bindings setup ##
|
## Language bindings setup ##
|
||||||
|
@ -604,3 +613,24 @@ Enabled language bindings:
|
||||||
- Java............................ $BINDINGS_JAVA$sr_report_java
|
- Java............................ $BINDINGS_JAVA$sr_report_java
|
||||||
|
|
||||||
_EOF
|
_EOF
|
||||||
|
|
||||||
|
# Emit a warning if the C++ bindings are not being built.
|
||||||
|
AM_COND_IF([BINDINGS_CXX], [], [
|
||||||
|
cat >&AS_MESSAGE_FD <<_EOF
|
||||||
|
===============================================================================
|
||||||
|
WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
|
||||||
|
===============================================================================
|
||||||
|
=== ===
|
||||||
|
=== The libsigrok C++ bindings are not being built since you ===
|
||||||
|
=== are missing one or more dependencies (see above)! ===
|
||||||
|
=== ===
|
||||||
|
=== This means you won't be able to compile frontends that require ===
|
||||||
|
=== the C++ bindings (such as PulseView)! You also won't be able to build ===
|
||||||
|
=== other bindings and frontends using those (such as sigrok-meter)! ===
|
||||||
|
=== ===
|
||||||
|
===============================================================================
|
||||||
|
WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
|
||||||
|
===============================================================================
|
||||||
|
|
||||||
|
_EOF
|
||||||
|
])
|
||||||
|
|
|
@ -0,0 +1,298 @@
|
||||||
|
##
|
||||||
|
## This file is part of the libsigrok project.
|
||||||
|
##
|
||||||
|
## Copyright (C) 2010-2013 Uwe Hermann <uwe@hermann-uwe.de>
|
||||||
|
##
|
||||||
|
## 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/>.
|
||||||
|
##
|
||||||
|
|
||||||
|
#
|
||||||
|
# These rules do not grant any permission by itself, but flag devices
|
||||||
|
# supported by libsigrok.
|
||||||
|
# The access policy is stored in the 61-libsigrok-plugdev.rules and
|
||||||
|
# 61-libsigrok-uaccess.rules.
|
||||||
|
#
|
||||||
|
# Note: Any syntax changes here will need to be tested against the
|
||||||
|
# 'update-device-filter' Makefile target in the sigrok-androidutils
|
||||||
|
# repo, since that parses this file.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Please keep this list sorted alphabetically by vendor/device name.
|
||||||
|
#
|
||||||
|
|
||||||
|
ACTION!="add|change", GOTO="libsigrok_rules_end"
|
||||||
|
SUBSYSTEM!="usb|usbmisc|usb_device", GOTO="libsigrok_rules_end"
|
||||||
|
|
||||||
|
# Agilent USBTMC-connected devices
|
||||||
|
# 34405A
|
||||||
|
ATTRS{idVendor}=="0957", ATTRS{idProduct}=="0618", ENV{ID_SIGROK}="1"
|
||||||
|
# 34410A
|
||||||
|
ATTRS{idVendor}=="0957", ATTRS{idProduct}=="0607", ENV{ID_SIGROK}="1"
|
||||||
|
# DSO1000 series
|
||||||
|
ATTRS{idVendor}=="0957", ATTRS{idProduct}=="0588", ENV{ID_SIGROK}="1"
|
||||||
|
# MSO7000A series
|
||||||
|
ATTRS{idVendor}=="0957", ATTRS{idProduct}=="1735", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# ASIX SIGMA
|
||||||
|
# ASIX SIGMA2
|
||||||
|
ATTRS{idVendor}=="a600", ATTRS{idProduct}=="a000", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# Braintechnology USB-LPS
|
||||||
|
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"
|
||||||
|
|
||||||
|
# CWAV USBee AX
|
||||||
|
# ARMFLY AX-Pro (clone of the CWAV USBee AX)
|
||||||
|
# ARMFLY Mini-Logic (clone of the CWAV USBee AX)
|
||||||
|
# EE Electronics ESLA201A (clone of the CWAV USBee AX)
|
||||||
|
# HT USBee-AxPro (clone of the CWAV USBee AX)
|
||||||
|
# MCU123 USBee AX Pro clone (clone of the CWAV USBee AX)
|
||||||
|
# Noname LHT00SU1 (clone of the CWAV USBee AX)
|
||||||
|
# XZL_Studio AX (clone of the CWAV USBee AX)
|
||||||
|
ATTRS{idVendor}=="08a9", ATTRS{idProduct}=="0014", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# CWAV USBee DX
|
||||||
|
# HT USBee-DxPro (clone of the CWAV USBee DX), not yet supported!
|
||||||
|
# XZL_Studio DX (clone of the CWAV USBee DX)
|
||||||
|
ATTRS{idVendor}=="08a9", ATTRS{idProduct}=="0015", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# CWAV USBee SX
|
||||||
|
ATTRS{idVendor}=="08a9", ATTRS{idProduct}=="0009", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# CWAV USBee ZX
|
||||||
|
ATTRS{idVendor}=="08a9", ATTRS{idProduct}=="0005", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# Cypress FX2 eval boards without EEPROM:
|
||||||
|
# Lcsoft Mini Board
|
||||||
|
# Braintechnology USB Interface V2.x
|
||||||
|
# fx2grok-tiny
|
||||||
|
ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="8613", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# Dangerous Prototypes Buspirate (v3)
|
||||||
|
# ChronoVu LA8 (old VID/PID)
|
||||||
|
# ChronoVu LA16 (old VID/PID)
|
||||||
|
# ftdi-la
|
||||||
|
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# Dangerous Prototypes Buspirate (v4)
|
||||||
|
ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="fb00", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# DreamSourceLab DSLogic
|
||||||
|
ATTRS{idVendor}=="2a0e", ATTRS{idProduct}=="0001", ENV{ID_SIGROK}="1"
|
||||||
|
# DreamSourceLab DSLogic Pro
|
||||||
|
ATTRS{idVendor}=="2a0e", ATTRS{idProduct}=="0003", ENV{ID_SIGROK}="1"
|
||||||
|
# DreamSourceLab DScope
|
||||||
|
ATTRS{idVendor}=="2a0e", ATTRS{idProduct}=="0002", ENV{ID_SIGROK}="1"
|
||||||
|
# DreamSourceLab DSLogic Plus
|
||||||
|
ATTRS{idVendor}=="2a0e", ATTRS{idProduct}=="0020", ENV{ID_SIGROK}="1"
|
||||||
|
# DreamSourceLab DSLogic Basic
|
||||||
|
ATTRS{idVendor}=="2a0e", ATTRS{idProduct}=="0021", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# HAMEG HO720
|
||||||
|
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="ed72", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# HAMEG HO730
|
||||||
|
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="ed73", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# Hantek DSO-2090
|
||||||
|
# lsusb: "04b4:2090 Cypress Semiconductor Corp."
|
||||||
|
# lsusb after FW upload: "04b5:2090 ROHM LSI Systems USA, LLC"
|
||||||
|
ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="2090", ENV{ID_SIGROK}="1"
|
||||||
|
ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="2090", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# Hantek DSO-2150
|
||||||
|
# lsusb: "04b4:2150 Cypress Semiconductor Corp."
|
||||||
|
# lsusb after FW upload: "04b5:2150 ROHM LSI Systems USA, LLC"
|
||||||
|
ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="2150", ENV{ID_SIGROK}="1"
|
||||||
|
ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="2150", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# Hantek DSO-2250
|
||||||
|
# lsusb: "04b4:2250 Cypress Semiconductor Corp."
|
||||||
|
# lsusb after FW upload: "04b5:2250 ROHM LSI Systems USA, LLC"
|
||||||
|
ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="2250", ENV{ID_SIGROK}="1"
|
||||||
|
ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="2250", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# Hantek DSO-5200
|
||||||
|
# lsusb: "04b4:5200 Cypress Semiconductor Corp."
|
||||||
|
# lsusb after FW upload: "04b5:5200 ROHM LSI Systems USA, LLC"
|
||||||
|
ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="5200", ENV{ID_SIGROK}="1"
|
||||||
|
ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="5200", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# Hantek DSO-5200A
|
||||||
|
# lsusb: "04b4:520a Cypress Semiconductor Corp."
|
||||||
|
# lsusb after FW upload: "04b5:520a ROHM LSI Systems USA, LLC"
|
||||||
|
ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="520a", ENV{ID_SIGROK}="1"
|
||||||
|
ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="520a", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# Hantek 6022BE, renumerates as 1d50:608e "sigrok fx2lafw", Serial: Hantek 6022BE
|
||||||
|
ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="6022", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# Hantek 6022BL, renumerates as 1d50:608e "sigrok fx2lafw", Serial: Hantek 6022BL
|
||||||
|
ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="602a", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# Hantek 4032L
|
||||||
|
ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="4032", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# IKALOGIC Scanalogic-2
|
||||||
|
ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="4123", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# IKALOGIC ScanaPLUS
|
||||||
|
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6014", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# Kecheng KC-330B
|
||||||
|
ATTRS{idVendor}=="1041", ATTRS{idProduct}=="8101", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# Lascar Electronics EL-USB-2
|
||||||
|
# Lascar Electronics EL-USB-CO
|
||||||
|
# This is actually the generic SiLabs (Cygnal) F32x USBXpress VID:PID.
|
||||||
|
ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="0002", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# LeCroy LogicStudio16
|
||||||
|
ATTRS{idVendor}=="05ff", ATTRS{idProduct}=="a001", ENV{ID_SIGROK}="1"
|
||||||
|
ATTRS{idVendor}=="05ff", ATTRS{idProduct}=="a002", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# Link Instruments MSO-19
|
||||||
|
ATTRS{idVendor}=="3195", ATTRS{idProduct}=="f190", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# Logic Shrimp
|
||||||
|
ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="fa95", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# MiniLA Mockup
|
||||||
|
# ftdi-la
|
||||||
|
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6010", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# MIC 98581
|
||||||
|
# MIC 98583
|
||||||
|
# Tondaj SL-814
|
||||||
|
ATTRS{idVendor}=="067b", ATTRS{idProduct}=="2303", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# Openbench Logic Sniffer
|
||||||
|
ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="000a", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# Rigol DS1000 series
|
||||||
|
ATTRS{idVendor}=="1ab1", ATTRS{idProduct}=="0588", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# Rigol 1000Z series
|
||||||
|
ATTRS{idVendor}=="1ab1", ATTRS{idProduct}=="04ce", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# Rigol DS2000 series
|
||||||
|
ATTRS{idVendor}=="1ab1", ATTRS{idProduct}=="04b0", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# Rigol DS4000 series
|
||||||
|
ATTRS{idVendor}=="1ab1", ATTRS{idProduct}=="04b1", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# Rigol DG4000 series
|
||||||
|
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
|
||||||
|
ATTRS{idVendor}=="0aad", ATTRS{idProduct}=="0118", ENV{ID_SIGROK}="1"
|
||||||
|
ATTRS{idVendor}=="0aad", ATTRS{idProduct}=="0119", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# Sainsmart DDS120 / Rocktech BM102, renumerates as 1d50:608e "sigrok fx2lafw", Serial: Sainsmart DDS120
|
||||||
|
ATTRS{idVendor}=="8102", ATTRS{idProduct}=="8102", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# Saleae Logic
|
||||||
|
# EE Electronics ESLA100 (clone of the Saleae Logic)
|
||||||
|
# Hantek 6022BL in LA mode (clone of the Saleae Logic)
|
||||||
|
# Instrustar ISDS205X in LA mode (clone of the Saleae Logic)
|
||||||
|
# Robomotic MiniLogic (clone of the Saleae Logic)
|
||||||
|
# Robomotic BugLogic 3 (clone of the Saleae Logic)
|
||||||
|
# MCU123 Saleae Logic clone (clone of the Saleae Logic)
|
||||||
|
ATTRS{idVendor}=="0925", ATTRS{idProduct}=="3881", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# Saleae Logic16
|
||||||
|
ATTRS{idVendor}=="21a9", ATTRS{idProduct}=="1001", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# Saleae Logic Pro 16
|
||||||
|
ATTRS{idVendor}=="21a9", ATTRS{idProduct}=="1006", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# Siglent USBTMC devices.
|
||||||
|
# f4ec:ee3a: E.g. SDS1052DL+ 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"
|
||||||
|
|
||||||
|
# sigrok FX2 LA (8ch)
|
||||||
|
# fx2grok-flat (before and after renumeration)
|
||||||
|
ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="608c", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# sigrok FX2 LA (16ch)
|
||||||
|
ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="608d", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# sigrok FX2 DSO (2ch)
|
||||||
|
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
|
||||||
|
ATTRS{idVendor}=="2961", ATTRS{idProduct}=="6688", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
# SysClk LWLA1034
|
||||||
|
ATTRS{idVendor}=="2961", ATTRS{idProduct}=="6689", 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"
|
||||||
|
|
||||||
|
# ZEROPLUS Logic Cube LAP-C series
|
||||||
|
# There are various devices in the ZEROPLUS Logic Cube series:
|
||||||
|
# 0c12:7002: LAP-16128U
|
||||||
|
# 0c12:7009: LAP-C(16064)
|
||||||
|
# 0c12:700a: LAP-C(16128)
|
||||||
|
# 0c12:700b: LAP-C(32128)
|
||||||
|
# 0c12:700c: LAP-C(321000)
|
||||||
|
# 0c12:700d: LAP-C(322000)
|
||||||
|
# 0c12:700e: LAP-C(16032)
|
||||||
|
# 0c12:7016: LAP-C(162000)
|
||||||
|
# 0c12:7025: LAP-C(16128+)
|
||||||
|
# 0c12:7100: AKIP-9101
|
||||||
|
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="7002", ENV{ID_SIGROK}="1"
|
||||||
|
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="7007", ENV{ID_SIGROK}="1"
|
||||||
|
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="7009", ENV{ID_SIGROK}="1"
|
||||||
|
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="700a", ENV{ID_SIGROK}="1"
|
||||||
|
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="700b", ENV{ID_SIGROK}="1"
|
||||||
|
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="700c", ENV{ID_SIGROK}="1"
|
||||||
|
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="700d", ENV{ID_SIGROK}="1"
|
||||||
|
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="700e", ENV{ID_SIGROK}="1"
|
||||||
|
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="7016", ENV{ID_SIGROK}="1"
|
||||||
|
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="7025", ENV{ID_SIGROK}="1"
|
||||||
|
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="7100", ENV{ID_SIGROK}="1"
|
||||||
|
|
||||||
|
LABEL="libsigrok_rules_end"
|
|
@ -0,0 +1,31 @@
|
||||||
|
##
|
||||||
|
## This file is part of the libsigrok project.
|
||||||
|
##
|
||||||
|
## Copyright (C) 2017 Stefan Bruens <stefan.bruens@rwth-aachen.de>
|
||||||
|
##
|
||||||
|
## 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/>.
|
||||||
|
##
|
||||||
|
|
||||||
|
# Grant access permissions to users who are in the "plugdev" group.
|
||||||
|
# "plugdev" is typically used on Debian based distributions and may not
|
||||||
|
# exist elsewhere.
|
||||||
|
#
|
||||||
|
# This file, when installed, must be installed with a name lexicographically
|
||||||
|
# sorted later than the accompanied 60-libsigrok.rules
|
||||||
|
|
||||||
|
ACTION!="add|change", GOTO="libsigrok_rules_plugdev_end"
|
||||||
|
|
||||||
|
ENV{ID_SIGROK}=="1", MODE="660", GROUP="plugdev"
|
||||||
|
|
||||||
|
LABEL="libsigrok_rules_plugdev_end"
|
|
@ -0,0 +1,32 @@
|
||||||
|
##
|
||||||
|
## This file is part of the libsigrok project.
|
||||||
|
##
|
||||||
|
## Copyright (C) 2017 Stefan Bruens <stefan.bruens@rwth-aachen.de>
|
||||||
|
##
|
||||||
|
## 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/>.
|
||||||
|
##
|
||||||
|
|
||||||
|
# Grant access permissions to users who are currently logged in locally.
|
||||||
|
# This is the default policy for systems using systemd-logind (or a
|
||||||
|
# compatible replacement).
|
||||||
|
#
|
||||||
|
# This file, when installed, must be installed with a name lexicographically
|
||||||
|
# sorted later than the accompanied 60-libsigrok.rules, and earlier than
|
||||||
|
# the systemd upstream 71-seat.rules.
|
||||||
|
|
||||||
|
ACTION!="add|change", GOTO="libsigrok_rules_uaccess_end"
|
||||||
|
|
||||||
|
ENV{ID_SIGROK}=="1", TAG+="uaccess"
|
||||||
|
|
||||||
|
LABEL="libsigrok_rules_uaccess_end"
|
|
@ -1,243 +0,0 @@
|
||||||
##
|
|
||||||
## This file is part of the libsigrok project.
|
|
||||||
##
|
|
||||||
## Copyright (C) 2010-2013 Uwe Hermann <uwe@hermann-uwe.de>
|
|
||||||
##
|
|
||||||
## 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/>.
|
|
||||||
##
|
|
||||||
|
|
||||||
# NOTE: On a systemd based system, using tag=uaccess, this file _must_ be
|
|
||||||
# named/numbered to come before the seat rules are applied in 70-xxx.
|
|
||||||
|
|
||||||
##
|
|
||||||
## Please keep this list sorted alphabetically by vendor/device name.
|
|
||||||
##
|
|
||||||
|
|
||||||
ACTION!="add|change", GOTO="libsigrok_rules_end"
|
|
||||||
SUBSYSTEM!="usb|usbmisc|usb_device", GOTO="libsigrok_rules_end"
|
|
||||||
|
|
||||||
# Agilent USBTMC-connected devices
|
|
||||||
# 34405A
|
|
||||||
ATTRS{idVendor}=="0957", ATTRS{idProduct}=="0618", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
# 34410A
|
|
||||||
ATTRS{idVendor}=="0957", ATTRS{idProduct}=="0607", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
# DSO1000 series
|
|
||||||
ATTRS{idVendor}=="0957", ATTRS{idProduct}=="0588", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# ASIX SIGMA
|
|
||||||
# ASIX SIGMA2
|
|
||||||
ATTRS{idVendor}=="a600", ATTRS{idProduct}=="a000", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# Braintechnology USB-LPS
|
|
||||||
ATTRS{idVendor}=="16d0", ATTRS{idProduct}=="0498", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# CEM DT-8852
|
|
||||||
ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# ChronoVu LA8 (new VID/PID)
|
|
||||||
# ChronoVu LA16 (new VID/PID)
|
|
||||||
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8867", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# CWAV USBee AX
|
|
||||||
# ARMFLY AX-Pro (clone of the CWAV USBee AX)
|
|
||||||
# ARMFLY Mini-Logic (clone of the CWAV USBee AX)
|
|
||||||
# EE Electronics ESLA201A (clone of the CWAV USBee AX)
|
|
||||||
# MCU123 USBee AX Pro clone (clone of the CWAV USBee AX)
|
|
||||||
# XZL_Studio AX (clone of the CWAV USBee AX)
|
|
||||||
ATTRS{idVendor}=="08a9", ATTRS{idProduct}=="0014", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# CWAV USBee DX
|
|
||||||
# XZL_Studio DX (clone of the CWAV USBee DX)
|
|
||||||
ATTRS{idVendor}=="08a9", ATTRS{idProduct}=="0015", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# CWAV USBee SX
|
|
||||||
ATTRS{idVendor}=="08a9", ATTRS{idProduct}=="0009", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# Cypress FX2 eval boards without EEPROM:
|
|
||||||
# Lcsoft Mini Board
|
|
||||||
# Braintechnology USB Interface V2.x
|
|
||||||
ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="8613", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# Dangerous Prototypes Buspirate (v3)
|
|
||||||
# ChronoVu LA8 (old VID/PID)
|
|
||||||
# ChronoVu LA16 (old VID/PID)
|
|
||||||
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# Dangerous Prototypes Buspirate (v4)
|
|
||||||
ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="fb00", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# DreamSourceLab DSLogic
|
|
||||||
ATTRS{idVendor}=="2a0e", ATTRS{idProduct}=="0001", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
# DreamSourceLab DSLogic Pro
|
|
||||||
ATTRS{idVendor}=="2a0e", ATTRS{idProduct}=="0003", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
# DreamSourceLab DScope
|
|
||||||
ATTRS{idVendor}=="2a0e", ATTRS{idProduct}=="0002", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# HAMEG HO720
|
|
||||||
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="ed72", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# HAMEG HO730
|
|
||||||
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="ed73", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# Hantek DSO-2090
|
|
||||||
# lsusb: "04b4:2090 Cypress Semiconductor Corp."
|
|
||||||
# lsusb after FW upload: "04b5:2090 ROHM LSI Systems USA, LLC"
|
|
||||||
ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="2090", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="2090", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# Hantek DSO-2150
|
|
||||||
# lsusb: "04b4:2150 Cypress Semiconductor Corp."
|
|
||||||
# lsusb after FW upload: "04b5:2150 ROHM LSI Systems USA, LLC"
|
|
||||||
ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="2150", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="2150", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# Hantek DSO-2250
|
|
||||||
# lsusb: "04b4:2250 Cypress Semiconductor Corp."
|
|
||||||
# lsusb after FW upload: "04b5:2250 ROHM LSI Systems USA, LLC"
|
|
||||||
ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="2250", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="2250", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# Hantek DSO-5200
|
|
||||||
# lsusb: "04b4:5200 Cypress Semiconductor Corp."
|
|
||||||
# lsusb after FW upload: "04b5:5200 ROHM LSI Systems USA, LLC"
|
|
||||||
ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="5200", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="5200", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# Hantek DSO-5200A
|
|
||||||
# lsusb: "04b4:520a Cypress Semiconductor Corp."
|
|
||||||
# lsusb after FW upload: "04b5:520a ROHM LSI Systems USA, LLC"
|
|
||||||
ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="520a", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="520a", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# Hantek 6022BE
|
|
||||||
ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="6022", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="608e", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# Hantek 6022BL
|
|
||||||
ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="602a", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="608e", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# IKALOGIC Scanalogic-2
|
|
||||||
ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="4123", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# IKALOGIC ScanaPLUS
|
|
||||||
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6014", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# Kecheng KC-330B
|
|
||||||
ATTRS{idVendor}=="1041", ATTRS{idProduct}=="8101", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# Lascar Electronics EL-USB-2
|
|
||||||
# Lascar Electronics EL-USB-CO
|
|
||||||
# This is actually the generic SiLabs (Cygnal) F32x USBXpress VID:PID.
|
|
||||||
ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="0002", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# LeCroy LogicStudio16
|
|
||||||
ATTRS{idVendor}=="05ff", ATTRS{idProduct}=="a001", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
ATTRS{idVendor}=="05ff", ATTRS{idProduct}=="a002", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# Link Instruments MSO-19
|
|
||||||
ATTRS{idVendor}=="3195", ATTRS{idProduct}=="f190", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# Logic Shrimp
|
|
||||||
ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="fa95", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# MiniLA Mockup
|
|
||||||
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6010", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# MIC 98581
|
|
||||||
# MIC 98583
|
|
||||||
# Tondaj SL-814
|
|
||||||
ATTRS{idVendor}=="067b", ATTRS{idProduct}=="2303", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# Openbench Logic Sniffer
|
|
||||||
ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="000a", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# Rigol DS1000 series
|
|
||||||
ATTRS{idVendor}=="1ab1", ATTRS{idProduct}=="0588", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# Rigol 1000Z series
|
|
||||||
ATTRS{idVendor}=="1ab1", ATTRS{idProduct}=="04ce", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# Rigol DS2000 series
|
|
||||||
ATTRS{idVendor}=="1ab1", ATTRS{idProduct}=="04b0", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# Rigol DG4000 series
|
|
||||||
ATTRS{idVendor}=="1ab1", ATTRS{idProduct}=="0641", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# Rohde&Schwarz HMO1002 Series VCP/USBTMC mode
|
|
||||||
ATTRS{idVendor}=="0aad", ATTRS{idProduct}=="0118", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
ATTRS{idVendor}=="0aad", ATTRS{idProduct}=="0119", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# Sainsmart DDS120 / Rocktech BM102
|
|
||||||
ATTRS{idVendor}=="8102", ATTRS{idProduct}=="8102", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="608e", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# Saleae Logic
|
|
||||||
# EE Electronics ESLA100 (clone of the Saleae Logic)
|
|
||||||
# Robomotic MiniLogic (clone of the Saleae Logic)
|
|
||||||
# Robomotic BugLogic 3 (clone of the Saleae Logic)
|
|
||||||
# MCU123 Saleae Logic clone (clone of the Saleae Logic)
|
|
||||||
ATTRS{idVendor}=="0925", ATTRS{idProduct}=="3881", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# Saleae Logic16
|
|
||||||
ATTRS{idVendor}=="21a9", ATTRS{idProduct}=="1001", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# sigrok FX2 LA (8ch)
|
|
||||||
ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="608c", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# sigrok FX2 LA (16ch)
|
|
||||||
ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="608d", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# SysClk LWLA1016
|
|
||||||
ATTRS{idVendor}=="2961", ATTRS{idProduct}=="6688", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# SysClk LWLA1034
|
|
||||||
ATTRS{idVendor}=="2961", ATTRS{idProduct}=="6689", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# Testo 435
|
|
||||||
ATTRS{idVendor}=="128d", ATTRS{idProduct}=="0003", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# 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", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# 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", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# Victor 70C
|
|
||||||
# Victor 86C
|
|
||||||
ATTRS{idVendor}=="1244", ATTRS{idProduct}=="d237", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
# ZEROPLUS Logic Cube LAP-C series
|
|
||||||
# There are various devices in the ZEROPLUS Logic Cube series:
|
|
||||||
# 0c12:7002: LAP-16128U
|
|
||||||
# 0c12:7009: LAP-C(16064)
|
|
||||||
# 0c12:700a: LAP-C(16128)
|
|
||||||
# 0c12:700b: LAP-C(32128)
|
|
||||||
# 0c12:700c: LAP-C(321000)
|
|
||||||
# 0c12:700d: LAP-C(322000)
|
|
||||||
# 0c12:700e: LAP-C(16032)
|
|
||||||
# 0c12:7016: LAP-C(162000)
|
|
||||||
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="7002", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="7009", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="700a", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="700b", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="700c", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="700d", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="700e", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="7016", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
|
||||||
|
|
||||||
LABEL="libsigrok_rules_end"
|
|
|
@ -84,11 +84,11 @@ enum sr_error_code {
|
||||||
|
|
||||||
/* Handy little macros */
|
/* Handy little macros */
|
||||||
#define SR_HZ(n) (n)
|
#define SR_HZ(n) (n)
|
||||||
#define SR_KHZ(n) ((n) * (uint64_t)(1000ULL))
|
#define SR_KHZ(n) ((n) * UINT64_C(1000))
|
||||||
#define SR_MHZ(n) ((n) * (uint64_t)(1000000ULL))
|
#define SR_MHZ(n) ((n) * UINT64_C(1000000))
|
||||||
#define SR_GHZ(n) ((n) * (uint64_t)(1000000000ULL))
|
#define SR_GHZ(n) ((n) * UINT64_C(1000000000))
|
||||||
|
|
||||||
#define SR_HZ_TO_NS(n) ((uint64_t)(1000000000ULL) / (n))
|
#define SR_HZ_TO_NS(n) (UINT64_C(1000000000) / (n))
|
||||||
|
|
||||||
/** libsigrok loglevels. */
|
/** libsigrok loglevels. */
|
||||||
enum sr_loglevel {
|
enum sr_loglevel {
|
||||||
|
@ -650,11 +650,11 @@ struct sr_key_info {
|
||||||
/** Configuration capabilities. */
|
/** Configuration capabilities. */
|
||||||
enum sr_configcap {
|
enum sr_configcap {
|
||||||
/** Value can be read. */
|
/** Value can be read. */
|
||||||
SR_CONF_GET = (1 << 31),
|
SR_CONF_GET = (1UL << 31),
|
||||||
/** Value can be written. */
|
/** Value can be written. */
|
||||||
SR_CONF_SET = (1 << 30),
|
SR_CONF_SET = (1UL << 30),
|
||||||
/** Possible values can be enumerated. */
|
/** Possible values can be enumerated. */
|
||||||
SR_CONF_LIST = (1 << 29),
|
SR_CONF_LIST = (1UL << 29),
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Configuration keys */
|
/** Configuration keys */
|
||||||
|
@ -703,6 +703,9 @@ enum sr_configkey {
|
||||||
/** The device can act as a function generator. */
|
/** The device can act as a function generator. */
|
||||||
SR_CONF_SIGNAL_GENERATOR,
|
SR_CONF_SIGNAL_GENERATOR,
|
||||||
|
|
||||||
|
/** The device can measure power. */
|
||||||
|
SR_CONF_POWERMETER,
|
||||||
|
|
||||||
/* Update sr_key_info_config[] (hwdriver.c) upon changes! */
|
/* Update sr_key_info_config[] (hwdriver.c) upon changes! */
|
||||||
|
|
||||||
/*--- Driver scan options -------------------------------------------*/
|
/*--- Driver scan options -------------------------------------------*/
|
||||||
|
@ -983,6 +986,15 @@ enum sr_configkey {
|
||||||
/** Trigger level. */
|
/** Trigger level. */
|
||||||
SR_CONF_TRIGGER_LEVEL,
|
SR_CONF_TRIGGER_LEVEL,
|
||||||
|
|
||||||
|
/** Under-voltage condition threshold. */
|
||||||
|
SR_CONF_UNDER_VOLTAGE_CONDITION_THRESHOLD,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Which external clock source to use if the device supports
|
||||||
|
* multiple external clock channels.
|
||||||
|
*/
|
||||||
|
SR_CONF_EXTERNAL_CLOCK_SOURCE,
|
||||||
|
|
||||||
/* Update sr_key_info_config[] (hwdriver.c) upon changes! */
|
/* Update sr_key_info_config[] (hwdriver.c) upon changes! */
|
||||||
|
|
||||||
/*--- Special stuff -------------------------------------------------*/
|
/*--- Special stuff -------------------------------------------------*/
|
||||||
|
|
|
@ -50,6 +50,14 @@ SR_API GSList *sr_buildinfo_libs_get(void);
|
||||||
SR_API char *sr_buildinfo_host_get(void);
|
SR_API char *sr_buildinfo_host_get(void);
|
||||||
SR_API char *sr_buildinfo_scpi_backends_get(void);
|
SR_API char *sr_buildinfo_scpi_backends_get(void);
|
||||||
|
|
||||||
|
/*--- conversion.c ----------------------------------------------------------*/
|
||||||
|
|
||||||
|
SR_API int sr_a2l_threshold(const struct sr_datafeed_analog *analog,
|
||||||
|
float threshold, uint8_t *output, uint64_t count);
|
||||||
|
SR_API int sr_a2l_schmitt_trigger(const struct sr_datafeed_analog *analog,
|
||||||
|
float lo_thr, float hi_thr, uint8_t *state, uint8_t *output,
|
||||||
|
uint64_t count);
|
||||||
|
|
||||||
/*--- log.c -----------------------------------------------------------------*/
|
/*--- log.c -----------------------------------------------------------------*/
|
||||||
|
|
||||||
typedef int (*sr_log_callback)(void *cb_data, int loglevel,
|
typedef int (*sr_log_callback)(void *cb_data, int loglevel,
|
||||||
|
@ -59,6 +67,7 @@ SR_API int sr_log_loglevel_set(int loglevel);
|
||||||
SR_API int sr_log_loglevel_get(void);
|
SR_API int sr_log_loglevel_get(void);
|
||||||
SR_API int sr_log_callback_set(sr_log_callback cb, void *cb_data);
|
SR_API int sr_log_callback_set(sr_log_callback cb, void *cb_data);
|
||||||
SR_API int sr_log_callback_set_default(void);
|
SR_API int sr_log_callback_set_default(void);
|
||||||
|
SR_API int sr_log_callback_get(sr_log_callback *cb, void **cb_data);
|
||||||
|
|
||||||
/*--- device.c --------------------------------------------------------------*/
|
/*--- device.c --------------------------------------------------------------*/
|
||||||
|
|
||||||
|
@ -145,6 +154,10 @@ SR_API int sr_session_is_running(struct sr_session *session);
|
||||||
SR_API int sr_session_stopped_callback_set(struct sr_session *session,
|
SR_API int sr_session_stopped_callback_set(struct sr_session *session,
|
||||||
sr_session_stopped_callback cb, void *cb_data);
|
sr_session_stopped_callback cb, void *cb_data);
|
||||||
|
|
||||||
|
SR_API int sr_packet_copy(const struct sr_datafeed_packet *packet,
|
||||||
|
struct sr_datafeed_packet **copy);
|
||||||
|
SR_API void sr_packet_free(struct sr_datafeed_packet *packet);
|
||||||
|
|
||||||
/*--- input/input.c ---------------------------------------------------------*/
|
/*--- input/input.c ---------------------------------------------------------*/
|
||||||
|
|
||||||
SR_API const struct sr_input_module **sr_input_list(void);
|
SR_API const struct sr_input_module **sr_input_list(void);
|
||||||
|
@ -155,13 +168,12 @@ SR_API const char *const *sr_input_extensions_get(
|
||||||
const struct sr_input_module *imod);
|
const struct sr_input_module *imod);
|
||||||
SR_API const struct sr_input_module *sr_input_find(char *id);
|
SR_API const struct sr_input_module *sr_input_find(char *id);
|
||||||
SR_API const struct sr_option **sr_input_options_get(const struct sr_input_module *imod);
|
SR_API const struct sr_option **sr_input_options_get(const struct sr_input_module *imod);
|
||||||
SR_API gboolean sr_output_test_flag(const struct sr_output_module *omod,
|
|
||||||
uint64_t flag);
|
|
||||||
SR_API void sr_input_options_free(const struct sr_option **options);
|
SR_API void sr_input_options_free(const struct sr_option **options);
|
||||||
SR_API struct sr_input *sr_input_new(const struct sr_input_module *imod,
|
SR_API struct sr_input *sr_input_new(const struct sr_input_module *imod,
|
||||||
GHashTable *options);
|
GHashTable *options);
|
||||||
SR_API int sr_input_scan_buffer(GString *buf, const struct sr_input **in);
|
SR_API int sr_input_scan_buffer(GString *buf, const struct sr_input **in);
|
||||||
SR_API int sr_input_scan_file(const char *filename, const struct sr_input **in);
|
SR_API int sr_input_scan_file(const char *filename, const struct sr_input **in);
|
||||||
|
SR_API const struct sr_input_module *sr_input_module_get(const struct sr_input *in);
|
||||||
SR_API struct sr_dev_inst *sr_input_dev_inst_get(const struct sr_input *in);
|
SR_API struct sr_dev_inst *sr_input_dev_inst_get(const struct sr_input *in);
|
||||||
SR_API int sr_input_send(const struct sr_input *in, GString *buf);
|
SR_API int sr_input_send(const struct sr_input *in, GString *buf);
|
||||||
SR_API int sr_input_end(const struct sr_input *in);
|
SR_API int sr_input_end(const struct sr_input *in);
|
||||||
|
@ -182,6 +194,8 @@ SR_API void sr_output_options_free(const struct sr_option **opts);
|
||||||
SR_API const struct sr_output *sr_output_new(const struct sr_output_module *omod,
|
SR_API const struct sr_output *sr_output_new(const struct sr_output_module *omod,
|
||||||
GHashTable *params, const struct sr_dev_inst *sdi,
|
GHashTable *params, const struct sr_dev_inst *sdi,
|
||||||
const char *filename);
|
const char *filename);
|
||||||
|
SR_API gboolean sr_output_test_flag(const struct sr_output_module *omod,
|
||||||
|
uint64_t flag);
|
||||||
SR_API int sr_output_send(const struct sr_output *o,
|
SR_API int sr_output_send(const struct sr_output *o,
|
||||||
const struct sr_datafeed_packet *packet, GString **out);
|
const struct sr_datafeed_packet *packet, GString **out);
|
||||||
SR_API int sr_output_free(const struct sr_output *o);
|
SR_API int sr_output_free(const struct sr_output *o);
|
||||||
|
@ -221,6 +235,8 @@ typedef int (*sr_resource_close_callback)(struct sr_resource *res,
|
||||||
typedef gssize (*sr_resource_read_callback)(const struct sr_resource *res,
|
typedef gssize (*sr_resource_read_callback)(const struct sr_resource *res,
|
||||||
void *buf, size_t count, void *cb_data);
|
void *buf, size_t count, void *cb_data);
|
||||||
|
|
||||||
|
SR_API GSList *sr_resourcepaths_get(int res_type);
|
||||||
|
|
||||||
SR_API int sr_resource_set_hooks(struct sr_context *ctx,
|
SR_API int sr_resource_set_hooks(struct sr_context *ctx,
|
||||||
sr_resource_open_callback open_cb,
|
sr_resource_open_callback open_cb,
|
||||||
sr_resource_close_callback close_cb,
|
sr_resource_close_callback close_cb,
|
||||||
|
@ -237,6 +253,12 @@ SR_API uint64_t sr_parse_timestring(const char *timestring);
|
||||||
SR_API gboolean sr_parse_boolstring(const char *boolstring);
|
SR_API gboolean sr_parse_boolstring(const char *boolstring);
|
||||||
SR_API int sr_parse_period(const char *periodstr, uint64_t *p, uint64_t *q);
|
SR_API int sr_parse_period(const char *periodstr, uint64_t *p, uint64_t *q);
|
||||||
SR_API int sr_parse_voltage(const char *voltstr, uint64_t *p, uint64_t *q);
|
SR_API int sr_parse_voltage(const char *voltstr, uint64_t *p, uint64_t *q);
|
||||||
|
SR_API int sr_sprintf_ascii(char *buf, const char *format, ...);
|
||||||
|
SR_API int sr_vsprintf_ascii(char *buf, const char *format, va_list args);
|
||||||
|
SR_API int sr_snprintf_ascii(char *buf, size_t buf_size,
|
||||||
|
const char *format, ...);
|
||||||
|
SR_API int sr_vsnprintf_ascii(char *buf, size_t buf_size,
|
||||||
|
const char *format, va_list args);
|
||||||
SR_API int sr_parse_rational(const char *str, struct sr_rational *ret);
|
SR_API int sr_parse_rational(const char *str, struct sr_rational *ret);
|
||||||
|
|
||||||
/*--- version.c -------------------------------------------------------------*/
|
/*--- version.c -------------------------------------------------------------*/
|
||||||
|
|
18
src/analog.c
18
src/analog.c
|
@ -174,8 +174,7 @@ SR_PRIV int sr_analog_init(struct sr_datafeed_analog *analog,
|
||||||
SR_API int sr_analog_to_float(const struct sr_datafeed_analog *analog,
|
SR_API int sr_analog_to_float(const struct sr_datafeed_analog *analog,
|
||||||
float *outbuf)
|
float *outbuf)
|
||||||
{
|
{
|
||||||
float offset;
|
unsigned int b, count;
|
||||||
unsigned int b, i, count;
|
|
||||||
gboolean bigendian;
|
gboolean bigendian;
|
||||||
|
|
||||||
if (!analog || !(analog->data) || !(analog->meaning)
|
if (!analog || !(analog->data) || !(analog->meaning)
|
||||||
|
@ -275,7 +274,7 @@ SR_API int sr_analog_to_float(const struct sr_datafeed_analog *analog,
|
||||||
/* The data is already in the right format. */
|
/* The data is already in the right format. */
|
||||||
memcpy(outbuf, analog->data, count * sizeof(float));
|
memcpy(outbuf, analog->data, count * sizeof(float));
|
||||||
} else {
|
} else {
|
||||||
for (i = 0; i < count; i += analog->encoding->unitsize) {
|
for (unsigned int i = 0; i < count; i += analog->encoding->unitsize) {
|
||||||
for (b = 0; b < analog->encoding->unitsize; b++) {
|
for (b = 0; b < analog->encoding->unitsize; b++) {
|
||||||
if (analog->encoding->is_bigendian == bigendian)
|
if (analog->encoding->is_bigendian == bigendian)
|
||||||
((uint8_t *)outbuf)[i + b] =
|
((uint8_t *)outbuf)[i + b] =
|
||||||
|
@ -287,7 +286,7 @@ SR_API int sr_analog_to_float(const struct sr_datafeed_analog *analog,
|
||||||
if (analog->encoding->scale.p != 1
|
if (analog->encoding->scale.p != 1
|
||||||
|| analog->encoding->scale.q != 1)
|
|| analog->encoding->scale.q != 1)
|
||||||
outbuf[i] = (outbuf[i] * analog->encoding->scale.p) / analog->encoding->scale.q;
|
outbuf[i] = (outbuf[i] * analog->encoding->scale.p) / analog->encoding->scale.q;
|
||||||
offset = ((float)analog->encoding->offset.p / (float)analog->encoding->offset.q);
|
float offset = ((float)analog->encoding->offset.p / (float)analog->encoding->offset.q);
|
||||||
outbuf[i] += offset;
|
outbuf[i] += offset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -366,12 +365,9 @@ SR_API gboolean sr_analog_si_prefix_friendly(enum sr_unit unit)
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(prefix_friendly_units); i++)
|
for (i = 0; i < ARRAY_SIZE(prefix_friendly_units); i++)
|
||||||
if (unit == prefix_friendly_units[i])
|
if (unit == prefix_friendly_units[i])
|
||||||
break;
|
|
||||||
|
|
||||||
if (unit != prefix_friendly_units[i])
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -555,8 +551,8 @@ SR_API int sr_rational_mult(struct sr_rational *res, const struct sr_rational *a
|
||||||
return SR_ERR_ARG;
|
return SR_ERR_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
res->p = (int64_t)(p);
|
res->p = (int64_t)p;
|
||||||
res->q = (uint64_t)(q);
|
res->q = (uint64_t)q;
|
||||||
|
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
|
|
||||||
|
|
|
@ -153,8 +153,14 @@ SR_API GSList *sr_buildinfo_libs_get(void)
|
||||||
m = g_slist_append(m, g_strdup_printf("%s", CONF_LIBUSB_1_0_VERSION));
|
m = g_slist_append(m, g_strdup_printf("%s", CONF_LIBUSB_1_0_VERSION));
|
||||||
#else
|
#else
|
||||||
lv = libusb_get_version();
|
lv = libusb_get_version();
|
||||||
m = g_slist_append(m, g_strdup_printf("%d.%d.%d.%d%s",
|
m = g_slist_append(m, g_strdup_printf("%d.%d.%d.%d%s API 0x%08x",
|
||||||
lv->major, lv->minor, lv->micro, lv->nano, lv->rc));
|
lv->major, lv->minor, lv->micro, lv->nano, lv->rc,
|
||||||
|
#if defined(LIBUSB_API_VERSION)
|
||||||
|
LIBUSB_API_VERSION
|
||||||
|
#elif defined(LIBUSBX_API_VERSION)
|
||||||
|
LIBUSBX_API_VERSION
|
||||||
|
#endif
|
||||||
|
));
|
||||||
#endif
|
#endif
|
||||||
l = g_slist_append(l, m);
|
l = g_slist_append(l, m);
|
||||||
#endif
|
#endif
|
||||||
|
@ -255,6 +261,17 @@ static void print_versions(void)
|
||||||
g_free(str);
|
g_free(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void print_resourcepaths(void)
|
||||||
|
{
|
||||||
|
GSList *l, *l_orig;
|
||||||
|
|
||||||
|
sr_dbg("Firmware search paths:");
|
||||||
|
l_orig = sr_resourcepaths_get(SR_RESOURCE_FIRMWARE);
|
||||||
|
for (l = l_orig; l; l = l->next)
|
||||||
|
sr_dbg(" - %s", (const char *)l->data);
|
||||||
|
g_slist_free_full(l_orig, g_free);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sanity-check all libsigrok drivers.
|
* Sanity-check all libsigrok drivers.
|
||||||
*
|
*
|
||||||
|
@ -309,7 +326,10 @@ static int sanity_check_all_drivers(const struct sr_context *ctx)
|
||||||
sr_err("No dev_list in driver %d ('%s').", i, d);
|
sr_err("No dev_list in driver %d ('%s').", i, d);
|
||||||
errors++;
|
errors++;
|
||||||
}
|
}
|
||||||
/* Note: dev_clear() is optional. */
|
if (!drivers[i]->dev_clear) {
|
||||||
|
sr_err("No dev_clear in driver %d ('%s').", i, d);
|
||||||
|
errors++;
|
||||||
|
}
|
||||||
/* Note: config_get() is optional. */
|
/* Note: config_get() is optional. */
|
||||||
if (!drivers[i]->config_set) {
|
if (!drivers[i]->config_set) {
|
||||||
sr_err("No config_set in driver %d ('%s').", i, d);
|
sr_err("No config_set in driver %d ('%s').", i, d);
|
||||||
|
@ -526,6 +546,8 @@ SR_API int sr_init(struct sr_context **ctx)
|
||||||
|
|
||||||
print_versions();
|
print_versions();
|
||||||
|
|
||||||
|
print_resourcepaths();
|
||||||
|
|
||||||
if (!ctx) {
|
if (!ctx) {
|
||||||
sr_err("%s(): libsigrok context was NULL.", __func__);
|
sr_err("%s(): libsigrok context was NULL.", __func__);
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
|
@ -537,22 +559,22 @@ SR_API int sr_init(struct sr_context **ctx)
|
||||||
|
|
||||||
if (sanity_check_all_drivers(context) < 0) {
|
if (sanity_check_all_drivers(context) < 0) {
|
||||||
sr_err("Internal driver error(s), aborting.");
|
sr_err("Internal driver error(s), aborting.");
|
||||||
return ret;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sanity_check_all_input_modules() < 0) {
|
if (sanity_check_all_input_modules() < 0) {
|
||||||
sr_err("Internal input module error(s), aborting.");
|
sr_err("Internal input module error(s), aborting.");
|
||||||
return ret;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sanity_check_all_output_modules() < 0) {
|
if (sanity_check_all_output_modules() < 0) {
|
||||||
sr_err("Internal output module error(s), aborting.");
|
sr_err("Internal output module error(s), aborting.");
|
||||||
return ret;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sanity_check_all_transform_modules() < 0) {
|
if (sanity_check_all_transform_modules() < 0) {
|
||||||
sr_err("Internal transform module error(s), aborting.");
|
sr_err("Internal transform module error(s), aborting.");
|
||||||
return ret;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
@ -577,9 +599,7 @@ SR_API int sr_init(struct sr_context **ctx)
|
||||||
context = NULL;
|
context = NULL;
|
||||||
ret = SR_OK;
|
ret = SR_OK;
|
||||||
|
|
||||||
#if defined(HAVE_LIBUSB_1_0) || defined(_WIN32)
|
|
||||||
done:
|
done:
|
||||||
#endif
|
|
||||||
g_free(context);
|
g_free(context);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the libsigrok project.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Soeren Apel <soeren@apelpie.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 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
*
|
||||||
|
* Conversion helper functions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libsigrok/libsigrok.h>
|
||||||
|
#include "libsigrok-internal.h"
|
||||||
|
|
||||||
|
#define LOG_PREFIX "conv"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert analog values to logic values by using a fixed threshold.
|
||||||
|
*
|
||||||
|
* @param[in] analog The analog input values.
|
||||||
|
* @param[in] threshold The threshold to use.
|
||||||
|
* @param[out] output The converted output values; either 0 or 1. Must provide
|
||||||
|
* space for count bytes.
|
||||||
|
* @param[in] count The number of samples to process.
|
||||||
|
*
|
||||||
|
* @return SR_OK on success or SR_ERR on failure.
|
||||||
|
*/
|
||||||
|
SR_API int sr_a2l_threshold(const struct sr_datafeed_analog *analog,
|
||||||
|
float threshold, uint8_t *output, uint64_t count)
|
||||||
|
{
|
||||||
|
float *input;
|
||||||
|
|
||||||
|
if (!analog->encoding->is_float) {
|
||||||
|
input = g_try_malloc(sizeof(float) * count);
|
||||||
|
if (!input)
|
||||||
|
return SR_ERR;
|
||||||
|
|
||||||
|
sr_analog_to_float(analog, input);
|
||||||
|
} else
|
||||||
|
input = analog->data;
|
||||||
|
|
||||||
|
for (uint64_t i = 0; i < count; i++)
|
||||||
|
output[i] = (input[i] >= threshold) ? 1 : 0;
|
||||||
|
|
||||||
|
if (!analog->encoding->is_float)
|
||||||
|
g_free(input);
|
||||||
|
|
||||||
|
return SR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert analog values to logic values by using a Schmitt-trigger algorithm.
|
||||||
|
*
|
||||||
|
* @param analog The analog input values.
|
||||||
|
* @param lo_thr The low threshold - result becomes 0 below it.
|
||||||
|
* @param lo_thr The high threshold - result becomes 1 above it.
|
||||||
|
* @param state The internal converter state. Must contain the state of logic
|
||||||
|
* sample n-1, will contain the state of logic sample n+count upon exit.
|
||||||
|
* @param output The converted output values; either 0 or 1. Must provide
|
||||||
|
* space for count bytes.
|
||||||
|
* @param count The number of samples to process.
|
||||||
|
*
|
||||||
|
* @return SR_OK on success or SR_ERR on failure.
|
||||||
|
*/
|
||||||
|
SR_API int sr_a2l_schmitt_trigger(const struct sr_datafeed_analog *analog,
|
||||||
|
float lo_thr, float hi_thr, uint8_t *state, uint8_t *output,
|
||||||
|
uint64_t count)
|
||||||
|
{
|
||||||
|
float *input;
|
||||||
|
|
||||||
|
if (!analog->encoding->is_float) {
|
||||||
|
input = g_try_malloc(sizeof(float) * count);
|
||||||
|
if (!input)
|
||||||
|
return SR_ERR;
|
||||||
|
|
||||||
|
sr_analog_to_float(analog, input);
|
||||||
|
} else
|
||||||
|
input = analog->data;
|
||||||
|
|
||||||
|
for (uint64_t i = 0; i < count; i++) {
|
||||||
|
if (input[i] < lo_thr)
|
||||||
|
*state = 0;
|
||||||
|
else if (input[i] > hi_thr)
|
||||||
|
*state = 1;
|
||||||
|
|
||||||
|
output[i] = *state;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!analog->encoding->is_float)
|
||||||
|
g_free(input);
|
||||||
|
|
||||||
|
return SR_OK;
|
||||||
|
}
|
184
src/device.c
184
src/device.c
|
@ -18,8 +18,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include <stdio.h>
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
#include <libsigrok/libsigrok.h>
|
#include <libsigrok/libsigrok.h>
|
||||||
#include "libsigrok-internal.h"
|
#include "libsigrok-internal.h"
|
||||||
|
|
||||||
|
@ -73,6 +74,30 @@ SR_PRIV struct sr_channel *sr_channel_new(struct sr_dev_inst *sdi,
|
||||||
return ch;
|
return ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Release a previously allocated struct sr_channel.
|
||||||
|
*
|
||||||
|
* @param[in] ch Pointer to struct sr_channel.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
SR_PRIV void sr_channel_free(struct sr_channel *ch)
|
||||||
|
{
|
||||||
|
if (!ch)
|
||||||
|
return;
|
||||||
|
g_free(ch->name);
|
||||||
|
g_free(ch->priv);
|
||||||
|
g_free(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper around @ref sr_channel_free(), suitable for glib iterators.
|
||||||
|
*/
|
||||||
|
SR_PRIV void sr_channel_free_cb(void *p)
|
||||||
|
{
|
||||||
|
sr_channel_free(p);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the name of the specified channel.
|
* Set the name of the specified channel.
|
||||||
*
|
*
|
||||||
|
@ -135,10 +160,18 @@ SR_API int sr_dev_channel_enable(struct sr_channel *channel, gboolean state)
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns the next enabled channel, wrapping around if necessary. */
|
/**
|
||||||
/** @private */
|
* Returns the next enabled channel, wrapping around if necessary.
|
||||||
|
*
|
||||||
|
* @param[in] sdi The device instance the channel is connected to.
|
||||||
|
* Must not be NULL.
|
||||||
|
* @param[in] cur_channel The current channel.
|
||||||
|
*
|
||||||
|
* @return A pointer to the next enabled channel of this device.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
SR_PRIV struct sr_channel *sr_next_enabled_channel(const struct sr_dev_inst *sdi,
|
SR_PRIV struct sr_channel *sr_next_enabled_channel(const struct sr_dev_inst *sdi,
|
||||||
|
|
||||||
struct sr_channel *cur_channel)
|
struct sr_channel *cur_channel)
|
||||||
{
|
{
|
||||||
struct sr_channel *next_channel;
|
struct sr_channel *next_channel;
|
||||||
|
@ -156,6 +189,69 @@ SR_PRIV struct sr_channel *sr_next_enabled_channel(const struct sr_dev_inst *sdi
|
||||||
return next_channel;
|
return next_channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare two channels, return whether they differ.
|
||||||
|
*
|
||||||
|
* The channels' names and types are checked. The enabled state is not
|
||||||
|
* considered a condition for difference. The test is motivated by the
|
||||||
|
* desire to detect changes in the configuration of acquisition setups
|
||||||
|
* between re-reads of an input file.
|
||||||
|
*
|
||||||
|
* @param[in] ch1 First channel.
|
||||||
|
* @param[in] ch2 Second channel.
|
||||||
|
*
|
||||||
|
* @return #TRUE upon differences or unexpected input, #FALSE otherwise.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
SR_PRIV gboolean sr_channels_differ(struct sr_channel *ch1, struct sr_channel *ch2)
|
||||||
|
{
|
||||||
|
if (!ch1 || !ch2)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
if (ch1->type != ch2->type)
|
||||||
|
return TRUE;
|
||||||
|
if (strcmp(ch1->name, ch2->name))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare two channel lists, return whether they differ.
|
||||||
|
*
|
||||||
|
* Listing the same set of channels but in a different order is considered
|
||||||
|
* a difference in the lists.
|
||||||
|
*
|
||||||
|
* @param[in] l1 First channel list.
|
||||||
|
* @param[in] l2 Second channel list.
|
||||||
|
*
|
||||||
|
* @return #TRUE upon differences or unexpected input, #FALSE otherwise.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
SR_PRIV gboolean sr_channel_lists_differ(GSList *l1, GSList *l2)
|
||||||
|
{
|
||||||
|
struct sr_channel *ch1, *ch2;
|
||||||
|
|
||||||
|
while (l1 && l2) {
|
||||||
|
ch1 = l1->data;
|
||||||
|
ch2 = l2->data;
|
||||||
|
l1 = l1->next;
|
||||||
|
l2 = l2->next;
|
||||||
|
if (!ch1 || !ch2)
|
||||||
|
return TRUE;
|
||||||
|
if (sr_channels_differ(ch1, ch2))
|
||||||
|
return TRUE;
|
||||||
|
if (ch1->index != ch2->index)
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
if (l1 || l2)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine whether the specified device instance has the specified
|
* Determine whether the specified device instance has the specified
|
||||||
* capability.
|
* capability.
|
||||||
|
@ -356,9 +452,7 @@ SR_PRIV void sr_dev_inst_free(struct sr_dev_inst *sdi)
|
||||||
|
|
||||||
for (l = sdi->channels; l; l = l->next) {
|
for (l = sdi->channels; l; l = l->next) {
|
||||||
ch = l->data;
|
ch = l->data;
|
||||||
g_free(ch->name);
|
sr_channel_free(ch);
|
||||||
g_free(ch->priv);
|
|
||||||
g_free(ch);
|
|
||||||
}
|
}
|
||||||
g_slist_free(sdi->channels);
|
g_slist_free(sdi->channels);
|
||||||
|
|
||||||
|
@ -529,27 +623,40 @@ SR_API GSList *sr_dev_list(const struct sr_dev_driver *driver)
|
||||||
*/
|
*/
|
||||||
SR_API int sr_dev_clear(const struct sr_dev_driver *driver)
|
SR_API int sr_dev_clear(const struct sr_dev_driver *driver)
|
||||||
{
|
{
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!driver) {
|
if (!driver) {
|
||||||
sr_err("Invalid driver.");
|
sr_err("Invalid driver.");
|
||||||
return SR_ERR_ARG;
|
return SR_ERR_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (driver->dev_clear)
|
if (!driver->context) {
|
||||||
ret = driver->dev_clear(driver);
|
/*
|
||||||
else
|
* Driver was never initialized, nothing to do.
|
||||||
ret = std_dev_clear(driver, NULL);
|
*
|
||||||
|
* No log message since this usually gets called for all
|
||||||
|
* drivers, whether they were initialized or not.
|
||||||
|
*/
|
||||||
|
return SR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
/* No log message here, too verbose and not very useful. */
|
||||||
|
|
||||||
|
return driver->dev_clear(driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open the specified device.
|
* Open the specified device instance.
|
||||||
|
*
|
||||||
|
* If the device instance is already open (sdi->status == SR_ST_ACTIVE),
|
||||||
|
* SR_ERR will be returned and no re-opening of the device will be attempted.
|
||||||
|
*
|
||||||
|
* If opening was successful, sdi->status is set to SR_ST_ACTIVE, otherwise
|
||||||
|
* it will be left unchanged.
|
||||||
*
|
*
|
||||||
* @param sdi Device instance to use. Must not be NULL.
|
* @param sdi Device instance to use. Must not be NULL.
|
||||||
*
|
*
|
||||||
* @return SR_OK upon success, a negative error code upon errors.
|
* @retval SR_OK Success.
|
||||||
|
* @retval SR_ERR_ARG Invalid arguments.
|
||||||
|
* @retval SR_ERR Device instance was already active, or other error.
|
||||||
*
|
*
|
||||||
* @since 0.2.0
|
* @since 0.2.0
|
||||||
*/
|
*/
|
||||||
|
@ -558,32 +665,59 @@ SR_API int sr_dev_open(struct sr_dev_inst *sdi)
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!sdi || !sdi->driver || !sdi->driver->dev_open)
|
if (!sdi || !sdi->driver || !sdi->driver->dev_open)
|
||||||
|
return SR_ERR_ARG;
|
||||||
|
|
||||||
|
if (sdi->status == SR_ST_ACTIVE) {
|
||||||
|
sr_err("%s: Device instance already active, can't re-open.",
|
||||||
|
sdi->driver->name);
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
sr_dbg("%s: Opening device instance.", sdi->driver->name);
|
||||||
|
|
||||||
ret = sdi->driver->dev_open(sdi);
|
ret = sdi->driver->dev_open(sdi);
|
||||||
|
|
||||||
|
if (ret == SR_OK)
|
||||||
|
sdi->status = SR_ST_ACTIVE;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close the specified device.
|
* Close the specified device instance.
|
||||||
|
*
|
||||||
|
* If the device instance is not open (sdi->status != SR_ST_ACTIVE),
|
||||||
|
* SR_ERR_DEV_CLOSED will be returned and no closing will be attempted.
|
||||||
|
*
|
||||||
|
* Note: sdi->status will be set to SR_ST_INACTIVE, regardless of whether
|
||||||
|
* there are any errors during closing of the device instance (any errors
|
||||||
|
* will be reported via error code and log message, though).
|
||||||
*
|
*
|
||||||
* @param sdi Device instance to use. Must not be NULL.
|
* @param sdi Device instance to use. Must not be NULL.
|
||||||
*
|
*
|
||||||
* @return SR_OK upon success, a negative error code upon errors.
|
* @retval SR_OK Success.
|
||||||
|
* @retval SR_ERR_ARG Invalid arguments.
|
||||||
|
* @retval SR_ERR_DEV_CLOSED Device instance was not active.
|
||||||
|
* @retval SR_ERR Other error.
|
||||||
*
|
*
|
||||||
* @since 0.2.0
|
* @since 0.2.0
|
||||||
*/
|
*/
|
||||||
SR_API int sr_dev_close(struct sr_dev_inst *sdi)
|
SR_API int sr_dev_close(struct sr_dev_inst *sdi)
|
||||||
{
|
{
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!sdi || !sdi->driver || !sdi->driver->dev_close)
|
if (!sdi || !sdi->driver || !sdi->driver->dev_close)
|
||||||
return SR_ERR;
|
return SR_ERR_ARG;
|
||||||
|
|
||||||
ret = sdi->driver->dev_close(sdi);
|
if (sdi->status != SR_ST_ACTIVE) {
|
||||||
|
sr_err("%s: Device instance not active, can't close.",
|
||||||
|
sdi->driver->name);
|
||||||
|
return SR_ERR_DEV_CLOSED;
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
sdi->status = SR_ST_INACTIVE;
|
||||||
|
|
||||||
|
sr_dbg("%s: Closing device instance.", sdi->driver->name);
|
||||||
|
|
||||||
|
return sdi->driver->dev_close(sdi);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -713,7 +847,9 @@ SR_API const char *sr_dev_inst_connid_get(const struct sr_dev_inst *sdi)
|
||||||
if (b != usb->bus || a != usb->address)
|
if (b != usb->bus || a != usb->address)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
usb_get_port_path(devlist[i], connection_id, sizeof(connection_id));
|
if (usb_get_port_path(devlist[i], connection_id, sizeof(connection_id)) < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
((struct sr_dev_inst *)sdi)->connection_id = g_strdup(connection_id);
|
((struct sr_dev_inst *)sdi)->connection_id = g_strdup(connection_id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -379,7 +379,7 @@ static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
|
||||||
if (info->is_dc)
|
if (info->is_dc)
|
||||||
analog->meaning->mqflags |= SR_MQFLAG_DC;
|
analog->meaning->mqflags |= SR_MQFLAG_DC;
|
||||||
if (info->is_diode)
|
if (info->is_diode)
|
||||||
analog->meaning->mqflags |= SR_MQFLAG_DIODE;
|
analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
|
||||||
if (info->is_peak_max)
|
if (info->is_peak_max)
|
||||||
analog->meaning->mqflags |= SR_MQFLAG_MAX;
|
analog->meaning->mqflags |= SR_MQFLAG_MAX;
|
||||||
if (info->is_peak_min)
|
if (info->is_peak_min)
|
||||||
|
@ -519,7 +519,7 @@ SR_PRIV int sr_asycii_parse(const uint8_t *buf, float *floatval,
|
||||||
int ret, exponent;
|
int ret, exponent;
|
||||||
struct asycii_info *info_local;
|
struct asycii_info *info_local;
|
||||||
|
|
||||||
info_local = (struct asycii_info *)info;
|
info_local = info;
|
||||||
|
|
||||||
/* Don't print byte 15. That one contains the carriage return. */
|
/* Don't print byte 15. That one contains the carriage return. */
|
||||||
sr_dbg("DMM packet: \"%.15s\"", buf);
|
sr_dbg("DMM packet: \"%.15s\"", buf);
|
||||||
|
|
|
@ -173,7 +173,7 @@ SR_PRIV int sr_brymen_bm25x_parse(const uint8_t *buf, float *floatval,
|
||||||
analog->meaning->mq = SR_MQ_VOLTAGE;
|
analog->meaning->mq = SR_MQ_VOLTAGE;
|
||||||
analog->meaning->unit = SR_UNIT_VOLT;
|
analog->meaning->unit = SR_UNIT_VOLT;
|
||||||
if ((analog->meaning->mqflags & (SR_MQFLAG_DC | SR_MQFLAG_AC)) == 0)
|
if ((analog->meaning->mqflags & (SR_MQFLAG_DC | SR_MQFLAG_AC)) == 0)
|
||||||
analog->meaning->mqflags |= SR_MQFLAG_DIODE;
|
analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
|
||||||
}
|
}
|
||||||
if (buf[14] & 2) {
|
if (buf[14] & 2) {
|
||||||
analog->meaning->mq = SR_MQ_CURRENT;
|
analog->meaning->mq = SR_MQ_CURRENT;
|
||||||
|
|
|
@ -254,6 +254,8 @@ static void parse_flags(const uint8_t *buf, struct dtm0660_info *info)
|
||||||
static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
|
static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
|
||||||
int *exponent, const struct dtm0660_info *info)
|
int *exponent, const struct dtm0660_info *info)
|
||||||
{
|
{
|
||||||
|
int initial_exponent = *exponent;
|
||||||
|
|
||||||
/* Factors */
|
/* Factors */
|
||||||
if (info->is_nano)
|
if (info->is_nano)
|
||||||
*exponent -= 9;
|
*exponent -= 9;
|
||||||
|
@ -265,7 +267,7 @@ static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
|
||||||
*exponent += 3;
|
*exponent += 3;
|
||||||
if (info->is_mega)
|
if (info->is_mega)
|
||||||
*exponent += 6;
|
*exponent += 6;
|
||||||
*floatval *= powf(10, *exponent);
|
*floatval *= powf(10, (*exponent - initial_exponent));
|
||||||
|
|
||||||
/* Measurement modes */
|
/* Measurement modes */
|
||||||
if (info->is_volt) {
|
if (info->is_volt) {
|
||||||
|
@ -318,7 +320,7 @@ static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
|
||||||
if (info->is_auto)
|
if (info->is_auto)
|
||||||
analog->meaning->mqflags |= SR_MQFLAG_AUTORANGE;
|
analog->meaning->mqflags |= SR_MQFLAG_AUTORANGE;
|
||||||
if (info->is_diode)
|
if (info->is_diode)
|
||||||
analog->meaning->mqflags |= SR_MQFLAG_DIODE;
|
analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
|
||||||
if (info->is_hold)
|
if (info->is_hold)
|
||||||
analog->meaning->mqflags |= SR_MQFLAG_HOLD;
|
analog->meaning->mqflags |= SR_MQFLAG_HOLD;
|
||||||
if (info->is_rel)
|
if (info->is_rel)
|
||||||
|
@ -373,7 +375,7 @@ SR_PRIV int sr_dtm0660_parse(const uint8_t *buf, float *floatval,
|
||||||
int ret, exponent = 0;
|
int ret, exponent = 0;
|
||||||
struct dtm0660_info *info_local;
|
struct dtm0660_info *info_local;
|
||||||
|
|
||||||
info_local = (struct dtm0660_info *)info;
|
info_local = info;
|
||||||
|
|
||||||
if ((ret = parse_value(buf, floatval, &exponent)) != SR_OK) {
|
if ((ret = parse_value(buf, floatval, &exponent)) != SR_OK) {
|
||||||
sr_dbg("Error parsing value: %d.", ret);
|
sr_dbg("Error parsing value: %d.", ret);
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -502,7 +502,7 @@ static void handle_flags(struct sr_datafeed_analog *analog,
|
||||||
if (info->is_auto)
|
if (info->is_auto)
|
||||||
analog->meaning->mqflags |= SR_MQFLAG_AUTORANGE;
|
analog->meaning->mqflags |= SR_MQFLAG_AUTORANGE;
|
||||||
if (info->is_diode)
|
if (info->is_diode)
|
||||||
analog->meaning->mqflags |= SR_MQFLAG_DIODE;
|
analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
|
||||||
if (info->is_hold)
|
if (info->is_hold)
|
||||||
/*
|
/*
|
||||||
* Note: HOLD only affects the number displayed on the LCD,
|
* Note: HOLD only affects the number displayed on the LCD,
|
||||||
|
|
|
@ -302,7 +302,7 @@ static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
|
||||||
if (info->is_auto)
|
if (info->is_auto)
|
||||||
analog->meaning->mqflags |= SR_MQFLAG_AUTORANGE;
|
analog->meaning->mqflags |= SR_MQFLAG_AUTORANGE;
|
||||||
if (info->is_diode)
|
if (info->is_diode)
|
||||||
analog->meaning->mqflags |= SR_MQFLAG_DIODE;
|
analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
|
||||||
if (info->is_hold)
|
if (info->is_hold)
|
||||||
analog->meaning->mqflags |= SR_MQFLAG_HOLD;
|
analog->meaning->mqflags |= SR_MQFLAG_HOLD;
|
||||||
if (info->is_rel)
|
if (info->is_rel)
|
||||||
|
@ -353,7 +353,7 @@ SR_PRIV int sr_fs9721_parse(const uint8_t *buf, float *floatval,
|
||||||
int ret, exponent = 0;
|
int ret, exponent = 0;
|
||||||
struct fs9721_info *info_local;
|
struct fs9721_info *info_local;
|
||||||
|
|
||||||
info_local = (struct fs9721_info *)info;
|
info_local = info;
|
||||||
|
|
||||||
if ((ret = parse_value(buf, floatval, &exponent)) != SR_OK) {
|
if ((ret = parse_value(buf, floatval, &exponent)) != SR_OK) {
|
||||||
sr_dbg("Error parsing value: %d.", ret);
|
sr_dbg("Error parsing value: %d.", ret);
|
||||||
|
@ -373,7 +373,7 @@ SR_PRIV void sr_fs9721_00_temp_c(struct sr_datafeed_analog *analog, void *info)
|
||||||
{
|
{
|
||||||
struct fs9721_info *info_local;
|
struct fs9721_info *info_local;
|
||||||
|
|
||||||
info_local = (struct fs9721_info *)info;
|
info_local = info;
|
||||||
|
|
||||||
/* User-defined FS9721_LP3 flag 'c2c1_00' means temperature (C). */
|
/* User-defined FS9721_LP3 flag 'c2c1_00' means temperature (C). */
|
||||||
if (info_local->is_c2c1_00) {
|
if (info_local->is_c2c1_00) {
|
||||||
|
@ -386,7 +386,7 @@ SR_PRIV void sr_fs9721_01_temp_c(struct sr_datafeed_analog *analog, void *info)
|
||||||
{
|
{
|
||||||
struct fs9721_info *info_local;
|
struct fs9721_info *info_local;
|
||||||
|
|
||||||
info_local = (struct fs9721_info *)info;
|
info_local = info;
|
||||||
|
|
||||||
/* User-defined FS9721_LP3 flag 'c2c1_01' means temperature (C). */
|
/* User-defined FS9721_LP3 flag 'c2c1_01' means temperature (C). */
|
||||||
if (info_local->is_c2c1_01) {
|
if (info_local->is_c2c1_01) {
|
||||||
|
@ -399,7 +399,7 @@ SR_PRIV void sr_fs9721_10_temp_c(struct sr_datafeed_analog *analog, void *info)
|
||||||
{
|
{
|
||||||
struct fs9721_info *info_local;
|
struct fs9721_info *info_local;
|
||||||
|
|
||||||
info_local = (struct fs9721_info *)info;
|
info_local = info;
|
||||||
|
|
||||||
/* User-defined FS9721_LP3 flag 'c2c1_10' means temperature (C). */
|
/* User-defined FS9721_LP3 flag 'c2c1_10' means temperature (C). */
|
||||||
if (info_local->is_c2c1_10) {
|
if (info_local->is_c2c1_10) {
|
||||||
|
@ -412,7 +412,7 @@ SR_PRIV void sr_fs9721_01_10_temp_f_c(struct sr_datafeed_analog *analog, void *i
|
||||||
{
|
{
|
||||||
struct fs9721_info *info_local;
|
struct fs9721_info *info_local;
|
||||||
|
|
||||||
info_local = (struct fs9721_info *)info;
|
info_local = info;
|
||||||
|
|
||||||
/* User-defined FS9721_LP3 flag 'c2c1_01' means temperature (F). */
|
/* User-defined FS9721_LP3 flag 'c2c1_01' means temperature (F). */
|
||||||
if (info_local->is_c2c1_01) {
|
if (info_local->is_c2c1_01) {
|
||||||
|
@ -431,7 +431,7 @@ SR_PRIV void sr_fs9721_max_c_min(struct sr_datafeed_analog *analog, void *info)
|
||||||
{
|
{
|
||||||
struct fs9721_info *info_local;
|
struct fs9721_info *info_local;
|
||||||
|
|
||||||
info_local = (struct fs9721_info *)info;
|
info_local = info;
|
||||||
|
|
||||||
/* User-defined FS9721_LP3 flag 'c2c1_00' means MAX. */
|
/* User-defined FS9721_LP3 flag 'c2c1_00' means MAX. */
|
||||||
if (info_local->is_c2c1_00)
|
if (info_local->is_c2c1_00)
|
||||||
|
|
|
@ -290,7 +290,7 @@ static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
|
||||||
if (info->is_auto)
|
if (info->is_auto)
|
||||||
analog->meaning->mqflags |= SR_MQFLAG_AUTORANGE;
|
analog->meaning->mqflags |= SR_MQFLAG_AUTORANGE;
|
||||||
if (info->is_diode)
|
if (info->is_diode)
|
||||||
analog->meaning->mqflags |= SR_MQFLAG_DIODE;
|
analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
|
||||||
if (info->is_hold)
|
if (info->is_hold)
|
||||||
analog->meaning->mqflags |= SR_MQFLAG_HOLD;
|
analog->meaning->mqflags |= SR_MQFLAG_HOLD;
|
||||||
if (info->is_max)
|
if (info->is_max)
|
||||||
|
@ -359,7 +359,7 @@ SR_PRIV int sr_fs9922_parse(const uint8_t *buf, float *floatval,
|
||||||
int ret, exponent = 0;
|
int ret, exponent = 0;
|
||||||
struct fs9922_info *info_local;
|
struct fs9922_info *info_local;
|
||||||
|
|
||||||
info_local = (struct fs9922_info *)info;
|
info_local = info;
|
||||||
|
|
||||||
if ((ret = parse_value(buf, floatval, &exponent)) != SR_OK) {
|
if ((ret = parse_value(buf, floatval, &exponent)) != SR_OK) {
|
||||||
sr_dbg("Error parsing value: %d.", ret);
|
sr_dbg("Error parsing value: %d.", ret);
|
||||||
|
@ -379,12 +379,12 @@ SR_PRIV void sr_fs9922_z1_diode(struct sr_datafeed_analog *analog, void *info)
|
||||||
{
|
{
|
||||||
struct fs9922_info *info_local;
|
struct fs9922_info *info_local;
|
||||||
|
|
||||||
info_local = (struct fs9922_info *)info;
|
info_local = info;
|
||||||
|
|
||||||
/* User-defined z1 flag means "diode mode". */
|
/* User-defined z1 flag means "diode mode". */
|
||||||
if (info_local->is_z1) {
|
if (info_local->is_z1) {
|
||||||
analog->meaning->mq = SR_MQ_VOLTAGE;
|
analog->meaning->mq = SR_MQ_VOLTAGE;
|
||||||
analog->meaning->unit = SR_UNIT_VOLT;
|
analog->meaning->unit = SR_UNIT_VOLT;
|
||||||
analog->meaning->mqflags |= SR_MQFLAG_DIODE;
|
analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ SR_PRIV gboolean sr_m2110_packet_valid(const uint8_t *buf)
|
||||||
if (!strncmp((const char *)buf, "OVERRNG", 7))
|
if (!strncmp((const char *)buf, "OVERRNG", 7))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
if (sscanf((const char *)buf, "%f", &val) == 1)
|
if (sr_atof_ascii((const char *)buf, &val) == SR_OK)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
else
|
else
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -65,7 +65,7 @@ SR_PRIV int sr_m2110_parse(const uint8_t *buf, float *floatval,
|
||||||
|
|
||||||
if (!strncmp((const char *)buf, "OVERRNG", 7))
|
if (!strncmp((const char *)buf, "OVERRNG", 7))
|
||||||
*floatval = INFINITY;
|
*floatval = INFINITY;
|
||||||
else if (sscanf((const char *)buf, "%f", &val) == 1) {
|
else if (sr_atof_ascii((const char *)buf, &val) == SR_OK) {
|
||||||
*floatval = val;
|
*floatval = val;
|
||||||
dot_pos = strcspn((const char *)buf, ".");
|
dot_pos = strcspn((const char *)buf, ".");
|
||||||
if (dot_pos < 7)
|
if (dot_pos < 7)
|
||||||
|
|
|
@ -86,7 +86,7 @@ static int parse_value(const uint8_t *buf, struct metex14_info *info,
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
|
|
||||||
/* Bytes 2-8: Sign, value (up to 5 digits) and decimal point */
|
/* Bytes 2-8: Sign, value (up to 5 digits) and decimal point */
|
||||||
sscanf((const char *)&valstr, "%f", result);
|
sr_atof_ascii((const char *)&valstr, result);
|
||||||
|
|
||||||
dot_pos = strcspn(valstr, ".");
|
dot_pos = strcspn(valstr, ".");
|
||||||
if (dot_pos < cnt)
|
if (dot_pos < cnt)
|
||||||
|
@ -146,8 +146,14 @@ static void parse_flags(const char *buf, struct metex14_info *info)
|
||||||
info->is_kilo = info->is_hertz = TRUE;
|
info->is_kilo = info->is_hertz = TRUE;
|
||||||
else if (!g_ascii_strcasecmp(u, "C"))
|
else if (!g_ascii_strcasecmp(u, "C"))
|
||||||
info->is_celsius = TRUE;
|
info->is_celsius = TRUE;
|
||||||
|
else if (!g_ascii_strcasecmp(u, "F"))
|
||||||
|
info->is_fahrenheit = TRUE;
|
||||||
else if (!g_ascii_strcasecmp(u, "DB"))
|
else if (!g_ascii_strcasecmp(u, "DB"))
|
||||||
info->is_decibel = TRUE;
|
info->is_decibel = TRUE;
|
||||||
|
else if (!g_ascii_strcasecmp(u, "dBm"))
|
||||||
|
info->is_decibel_mw = TRUE;
|
||||||
|
else if (!g_ascii_strcasecmp(u, "W"))
|
||||||
|
info->is_watt = TRUE;
|
||||||
else if (!g_ascii_strcasecmp(u, ""))
|
else if (!g_ascii_strcasecmp(u, ""))
|
||||||
info->is_unitless = TRUE;
|
info->is_unitless = TRUE;
|
||||||
|
|
||||||
|
@ -156,15 +162,25 @@ static void parse_flags(const char *buf, struct metex14_info *info)
|
||||||
(!strncmp(buf, " ", 2) && info->is_ohm);
|
(!strncmp(buf, " ", 2) && info->is_ohm);
|
||||||
info->is_capacity = !strncmp(buf, "CA", 2) ||
|
info->is_capacity = !strncmp(buf, "CA", 2) ||
|
||||||
(!strncmp(buf, " ", 2) && info->is_farad);
|
(!strncmp(buf, " ", 2) && info->is_farad);
|
||||||
info->is_temperature = !strncmp(buf, "TE", 2);
|
info->is_temperature = !strncmp(buf, "TE", 2) ||
|
||||||
|
info->is_celsius || info->is_fahrenheit;
|
||||||
info->is_diode = !strncmp(buf, "DI", 2) ||
|
info->is_diode = !strncmp(buf, "DI", 2) ||
|
||||||
(!strncmp(buf, " ", 2) && info->is_volt && info->is_milli);
|
(!strncmp(buf, " ", 2) && info->is_volt && info->is_milli);
|
||||||
info->is_frequency = !strncmp(buf, "FR", 2) ||
|
info->is_frequency = !strncmp(buf, "FR", 2) ||
|
||||||
(!strncmp(buf, " ", 2) && info->is_hertz);
|
(!strncmp(buf, " ", 2) && info->is_hertz);
|
||||||
info->is_gain = !strncmp(buf, "DB", 2);
|
info->is_gain = !strncmp(buf, "DB", 2) && info->is_decibel;
|
||||||
|
info->is_power = (!strncmp(buf, "dB", 2) && info->is_decibel_mw) ||
|
||||||
|
((!strncmp(buf, "WT", 2) && info->is_watt));
|
||||||
|
info->is_power_factor = !strncmp(buf, "CO", 2) && info->is_unitless;
|
||||||
info->is_hfe = !strncmp(buf, "HF", 2) ||
|
info->is_hfe = !strncmp(buf, "HF", 2) ||
|
||||||
(!strncmp(buf, " ", 2) && !info->is_volt && !info->is_ohm &&
|
(!strncmp(buf, " ", 2) && !info->is_ampere &&!info->is_volt &&
|
||||||
!info->is_logic && !info->is_farad && !info->is_hertz);
|
!info->is_resistance && !info->is_capacity && !info->is_frequency &&
|
||||||
|
!info->is_temperature && !info->is_power && !info->is_power_factor &&
|
||||||
|
!info->is_gain && !info->is_logic && !info->is_diode);
|
||||||
|
info->is_min = !strncmp(buf, "MN", 2);
|
||||||
|
info->is_max = !strncmp(buf, "MX", 2);
|
||||||
|
info->is_avg = !strncmp(buf, "AG", 2);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note:
|
* Note:
|
||||||
* - Protocol doesn't distinguish "resistance" from "beep" mode.
|
* - Protocol doesn't distinguish "resistance" from "beep" mode.
|
||||||
|
@ -178,8 +194,12 @@ static void parse_flags(const char *buf, struct metex14_info *info)
|
||||||
static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
|
static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
|
||||||
int *exponent, const struct metex14_info *info)
|
int *exponent, const struct metex14_info *info)
|
||||||
{
|
{
|
||||||
int factor = 0;
|
int factor;
|
||||||
|
|
||||||
|
(void)exponent;
|
||||||
|
|
||||||
/* Factors */
|
/* Factors */
|
||||||
|
factor = 0;
|
||||||
if (info->is_pico)
|
if (info->is_pico)
|
||||||
factor -= 12;
|
factor -= 12;
|
||||||
if (info->is_nano)
|
if (info->is_nano)
|
||||||
|
@ -193,7 +213,6 @@ static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
|
||||||
if (info->is_mega)
|
if (info->is_mega)
|
||||||
factor += 6;
|
factor += 6;
|
||||||
*floatval *= powf(10, factor);
|
*floatval *= powf(10, factor);
|
||||||
*exponent += factor;
|
|
||||||
|
|
||||||
/* Measurement modes */
|
/* Measurement modes */
|
||||||
if (info->is_volt) {
|
if (info->is_volt) {
|
||||||
|
@ -216,14 +235,32 @@ static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
|
||||||
analog->meaning->mq = SR_MQ_CAPACITANCE;
|
analog->meaning->mq = SR_MQ_CAPACITANCE;
|
||||||
analog->meaning->unit = SR_UNIT_FARAD;
|
analog->meaning->unit = SR_UNIT_FARAD;
|
||||||
}
|
}
|
||||||
if (info->is_celsius) {
|
if (info->is_temperature) {
|
||||||
analog->meaning->mq = SR_MQ_TEMPERATURE;
|
analog->meaning->mq = SR_MQ_TEMPERATURE;
|
||||||
|
if (info->is_celsius)
|
||||||
analog->meaning->unit = SR_UNIT_CELSIUS;
|
analog->meaning->unit = SR_UNIT_CELSIUS;
|
||||||
|
else if (info->is_fahrenheit)
|
||||||
|
analog->meaning->unit = SR_UNIT_FAHRENHEIT;
|
||||||
|
else
|
||||||
|
analog->meaning->unit = SR_UNIT_UNITLESS;
|
||||||
}
|
}
|
||||||
if (info->is_diode) {
|
if (info->is_diode) {
|
||||||
analog->meaning->mq = SR_MQ_VOLTAGE;
|
analog->meaning->mq = SR_MQ_VOLTAGE;
|
||||||
analog->meaning->unit = SR_UNIT_VOLT;
|
analog->meaning->unit = SR_UNIT_VOLT;
|
||||||
}
|
}
|
||||||
|
if (info->is_power) {
|
||||||
|
analog->meaning->mq = SR_MQ_POWER;
|
||||||
|
if (info->is_decibel_mw)
|
||||||
|
analog->meaning->unit = SR_UNIT_DECIBEL_MW;
|
||||||
|
else if (info->is_watt)
|
||||||
|
analog->meaning->unit = SR_UNIT_WATT;
|
||||||
|
else
|
||||||
|
analog->meaning->unit = SR_UNIT_UNITLESS;
|
||||||
|
}
|
||||||
|
if (info->is_power_factor) {
|
||||||
|
analog->meaning->mq = SR_MQ_POWER_FACTOR;
|
||||||
|
analog->meaning->unit = SR_UNIT_UNITLESS;
|
||||||
|
}
|
||||||
if (info->is_gain) {
|
if (info->is_gain) {
|
||||||
analog->meaning->mq = SR_MQ_GAIN;
|
analog->meaning->mq = SR_MQ_GAIN;
|
||||||
analog->meaning->unit = SR_UNIT_DECIBEL_VOLT;
|
analog->meaning->unit = SR_UNIT_DECIBEL_VOLT;
|
||||||
|
@ -243,7 +280,13 @@ static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
|
||||||
if (info->is_dc)
|
if (info->is_dc)
|
||||||
analog->meaning->mqflags |= SR_MQFLAG_DC;
|
analog->meaning->mqflags |= SR_MQFLAG_DC;
|
||||||
if (info->is_diode)
|
if (info->is_diode)
|
||||||
analog->meaning->mqflags |= SR_MQFLAG_DIODE;
|
analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
|
||||||
|
if (info->is_min)
|
||||||
|
analog->meaning->mqflags |= SR_MQFLAG_MIN;
|
||||||
|
if (info->is_max)
|
||||||
|
analog->meaning->mqflags |= SR_MQFLAG_MAX;
|
||||||
|
if (info->is_avg)
|
||||||
|
analog->meaning->mqflags |= SR_MQFLAG_AVG;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean flags_valid(const struct metex14_info *info)
|
static gboolean flags_valid(const struct metex14_info *info)
|
||||||
|
@ -293,7 +336,7 @@ SR_PRIV int sr_metex14_packet_request(struct sr_serial_dev_inst *serial)
|
||||||
|
|
||||||
sr_spew("Requesting DMM packet.");
|
sr_spew("Requesting DMM packet.");
|
||||||
|
|
||||||
return (serial_write_nonblocking(serial, &wbuf, 1) == 1) ? SR_OK : SR_ERR;
|
return serial_write_blocking(serial, &wbuf, 1, 0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -313,6 +356,25 @@ SR_PRIV gboolean sr_metex14_packet_valid(const uint8_t *buf)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SR_PRIV gboolean sr_metex14_4packets_valid(const uint8_t *buf)
|
||||||
|
{
|
||||||
|
struct metex14_info info;
|
||||||
|
size_t ch_idx;
|
||||||
|
const uint8_t *ch_buf;
|
||||||
|
|
||||||
|
ch_buf = buf;
|
||||||
|
for (ch_idx = 0; ch_idx < 4; ch_idx++) {
|
||||||
|
if (ch_buf[13] != '\r')
|
||||||
|
return FALSE;
|
||||||
|
memset(&info, 0x00, sizeof(info));
|
||||||
|
parse_flags((const char *)ch_buf, &info);
|
||||||
|
if (!flags_valid(&info))
|
||||||
|
return FALSE;
|
||||||
|
ch_buf += METEX14_PACKET_SIZE;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a protocol packet.
|
* Parse a protocol packet.
|
||||||
*
|
*
|
||||||
|
@ -334,7 +396,7 @@ SR_PRIV int sr_metex14_parse(const uint8_t *buf, float *floatval,
|
||||||
int ret, exponent = 0;
|
int ret, exponent = 0;
|
||||||
struct metex14_info *info_local;
|
struct metex14_info *info_local;
|
||||||
|
|
||||||
info_local = (struct metex14_info *)info;
|
info_local = info;
|
||||||
|
|
||||||
/* Don't print byte 13. That one contains the carriage return. */
|
/* Don't print byte 13. That one contains the carriage return. */
|
||||||
sr_dbg("DMM packet: \"%.13s\"", buf);
|
sr_dbg("DMM packet: \"%.13s\"", buf);
|
||||||
|
@ -354,3 +416,34 @@ SR_PRIV int sr_metex14_parse(const uint8_t *buf, float *floatval,
|
||||||
|
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse one out of four values of a four-display Metex14 variant.
|
||||||
|
*
|
||||||
|
* The caller's 'info' parameter can be used to track the channel index,
|
||||||
|
* as long as the information is kept across calls to the 14-byte packet
|
||||||
|
* parse routine (which clears the 'info' container).
|
||||||
|
*
|
||||||
|
* Since analog values have further details in the 'analog' parameter,
|
||||||
|
* passing multiple values per parse routine call is problematic. So we
|
||||||
|
* prefer the approach of passing one value per call, which is most
|
||||||
|
* reliable and shall fit every similar device with multiple displays.
|
||||||
|
*
|
||||||
|
* The meters which use this parse routine send one 14-byte packet per
|
||||||
|
* display. Each packet has the regular Metex14 layout.
|
||||||
|
*/
|
||||||
|
SR_PRIV int sr_metex14_4packets_parse(const uint8_t *buf, float *floatval,
|
||||||
|
struct sr_datafeed_analog *analog, void *info)
|
||||||
|
{
|
||||||
|
struct metex14_info *info_local;
|
||||||
|
size_t ch_idx;
|
||||||
|
const uint8_t *ch_buf;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
info_local = info;
|
||||||
|
ch_idx = info_local->ch_idx;
|
||||||
|
ch_buf = buf + ch_idx * METEX14_PACKET_SIZE;
|
||||||
|
rc = sr_metex14_parse(ch_buf, floatval, analog, info);
|
||||||
|
info_local->ch_idx = ch_idx + 1;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,389 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the libsigrok project.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Uwe Hermann <uwe@hermann-uwe.de>
|
||||||
|
* Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@gmail.com>
|
||||||
|
* Copyright (C) 2018 Stefan Mandl
|
||||||
|
*
|
||||||
|
* 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 MS8250D protocol parser.
|
||||||
|
*
|
||||||
|
* Sends 18 bytes.
|
||||||
|
* 40 02 32 75 53 33 35 5303 10 00 00 00 00 00 00 10 00
|
||||||
|
*
|
||||||
|
* - Communication parameters: Unidirectional, 2400/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 "ms8250d"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Main display (7-segment LCD value): xxDGA xxEF xxxx xxCB
|
||||||
|
* https://en.wikipedia.org/wiki/Seven-segment_display
|
||||||
|
*/
|
||||||
|
static int parse_digit(uint16_t b)
|
||||||
|
{
|
||||||
|
switch (b) {
|
||||||
|
case 0x0: /* 7-segment not active */
|
||||||
|
return 0;
|
||||||
|
case 0x430: /* Overflow */
|
||||||
|
return 0xF;
|
||||||
|
case 0x533:
|
||||||
|
return 0;
|
||||||
|
case 0x003:
|
||||||
|
return 1;
|
||||||
|
case 0x721:
|
||||||
|
return 2;
|
||||||
|
case 0x703:
|
||||||
|
return 3;
|
||||||
|
case 0x213:
|
||||||
|
return 4;
|
||||||
|
case 0x712:
|
||||||
|
return 5;
|
||||||
|
case 0x732:
|
||||||
|
return 6;
|
||||||
|
case 0x103:
|
||||||
|
return 7;
|
||||||
|
case 0x733:
|
||||||
|
return 8;
|
||||||
|
case 0x713:
|
||||||
|
return 9;
|
||||||
|
default:
|
||||||
|
sr_dbg("Invalid digit word: 0x%04x.", b);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse second display. */
|
||||||
|
static int parse_digit2(uint16_t b)
|
||||||
|
{
|
||||||
|
switch (b) {
|
||||||
|
case 0x00:
|
||||||
|
return 0;
|
||||||
|
case 0x7D:
|
||||||
|
return 0;
|
||||||
|
case 0x05:
|
||||||
|
return 1;
|
||||||
|
case 0x1B:
|
||||||
|
return 2;
|
||||||
|
case 0x1F:
|
||||||
|
return 3;
|
||||||
|
case 0x27:
|
||||||
|
return 4;
|
||||||
|
case 0x3E:
|
||||||
|
return 5;
|
||||||
|
case 0x7E:
|
||||||
|
return 6;
|
||||||
|
case 0x15:
|
||||||
|
return 7;
|
||||||
|
case 0x7F:
|
||||||
|
return 8;
|
||||||
|
case 0x3F:
|
||||||
|
return 9;
|
||||||
|
default:
|
||||||
|
sr_dbg("Invalid second display digit word: 0x%04x.", b);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_flags(const uint8_t *buf, struct ms8250d_info *info)
|
||||||
|
{
|
||||||
|
info->is_volt = (buf[9] & (1 << 4)) ? 1 : 0;
|
||||||
|
info->is_ohm = (buf[9] & (1 << 6)) ? 1 : 0;
|
||||||
|
info->is_ampere = (buf[10] & (1 << 0)) ? 1 : 0;
|
||||||
|
info->is_hz = (buf[10] & (1 << 2)) ? 1 : 0;
|
||||||
|
info->is_farad = (buf[10] & (1 << 1)) ? 1 : 0;
|
||||||
|
|
||||||
|
/* Micro */
|
||||||
|
if (!info->is_farad)
|
||||||
|
info->is_micro = (buf[8] & (1 << 4)) ? 1 : 0;
|
||||||
|
else
|
||||||
|
info->is_micro = (buf[9] & (1 << 1)) ? 1 : 0; /* uF */
|
||||||
|
|
||||||
|
info->is_nano = (buf[8] & (1 << 5)) ? 1 : 0;
|
||||||
|
info->is_milli = (buf[9] & (1 << 0)) ? 1 : 0;
|
||||||
|
info->is_kilo = (buf[9] & (1 << 2)) ? 1 : 0;
|
||||||
|
info->is_mega = (buf[8] & (1 << 6)) ? 1 : 0;
|
||||||
|
|
||||||
|
info->is_autotimer = (buf[1] & (1 << 0)) ? 1 : 0; /* Auto off timer */
|
||||||
|
info->is_rs232 = (buf[1] & (1 << 1)) ? 1 : 0; /* RS232 via USB */
|
||||||
|
info->is_ac = (buf[1] & (1 << 4)) ? 1 : 0;
|
||||||
|
info->is_dc = (buf[2] & (1 << 1)) ? 1 : 0;
|
||||||
|
info->is_auto = (buf[16] & (1 << 4)) ? 1 : 0;
|
||||||
|
info->is_bat = (buf[1] & (1 << 5)) ? 1 : 0; /* Low battery */
|
||||||
|
info->is_min = (buf[16] & (1 << 2)) ? 1 : 0;
|
||||||
|
info->is_max = (buf[16] & (1 << 1)) ? 1 : 0;
|
||||||
|
info->is_rel = (buf[15] & (1 << 7)) ? 1 : 0;
|
||||||
|
info->is_hold = (buf[16] & (1 << 3)) ? 1 : 0;
|
||||||
|
info->is_diode = (buf[11] & (1 << 0)) ? 1 : 0;
|
||||||
|
info->is_beep = (buf[11] & (1 << 1)) ? 1 : 0;
|
||||||
|
info->is_ncv = (buf[0] & (1 << 0)) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean flags_valid(const struct ms8250d_info *info)
|
||||||
|
{
|
||||||
|
int count;
|
||||||
|
|
||||||
|
/* Does the packet have more than one multiplier? */
|
||||||
|
count = 0;
|
||||||
|
count += (info->is_nano) ? 1 : 0;
|
||||||
|
count += (info->is_micro) ? 1 : 0;
|
||||||
|
count += (info->is_milli) ? 1 : 0;
|
||||||
|
count += (info->is_kilo) ? 1 : 0;
|
||||||
|
count += (info->is_mega) ? 1 : 0;
|
||||||
|
if (count > 1) {
|
||||||
|
sr_dbg("More than one multiplier detected in packet.");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Does the packet "measure" more than one type of value? */
|
||||||
|
count = 0;
|
||||||
|
count += (info->is_hz) ? 1 : 0;
|
||||||
|
count += (info->is_ohm) ? 1 : 0;
|
||||||
|
count += (info->is_farad) ? 1 : 0;
|
||||||
|
count += (info->is_ampere) ? 1 : 0;
|
||||||
|
count += (info->is_volt) ? 1 : 0;
|
||||||
|
if (count > 1) {
|
||||||
|
sr_dbg("More than one measurement type detected in packet.");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Both AC and DC set? */
|
||||||
|
if (info->is_ac && info->is_dc) {
|
||||||
|
sr_dbg("Both AC and DC flags detected in packet.");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* RS232 flag set? */
|
||||||
|
if (!info->is_rs232) {
|
||||||
|
sr_dbg("No RS232 flag detected in packet.");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
|
||||||
|
int *exponent, const struct ms8250d_info *info)
|
||||||
|
{
|
||||||
|
/* Factors */
|
||||||
|
if (info->is_nano)
|
||||||
|
*exponent -= 9;
|
||||||
|
if (info->is_micro)
|
||||||
|
*exponent -= 6;
|
||||||
|
if (info->is_milli)
|
||||||
|
*exponent -= 3;
|
||||||
|
if (info->is_kilo)
|
||||||
|
*exponent += 3;
|
||||||
|
if (info->is_mega)
|
||||||
|
*exponent += 6;
|
||||||
|
*floatval *= powf(10, *exponent);
|
||||||
|
|
||||||
|
/* 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_percent) {
|
||||||
|
analog->meaning->mq = SR_MQ_DUTY_CYCLE;
|
||||||
|
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;
|
||||||
|
if (info->is_hold)
|
||||||
|
analog->meaning->mqflags |= SR_MQFLAG_HOLD;
|
||||||
|
if (info->is_rel)
|
||||||
|
analog->meaning->mqflags |= SR_MQFLAG_RELATIVE;
|
||||||
|
|
||||||
|
/* Other flags */
|
||||||
|
if (info->is_rs232)
|
||||||
|
sr_spew("RS232 enabled.");
|
||||||
|
if (info->is_bat)
|
||||||
|
sr_spew("Battery is low.");
|
||||||
|
if (info->is_beep)
|
||||||
|
sr_spew("Beep is active");
|
||||||
|
}
|
||||||
|
|
||||||
|
SR_PRIV gboolean sr_ms8250d_packet_valid(const uint8_t *buf)
|
||||||
|
{
|
||||||
|
struct ms8250d_info info;
|
||||||
|
|
||||||
|
sr_dbg("DMM packet: %02x %02x %02x %02x %02x %02x %02x "
|
||||||
|
"%02x %02x %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], buf[9], buf[10], buf[11], buf[12], buf[13],
|
||||||
|
buf[14], buf[15], buf[16], buf[17]);
|
||||||
|
|
||||||
|
parse_flags(buf, &info);
|
||||||
|
|
||||||
|
if ((buf[17] == 0x00) && flags_valid(&info))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a protocol packet.
|
||||||
|
*
|
||||||
|
* @param buf Buffer containing the 18-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 ms8250d_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_ms8250d_parse(const uint8_t *buf, float *floatval,
|
||||||
|
struct sr_datafeed_analog *analog, void *info)
|
||||||
|
{
|
||||||
|
int exponent = 0, sec_exponent = 0, sign;
|
||||||
|
float sec_floatval;
|
||||||
|
|
||||||
|
/* buf[0] bar display. */
|
||||||
|
/* buf[1] bar display. */
|
||||||
|
|
||||||
|
/* Parse seven segment digit. */
|
||||||
|
int16_t digit4 = parse_digit(((buf[7] & 0x73) << 4) | (buf[8] & 0x3));
|
||||||
|
|
||||||
|
int16_t digit3 = parse_digit(((buf[6] & 0x07) << 8) | (buf[5] & 0x30) \
|
||||||
|
| ((buf[6] & 0x30) >> 4));
|
||||||
|
|
||||||
|
int16_t digit2 = parse_digit(((buf[4] & 0x73) << 4) | (buf[5] & 0x03));
|
||||||
|
|
||||||
|
int16_t digit1 = parse_digit(((buf[3] & 0x07) << 8) | (buf[2] & 0x30) \
|
||||||
|
| ((buf[3] & 0x30) >> 4));
|
||||||
|
|
||||||
|
sr_dbg("Digits: %d %d %d %d.", digit1, digit2, digit3, digit4);
|
||||||
|
|
||||||
|
/* Decimal point position. */
|
||||||
|
if ((buf[3] & (1 << 6)) != 0) {
|
||||||
|
exponent = -3;
|
||||||
|
sr_spew("Decimal point after first digit.");
|
||||||
|
} else if ((buf[5] & (1 << 6)) != 0) {
|
||||||
|
exponent = -2;
|
||||||
|
sr_spew("Decimal point after second digit.");
|
||||||
|
} else if ((buf[7] & (1 << 2)) != 0) {
|
||||||
|
exponent = -1;
|
||||||
|
sr_spew("Decimal point after third digit.");
|
||||||
|
} else {
|
||||||
|
exponent = 0;
|
||||||
|
sr_spew("No decimal point in the number.");
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ms8250d_info *info_local;
|
||||||
|
|
||||||
|
info_local = info;
|
||||||
|
|
||||||
|
parse_flags(buf, info_local);
|
||||||
|
|
||||||
|
/* Sign */
|
||||||
|
sign = (buf[0] & (1 << 2)) ? -1 : 1;
|
||||||
|
|
||||||
|
/* Parse second display. */
|
||||||
|
int16_t sec_digit4 = parse_digit2(buf[12] & 0x7F);
|
||||||
|
int16_t sec_digit3 = parse_digit2(buf[13] & 0x7F);
|
||||||
|
int16_t sec_digit2 = parse_digit2(buf[14] & 0x7F);
|
||||||
|
int16_t sec_digit1 = parse_digit2(buf[15] & 0x7F);
|
||||||
|
|
||||||
|
sr_dbg("Digits (2nd display): %d %d %d %d.",
|
||||||
|
sec_digit1, sec_digit2, sec_digit3, sec_digit4);
|
||||||
|
|
||||||
|
/* Second display decimal point position. */
|
||||||
|
if ((buf[14] & (1 << 7)) != 0) {
|
||||||
|
sec_exponent = -3;
|
||||||
|
sr_spew("Sec decimal point after first digit.");
|
||||||
|
} else if ((buf[13] & (1 << 7)) != 0) {
|
||||||
|
sec_exponent = -2;
|
||||||
|
sr_spew("Sec decimal point after second digit.");
|
||||||
|
} else if ((buf[12] & (1 << 7)) != 0) {
|
||||||
|
sec_exponent = -1;
|
||||||
|
sr_spew("Sec decimal point after third digit.");
|
||||||
|
} else {
|
||||||
|
sec_exponent = 0;
|
||||||
|
sr_spew("Sec no decimal point in the number.");
|
||||||
|
}
|
||||||
|
|
||||||
|
*floatval = (double)((digit1 * 1000) + (digit2 * 100) + (digit3 * 10) + digit4);
|
||||||
|
|
||||||
|
sec_floatval = (double)(sec_digit1 * 1000) + (sec_digit2 * 100) + (sec_digit3 * 10) + sec_digit4;
|
||||||
|
sec_floatval *= powf(10, sec_exponent);
|
||||||
|
|
||||||
|
/* Apply sign. */
|
||||||
|
*floatval *= sign;
|
||||||
|
|
||||||
|
handle_flags(analog, floatval, &exponent, info_local);
|
||||||
|
|
||||||
|
/* Check for "OL". */
|
||||||
|
if (digit3 == 0x0F) {
|
||||||
|
sr_spew("Over limit.");
|
||||||
|
*floatval = INFINITY;
|
||||||
|
return SR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
sr_spew("The display value is %f.", (double)*floatval);
|
||||||
|
sr_spew("The 2nd display value is %f.", sec_floatval);
|
||||||
|
|
||||||
|
analog->encoding->digits = -exponent;
|
||||||
|
analog->spec->spec_digits = -exponent;
|
||||||
|
|
||||||
|
return SR_OK;
|
||||||
|
}
|
|
@ -284,7 +284,7 @@ static void handle_flags(struct sr_datafeed_analog *analog,
|
||||||
if (info->is_auto)
|
if (info->is_auto)
|
||||||
analog->meaning->mqflags |= SR_MQFLAG_AUTORANGE;
|
analog->meaning->mqflags |= SR_MQFLAG_AUTORANGE;
|
||||||
if (info->is_diode)
|
if (info->is_diode)
|
||||||
analog->meaning->mqflags |= SR_MQFLAG_DIODE;
|
analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean flags_valid(const struct ut71x_info *info)
|
static gboolean flags_valid(const struct ut71x_info *info)
|
||||||
|
@ -336,7 +336,7 @@ SR_PRIV int sr_ut71x_parse(const uint8_t *buf, float *floatval,
|
||||||
int ret, exponent = 0;
|
int ret, exponent = 0;
|
||||||
struct ut71x_info *info_local;
|
struct ut71x_info *info_local;
|
||||||
|
|
||||||
info_local = (struct ut71x_info *)info;
|
info_local = info;
|
||||||
memset(info_local, 0, sizeof(struct ut71x_info));
|
memset(info_local, 0, sizeof(struct ut71x_info));
|
||||||
|
|
||||||
if (!sr_ut71x_packet_valid(buf))
|
if (!sr_ut71x_packet_valid(buf))
|
||||||
|
|
|
@ -360,7 +360,7 @@ static void handle_flags(struct sr_datafeed_analog *analog,
|
||||||
if (info->is_auto)
|
if (info->is_auto)
|
||||||
analog->meaning->mqflags |= SR_MQFLAG_AUTORANGE;
|
analog->meaning->mqflags |= SR_MQFLAG_AUTORANGE;
|
||||||
if (info->is_diode)
|
if (info->is_diode)
|
||||||
analog->meaning->mqflags |= SR_MQFLAG_DIODE;
|
analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
|
||||||
if (info->is_hold)
|
if (info->is_hold)
|
||||||
/*
|
/*
|
||||||
* Note: HOLD only affects the number displayed on the LCD,
|
* Note: HOLD only affects the number displayed on the LCD,
|
||||||
|
@ -410,7 +410,7 @@ SR_PRIV int sr_vc870_parse(const uint8_t *buf, float *floatval,
|
||||||
int ret, exponent = 0;
|
int ret, exponent = 0;
|
||||||
struct vc870_info *info_local;
|
struct vc870_info *info_local;
|
||||||
|
|
||||||
info_local = (struct vc870_info *)info;
|
info_local = info;
|
||||||
memset(info_local, 0, sizeof(struct vc870_info));
|
memset(info_local, 0, sizeof(struct vc870_info));
|
||||||
|
|
||||||
if (!sr_vc870_packet_valid(buf))
|
if (!sr_vc870_packet_valid(buf))
|
||||||
|
|
|
@ -0,0 +1,288 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the libsigrok project.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012-2013 Uwe Hermann <uwe@hermann-uwe.de>
|
||||||
|
* Copyright (C) 2018 Matthias Schulz <matthschulz@arcor.de>
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Voltcraft 13-bytes ASCII protocol parser.
|
||||||
|
*
|
||||||
|
* Bytes 1-3 measuring mode, byte 4 '-' for negative,
|
||||||
|
* bytes 5-9 value, bytes 10-11 unit, bytes 12-13 CRLF 0d 0a.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <strings.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <glib.h>
|
||||||
|
#include <libsigrok/libsigrok.h>
|
||||||
|
#include "libsigrok-internal.h"
|
||||||
|
|
||||||
|
#define LOG_PREFIX "vc96"
|
||||||
|
|
||||||
|
/** Parse value from buf, byte 3-8. */
|
||||||
|
static int parse_value(const uint8_t *buf, struct vc96_info *info,
|
||||||
|
float *result, int *exponent)
|
||||||
|
{
|
||||||
|
int i, is_ol, cnt, dot_pos;
|
||||||
|
char valstr[8 + 1];
|
||||||
|
|
||||||
|
(void)info;
|
||||||
|
|
||||||
|
/* Strip all spaces from bytes 3-8. */
|
||||||
|
memset(&valstr, 0, 6 + 1);
|
||||||
|
for (i = 0, cnt = 0; i < 6; i++) {
|
||||||
|
if (buf[3 + i] != ' ')
|
||||||
|
valstr[cnt++] = buf[3 + i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Bytes 5-7: Over limit (various forms) */
|
||||||
|
is_ol = 0;
|
||||||
|
is_ol += (!g_ascii_strcasecmp((const char *)&valstr, ".OL")) ? 1 : 0;
|
||||||
|
is_ol += (!g_ascii_strcasecmp((const char *)&valstr, "O.L")) ? 1 : 0;
|
||||||
|
is_ol += (!g_ascii_strcasecmp((const char *)&valstr, "OL.")) ? 1 : 0;
|
||||||
|
is_ol += (!g_ascii_strcasecmp((const char *)&valstr, "OL")) ? 1 : 0;
|
||||||
|
is_ol += (!g_ascii_strcasecmp((const char *)&valstr, "-.OL")) ? 1 : 0;
|
||||||
|
is_ol += (!g_ascii_strcasecmp((const char *)&valstr, "-O.L")) ? 1 : 0;
|
||||||
|
is_ol += (!g_ascii_strcasecmp((const char *)&valstr, "-OL.")) ? 1 : 0;
|
||||||
|
is_ol += (!g_ascii_strcasecmp((const char *)&valstr, "-OL")) ? 1 : 0;
|
||||||
|
if (is_ol != 0) {
|
||||||
|
sr_spew("Over limit.");
|
||||||
|
*result = INFINITY;
|
||||||
|
return SR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Bytes 3-10: Sign, value (up to 5 digits) and decimal point */
|
||||||
|
sr_atof_ascii((const char *)&valstr, result);
|
||||||
|
|
||||||
|
dot_pos = strcspn(valstr, ".");
|
||||||
|
if (dot_pos < cnt)
|
||||||
|
*exponent = -(cnt - dot_pos - 1);
|
||||||
|
else
|
||||||
|
*exponent = 0;
|
||||||
|
|
||||||
|
sr_spew("The display value is %f.", *result);
|
||||||
|
|
||||||
|
return SR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_flags(const char *buf, struct vc96_info *info)
|
||||||
|
{
|
||||||
|
int i, cnt;
|
||||||
|
char unit[4 + 1];
|
||||||
|
const char *u;
|
||||||
|
|
||||||
|
/* Bytes 0-1: Measurement mode AC, DC */
|
||||||
|
info->is_ac = !strncmp(buf, "AC", 2);
|
||||||
|
info->is_dc = !strncmp(buf, "DC", 2);
|
||||||
|
|
||||||
|
/* Bytes 0-2: Measurement mode DIO, OHM */
|
||||||
|
info->is_ohm = !strncmp(buf, "OHM", 3);
|
||||||
|
info->is_diode = !strncmp(buf, "DIO", 3);
|
||||||
|
info->is_hfe = !strncmp(buf, "hfe", 3);
|
||||||
|
|
||||||
|
/* Bytes 3-8: See parse_value(). */
|
||||||
|
|
||||||
|
/* Strip all spaces from bytes 9-10. */
|
||||||
|
memset(&unit, 0, 2 + 1);
|
||||||
|
for (i = 0, cnt = 0; i < 2; i++) {
|
||||||
|
if (buf[9 + i] != ' ')
|
||||||
|
unit[cnt++] = buf[9 + i];
|
||||||
|
}
|
||||||
|
sr_spew("Bytes 9..10 without spaces \"%.4s\".", unit);
|
||||||
|
|
||||||
|
/* Bytes 9-10: Unit */
|
||||||
|
u = (const char *)&unit;
|
||||||
|
if (!g_ascii_strcasecmp(u, "A"))
|
||||||
|
info->is_ampere = TRUE;
|
||||||
|
else if (!g_ascii_strcasecmp(u, "mA"))
|
||||||
|
info->is_milli = info->is_ampere = TRUE;
|
||||||
|
else if (!g_ascii_strcasecmp(u, "uA"))
|
||||||
|
info->is_micro = info->is_ampere = TRUE;
|
||||||
|
else if (!g_ascii_strcasecmp(u, "V"))
|
||||||
|
info->is_volt = TRUE;
|
||||||
|
else if (!g_ascii_strcasecmp(u, "mV"))
|
||||||
|
info->is_milli = info->is_volt = TRUE;
|
||||||
|
else if (!g_ascii_strcasecmp(u, "K"))
|
||||||
|
info->is_kilo = TRUE;
|
||||||
|
else if (!g_ascii_strcasecmp(u, "M"))
|
||||||
|
info->is_mega = TRUE;
|
||||||
|
else if (!g_ascii_strcasecmp(u, ""))
|
||||||
|
info->is_unitless = TRUE;
|
||||||
|
|
||||||
|
/* Bytes 0-2: Measurement mode, except AC/DC */
|
||||||
|
info->is_resistance = !strncmp(buf, "OHM", 3) ||
|
||||||
|
(!strncmp(buf, " ", 3) && info->is_ohm);
|
||||||
|
info->is_diode = !strncmp(buf, "DIO", 3) ||
|
||||||
|
(!strncmp(buf, " ", 3) && info->is_volt && info->is_milli);
|
||||||
|
info->is_hfe = !strncmp(buf, "hfe", 3) ||
|
||||||
|
(!strncmp(buf, " ", 3) && !info->is_ampere && !info->is_volt &&
|
||||||
|
!info->is_resistance && !info->is_diode);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note:
|
||||||
|
* - Protocol doesn't distinguish "resistance" from "beep" mode.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Byte 12: Always '\r' (carriage return, 0x0d, 12) */
|
||||||
|
/* Byte 13: Always '\n' (carriage return, 0x0a, 13) */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
|
||||||
|
int *exponent, const struct vc96_info *info)
|
||||||
|
{
|
||||||
|
int factor;
|
||||||
|
|
||||||
|
(void)exponent;
|
||||||
|
|
||||||
|
/* Factors */
|
||||||
|
factor = 0;
|
||||||
|
if (info->is_micro)
|
||||||
|
factor -= 6;
|
||||||
|
if (info->is_milli)
|
||||||
|
factor -= 3;
|
||||||
|
if (info->is_kilo)
|
||||||
|
factor += 3;
|
||||||
|
if (info->is_mega)
|
||||||
|
factor += 6;
|
||||||
|
*floatval *= powf(10, factor);
|
||||||
|
|
||||||
|
/* 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_diode) {
|
||||||
|
analog->meaning->mq = SR_MQ_VOLTAGE;
|
||||||
|
analog->meaning->unit = SR_UNIT_VOLT;
|
||||||
|
}
|
||||||
|
if (info->is_hfe) {
|
||||||
|
analog->meaning->mq = SR_MQ_GAIN;
|
||||||
|
analog->meaning->unit = SR_UNIT_UNITLESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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_diode)
|
||||||
|
analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean flags_valid(const struct vc96_info *info)
|
||||||
|
{
|
||||||
|
int count;
|
||||||
|
|
||||||
|
/* Does the packet have more than one multiplier? */
|
||||||
|
count = 0;
|
||||||
|
count += (info->is_micro) ? 1 : 0;
|
||||||
|
count += (info->is_milli) ? 1 : 0;
|
||||||
|
count += (info->is_kilo) ? 1 : 0;
|
||||||
|
count += (info->is_mega) ? 1 : 0;
|
||||||
|
if (count > 1) {
|
||||||
|
sr_dbg("More than one multiplier detected in packet.");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Does the packet "measure" more than one type of value? */
|
||||||
|
count = 0;
|
||||||
|
count += (info->is_ac) ? 1 : 0;
|
||||||
|
count += (info->is_dc) ? 1 : 0;
|
||||||
|
count += (info->is_resistance) ? 1 : 0;
|
||||||
|
count += (info->is_diode) ? 1 : 0;
|
||||||
|
if (count > 1) {
|
||||||
|
sr_dbg("More than one measurement type detected in packet.");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Both AC and DC set? */
|
||||||
|
if (info->is_ac && info->is_dc) {
|
||||||
|
sr_dbg("Both AC and DC flags detected in packet.");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
SR_PRIV gboolean sr_vc96_packet_valid(const uint8_t *buf)
|
||||||
|
{
|
||||||
|
struct vc96_info info;
|
||||||
|
|
||||||
|
memset(&info, 0x00, sizeof(struct vc96_info));
|
||||||
|
parse_flags((const char *)buf, &info);
|
||||||
|
|
||||||
|
if (!flags_valid(&info))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if ((buf[11] != '\r') || (buf[12] != '\n'))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a protocol packet.
|
||||||
|
*
|
||||||
|
* @param buf Buffer containing the protocol packet. Must not be NULL.
|
||||||
|
* @param floatval Pointer to a float variable. That variable will be modified
|
||||||
|
* in-place depending on the protocol packet. 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 vc96_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_vc96_parse(const uint8_t *buf, float *floatval,
|
||||||
|
struct sr_datafeed_analog *analog, void *info)
|
||||||
|
{
|
||||||
|
int ret, exponent = 0;
|
||||||
|
struct vc96_info *info_local;
|
||||||
|
|
||||||
|
info_local = info;
|
||||||
|
|
||||||
|
/* Don't print byte 12 + 13. Those contain the CR LF. */
|
||||||
|
sr_dbg("DMM packet: \"%.11s\".", buf);
|
||||||
|
|
||||||
|
memset(info_local, 0x00, sizeof(struct vc96_info));
|
||||||
|
|
||||||
|
if ((ret = parse_value(buf, info_local, floatval, &exponent)) < 0) {
|
||||||
|
sr_dbg("Error parsing value: %d.", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_flags((const char *)buf, info_local);
|
||||||
|
handle_flags(analog, floatval, &exponent, info_local);
|
||||||
|
|
||||||
|
analog->encoding->digits = -exponent;
|
||||||
|
analog->spec->spec_digits = -exponent;
|
||||||
|
|
||||||
|
return SR_OK;
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the libsigrok project.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Marcus Comstedt <marcus@mc.pp.se>
|
||||||
|
*
|
||||||
|
* 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 <glib.h>
|
||||||
|
#include <libsigrok/libsigrok.h>
|
||||||
|
#include "libsigrok-internal.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This marks the start of the driver list. This file must be linked
|
||||||
|
* before any actual drivers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
SR_PRIV const struct sr_dev_driver *sr_driver_list__start[]
|
||||||
|
__attribute__((section (SR_DRIVER_LIST_SECTION),
|
||||||
|
used, aligned(sizeof(struct sr_dev_driver *))))
|
||||||
|
= { NULL /* Dummy item, as zero length arrays are not allowed by C99 */ };
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the libsigrok project.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Marcus Comstedt <marcus@mc.pp.se>
|
||||||
|
*
|
||||||
|
* 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 <glib.h>
|
||||||
|
#include <libsigrok/libsigrok.h>
|
||||||
|
#include "libsigrok-internal.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This marks the end of the driver list. This file must be linked
|
||||||
|
* after any actual drivers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
SR_PRIV const struct sr_dev_driver *sr_driver_list__stop[]
|
||||||
|
__attribute__((section (SR_DRIVER_LIST_SECTION),
|
||||||
|
used, aligned(sizeof(struct sr_dev_driver *))))
|
||||||
|
= { NULL /* Dummy item, as zero length arrays are not allowed by C99 */ };
|
|
@ -3,6 +3,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (C) 2016 Lars-Peter Clausen <lars@metafoo.de>
|
* Copyright (C) 2016 Lars-Peter Clausen <lars@metafoo.de>
|
||||||
* Copyright (C) 2016 Aurelien Jacobs <aurel@gnuage.org>
|
* Copyright (C) 2016 Aurelien Jacobs <aurel@gnuage.org>
|
||||||
|
* Copyright (C) 2017 Marcus Comstedt <marcus@mc.pp.se>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -26,17 +27,12 @@
|
||||||
/*
|
/*
|
||||||
* sr_driver_list is a special section contains pointers to all the hardware
|
* sr_driver_list is a special section contains pointers to all the hardware
|
||||||
* drivers built into the library. The __start and __stop symbols are
|
* drivers built into the library. The __start and __stop symbols are
|
||||||
* auto-generated by the linker (OSX needs a little help) and point to the start
|
* created from driver_list_start.c and driver_list_stop.c, and point to the
|
||||||
* and end of the section. They are used to iterate over the list of all
|
* start and end of the section. They are used to iterate over the list of
|
||||||
* drivers.
|
* all drivers.
|
||||||
*/
|
*/
|
||||||
#ifdef __APPLE__
|
SR_PRIV extern const struct sr_dev_driver *sr_driver_list__start[];
|
||||||
extern struct sr_dev_driver *__start_sr_driver_list __asm("section$start$__DATA$__sr_driver_list");
|
SR_PRIV extern const struct sr_dev_driver *sr_driver_list__stop[];
|
||||||
extern struct sr_dev_driver *__stop_sr_driver_list __asm("section$end$__DATA$__sr_driver_list");
|
|
||||||
#else
|
|
||||||
extern struct sr_dev_driver *__start_sr_driver_list;
|
|
||||||
extern struct sr_dev_driver *__stop_sr_driver_list;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** @private
|
/** @private
|
||||||
* Initialize the driver list in a fresh libsigrok context.
|
* Initialize the driver list in a fresh libsigrok context.
|
||||||
|
@ -49,8 +45,8 @@ SR_API void sr_drivers_init(struct sr_context *ctx)
|
||||||
|
|
||||||
array = g_array_new(TRUE, FALSE, sizeof(struct sr_dev_driver *));
|
array = g_array_new(TRUE, FALSE, sizeof(struct sr_dev_driver *));
|
||||||
#ifdef HAVE_DRIVERS
|
#ifdef HAVE_DRIVERS
|
||||||
for (struct sr_dev_driver **drivers = &__start_sr_driver_list;
|
for (const struct sr_dev_driver **drivers = sr_driver_list__start + 1;
|
||||||
drivers < &__stop_sr_driver_list; drivers++)
|
drivers < sr_driver_list__stop; drivers++)
|
||||||
g_array_append_val(array, *drivers);
|
g_array_append_val(array, *drivers);
|
||||||
#endif
|
#endif
|
||||||
ctx->driver_list = (struct sr_dev_driver **)array->data;
|
ctx->driver_list = (struct sr_dev_driver **)array->data;
|
||||||
|
|
|
@ -51,11 +51,7 @@ static const uint64_t samplerates[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *data_sources[] = {
|
static const char *data_sources[] = {
|
||||||
"Live",
|
"Live", "Log-Hand", "Log-Trig", "Log-Auto", "Log-Export",
|
||||||
"Log-Hand",
|
|
||||||
"Log-Trig",
|
|
||||||
"Log-Auto",
|
|
||||||
"Log-Export",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const struct agdmm_job agdmm_jobs_live[];
|
extern const struct agdmm_job agdmm_jobs_live[];
|
||||||
|
@ -187,25 +183,22 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
return std_scan_complete(di, devices);
|
return std_scan_complete(di, devices);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
|
static int config_get(uint32_t key, GVariant **data,
|
||||||
const struct sr_channel_group *cg)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
int ret;
|
|
||||||
|
|
||||||
(void)cg;
|
(void)cg;
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
ret = SR_OK;
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case SR_CONF_SAMPLERATE:
|
case SR_CONF_SAMPLERATE:
|
||||||
*data = g_variant_new_uint64(devc->cur_samplerate);
|
*data = g_variant_new_uint64(devc->cur_samplerate);
|
||||||
break;
|
break;
|
||||||
case SR_CONF_LIMIT_SAMPLES:
|
case SR_CONF_LIMIT_SAMPLES:
|
||||||
case SR_CONF_LIMIT_MSEC:
|
case SR_CONF_LIMIT_MSEC:
|
||||||
ret = sr_sw_limits_config_get(&devc->limits, key, data);
|
return sr_sw_limits_config_get(&devc->limits, key, data);
|
||||||
break;
|
|
||||||
case SR_CONF_DATA_SOURCE:
|
case SR_CONF_DATA_SOURCE:
|
||||||
*data = g_variant_new_string(data_sources[devc->data_source]);
|
*data = g_variant_new_string(data_sources[devc->data_source]);
|
||||||
break;
|
break;
|
||||||
|
@ -213,91 +206,54 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s
|
||||||
return SR_ERR_NA;
|
return SR_ERR_NA;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
|
static int config_set(uint32_t key, GVariant *data,
|
||||||
const struct sr_channel_group *cg)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
uint64_t samplerate;
|
uint64_t samplerate;
|
||||||
const char *tmp_str;
|
int idx;
|
||||||
unsigned int i;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
(void)cg;
|
(void)cg;
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
ret = SR_OK;
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case SR_CONF_SAMPLERATE:
|
case SR_CONF_SAMPLERATE:
|
||||||
samplerate = g_variant_get_uint64(data);
|
samplerate = g_variant_get_uint64(data);
|
||||||
if (samplerate < samplerates[0] || samplerate > samplerates[1])
|
if (samplerate < samplerates[0] || samplerate > samplerates[1])
|
||||||
ret = SR_ERR_ARG;
|
return SR_ERR_ARG;
|
||||||
else
|
|
||||||
devc->cur_samplerate = g_variant_get_uint64(data);
|
devc->cur_samplerate = g_variant_get_uint64(data);
|
||||||
break;
|
break;
|
||||||
case SR_CONF_LIMIT_SAMPLES:
|
case SR_CONF_LIMIT_SAMPLES:
|
||||||
case SR_CONF_LIMIT_MSEC:
|
case SR_CONF_LIMIT_MSEC:
|
||||||
ret = sr_sw_limits_config_set(&devc->limits, key, data);
|
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;
|
break;
|
||||||
case SR_CONF_DATA_SOURCE: {
|
|
||||||
tmp_str = g_variant_get_string(data, NULL);
|
|
||||||
for (i = 0; i < ARRAY_SIZE(data_sources); i++)
|
|
||||||
if (!strcmp(tmp_str, data_sources[i])) {
|
|
||||||
devc->data_source = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (i == ARRAY_SIZE(data_sources))
|
|
||||||
return SR_ERR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
ret = SR_ERR_NA;
|
return SR_ERR_NA;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
|
static int config_list(uint32_t key, GVariant **data,
|
||||||
const struct sr_channel_group *cg)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
GVariant *gvar;
|
|
||||||
GVariantBuilder gvb;
|
|
||||||
|
|
||||||
if (key == SR_CONF_SCAN_OPTIONS) {
|
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
|
|
||||||
return SR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key == SR_CONF_DEVICE_OPTIONS && !sdi) {
|
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
drvopts, ARRAY_SIZE(drvopts), sizeof(uint32_t));
|
|
||||||
return SR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!sdi || cg)
|
|
||||||
return SR_ERR_ARG;
|
|
||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
|
case SR_CONF_SCAN_OPTIONS:
|
||||||
case SR_CONF_DEVICE_OPTIONS:
|
case SR_CONF_DEVICE_OPTIONS:
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
|
||||||
devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
|
|
||||||
break;
|
|
||||||
case SR_CONF_SAMPLERATE:
|
case SR_CONF_SAMPLERATE:
|
||||||
g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
|
*data = std_gvar_samplerates_steps(ARRAY_AND_SIZE(samplerates));
|
||||||
gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), samplerates,
|
|
||||||
ARRAY_SIZE(samplerates), sizeof(uint64_t));
|
|
||||||
g_variant_builder_add(&gvb, "{sv}", "samplerate-steps", gvar);
|
|
||||||
*data = g_variant_builder_end(&gvb);
|
|
||||||
break;
|
break;
|
||||||
case SR_CONF_DATA_SOURCE:
|
case SR_CONF_DATA_SOURCE:
|
||||||
*data = g_variant_new_strv(data_sources, ARRAY_SIZE(data_sources));
|
*data = g_variant_new_strv(ARRAY_AND_SIZE(data_sources));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return SR_ERR_NA;
|
return SR_ERR_NA;
|
||||||
|
@ -311,9 +267,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||||
struct dev_context *devc = sdi->priv;
|
struct dev_context *devc = sdi->priv;
|
||||||
struct sr_serial_dev_inst *serial;
|
struct sr_serial_dev_inst *serial;
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
devc->cur_channel = sr_next_enabled_channel(sdi, NULL);
|
devc->cur_channel = sr_next_enabled_channel(sdi, NULL);
|
||||||
devc->cur_conf = sr_next_enabled_channel(sdi, NULL);
|
devc->cur_conf = sr_next_enabled_channel(sdi, NULL);
|
||||||
devc->cur_sample = 1;
|
devc->cur_sample = 1;
|
||||||
|
@ -338,7 +291,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||||
sr_sw_limits_acquisition_start(&devc->limits);
|
sr_sw_limits_acquisition_start(&devc->limits);
|
||||||
std_session_send_df_header(sdi);
|
std_session_send_df_header(sdi);
|
||||||
|
|
||||||
/* Poll every 10ms, or whenever some data comes in. */
|
|
||||||
serial = sdi->conn;
|
serial = sdi->conn;
|
||||||
serial_source_add(sdi->session, serial, G_IO_IN, 10,
|
serial_source_add(sdi->session, serial, G_IO_IN, 10,
|
||||||
agdmm_receive_data, (void *)sdi);
|
agdmm_receive_data, (void *)sdi);
|
||||||
|
@ -354,7 +306,7 @@ static struct sr_dev_driver agdmm_driver_info = {
|
||||||
.cleanup = std_cleanup,
|
.cleanup = std_cleanup,
|
||||||
.scan = scan,
|
.scan = scan,
|
||||||
.dev_list = std_dev_list,
|
.dev_list = std_dev_list,
|
||||||
.dev_clear = NULL,
|
.dev_clear = std_dev_clear,
|
||||||
.config_get = config_get,
|
.config_get = config_get,
|
||||||
.config_set = config_set,
|
.config_set = config_set,
|
||||||
.config_list = config_list,
|
.config_list = config_list,
|
||||||
|
|
|
@ -77,7 +77,7 @@ static const struct agdmm_job *job_next(struct dev_context *devc)
|
||||||
devc->current_job++;
|
devc->current_job++;
|
||||||
if (!job_current(devc)->send)
|
if (!job_current(devc)->send)
|
||||||
devc->current_job = 0;
|
devc->current_job = 0;
|
||||||
} while(job_in_interval(devc) && devc->current_job != current_job);
|
} while (job_in_interval(devc) && devc->current_job != current_job);
|
||||||
return job_current(devc);
|
return job_current(devc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,7 +200,7 @@ SR_PRIV int agdmm_receive_data(int fd, int revents, void *cb_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sr_sw_limits_check(&devc->limits) || stop)
|
if (sr_sw_limits_check(&devc->limits) || stop)
|
||||||
sdi->driver->dev_acquisition_stop(sdi);
|
sr_dev_acquisition_stop(sdi);
|
||||||
else
|
else
|
||||||
dispatch(sdi);
|
dispatch(sdi);
|
||||||
|
|
||||||
|
@ -600,7 +600,7 @@ static int recv_conf_u123x(const struct sr_dev_inst *sdi, GMatchInfo *match)
|
||||||
} else if (!strcmp(mstr, "DIOD")) {
|
} else if (!strcmp(mstr, "DIOD")) {
|
||||||
devc->cur_mq[i] = SR_MQ_VOLTAGE;
|
devc->cur_mq[i] = SR_MQ_VOLTAGE;
|
||||||
devc->cur_unit[i] = SR_UNIT_VOLT;
|
devc->cur_unit[i] = SR_UNIT_VOLT;
|
||||||
devc->cur_mqflags[i] = SR_MQFLAG_DIODE;
|
devc->cur_mqflags[i] = SR_MQFLAG_DIODE | SR_MQFLAG_DC;
|
||||||
devc->cur_exponent[i] = 0;
|
devc->cur_exponent[i] = 0;
|
||||||
devc->cur_digits[i] = 3;
|
devc->cur_digits[i] = 3;
|
||||||
} else if (!strcmp(mstr, "CAP")) {
|
} else if (!strcmp(mstr, "CAP")) {
|
||||||
|
@ -738,7 +738,7 @@ static int recv_conf_u124x_5x(const struct sr_dev_inst *sdi, GMatchInfo *match)
|
||||||
} else if (!strcmp(mstr, "DIOD")) {
|
} else if (!strcmp(mstr, "DIOD")) {
|
||||||
devc->cur_mq[i] = SR_MQ_VOLTAGE;
|
devc->cur_mq[i] = SR_MQ_VOLTAGE;
|
||||||
devc->cur_unit[i] = SR_UNIT_VOLT;
|
devc->cur_unit[i] = SR_UNIT_VOLT;
|
||||||
devc->cur_mqflags[i] = SR_MQFLAG_DIODE;
|
devc->cur_mqflags[i] = SR_MQFLAG_DIODE | SR_MQFLAG_DC;
|
||||||
devc->cur_exponent[i] = 0;
|
devc->cur_exponent[i] = 0;
|
||||||
if (devc->profile->model == KEYSIGHT_U1281 ||
|
if (devc->profile->model == KEYSIGHT_U1281 ||
|
||||||
devc->profile->model == KEYSIGHT_U1282) {
|
devc->profile->model == KEYSIGHT_U1282) {
|
||||||
|
@ -871,7 +871,7 @@ static int recv_log(const struct sr_dev_inst *sdi, GMatchInfo *match,
|
||||||
if (mstr[12] & 1) mqflags |= SR_MQFLAG_AVG;
|
if (mstr[12] & 1) mqflags |= SR_MQFLAG_AVG;
|
||||||
if (mstr[12] & 2) mqflags |= SR_MQFLAG_MIN;
|
if (mstr[12] & 2) mqflags |= SR_MQFLAG_MIN;
|
||||||
if (mstr[12] & 4) mqflags |= SR_MQFLAG_MAX;
|
if (mstr[12] & 4) mqflags |= SR_MQFLAG_MAX;
|
||||||
if (function == 5) mqflags |= SR_MQFLAG_DIODE;
|
if (function == 5) mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
|
||||||
g_free(mstr);
|
g_free(mstr);
|
||||||
|
|
||||||
mq = mqs[function];
|
mq = mqs[function];
|
||||||
|
|
|
@ -68,13 +68,11 @@ struct agdmm_profile {
|
||||||
const struct agdmm_recv *recvs;
|
const struct agdmm_recv *recvs;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Private, per-device-instance driver context. */
|
|
||||||
struct dev_context {
|
struct dev_context {
|
||||||
const struct agdmm_profile *profile;
|
const struct agdmm_profile *profile;
|
||||||
struct sr_sw_limits limits;
|
struct sr_sw_limits limits;
|
||||||
int data_source;
|
int data_source;
|
||||||
|
|
||||||
/* Runtime. */
|
|
||||||
const struct agdmm_job *jobs;
|
const struct agdmm_job *jobs;
|
||||||
int current_job;
|
int current_job;
|
||||||
gboolean job_running;
|
gboolean job_running;
|
||||||
|
|
|
@ -109,8 +109,8 @@ scan_cleanup:
|
||||||
return std_scan_complete(di, devices);
|
return std_scan_complete(di, devices);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
|
static int config_get(uint32_t key, GVariant **data,
|
||||||
const struct sr_channel_group *cg)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
struct dev_context *devc = sdi->priv;
|
struct dev_context *devc = sdi->priv;
|
||||||
|
|
||||||
|
@ -130,35 +130,25 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
|
static int config_set(uint32_t key, GVariant *data,
|
||||||
const struct sr_channel_group *cg)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
const char *tmp_str;
|
int idx;
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
(void)cg;
|
(void)cg;
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case SR_CONF_LIMIT_SAMPLES:
|
case SR_CONF_LIMIT_SAMPLES:
|
||||||
case SR_CONF_LIMIT_MSEC:
|
case SR_CONF_LIMIT_MSEC:
|
||||||
return sr_sw_limits_config_set(&devc->limits, key, data);
|
return sr_sw_limits_config_set(&devc->limits, key, data);
|
||||||
case SR_CONF_DATA_SOURCE: {
|
case SR_CONF_DATA_SOURCE:
|
||||||
tmp_str = g_variant_get_string(data, NULL);
|
if ((idx = std_str_idx(data, ARRAY_AND_SIZE(data_sources))) < 0)
|
||||||
for (i = 0; i < ARRAY_SIZE(data_sources); i++)
|
return SR_ERR_ARG;
|
||||||
if (!strcmp(tmp_str, data_sources[i])) {
|
devc->data_source = idx;
|
||||||
devc->data_source = i;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
if (i == ARRAY_SIZE(data_sources))
|
|
||||||
return SR_ERR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
return SR_ERR_NA;
|
return SR_ERR_NA;
|
||||||
}
|
}
|
||||||
|
@ -166,26 +156,15 @@ static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sd
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
|
static int config_list(uint32_t key, GVariant **data,
|
||||||
const struct sr_channel_group *cg)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
(void)cg;
|
|
||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case SR_CONF_SCAN_OPTIONS:
|
case SR_CONF_SCAN_OPTIONS:
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
|
|
||||||
break;
|
|
||||||
case SR_CONF_DEVICE_OPTIONS:
|
case SR_CONF_DEVICE_OPTIONS:
|
||||||
if (!sdi)
|
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
drvopts, ARRAY_SIZE(drvopts), sizeof(uint32_t));
|
|
||||||
else
|
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
|
|
||||||
break;
|
|
||||||
case SR_CONF_DATA_SOURCE:
|
case SR_CONF_DATA_SOURCE:
|
||||||
*data = g_variant_new_strv(data_sources, ARRAY_SIZE(data_sources));
|
*data = g_variant_new_strv(ARRAY_AND_SIZE(data_sources));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return SR_ERR_NA;
|
return SR_ERR_NA;
|
||||||
|
@ -200,16 +179,12 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
|
|
||||||
serial = sdi->conn;
|
serial = sdi->conn;
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
sr_sw_limits_acquisition_start(&devc->limits);
|
sr_sw_limits_acquisition_start(&devc->limits);
|
||||||
|
|
||||||
std_session_send_df_header(sdi);
|
std_session_send_df_header(sdi);
|
||||||
|
|
||||||
/* Poll every 50ms, or whenever some data comes in. */
|
|
||||||
serial_source_add(sdi->session, serial, G_IO_IN, 50,
|
serial_source_add(sdi->session, serial, G_IO_IN, 50,
|
||||||
appa_55ii_receive_data, (void *)sdi);
|
appa_55ii_receive_data, (void *)sdi);
|
||||||
|
|
||||||
|
@ -224,7 +199,7 @@ static struct sr_dev_driver appa_55ii_driver_info = {
|
||||||
.cleanup = std_cleanup,
|
.cleanup = std_cleanup,
|
||||||
.scan = scan,
|
.scan = scan,
|
||||||
.dev_list = std_dev_list,
|
.dev_list = std_dev_list,
|
||||||
.dev_clear = NULL,
|
.dev_clear = std_dev_clear,
|
||||||
.config_get = config_get,
|
.config_get = config_get,
|
||||||
.config_set = config_set,
|
.config_set = config_set,
|
||||||
.config_list = config_list,
|
.config_list = config_list,
|
||||||
|
|
|
@ -224,7 +224,7 @@ static void appa_55ii_log_end(struct sr_dev_inst *sdi)
|
||||||
if (devc->data_source != DATA_SOURCE_MEMORY)
|
if (devc->data_source != DATA_SOURCE_MEMORY)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
sdi->driver->dev_acquisition_stop(sdi);
|
sr_dev_acquisition_stop(sdi);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const uint8_t *appa_55ii_parse_data(struct sr_dev_inst *sdi,
|
static const uint8_t *appa_55ii_parse_data(struct sr_dev_inst *sdi,
|
||||||
|
@ -309,7 +309,7 @@ SR_PRIV int appa_55ii_receive_data(int fd, int revents, void *cb_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sr_sw_limits_check(&devc->limits)) {
|
if (sr_sw_limits_check(&devc->limits)) {
|
||||||
sdi->driver->dev_acquisition_stop(sdi);
|
sr_dev_acquisition_stop(sdi);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,13 +36,10 @@ enum {
|
||||||
DATA_SOURCE_MEMORY,
|
DATA_SOURCE_MEMORY,
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Private, per-device-instance driver context. */
|
|
||||||
struct dev_context {
|
struct dev_context {
|
||||||
/* Acquisition settings */
|
|
||||||
struct sr_sw_limits limits;
|
struct sr_sw_limits limits;
|
||||||
gboolean data_source; /**< Whether to read live samples or memory */
|
gboolean data_source; /**< Whether to read live samples or memory */
|
||||||
|
|
||||||
/* Temporary state across callbacks */
|
|
||||||
uint8_t buf[APPA_55II_BUF_SIZE];
|
uint8_t buf[APPA_55II_BUF_SIZE];
|
||||||
unsigned int buf_len;
|
unsigned int buf_len;
|
||||||
uint8_t log_buf[64];
|
uint8_t log_buf[64];
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
#define CMD_VERSION "version\r\n"
|
#define CMD_VERSION "version\r\n"
|
||||||
#define CMD_MONITOR "monitor 200\r\n"
|
#define CMD_MONITOR "monitor 200\r\n"
|
||||||
|
#define CMD_MONITOR_STOP "monitor 0\r\n"
|
||||||
|
|
||||||
static const uint32_t scanopts[] = {
|
static const uint32_t scanopts[] = {
|
||||||
SR_CONF_CONN,
|
SR_CONF_CONN,
|
||||||
|
@ -43,7 +44,7 @@ static const uint32_t devopts[] = {
|
||||||
|
|
||||||
static const uint32_t devopts_cg[] = {
|
static const uint32_t devopts_cg[] = {
|
||||||
SR_CONF_ENABLED | SR_CONF_SET,
|
SR_CONF_ENABLED | SR_CONF_SET,
|
||||||
SR_CONF_REGULATION | SR_CONF_GET,
|
SR_CONF_REGULATION | SR_CONF_GET | SR_CONF_LIST,
|
||||||
SR_CONF_VOLTAGE | SR_CONF_GET,
|
SR_CONF_VOLTAGE | SR_CONF_GET,
|
||||||
SR_CONF_CURRENT | SR_CONF_GET,
|
SR_CONF_CURRENT | SR_CONF_GET,
|
||||||
SR_CONF_CURRENT_LIMIT | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
|
SR_CONF_CURRENT_LIMIT | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
|
||||||
|
@ -53,6 +54,12 @@ static const uint32_t devopts_cg[] = {
|
||||||
SR_CONF_OVER_TEMPERATURE_PROTECTION_ACTIVE | SR_CONF_GET,
|
SR_CONF_OVER_TEMPERATURE_PROTECTION_ACTIVE | SR_CONF_GET,
|
||||||
SR_CONF_UNDER_VOLTAGE_CONDITION | SR_CONF_GET,
|
SR_CONF_UNDER_VOLTAGE_CONDITION | SR_CONF_GET,
|
||||||
SR_CONF_UNDER_VOLTAGE_CONDITION_ACTIVE | SR_CONF_GET,
|
SR_CONF_UNDER_VOLTAGE_CONDITION_ACTIVE | SR_CONF_GET,
|
||||||
|
SR_CONF_UNDER_VOLTAGE_CONDITION_THRESHOLD | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *regulation[] = {
|
||||||
|
/* CC mode only. */
|
||||||
|
"CC",
|
||||||
};
|
};
|
||||||
|
|
||||||
static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
|
@ -94,6 +101,19 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
|
|
||||||
serial_flush(serial);
|
serial_flush(serial);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* First stop potentially running monitoring and wait for 50ms before
|
||||||
|
* next command can be sent.
|
||||||
|
*/
|
||||||
|
if (serial_write_blocking(serial, CMD_MONITOR_STOP,
|
||||||
|
strlen(CMD_MONITOR_STOP), serial_timeout(serial,
|
||||||
|
strlen(CMD_MONITOR_STOP))) < (int)strlen(CMD_MONITOR_STOP)) {
|
||||||
|
sr_dbg("Unable to write while probing for hardware.");
|
||||||
|
serial_close(serial);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
g_usleep(50 * 1000);
|
||||||
|
|
||||||
if (serial_write_blocking(serial, CMD_VERSION,
|
if (serial_write_blocking(serial, CMD_VERSION,
|
||||||
strlen(CMD_VERSION), serial_timeout(serial,
|
strlen(CMD_VERSION), serial_timeout(serial,
|
||||||
strlen(CMD_VERSION))) < (int)strlen(CMD_VERSION)) {
|
strlen(CMD_VERSION))) < (int)strlen(CMD_VERSION)) {
|
||||||
|
@ -135,7 +155,7 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
ch = sr_channel_new(sdi, 0, SR_CHANNEL_ANALOG, TRUE, "V");
|
ch = sr_channel_new(sdi, 0, SR_CHANNEL_ANALOG, TRUE, "V");
|
||||||
cg->channels = g_slist_append(cg->channels, ch);
|
cg->channels = g_slist_append(cg->channels, ch);
|
||||||
|
|
||||||
ch = sr_channel_new(sdi, 0, SR_CHANNEL_ANALOG, TRUE, "I");
|
ch = sr_channel_new(sdi, 1, SR_CHANNEL_ANALOG, TRUE, "I");
|
||||||
cg->channels = g_slist_append(cg->channels, ch);
|
cg->channels = g_slist_append(cg->channels, ch);
|
||||||
|
|
||||||
devc = g_malloc0(sizeof(struct dev_context));
|
devc = g_malloc0(sizeof(struct dev_context));
|
||||||
|
@ -150,64 +170,34 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
static int config_list(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)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
GVariantBuilder gvb;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* Always available. */
|
|
||||||
if (key == SR_CONF_SCAN_OPTIONS) {
|
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
|
|
||||||
return SR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key == SR_CONF_DEVICE_OPTIONS && !sdi) {
|
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
drvopts, ARRAY_SIZE(drvopts), sizeof(uint32_t));
|
|
||||||
return SR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!sdi)
|
|
||||||
return SR_ERR_ARG;
|
|
||||||
|
|
||||||
ret = SR_OK;
|
|
||||||
|
|
||||||
if (!cg) {
|
if (!cg) {
|
||||||
/* No channel group: global options. */
|
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
|
||||||
switch (key) {
|
|
||||||
case SR_CONF_DEVICE_OPTIONS:
|
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return SR_ERR_NA;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case SR_CONF_DEVICE_OPTIONS:
|
case SR_CONF_DEVICE_OPTIONS:
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
*data = std_gvar_array_u32(ARRAY_AND_SIZE(devopts_cg));
|
||||||
devopts_cg, ARRAY_SIZE(devopts_cg), sizeof(uint32_t));
|
break;
|
||||||
|
case SR_CONF_REGULATION:
|
||||||
|
*data = std_gvar_array_str(ARRAY_AND_SIZE(regulation));
|
||||||
break;
|
break;
|
||||||
case SR_CONF_CURRENT_LIMIT:
|
case SR_CONF_CURRENT_LIMIT:
|
||||||
g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
|
*data = std_gvar_min_max_step(0.0, 6.0, 0.001);
|
||||||
/* Min, max, step. */
|
break;
|
||||||
g_variant_builder_add_value(&gvb, g_variant_new_double(0.0));
|
case SR_CONF_UNDER_VOLTAGE_CONDITION_THRESHOLD:
|
||||||
g_variant_builder_add_value(&gvb, g_variant_new_double(6.0));
|
*data = std_gvar_min_max_step(0.0, 60.0, 0.001);
|
||||||
g_variant_builder_add_value(&gvb, g_variant_new_double(0.001)); /* 1mA steps */
|
|
||||||
*data = g_variant_builder_end(&gvb);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return SR_ERR_NA;
|
return SR_ERR_NA;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_get(uint32_t key, GVariant **data,
|
static int config_get(uint32_t key, GVariant **data,
|
||||||
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
int ret;
|
|
||||||
float fvalue;
|
float fvalue;
|
||||||
|
|
||||||
(void)cg;
|
(void)cg;
|
||||||
|
@ -223,7 +213,6 @@ static int config_get(uint32_t key, GVariant **data,
|
||||||
* - SR_CONF_ENABLED (state cannot be queried, only set)
|
* - SR_CONF_ENABLED (state cannot be queried, only set)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ret = SR_OK;
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case SR_CONF_LIMIT_SAMPLES:
|
case SR_CONF_LIMIT_SAMPLES:
|
||||||
case SR_CONF_LIMIT_MSEC:
|
case SR_CONF_LIMIT_MSEC:
|
||||||
|
@ -258,48 +247,59 @@ static int config_get(uint32_t key, GVariant **data,
|
||||||
*data = g_variant_new_boolean(devc->otp_active);
|
*data = g_variant_new_boolean(devc->otp_active);
|
||||||
break;
|
break;
|
||||||
case SR_CONF_UNDER_VOLTAGE_CONDITION:
|
case SR_CONF_UNDER_VOLTAGE_CONDITION:
|
||||||
*data = g_variant_new_boolean(TRUE); /* Always on. */
|
if (reloadpro_get_under_voltage_threshold(sdi, &fvalue) == SR_OK)
|
||||||
|
*data = g_variant_new_boolean(fvalue != 0.0);
|
||||||
break;
|
break;
|
||||||
case SR_CONF_UNDER_VOLTAGE_CONDITION_ACTIVE:
|
case SR_CONF_UNDER_VOLTAGE_CONDITION_ACTIVE:
|
||||||
*data = g_variant_new_boolean(devc->uvc_active);
|
*data = g_variant_new_boolean(devc->uvc_active);
|
||||||
break;
|
break;
|
||||||
|
case SR_CONF_UNDER_VOLTAGE_CONDITION_THRESHOLD:
|
||||||
|
if (reloadpro_get_under_voltage_threshold(sdi, &fvalue) == SR_OK)
|
||||||
|
*data = g_variant_new_double(fvalue);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return SR_ERR_NA;
|
return SR_ERR_NA;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_set(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)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
int ret;
|
|
||||||
|
|
||||||
(void)cg;
|
(void)cg;
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
ret = SR_OK;
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case SR_CONF_LIMIT_SAMPLES:
|
case SR_CONF_LIMIT_SAMPLES:
|
||||||
case SR_CONF_LIMIT_MSEC:
|
case SR_CONF_LIMIT_MSEC:
|
||||||
return sr_sw_limits_config_set(&devc->limits, key, data);
|
return sr_sw_limits_config_set(&devc->limits, key, data);
|
||||||
case SR_CONF_ENABLED:
|
case SR_CONF_ENABLED:
|
||||||
ret = reloadpro_set_on_off(sdi, g_variant_get_boolean(data));
|
return reloadpro_set_on_off(sdi, g_variant_get_boolean(data));
|
||||||
break;
|
|
||||||
case SR_CONF_CURRENT_LIMIT:
|
case SR_CONF_CURRENT_LIMIT:
|
||||||
ret = reloadpro_set_current_limit(sdi,
|
return reloadpro_set_current_limit(sdi, g_variant_get_double(data));
|
||||||
|
case SR_CONF_UNDER_VOLTAGE_CONDITION_THRESHOLD:
|
||||||
|
return reloadpro_set_under_voltage_threshold(sdi,
|
||||||
g_variant_get_double(data));
|
g_variant_get_double(data));
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
ret = SR_ERR_NA;
|
return SR_ERR_NA;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return SR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dev_close(struct sr_dev_inst *sdi)
|
||||||
|
{
|
||||||
|
if (serial_write_blocking(sdi->conn, CMD_MONITOR_STOP,
|
||||||
|
strlen(CMD_MONITOR_STOP), serial_timeout(sdi->conn,
|
||||||
|
strlen(CMD_MONITOR_STOP))) < (int)strlen(CMD_MONITOR_STOP)) {
|
||||||
|
sr_dbg("Unable to stop monitoring.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return std_serial_dev_close(sdi);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||||
|
@ -308,10 +308,9 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
struct sr_serial_dev_inst *serial;
|
struct sr_serial_dev_inst *serial;
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
devc->acquisition_running = TRUE;
|
||||||
|
|
||||||
serial = sdi->conn;
|
serial = sdi->conn;
|
||||||
|
|
||||||
/* Send the 'monitor <ms>' command (doesn't have a reply). */
|
/* Send the 'monitor <ms>' command (doesn't have a reply). */
|
||||||
|
@ -322,19 +321,34 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Poll every 100ms, or whenever some data comes in. */
|
|
||||||
serial_source_add(sdi->session, serial, G_IO_IN, 100,
|
|
||||||
reloadpro_receive_data, (void *)sdi);
|
|
||||||
|
|
||||||
sr_sw_limits_acquisition_start(&devc->limits);
|
sr_sw_limits_acquisition_start(&devc->limits);
|
||||||
std_session_send_df_header(sdi);
|
std_session_send_df_header(sdi);
|
||||||
|
|
||||||
memset(devc->buf, 0, RELOADPRO_BUFSIZE);
|
memset(devc->buf, 0, RELOADPRO_BUFSIZE);
|
||||||
devc->buflen = 0;
|
devc->buflen = 0;
|
||||||
|
|
||||||
|
g_mutex_init(&devc->acquisition_mutex);
|
||||||
|
|
||||||
|
serial_source_add(sdi->session, serial, G_IO_IN, 100,
|
||||||
|
reloadpro_receive_data, (void *)sdi);
|
||||||
|
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int dev_acquisition_stop(struct sr_dev_inst *sdi)
|
||||||
|
{
|
||||||
|
struct dev_context *devc;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
devc = sdi->priv;
|
||||||
|
devc->acquisition_running = FALSE;
|
||||||
|
|
||||||
|
ret = std_serial_dev_acquisition_stop(sdi);
|
||||||
|
g_mutex_clear(&devc->acquisition_mutex);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static struct sr_dev_driver arachnid_labs_re_load_pro_driver_info = {
|
static struct sr_dev_driver arachnid_labs_re_load_pro_driver_info = {
|
||||||
.name = "arachnid-labs-re-load-pro",
|
.name = "arachnid-labs-re-load-pro",
|
||||||
.longname = "Arachnid Labs Re:load Pro",
|
.longname = "Arachnid Labs Re:load Pro",
|
||||||
|
@ -343,13 +357,14 @@ static struct sr_dev_driver arachnid_labs_re_load_pro_driver_info = {
|
||||||
.cleanup = std_cleanup,
|
.cleanup = std_cleanup,
|
||||||
.scan = scan,
|
.scan = scan,
|
||||||
.dev_list = std_dev_list,
|
.dev_list = std_dev_list,
|
||||||
|
.dev_clear = std_dev_clear,
|
||||||
.config_get = config_get,
|
.config_get = config_get,
|
||||||
.config_set = config_set,
|
.config_set = config_set,
|
||||||
.config_list = config_list,
|
.config_list = config_list,
|
||||||
.dev_open = std_serial_dev_open,
|
.dev_open = std_serial_dev_open,
|
||||||
.dev_close = std_serial_dev_close,
|
.dev_close = dev_close,
|
||||||
.dev_acquisition_start = dev_acquisition_start,
|
.dev_acquisition_start = dev_acquisition_start,
|
||||||
.dev_acquisition_stop = std_serial_dev_acquisition_stop,
|
.dev_acquisition_stop = dev_acquisition_stop,
|
||||||
.context = NULL,
|
.context = NULL,
|
||||||
};
|
};
|
||||||
SR_REGISTER_DEV_DRIVER(arachnid_labs_re_load_pro_driver_info);
|
SR_REGISTER_DEV_DRIVER(arachnid_labs_re_load_pro_driver_info);
|
||||||
|
|
|
@ -18,18 +18,21 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
#include <math.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "protocol.h"
|
#include "protocol.h"
|
||||||
|
|
||||||
#define READ_TIMEOUT_MS 1000
|
#define READ_TIMEOUT_MS 500
|
||||||
|
|
||||||
static int send_cmd(const struct sr_dev_inst *sdi, const char *cmd,
|
static int send_cmd(const struct sr_dev_inst *sdi, const char *cmd,
|
||||||
char *replybuf, int replybufsize)
|
char *replybuf, int replybufsize)
|
||||||
{
|
{
|
||||||
char *bufptr;
|
char *bufptr;
|
||||||
int len, ret;
|
int len, ret;
|
||||||
|
struct dev_context *devc;
|
||||||
struct sr_serial_dev_inst *serial;
|
struct sr_serial_dev_inst *serial;
|
||||||
|
|
||||||
|
devc = sdi->priv;
|
||||||
serial = sdi->conn;
|
serial = sdi->conn;
|
||||||
|
|
||||||
/* Send the command (blocking, with timeout). */
|
/* Send the command (blocking, with timeout). */
|
||||||
|
@ -40,6 +43,7 @@ static int send_cmd(const struct sr_dev_inst *sdi, const char *cmd,
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!devc->acquisition_running) {
|
||||||
/* Read the reply (blocking, with timeout). */
|
/* Read the reply (blocking, with timeout). */
|
||||||
memset(replybuf, 0, replybufsize);
|
memset(replybuf, 0, replybufsize);
|
||||||
bufptr = replybuf;
|
bufptr = replybuf;
|
||||||
|
@ -56,66 +60,165 @@ static int send_cmd(const struct sr_dev_inst *sdi, const char *cmd,
|
||||||
sr_err("Device replied with an error: '%s'.", bufptr);
|
sr_err("Device replied with an error: '%s'.", bufptr);
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
SR_PRIV int reloadpro_set_current_limit(const struct sr_dev_inst *sdi,
|
SR_PRIV int reloadpro_set_current_limit(const struct sr_dev_inst *sdi,
|
||||||
float current)
|
float current_limit)
|
||||||
{
|
{
|
||||||
|
struct dev_context *devc;
|
||||||
int ret, ma;
|
int ret, ma;
|
||||||
char buf[100];
|
char buf[100];
|
||||||
char *cmd;
|
char *cmd;
|
||||||
|
|
||||||
if (current < 0 || current > 6) {
|
devc = sdi->priv;
|
||||||
sr_err("The current limit must be 0-6 A (was %f A).", current);
|
|
||||||
|
if (current_limit < 0 || current_limit > 6) {
|
||||||
|
sr_err("The current limit must be 0-6 A (was %f A).", current_limit);
|
||||||
return SR_ERR_ARG;
|
return SR_ERR_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hardware expects current in mA, integer (0..6000). */
|
/* Hardware expects current limit in mA, integer (0..6000). */
|
||||||
ma = (int)(current * 1000);
|
ma = (int)round(current_limit * 1000);
|
||||||
|
|
||||||
sr_err("Setting current limit to %f A (%d mA).", current, ma);
|
|
||||||
|
|
||||||
cmd = g_strdup_printf("set %d\n", ma);
|
cmd = g_strdup_printf("set %d\n", ma);
|
||||||
if ((ret = send_cmd(sdi, cmd, (char *)&buf, sizeof(buf))) < 0) {
|
g_mutex_lock(&devc->acquisition_mutex);
|
||||||
sr_err("Error sending current limit command: %d.", ret);
|
ret = send_cmd(sdi, cmd, (char *)&buf, sizeof(buf));
|
||||||
g_free(cmd);
|
g_mutex_unlock(&devc->acquisition_mutex);
|
||||||
return SR_ERR;
|
|
||||||
}
|
|
||||||
g_free(cmd);
|
g_free(cmd);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
sr_err("Error sending current limit command: %d.", ret);
|
||||||
|
return SR_ERR;
|
||||||
|
}
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
SR_PRIV int reloadpro_set_on_off(const struct sr_dev_inst *sdi, gboolean on)
|
SR_PRIV int reloadpro_set_on_off(const struct sr_dev_inst *sdi, gboolean on)
|
||||||
{
|
{
|
||||||
|
struct dev_context *devc;
|
||||||
int ret;
|
int ret;
|
||||||
char buf[100];
|
char buf[100];
|
||||||
const char *cmd;
|
const char *cmd;
|
||||||
|
|
||||||
|
devc = sdi->priv;
|
||||||
|
|
||||||
cmd = (on) ? "on\n" : "off\n";
|
cmd = (on) ? "on\n" : "off\n";
|
||||||
if ((ret = send_cmd(sdi, cmd, (char *)&buf, sizeof(buf))) < 0) {
|
g_mutex_lock(&devc->acquisition_mutex);
|
||||||
|
ret = send_cmd(sdi, cmd, (char *)&buf, sizeof(buf));
|
||||||
|
g_mutex_unlock(&devc->acquisition_mutex);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
sr_err("Error sending on/off command: %d.", ret);
|
sr_err("Error sending on/off command: %d.", ret);
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
}
|
}
|
||||||
|
return SR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
SR_PRIV int reloadpro_set_under_voltage_threshold(const struct sr_dev_inst *sdi,
|
||||||
|
float voltage)
|
||||||
|
{
|
||||||
|
struct dev_context *devc;
|
||||||
|
int ret, mv;
|
||||||
|
char buf[100];
|
||||||
|
char *cmd;
|
||||||
|
|
||||||
|
devc = sdi->priv;
|
||||||
|
|
||||||
|
if (voltage < 0 || voltage > 60) {
|
||||||
|
sr_err("The under voltage threshold must be 0-60 V (was %f V).",
|
||||||
|
voltage);
|
||||||
|
return SR_ERR_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hardware expects voltage in mV, integer (0..60000). */
|
||||||
|
mv = (int)round(voltage * 1000);
|
||||||
|
|
||||||
|
sr_spew("Setting under voltage threshold to %f V (%d mV).", voltage, mv);
|
||||||
|
|
||||||
|
cmd = g_strdup_printf("uvlo %d\n", mv);
|
||||||
|
g_mutex_lock(&devc->acquisition_mutex);
|
||||||
|
ret = send_cmd(sdi, cmd, (char *)&buf, sizeof(buf));
|
||||||
|
g_mutex_unlock(&devc->acquisition_mutex);
|
||||||
|
g_free(cmd);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
sr_err("Error sending under voltage threshold command: %d.", ret);
|
||||||
|
return SR_ERR;
|
||||||
|
}
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
SR_PRIV int reloadpro_get_current_limit(const struct sr_dev_inst *sdi,
|
SR_PRIV int reloadpro_get_current_limit(const struct sr_dev_inst *sdi,
|
||||||
float *current)
|
float *current_limit)
|
||||||
{
|
{
|
||||||
|
struct dev_context *devc;
|
||||||
int ret;
|
int ret;
|
||||||
char buf[100];
|
char buf[100];
|
||||||
|
gint64 end_time;
|
||||||
|
|
||||||
|
devc = sdi->priv;
|
||||||
|
|
||||||
|
g_mutex_lock(&devc->acquisition_mutex);
|
||||||
if ((ret = send_cmd(sdi, "set\n", (char *)&buf, sizeof(buf))) < 0) {
|
if ((ret = send_cmd(sdi, "set\n", (char *)&buf, sizeof(buf))) < 0) {
|
||||||
sr_err("Error sending current limit query: %d.", ret);
|
sr_err("Error sending current limit query: %d.", ret);
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hardware sends current in mA, integer (0..6000). */
|
if (devc->acquisition_running) {
|
||||||
*current = g_ascii_strtod(buf + 4, NULL) / 1000;
|
end_time = g_get_monotonic_time () + 5 * G_TIME_SPAN_SECOND;
|
||||||
|
if (!g_cond_wait_until(&devc->current_limit_cond,
|
||||||
|
&devc->acquisition_mutex, end_time)) {
|
||||||
|
/* Timeout has passed. */
|
||||||
|
g_mutex_unlock(&devc->acquisition_mutex);
|
||||||
|
return SR_ERR;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Hardware sends current limit in mA, integer (0..6000). */
|
||||||
|
devc->current_limit = g_ascii_strtod(buf + 4, NULL) / 1000;
|
||||||
|
}
|
||||||
|
g_mutex_unlock(&devc->acquisition_mutex);
|
||||||
|
|
||||||
|
if (current_limit)
|
||||||
|
*current_limit = devc->current_limit;
|
||||||
|
|
||||||
|
return SR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
SR_PRIV int reloadpro_get_under_voltage_threshold(const struct sr_dev_inst *sdi,
|
||||||
|
float *uvc_threshold)
|
||||||
|
{
|
||||||
|
struct dev_context *devc;
|
||||||
|
int ret;
|
||||||
|
char buf[100];
|
||||||
|
gint64 end_time;
|
||||||
|
|
||||||
|
devc = sdi->priv;
|
||||||
|
|
||||||
|
g_mutex_lock(&devc->acquisition_mutex);
|
||||||
|
if ((ret = send_cmd(sdi, "uvlo\n", (char *)&buf, sizeof(buf))) < 0) {
|
||||||
|
sr_err("Error sending under voltage threshold query: %d.", ret);
|
||||||
|
return SR_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (devc->acquisition_running) {
|
||||||
|
end_time = g_get_monotonic_time () + 5 * G_TIME_SPAN_SECOND;
|
||||||
|
if (!g_cond_wait_until(&devc->uvc_threshold_cond,
|
||||||
|
&devc->acquisition_mutex, end_time)) {
|
||||||
|
/* Timeout has passed. */
|
||||||
|
g_mutex_unlock(&devc->acquisition_mutex);
|
||||||
|
return SR_ERR;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Hardware sends voltage in mV, integer (0..60000). */
|
||||||
|
devc->uvc_threshold = g_ascii_strtod(buf + 5, NULL) / 1000;
|
||||||
|
}
|
||||||
|
g_mutex_unlock(&devc->acquisition_mutex);
|
||||||
|
|
||||||
|
if (uvc_threshold)
|
||||||
|
*uvc_threshold = devc->uvc_threshold;
|
||||||
|
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
@ -123,29 +226,72 @@ SR_PRIV int reloadpro_get_current_limit(const struct sr_dev_inst *sdi,
|
||||||
SR_PRIV int reloadpro_get_voltage_current(const struct sr_dev_inst *sdi,
|
SR_PRIV int reloadpro_get_voltage_current(const struct sr_dev_inst *sdi,
|
||||||
float *voltage, float *current)
|
float *voltage, float *current)
|
||||||
{
|
{
|
||||||
|
struct dev_context *devc;
|
||||||
int ret;
|
int ret;
|
||||||
char buf[100];
|
char buf[100];
|
||||||
char **tokens;
|
char **tokens;
|
||||||
|
gint64 end_time;
|
||||||
|
|
||||||
|
devc = sdi->priv;
|
||||||
|
|
||||||
|
g_mutex_lock(&devc->acquisition_mutex);
|
||||||
if ((ret = send_cmd(sdi, "read\n", (char *)&buf, sizeof(buf))) < 0) {
|
if ((ret = send_cmd(sdi, "read\n", (char *)&buf, sizeof(buf))) < 0) {
|
||||||
sr_err("Error sending voltage/current query: %d.", ret);
|
sr_err("Error sending voltage/current query: %d.", ret);
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (devc->acquisition_running) {
|
||||||
|
end_time = g_get_monotonic_time () + 5 * G_TIME_SPAN_SECOND;
|
||||||
|
if (!g_cond_wait_until(&devc->voltage_cond,
|
||||||
|
&devc->acquisition_mutex, end_time)) {
|
||||||
|
/* Timeout has passed. */
|
||||||
|
g_mutex_unlock(&devc->acquisition_mutex);
|
||||||
|
return SR_ERR;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
/* Reply: "read <current> <voltage>". */
|
/* Reply: "read <current> <voltage>". */
|
||||||
tokens = g_strsplit((const char *)&buf, " ", 3);
|
tokens = g_strsplit((const char *)&buf, " ", 3);
|
||||||
if (voltage)
|
devc->voltage = g_ascii_strtod(tokens[2], NULL) / 1000;
|
||||||
*voltage = g_ascii_strtod(tokens[2], NULL) / 1000;
|
devc->current = g_ascii_strtod(tokens[1], NULL) / 1000;
|
||||||
if (current)
|
|
||||||
*current = g_ascii_strtod(tokens[1], NULL) / 1000;
|
|
||||||
g_strfreev(tokens);
|
g_strfreev(tokens);
|
||||||
|
}
|
||||||
|
g_mutex_unlock(&devc->acquisition_mutex);
|
||||||
|
|
||||||
|
if (voltage)
|
||||||
|
*voltage = devc->voltage;
|
||||||
|
if (current)
|
||||||
|
*current = devc->current;
|
||||||
|
|
||||||
return SR_OK;
|
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)
|
static void handle_packet(const struct sr_dev_inst *sdi)
|
||||||
{
|
{
|
||||||
float voltage, current;
|
|
||||||
struct sr_datafeed_packet packet;
|
struct sr_datafeed_packet packet;
|
||||||
struct sr_datafeed_analog analog;
|
struct sr_datafeed_analog analog;
|
||||||
struct sr_analog_encoding encoding;
|
struct sr_analog_encoding encoding;
|
||||||
|
@ -160,12 +306,49 @@ static void handle_packet(const struct sr_dev_inst *sdi)
|
||||||
if (g_str_has_prefix((const char *)devc->buf, "overtemp")) {
|
if (g_str_has_prefix((const char *)devc->buf, "overtemp")) {
|
||||||
sr_warn("Overtemperature condition!");
|
sr_warn("Overtemperature condition!");
|
||||||
devc->otp_active = TRUE;
|
devc->otp_active = TRUE;
|
||||||
|
send_config_update_key(sdi, SR_CONF_OVER_TEMPERATURE_PROTECTION_ACTIVE,
|
||||||
|
g_variant_new_boolean(TRUE));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_str_has_prefix((const char *)devc->buf, "undervolt")) {
|
if (g_str_has_prefix((const char *)devc->buf, "undervolt")) {
|
||||||
sr_warn("Undervoltage condition!");
|
sr_warn("Undervoltage condition!");
|
||||||
devc->uvc_active = TRUE;
|
devc->uvc_active = TRUE;
|
||||||
|
send_config_update_key(sdi, SR_CONF_UNDER_VOLTAGE_CONDITION_ACTIVE,
|
||||||
|
g_variant_new_boolean(TRUE));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_str_has_prefix((const char *)devc->buf, "err ")) {
|
||||||
|
sr_err("Device replied with an error: '%s'.", devc->buf);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_str_has_prefix((const char *)devc->buf, "set ")) {
|
||||||
|
tokens = g_strsplit((const char *)devc->buf, " ", 2);
|
||||||
|
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,
|
||||||
|
g_variant_new_double(devc->current_limit));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_str_has_prefix((const char *)devc->buf, "uvlo ")) {
|
||||||
|
tokens = g_strsplit((const char *)devc->buf, " ", 2);
|
||||||
|
devc->uvc_threshold = g_ascii_strtod(tokens[1], NULL) / 1000;
|
||||||
|
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,
|
||||||
|
g_variant_new_boolean(FALSE));
|
||||||
|
} else {
|
||||||
|
send_config_update_key(sdi, SR_CONF_UNDER_VOLTAGE_CONDITION,
|
||||||
|
g_variant_new_boolean(TRUE));
|
||||||
|
send_config_update_key(sdi,
|
||||||
|
SR_CONF_UNDER_VOLTAGE_CONDITION_THRESHOLD,
|
||||||
|
g_variant_new_double(devc->uvc_threshold));
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,8 +358,8 @@ static void handle_packet(const struct sr_dev_inst *sdi)
|
||||||
}
|
}
|
||||||
|
|
||||||
tokens = g_strsplit((const char *)devc->buf, " ", 3);
|
tokens = g_strsplit((const char *)devc->buf, " ", 3);
|
||||||
voltage = g_ascii_strtod(tokens[2], NULL) / 1000;
|
devc->voltage = g_ascii_strtod(tokens[2], NULL) / 1000;
|
||||||
current = g_ascii_strtod(tokens[1], NULL) / 1000;
|
devc->current = g_ascii_strtod(tokens[1], NULL) / 1000;
|
||||||
g_strfreev(tokens);
|
g_strfreev(tokens);
|
||||||
|
|
||||||
/* Begin frame. */
|
/* Begin frame. */
|
||||||
|
@ -197,7 +380,8 @@ static void handle_packet(const struct sr_dev_inst *sdi)
|
||||||
meaning.mq = SR_MQ_VOLTAGE;
|
meaning.mq = SR_MQ_VOLTAGE;
|
||||||
meaning.mqflags = SR_MQFLAG_DC;
|
meaning.mqflags = SR_MQFLAG_DC;
|
||||||
meaning.unit = SR_UNIT_VOLT;
|
meaning.unit = SR_UNIT_VOLT;
|
||||||
analog.data = &voltage;
|
encoding.digits = 3;
|
||||||
|
analog.data = &devc->voltage;
|
||||||
sr_session_send(sdi, &packet);
|
sr_session_send(sdi, &packet);
|
||||||
g_slist_free(l);
|
g_slist_free(l);
|
||||||
|
|
||||||
|
@ -208,7 +392,8 @@ static void handle_packet(const struct sr_dev_inst *sdi)
|
||||||
meaning.mq = SR_MQ_CURRENT;
|
meaning.mq = SR_MQ_CURRENT;
|
||||||
meaning.mqflags = SR_MQFLAG_DC;
|
meaning.mqflags = SR_MQFLAG_DC;
|
||||||
meaning.unit = SR_UNIT_AMPERE;
|
meaning.unit = SR_UNIT_AMPERE;
|
||||||
analog.data = ¤t;
|
encoding.digits = 3;
|
||||||
|
analog.data = &devc->current;
|
||||||
sr_session_send(sdi, &packet);
|
sr_session_send(sdi, &packet);
|
||||||
g_slist_free(l);
|
g_slist_free(l);
|
||||||
|
|
||||||
|
@ -225,26 +410,34 @@ static void handle_new_data(const struct sr_dev_inst *sdi)
|
||||||
int len;
|
int len;
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
struct sr_serial_dev_inst *serial;
|
struct sr_serial_dev_inst *serial;
|
||||||
|
char *buf;
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
serial = sdi->conn;
|
serial = sdi->conn;
|
||||||
|
|
||||||
/* Try to get as much data as the buffer can hold. */
|
|
||||||
len = RELOADPRO_BUFSIZE - devc->buflen;
|
len = RELOADPRO_BUFSIZE - devc->buflen;
|
||||||
len = serial_read_nonblocking(serial, devc->buf + devc->buflen, len);
|
buf = devc->buf;
|
||||||
if (len == 0)
|
g_mutex_lock(&devc->acquisition_mutex);
|
||||||
|
if (serial_readline(serial, &buf, &len, 250) != SR_OK) {
|
||||||
|
g_mutex_unlock(&devc->acquisition_mutex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len == 0) {
|
||||||
|
g_mutex_unlock(&devc->acquisition_mutex);
|
||||||
return; /* No new bytes, nothing to do. */
|
return; /* No new bytes, nothing to do. */
|
||||||
|
}
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
sr_err("Serial port read error: %d.", len);
|
sr_err("Serial port read error: %d.", len);
|
||||||
|
g_mutex_unlock(&devc->acquisition_mutex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
devc->buflen += len;
|
devc->buflen += len;
|
||||||
|
|
||||||
if (g_str_has_suffix((const char *)devc->buf, "\n")) {
|
|
||||||
handle_packet(sdi);
|
handle_packet(sdi);
|
||||||
|
g_mutex_unlock(&devc->acquisition_mutex);
|
||||||
memset(devc->buf, 0, RELOADPRO_BUFSIZE);
|
memset(devc->buf, 0, RELOADPRO_BUFSIZE);
|
||||||
devc->buflen = 0;
|
devc->buflen = 0;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SR_PRIV int reloadpro_receive_data(int fd, int revents, void *cb_data)
|
SR_PRIV int reloadpro_receive_data(int fd, int revents, void *cb_data)
|
||||||
|
@ -263,7 +456,7 @@ SR_PRIV int reloadpro_receive_data(int fd, int revents, void *cb_data)
|
||||||
handle_new_data(sdi);
|
handle_new_data(sdi);
|
||||||
|
|
||||||
if (sr_sw_limits_check(&devc->limits))
|
if (sr_sw_limits_check(&devc->limits))
|
||||||
sdi->driver->dev_acquisition_stop(sdi);
|
sr_dev_acquisition_stop(sdi);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,24 +25,40 @@
|
||||||
#include <libsigrok/libsigrok.h>
|
#include <libsigrok/libsigrok.h>
|
||||||
#include "libsigrok-internal.h"
|
#include "libsigrok-internal.h"
|
||||||
|
|
||||||
#define LOG_PREFIX "re-load-pro"
|
#define LOG_PREFIX "arachnid-labs-re-load-pro"
|
||||||
|
|
||||||
#define RELOADPRO_BUFSIZE 100
|
#define RELOADPRO_BUFSIZE 100
|
||||||
|
|
||||||
/** Private, per-device-instance driver context. */
|
|
||||||
struct dev_context {
|
struct dev_context {
|
||||||
struct sr_sw_limits limits;
|
struct sr_sw_limits limits;
|
||||||
uint8_t buf[RELOADPRO_BUFSIZE];
|
|
||||||
|
char buf[RELOADPRO_BUFSIZE];
|
||||||
int buflen;
|
int buflen;
|
||||||
|
|
||||||
|
float current_limit;
|
||||||
|
float voltage;
|
||||||
|
float current;
|
||||||
gboolean otp_active;
|
gboolean otp_active;
|
||||||
gboolean uvc_active;
|
gboolean uvc_active;
|
||||||
|
float uvc_threshold;
|
||||||
|
|
||||||
|
gboolean acquisition_running;
|
||||||
|
GMutex acquisition_mutex;
|
||||||
|
|
||||||
|
GCond current_limit_cond;
|
||||||
|
GCond voltage_cond;
|
||||||
|
GCond uvc_threshold_cond;
|
||||||
};
|
};
|
||||||
|
|
||||||
SR_PRIV int reloadpro_set_current_limit(const struct sr_dev_inst *sdi,
|
SR_PRIV int reloadpro_set_current_limit(const struct sr_dev_inst *sdi,
|
||||||
float current);
|
float current);
|
||||||
SR_PRIV int reloadpro_set_on_off(const struct sr_dev_inst *sdi, gboolean on);
|
SR_PRIV int reloadpro_set_on_off(const struct sr_dev_inst *sdi, gboolean on);
|
||||||
|
SR_PRIV int reloadpro_set_under_voltage_threshold(const struct sr_dev_inst *sdi,
|
||||||
|
float uvc_threshold);
|
||||||
SR_PRIV int reloadpro_get_current_limit(const struct sr_dev_inst *sdi,
|
SR_PRIV int reloadpro_get_current_limit(const struct sr_dev_inst *sdi,
|
||||||
float *current);
|
float *current_limit);
|
||||||
|
SR_PRIV int reloadpro_get_under_voltage_threshold(const struct sr_dev_inst *sdi,
|
||||||
|
float *uvc_threshold);
|
||||||
SR_PRIV int reloadpro_get_voltage_current(const struct sr_dev_inst *sdi,
|
SR_PRIV int reloadpro_get_voltage_current(const struct sr_dev_inst *sdi,
|
||||||
float *voltage, float *current);
|
float *voltage, float *current);
|
||||||
SR_PRIV int reloadpro_receive_data(int fd, int revents, void *cb_data);
|
SR_PRIV int reloadpro_receive_data(int fd, int revents, void *cb_data);
|
||||||
|
|
|
@ -19,10 +19,6 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
* ASIX SIGMA/SIGMA2 logic analyzer driver
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include "protocol.h"
|
#include "protocol.h"
|
||||||
|
|
||||||
|
@ -59,9 +55,14 @@ static const int32_t trigger_matches[] = {
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void clear_helper(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
ftdi_deinit(&devc->ftdic);
|
||||||
|
}
|
||||||
|
|
||||||
static int dev_clear(const struct sr_dev_driver *di)
|
static int dev_clear(const struct sr_dev_driver *di)
|
||||||
{
|
{
|
||||||
return std_dev_clear(di, sigma_clear_helper);
|
return std_dev_clear_with_callback(di, (std_dev_clear_callback)clear_helper);
|
||||||
}
|
}
|
||||||
|
|
||||||
static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
|
@ -80,8 +81,6 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
|
|
||||||
ftdi_init(&devc->ftdic);
|
ftdi_init(&devc->ftdic);
|
||||||
|
|
||||||
/* Look for SIGMAs. */
|
|
||||||
|
|
||||||
if ((ret = ftdi_usb_find_all(&devc->ftdic, &devlist,
|
if ((ret = ftdi_usb_find_all(&devc->ftdic, &devlist,
|
||||||
USB_VENDOR, USB_PRODUCT)) <= 0) {
|
USB_VENDOR, USB_PRODUCT)) <= 0) {
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -111,18 +110,16 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
devc->capture_ratio = 50;
|
devc->capture_ratio = 50;
|
||||||
devc->use_triggers = 0;
|
devc->use_triggers = 0;
|
||||||
|
|
||||||
/* Register SIGMA device. */
|
|
||||||
sdi = g_malloc0(sizeof(struct sr_dev_inst));
|
sdi = g_malloc0(sizeof(struct sr_dev_inst));
|
||||||
sdi->status = SR_ST_INITIALIZING;
|
sdi->status = SR_ST_INITIALIZING;
|
||||||
sdi->vendor = g_strdup(USB_VENDOR_NAME);
|
sdi->vendor = g_strdup("ASIX");
|
||||||
sdi->model = g_strdup(USB_MODEL_NAME);
|
sdi->model = g_strdup("SIGMA");
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(channel_names); i++)
|
for (i = 0; i < ARRAY_SIZE(channel_names); i++)
|
||||||
sr_channel_new(sdi, i, SR_CHANNEL_LOGIC, TRUE, channel_names[i]);
|
sr_channel_new(sdi, i, SR_CHANNEL_LOGIC, TRUE, channel_names[i]);
|
||||||
|
|
||||||
sdi->priv = devc;
|
sdi->priv = devc;
|
||||||
|
|
||||||
/* We will open the device again when we need it. */
|
|
||||||
ftdi_list_free(&devlist);
|
ftdi_list_free(&devlist);
|
||||||
|
|
||||||
return std_scan_complete(di, g_slist_append(NULL, sdi));
|
return std_scan_complete(di, g_slist_append(NULL, sdi));
|
||||||
|
@ -140,18 +137,13 @@ static int dev_open(struct sr_dev_inst *sdi)
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
/* Make sure it's an ASIX SIGMA. */
|
|
||||||
if ((ret = ftdi_usb_open_desc(&devc->ftdic,
|
if ((ret = ftdi_usb_open_desc(&devc->ftdic,
|
||||||
USB_VENDOR, USB_PRODUCT, USB_DESCRIPTION, NULL)) < 0) {
|
USB_VENDOR, USB_PRODUCT, USB_DESCRIPTION, NULL)) < 0) {
|
||||||
|
sr_err("Failed to open device (%d): %s.",
|
||||||
sr_err("ftdi_usb_open failed: %s",
|
ret, ftdi_get_error_string(&devc->ftdic));
|
||||||
ftdi_get_error_string(&devc->ftdic));
|
return SR_ERR;
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sdi->status = SR_ST_ACTIVE;
|
|
||||||
|
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,17 +153,11 @@ static int dev_close(struct sr_dev_inst *sdi)
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
/* TODO */
|
return (ftdi_usb_close(&devc->ftdic) == 0) ? SR_OK : SR_ERR;
|
||||||
if (sdi->status == SR_ST_ACTIVE)
|
|
||||||
ftdi_usb_close(&devc->ftdic);
|
|
||||||
|
|
||||||
sdi->status = SR_ST_INACTIVE;
|
|
||||||
|
|
||||||
return SR_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
|
static int config_get(uint32_t key, GVariant **data,
|
||||||
const struct sr_channel_group *cg)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
|
|
||||||
|
@ -203,81 +189,50 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
|
static int config_set(uint32_t key, GVariant *data,
|
||||||
const struct sr_channel_group *cg)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
uint64_t tmp;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
(void)cg;
|
(void)cg;
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
ret = SR_OK;
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case SR_CONF_SAMPLERATE:
|
case SR_CONF_SAMPLERATE:
|
||||||
ret = sigma_set_samplerate(sdi, g_variant_get_uint64(data));
|
return sigma_set_samplerate(sdi, g_variant_get_uint64(data));
|
||||||
break;
|
|
||||||
case SR_CONF_LIMIT_MSEC:
|
case SR_CONF_LIMIT_MSEC:
|
||||||
tmp = g_variant_get_uint64(data);
|
|
||||||
if (tmp > 0)
|
|
||||||
devc->limit_msec = g_variant_get_uint64(data);
|
devc->limit_msec = g_variant_get_uint64(data);
|
||||||
else
|
|
||||||
ret = SR_ERR;
|
|
||||||
break;
|
break;
|
||||||
case SR_CONF_LIMIT_SAMPLES:
|
case SR_CONF_LIMIT_SAMPLES:
|
||||||
tmp = g_variant_get_uint64(data);
|
devc->limit_samples = g_variant_get_uint64(data);
|
||||||
devc->limit_samples = tmp;
|
devc->limit_msec = sigma_limit_samples_to_msec(devc,
|
||||||
devc->limit_msec = sigma_limit_samples_to_msec(devc, tmp);
|
devc->limit_samples);
|
||||||
break;
|
break;
|
||||||
#if ASIX_SIGMA_WITH_TRIGGER
|
#if ASIX_SIGMA_WITH_TRIGGER
|
||||||
case SR_CONF_CAPTURE_RATIO:
|
case SR_CONF_CAPTURE_RATIO:
|
||||||
tmp = g_variant_get_uint64(data);
|
devc->capture_ratio = g_variant_get_uint64(data);
|
||||||
if (tmp > 100)
|
|
||||||
return SR_ERR;
|
|
||||||
devc->capture_ratio = tmp;
|
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
ret = SR_ERR_NA;
|
return SR_ERR_NA;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
|
static int config_list(uint32_t key, GVariant **data,
|
||||||
const struct sr_channel_group *cg)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
GVariant *gvar;
|
|
||||||
GVariantBuilder gvb;
|
|
||||||
|
|
||||||
(void)cg;
|
|
||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case SR_CONF_DEVICE_OPTIONS:
|
case SR_CONF_DEVICE_OPTIONS:
|
||||||
if (!sdi)
|
return STD_CONFIG_LIST(key, data, sdi, cg, NO_OPTS, drvopts, devopts);
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
drvopts, ARRAY_SIZE(drvopts), sizeof(uint32_t));
|
|
||||||
else
|
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
|
|
||||||
break;
|
|
||||||
case SR_CONF_SAMPLERATE:
|
case SR_CONF_SAMPLERATE:
|
||||||
g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
|
*data = std_gvar_samplerates(samplerates, samplerates_count);
|
||||||
gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), samplerates,
|
|
||||||
samplerates_count, sizeof(samplerates[0]));
|
|
||||||
g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar);
|
|
||||||
*data = g_variant_builder_end(&gvb);
|
|
||||||
break;
|
break;
|
||||||
#if ASIX_SIGMA_WITH_TRIGGER
|
#if ASIX_SIGMA_WITH_TRIGGER
|
||||||
case SR_CONF_TRIGGER_MATCH:
|
case SR_CONF_TRIGGER_MATCH:
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
|
*data = std_gvar_array_i32(ARRAY_AND_SIZE(trigger_matches));
|
||||||
trigger_matches, ARRAY_SIZE(trigger_matches),
|
|
||||||
sizeof(int32_t));
|
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
|
@ -299,9 +254,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||||
uint8_t clock_bytes[sizeof(clockselect)];
|
uint8_t clock_bytes[sizeof(clockselect)];
|
||||||
size_t clock_idx;
|
size_t clock_idx;
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
if (sigma_convert_trigger(sdi) != SR_OK) {
|
if (sigma_convert_trigger(sdi) != SR_OK) {
|
||||||
|
@ -411,9 +363,20 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi)
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
devc->state.state = SIGMA_IDLE;
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When acquisition is currently running, keep the receive
|
||||||
|
* routine registered and have it stop the acquisition upon the
|
||||||
|
* next invocation. Else unregister the receive routine here
|
||||||
|
* already. The detour is required to have sample data retrieved
|
||||||
|
* for forced acquisition stops.
|
||||||
|
*/
|
||||||
|
if (devc->state.state == SIGMA_CAPTURE) {
|
||||||
|
devc->state.state = SIGMA_STOPPING;
|
||||||
|
} else {
|
||||||
|
devc->state.state = SIGMA_IDLE;
|
||||||
sr_session_source_remove(sdi->session, -1);
|
sr_session_source_remove(sdi->session, -1);
|
||||||
|
}
|
||||||
|
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ SR_PRIV const uint64_t samplerates[] = {
|
||||||
|
|
||||||
SR_PRIV const size_t samplerates_count = ARRAY_SIZE(samplerates);
|
SR_PRIV const size_t samplerates_count = ARRAY_SIZE(samplerates);
|
||||||
|
|
||||||
static const char sigma_firmware_files[][24] = {
|
static const char firmware_files[][24] = {
|
||||||
/* 50 MHz, supports 8 bit fractions */
|
/* 50 MHz, supports 8 bit fractions */
|
||||||
"asix-sigma-50.fw",
|
"asix-sigma-50.fw",
|
||||||
/* 100 MHz */
|
/* 100 MHz */
|
||||||
|
@ -78,12 +78,11 @@ static int sigma_write(void *buf, size_t size, struct dev_context *devc)
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = ftdi_write_data(&devc->ftdic, (unsigned char *)buf, size);
|
ret = ftdi_write_data(&devc->ftdic, (unsigned char *)buf, size);
|
||||||
if (ret < 0) {
|
if (ret < 0)
|
||||||
sr_err("ftdi_write_data failed: %s",
|
sr_err("ftdi_write_data failed: %s",
|
||||||
ftdi_get_error_string(&devc->ftdic));
|
ftdi_get_error_string(&devc->ftdic));
|
||||||
} else if ((size_t) ret != size) {
|
else if ((size_t) ret != size)
|
||||||
sr_err("ftdi_write_data did not complete write.");
|
sr_err("ftdi_write_data did not complete write.");
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -272,15 +271,6 @@ SR_PRIV int sigma_write_trigger_lut(struct triggerlut *lut, struct dev_context *
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
SR_PRIV void sigma_clear_helper(void *priv)
|
|
||||||
{
|
|
||||||
struct dev_context *devc;
|
|
||||||
|
|
||||||
devc = priv;
|
|
||||||
|
|
||||||
ftdi_deinit(&devc->ftdic);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Configure the FPGA for bitbang mode.
|
* Configure the FPGA for bitbang mode.
|
||||||
* This sequence is documented in section 2. of the ASIX Sigma programming
|
* This sequence is documented in section 2. of the ASIX Sigma programming
|
||||||
|
@ -446,38 +436,27 @@ static int upload_firmware(struct sr_context *ctx,
|
||||||
unsigned char pins;
|
unsigned char pins;
|
||||||
size_t buf_size;
|
size_t buf_size;
|
||||||
const char *firmware;
|
const char *firmware;
|
||||||
struct ftdi_context *ftdic;
|
|
||||||
|
|
||||||
/* Avoid downloading the same firmware multiple times. */
|
/* Avoid downloading the same firmware multiple times. */
|
||||||
firmware = sigma_firmware_files[firmware_idx];
|
firmware = firmware_files[firmware_idx];
|
||||||
if (devc->cur_firmware == firmware_idx) {
|
if (devc->cur_firmware == firmware_idx) {
|
||||||
sr_info("Not uploading firmware file '%s' again.", firmware);
|
sr_info("Not uploading firmware file '%s' again.", firmware);
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure it's an ASIX SIGMA. */
|
ret = ftdi_set_bitmode(&devc->ftdic, 0xdf, BITMODE_BITBANG);
|
||||||
ftdic = &devc->ftdic;
|
|
||||||
ret = ftdi_usb_open_desc(ftdic, USB_VENDOR, USB_PRODUCT,
|
|
||||||
USB_DESCRIPTION, NULL);
|
|
||||||
if (ret < 0) {
|
|
||||||
sr_err("ftdi_usb_open failed: %s",
|
|
||||||
ftdi_get_error_string(ftdic));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = ftdi_set_bitmode(ftdic, 0xdf, BITMODE_BITBANG);
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
sr_err("ftdi_set_bitmode failed: %s",
|
sr_err("ftdi_set_bitmode failed: %s",
|
||||||
ftdi_get_error_string(ftdic));
|
ftdi_get_error_string(&devc->ftdic));
|
||||||
return 0;
|
return SR_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Four times the speed of sigmalogan - Works well. */
|
/* Four times the speed of sigmalogan - Works well. */
|
||||||
ret = ftdi_set_baudrate(ftdic, 750 * 1000);
|
ret = ftdi_set_baudrate(&devc->ftdic, 750 * 1000);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
sr_err("ftdi_set_baudrate failed: %s",
|
sr_err("ftdi_set_baudrate failed: %s",
|
||||||
ftdi_get_error_string(ftdic));
|
ftdi_get_error_string(&devc->ftdic));
|
||||||
return 0;
|
return SR_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize the FPGA for firmware upload. */
|
/* Initialize the FPGA for firmware upload. */
|
||||||
|
@ -499,14 +478,14 @@ static int upload_firmware(struct sr_context *ctx,
|
||||||
|
|
||||||
g_free(buf);
|
g_free(buf);
|
||||||
|
|
||||||
ret = ftdi_set_bitmode(ftdic, 0x00, BITMODE_RESET);
|
ret = ftdi_set_bitmode(&devc->ftdic, 0x00, BITMODE_RESET);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
sr_err("ftdi_set_bitmode failed: %s",
|
sr_err("ftdi_set_bitmode failed: %s",
|
||||||
ftdi_get_error_string(ftdic));
|
ftdi_get_error_string(&devc->ftdic));
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
ftdi_usb_purge_buffers(ftdic);
|
ftdi_usb_purge_buffers(&devc->ftdic);
|
||||||
|
|
||||||
/* Discard garbage. */
|
/* Discard garbage. */
|
||||||
while (sigma_read(&pins, 1, devc) == 1)
|
while (sigma_read(&pins, 1, devc) == 1)
|
||||||
|
@ -554,6 +533,7 @@ SR_PRIV int sigma_set_samplerate(const struct sr_dev_inst *sdi, uint64_t sampler
|
||||||
struct drv_context *drvc;
|
struct drv_context *drvc;
|
||||||
size_t i;
|
size_t i;
|
||||||
int ret;
|
int ret;
|
||||||
|
int num_channels;
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
drvc = sdi->driver->context;
|
drvc = sdi->driver->context;
|
||||||
|
@ -572,15 +552,16 @@ SR_PRIV int sigma_set_samplerate(const struct sr_dev_inst *sdi, uint64_t sampler
|
||||||
* firmware is required and higher rates might limit the set
|
* firmware is required and higher rates might limit the set
|
||||||
* of available channels.
|
* of available channels.
|
||||||
*/
|
*/
|
||||||
|
num_channels = devc->num_channels;
|
||||||
if (samplerate <= SR_MHZ(50)) {
|
if (samplerate <= SR_MHZ(50)) {
|
||||||
ret = upload_firmware(drvc->sr_ctx, 0, devc);
|
ret = upload_firmware(drvc->sr_ctx, 0, devc);
|
||||||
devc->num_channels = 16;
|
num_channels = 16;
|
||||||
} else if (samplerate == SR_MHZ(100)) {
|
} else if (samplerate == SR_MHZ(100)) {
|
||||||
ret = upload_firmware(drvc->sr_ctx, 1, devc);
|
ret = upload_firmware(drvc->sr_ctx, 1, devc);
|
||||||
devc->num_channels = 8;
|
num_channels = 8;
|
||||||
} else if (samplerate == SR_MHZ(200)) {
|
} else if (samplerate == SR_MHZ(200)) {
|
||||||
ret = upload_firmware(drvc->sr_ctx, 2, devc);
|
ret = upload_firmware(drvc->sr_ctx, 2, devc);
|
||||||
devc->num_channels = 4;
|
num_channels = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -589,6 +570,7 @@ SR_PRIV int sigma_set_samplerate(const struct sr_dev_inst *sdi, uint64_t sampler
|
||||||
* an "event" (memory organization internal to the device).
|
* an "event" (memory organization internal to the device).
|
||||||
*/
|
*/
|
||||||
if (ret == SR_OK) {
|
if (ret == SR_OK) {
|
||||||
|
devc->num_channels = num_channels;
|
||||||
devc->cur_samplerate = samplerate;
|
devc->cur_samplerate = samplerate;
|
||||||
devc->samples_per_event = 16 / devc->num_channels;
|
devc->samples_per_event = 16 / devc->num_channels;
|
||||||
devc->state.state = SIGMA_IDLE;
|
devc->state.state = SIGMA_IDLE;
|
||||||
|
@ -663,16 +645,13 @@ SR_PRIV int sigma_convert_trigger(const struct sr_dev_inst *sdi)
|
||||||
if (match->match == SR_TRIGGER_ONE) {
|
if (match->match == SR_TRIGGER_ONE) {
|
||||||
devc->trigger.simplevalue |= channelbit;
|
devc->trigger.simplevalue |= channelbit;
|
||||||
devc->trigger.simplemask |= channelbit;
|
devc->trigger.simplemask |= channelbit;
|
||||||
}
|
} else if (match->match == SR_TRIGGER_ZERO) {
|
||||||
else if (match->match == SR_TRIGGER_ZERO) {
|
|
||||||
devc->trigger.simplevalue &= ~channelbit;
|
devc->trigger.simplevalue &= ~channelbit;
|
||||||
devc->trigger.simplemask |= channelbit;
|
devc->trigger.simplemask |= channelbit;
|
||||||
}
|
} else if (match->match == SR_TRIGGER_FALLING) {
|
||||||
else if (match->match == SR_TRIGGER_FALLING) {
|
|
||||||
devc->trigger.fallingmask |= channelbit;
|
devc->trigger.fallingmask |= channelbit;
|
||||||
trigger_set++;
|
trigger_set++;
|
||||||
}
|
} else if (match->match == SR_TRIGGER_RISING) {
|
||||||
else if (match->match == SR_TRIGGER_RISING) {
|
|
||||||
devc->trigger.risingmask |= channelbit;
|
devc->trigger.risingmask |= channelbit;
|
||||||
trigger_set++;
|
trigger_set++;
|
||||||
}
|
}
|
||||||
|
@ -694,7 +673,6 @@ SR_PRIV int sigma_convert_trigger(const struct sr_dev_inst *sdi)
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Software trigger to determine exact trigger position. */
|
/* Software trigger to determine exact trigger position. */
|
||||||
static int get_trigger_offset(uint8_t *samples, uint16_t last_sample,
|
static int get_trigger_offset(uint8_t *samples, uint16_t last_sample,
|
||||||
struct sigma_trigger *t)
|
struct sigma_trigger *t)
|
||||||
|
@ -1039,6 +1017,7 @@ static int download_capture(struct sr_dev_inst *sdi)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
sr_info("Downloading sample data.");
|
sr_info("Downloading sample data.");
|
||||||
|
devc->state.state = SIGMA_DOWNLOAD;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ask the hardware to stop data acquisition. Reception of the
|
* Ask the hardware to stop data acquisition. Reception of the
|
||||||
|
@ -1119,12 +1098,12 @@ static int download_capture(struct sr_dev_inst *sdi)
|
||||||
|
|
||||||
dl_lines_done += dl_lines_curr;
|
dl_lines_done += dl_lines_curr;
|
||||||
}
|
}
|
||||||
|
g_free(dram_line);
|
||||||
|
|
||||||
std_session_send_df_end(sdi);
|
std_session_send_df_end(sdi);
|
||||||
|
|
||||||
sdi->driver->dev_acquisition_stop(sdi);
|
devc->state.state = SIGMA_IDLE;
|
||||||
|
sr_dev_acquisition_stop(sdi);
|
||||||
g_free(dram_line);
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -1168,6 +1147,14 @@ SR_PRIV int sigma_receive_data(int fd, int revents, void *cb_data)
|
||||||
if (devc->state.state == SIGMA_IDLE)
|
if (devc->state.state == SIGMA_IDLE)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When the application has requested to stop the acquisition,
|
||||||
|
* then immediately start downloading sample data. Otherwise
|
||||||
|
* keep checking configured limits which will terminate the
|
||||||
|
* acquisition and initiate download.
|
||||||
|
*/
|
||||||
|
if (devc->state.state == SIGMA_STOPPING)
|
||||||
|
return download_capture(sdi);
|
||||||
if (devc->state.state == SIGMA_CAPTURE)
|
if (devc->state.state == SIGMA_CAPTURE)
|
||||||
return sigma_capture_mode(sdi);
|
return sigma_capture_mode(sdi);
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,8 @@
|
||||||
#include <libsigrok/libsigrok.h>
|
#include <libsigrok/libsigrok.h>
|
||||||
#include "libsigrok-internal.h"
|
#include "libsigrok-internal.h"
|
||||||
|
|
||||||
|
#define LOG_PREFIX "asix-sigma"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Triggers are not working in this implementation. Stop claiming
|
* Triggers are not working in this implementation. Stop claiming
|
||||||
* support for the feature which effectively is not available, until
|
* support for the feature which effectively is not available, until
|
||||||
|
@ -38,13 +40,9 @@
|
||||||
*/
|
*/
|
||||||
#define ASIX_SIGMA_WITH_TRIGGER 0
|
#define ASIX_SIGMA_WITH_TRIGGER 0
|
||||||
|
|
||||||
#define LOG_PREFIX "asix-sigma"
|
|
||||||
|
|
||||||
#define USB_VENDOR 0xa600
|
#define USB_VENDOR 0xa600
|
||||||
#define USB_PRODUCT 0xa000
|
#define USB_PRODUCT 0xa000
|
||||||
#define USB_DESCRIPTION "ASIX SIGMA"
|
#define USB_DESCRIPTION "ASIX SIGMA"
|
||||||
#define USB_VENDOR_NAME "ASIX"
|
|
||||||
#define USB_MODEL_NAME "SIGMA"
|
|
||||||
|
|
||||||
enum sigma_write_register {
|
enum sigma_write_register {
|
||||||
WRITE_CLOCK_SELECT = 0,
|
WRITE_CLOCK_SELECT = 0,
|
||||||
|
@ -248,14 +246,13 @@ struct sigma_state {
|
||||||
SIGMA_UNINITIALIZED = 0,
|
SIGMA_UNINITIALIZED = 0,
|
||||||
SIGMA_IDLE,
|
SIGMA_IDLE,
|
||||||
SIGMA_CAPTURE,
|
SIGMA_CAPTURE,
|
||||||
|
SIGMA_STOPPING,
|
||||||
SIGMA_DOWNLOAD,
|
SIGMA_DOWNLOAD,
|
||||||
} state;
|
} state;
|
||||||
|
|
||||||
uint16_t lastts;
|
uint16_t lastts;
|
||||||
uint16_t lastsample;
|
uint16_t lastsample;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Private, per-device-instance driver context. */
|
|
||||||
struct dev_context {
|
struct dev_context {
|
||||||
struct ftdi_context ftdic;
|
struct ftdi_context ftdic;
|
||||||
uint64_t cur_samplerate;
|
uint64_t cur_samplerate;
|
||||||
|
@ -267,7 +264,7 @@ struct dev_context {
|
||||||
int num_channels;
|
int num_channels;
|
||||||
int cur_channels;
|
int cur_channels;
|
||||||
int samples_per_event;
|
int samples_per_event;
|
||||||
int capture_ratio;
|
uint64_t capture_ratio;
|
||||||
struct sigma_trigger trigger;
|
struct sigma_trigger trigger;
|
||||||
int use_triggers;
|
int use_triggers;
|
||||||
struct sigma_state state;
|
struct sigma_state state;
|
||||||
|
@ -280,7 +277,6 @@ SR_PRIV int sigma_write_register(uint8_t reg, uint8_t *data, size_t len,
|
||||||
struct dev_context *devc);
|
struct dev_context *devc);
|
||||||
SR_PRIV int sigma_set_register(uint8_t reg, uint8_t value, struct dev_context *devc);
|
SR_PRIV int sigma_set_register(uint8_t reg, uint8_t value, struct dev_context *devc);
|
||||||
SR_PRIV int sigma_write_trigger_lut(struct triggerlut *lut, struct dev_context *devc);
|
SR_PRIV int sigma_write_trigger_lut(struct triggerlut *lut, struct dev_context *devc);
|
||||||
SR_PRIV void sigma_clear_helper(void *priv);
|
|
||||||
SR_PRIV uint64_t sigma_limit_samples_to_msec(const struct dev_context *devc,
|
SR_PRIV uint64_t sigma_limit_samples_to_msec(const struct dev_context *devc,
|
||||||
uint64_t limit_samples);
|
uint64_t limit_samples);
|
||||||
SR_PRIV int sigma_set_samplerate(const struct sr_dev_inst *sdi, uint64_t samplerate);
|
SR_PRIV int sigma_set_samplerate(const struct sr_dev_inst *sdi, uint64_t samplerate);
|
||||||
|
|
|
@ -182,21 +182,19 @@ static GSList *scan_3203(struct sr_dev_driver *di, GSList *options)
|
||||||
return scan(di, options, PPS_3203T_3S);
|
return scan(di, options, PPS_3203T_3S);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
|
static int config_get(uint32_t key, GVariant **data,
|
||||||
const struct sr_channel_group *cg)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
struct sr_channel *ch;
|
struct sr_channel *ch;
|
||||||
int channel, ret;
|
int channel;
|
||||||
|
|
||||||
if (!sdi)
|
if (!sdi)
|
||||||
return SR_ERR_ARG;
|
return SR_ERR_ARG;
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
ret = SR_OK;
|
|
||||||
if (!cg) {
|
if (!cg) {
|
||||||
/* No channel group: global options. */
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case SR_CONF_CHANNEL_CONFIG:
|
case SR_CONF_CHANNEL_CONFIG:
|
||||||
*data = g_variant_new_string(channel_modes[devc->channel_mode]);
|
*data = g_variant_new_string(channel_modes[devc->channel_mode]);
|
||||||
|
@ -233,64 +231,36 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int find_str(const char *str, const char **strings, int array_size)
|
static int config_set(uint32_t key, GVariant *data,
|
||||||
{
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
int idx, i;
|
|
||||||
|
|
||||||
idx = -1;
|
|
||||||
for (i = 0; i < array_size; i++) {
|
|
||||||
if (!strcmp(str, strings[i])) {
|
|
||||||
idx = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 dev_context *devc;
|
||||||
struct sr_channel *ch;
|
struct sr_channel *ch;
|
||||||
gdouble dval;
|
gdouble dval;
|
||||||
int channel, ret, ival;
|
int channel, ival;
|
||||||
const char *sval;
|
|
||||||
gboolean bval;
|
gboolean bval;
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
ret = SR_OK;
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
if (!cg) {
|
if (!cg) {
|
||||||
/* No channel group: global options. */
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case SR_CONF_CHANNEL_CONFIG:
|
case SR_CONF_CHANNEL_CONFIG:
|
||||||
sval = g_variant_get_string(data, NULL);
|
if ((ival = std_str_idx(data, ARRAY_AND_SIZE(channel_modes))) < 0)
|
||||||
if ((ival = find_str(sval, channel_modes,
|
return SR_ERR_ARG;
|
||||||
ARRAY_SIZE(channel_modes))) == -1) {
|
if (devc->model->channel_modes && (1 << ival) == 0)
|
||||||
ret = SR_ERR_ARG;
|
return SR_ERR_ARG; /* Not supported on this model. */
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (devc->model->channel_modes && (1 << ival) == 0) {
|
|
||||||
/* Not supported on this model. */
|
|
||||||
ret = SR_ERR_ARG;
|
|
||||||
}
|
|
||||||
if (ival == devc->channel_mode_set)
|
if (ival == devc->channel_mode_set)
|
||||||
/* Nothing to do. */
|
break; /* Nothing to do. */
|
||||||
break;
|
|
||||||
devc->channel_mode_set = ival;
|
devc->channel_mode_set = ival;
|
||||||
devc->config_dirty = TRUE;
|
devc->config_dirty = TRUE;
|
||||||
break;
|
break;
|
||||||
case SR_CONF_OVER_CURRENT_PROTECTION_ENABLED:
|
case SR_CONF_OVER_CURRENT_PROTECTION_ENABLED:
|
||||||
bval = g_variant_get_boolean(data);
|
bval = g_variant_get_boolean(data);
|
||||||
if (bval == devc->over_current_protection_set)
|
if (bval == devc->over_current_protection_set)
|
||||||
/* Nothing to do. */
|
break; /* Nothing to do. */
|
||||||
break;
|
|
||||||
devc->over_current_protection_set = bval;
|
devc->over_current_protection_set = bval;
|
||||||
devc->config_dirty = TRUE;
|
devc->config_dirty = TRUE;
|
||||||
break;
|
break;
|
||||||
|
@ -298,7 +268,6 @@ static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sd
|
||||||
return SR_ERR_NA;
|
return SR_ERR_NA;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Channel group specified: per-channel options. */
|
|
||||||
/* We only ever have one channel per channel group in this driver. */
|
/* We only ever have one channel per channel group in this driver. */
|
||||||
ch = cg->channels->data;
|
ch = cg->channels->data;
|
||||||
channel = ch->index;
|
channel = ch->index;
|
||||||
|
@ -307,116 +276,85 @@ static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sd
|
||||||
case SR_CONF_VOLTAGE_TARGET:
|
case SR_CONF_VOLTAGE_TARGET:
|
||||||
dval = g_variant_get_double(data);
|
dval = g_variant_get_double(data);
|
||||||
if (dval < 0 || dval > devc->model->channels[channel].voltage[1])
|
if (dval < 0 || dval > devc->model->channels[channel].voltage[1])
|
||||||
ret = SR_ERR_ARG;
|
return SR_ERR_ARG;
|
||||||
devc->config[channel].output_voltage_max = dval;
|
devc->config[channel].output_voltage_max = dval;
|
||||||
devc->config_dirty = TRUE;
|
devc->config_dirty = TRUE;
|
||||||
break;
|
break;
|
||||||
case SR_CONF_CURRENT_LIMIT:
|
case SR_CONF_CURRENT_LIMIT:
|
||||||
dval = g_variant_get_double(data);
|
dval = g_variant_get_double(data);
|
||||||
if (dval < 0 || dval > devc->model->channels[channel].current[1])
|
if (dval < 0 || dval > devc->model->channels[channel].current[1])
|
||||||
ret = SR_ERR_ARG;
|
return SR_ERR_ARG;
|
||||||
devc->config[channel].output_current_max = dval;
|
devc->config[channel].output_current_max = dval;
|
||||||
devc->config_dirty = TRUE;
|
devc->config_dirty = TRUE;
|
||||||
break;
|
break;
|
||||||
case SR_CONF_ENABLED:
|
case SR_CONF_ENABLED:
|
||||||
bval = g_variant_get_boolean(data);
|
bval = g_variant_get_boolean(data);
|
||||||
if (bval == devc->config[channel].output_enabled_set)
|
if (bval == devc->config[channel].output_enabled_set)
|
||||||
/* Nothing to do. */
|
break; /* Nothing to do. */
|
||||||
break;
|
|
||||||
devc->config[channel].output_enabled_set = bval;
|
devc->config[channel].output_enabled_set = bval;
|
||||||
devc->config_dirty = TRUE;
|
devc->config_dirty = TRUE;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret = SR_ERR_NA;
|
return SR_ERR_NA;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
|
static int config_list(uint32_t key, GVariant **data,
|
||||||
const struct sr_channel_group *cg)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
struct sr_channel *ch;
|
struct sr_channel *ch;
|
||||||
GVariant *gvar;
|
int channel;
|
||||||
GVariantBuilder gvb;
|
|
||||||
int channel, ret, i;
|
|
||||||
|
|
||||||
/* Always available. */
|
devc = (sdi) ? sdi->priv : NULL;
|
||||||
if (key == SR_CONF_SCAN_OPTIONS) {
|
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
|
|
||||||
return SR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key == SR_CONF_DEVICE_OPTIONS && !sdi) {
|
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
drvopts, ARRAY_SIZE(drvopts), sizeof(uint32_t));
|
|
||||||
return SR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!sdi)
|
|
||||||
return SR_ERR_ARG;
|
|
||||||
|
|
||||||
devc = sdi->priv;
|
|
||||||
ret = SR_OK;
|
|
||||||
if (!cg) {
|
if (!cg) {
|
||||||
/* No channel group: global options. */
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
|
case SR_CONF_SCAN_OPTIONS:
|
||||||
case SR_CONF_DEVICE_OPTIONS:
|
case SR_CONF_DEVICE_OPTIONS:
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
|
||||||
devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
|
|
||||||
break;
|
|
||||||
case SR_CONF_CHANNEL_CONFIG:
|
case SR_CONF_CHANNEL_CONFIG:
|
||||||
|
if (!devc || !devc->model)
|
||||||
|
return SR_ERR_ARG;
|
||||||
if (devc->model->channel_modes == CHANMODE_INDEPENDENT) {
|
if (devc->model->channel_modes == CHANMODE_INDEPENDENT) {
|
||||||
/* The 1-channel models. */
|
/* The 1-channel models. */
|
||||||
*data = g_variant_new_strv(channel_modes, 1);
|
*data = g_variant_new_strv(channel_modes, 1);
|
||||||
} else {
|
} else {
|
||||||
/* The other models support all modes. */
|
/* The other models support all modes. */
|
||||||
*data = g_variant_new_strv(channel_modes, ARRAY_SIZE(channel_modes));
|
*data = g_variant_new_strv(ARRAY_AND_SIZE(channel_modes));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return SR_ERR_NA;
|
return SR_ERR_NA;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Channel group specified: per-channel options. */
|
|
||||||
if (!sdi)
|
|
||||||
return SR_ERR_ARG;
|
|
||||||
/* We only ever have one channel per channel group in this driver. */
|
/* We only ever have one channel per channel group in this driver. */
|
||||||
ch = cg->channels->data;
|
ch = cg->channels->data;
|
||||||
channel = ch->index;
|
channel = ch->index;
|
||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case SR_CONF_DEVICE_OPTIONS:
|
case SR_CONF_DEVICE_OPTIONS:
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
*data = std_gvar_array_u32(ARRAY_AND_SIZE(devopts_cg));
|
||||||
devopts_cg, ARRAY_SIZE(devopts_cg), sizeof(uint32_t));
|
|
||||||
break;
|
break;
|
||||||
case SR_CONF_VOLTAGE_TARGET:
|
case SR_CONF_VOLTAGE_TARGET:
|
||||||
g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
|
if (!devc || !devc->model)
|
||||||
/* Min, max, step. */
|
return SR_ERR_ARG;
|
||||||
for (i = 0; i < 3; i++) {
|
*data = std_gvar_min_max_step_array(devc->model->channels[channel].voltage);
|
||||||
gvar = g_variant_new_double(devc->model->channels[channel].voltage[i]);
|
|
||||||
g_variant_builder_add_value(&gvb, gvar);
|
|
||||||
}
|
|
||||||
*data = g_variant_builder_end(&gvb);
|
|
||||||
break;
|
break;
|
||||||
case SR_CONF_CURRENT_LIMIT:
|
case SR_CONF_CURRENT_LIMIT:
|
||||||
g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
|
if (!devc || !devc->model)
|
||||||
/* Min, max, step. */
|
return SR_ERR_ARG;
|
||||||
for (i = 0; i < 3; i++) {
|
*data = std_gvar_min_max_step_array(devc->model->channels[channel].current);
|
||||||
gvar = g_variant_new_double(devc->model->channels[channel].current[i]);
|
|
||||||
g_variant_builder_add_value(&gvb, gvar);
|
|
||||||
}
|
|
||||||
*data = g_variant_builder_end(&gvb);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return SR_ERR_NA;
|
return SR_ERR_NA;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_close(struct sr_dev_inst *sdi)
|
static int dev_close(struct sr_dev_inst *sdi)
|
||||||
|
@ -424,6 +362,7 @@ static int dev_close(struct sr_dev_inst *sdi)
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
if (devc->config_dirty)
|
if (devc->config_dirty)
|
||||||
/* Some configuration changes were queued up but didn't
|
/* Some configuration changes were queued up but didn't
|
||||||
* get sent to the device, likely because we were never
|
* get sent to the device, likely because we were never
|
||||||
|
@ -439,9 +378,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||||
struct sr_serial_dev_inst *serial;
|
struct sr_serial_dev_inst *serial;
|
||||||
uint8_t packet[PACKET_SIZE];
|
uint8_t packet[PACKET_SIZE];
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
memset(devc->packet, 0x44, PACKET_SIZE);
|
memset(devc->packet, 0x44, PACKET_SIZE);
|
||||||
devc->packet_size = 0;
|
devc->packet_size = 0;
|
||||||
|
@ -466,9 +402,6 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi)
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
devc->acquisition_running = FALSE;
|
devc->acquisition_running = FALSE;
|
||||||
|
|
||||||
|
@ -483,7 +416,7 @@ static struct sr_dev_driver atten_pps3203_driver_info = {
|
||||||
.cleanup = std_cleanup,
|
.cleanup = std_cleanup,
|
||||||
.scan = scan_3203,
|
.scan = scan_3203,
|
||||||
.dev_list = std_dev_list,
|
.dev_list = std_dev_list,
|
||||||
.dev_clear = NULL,
|
.dev_clear = std_dev_clear,
|
||||||
.config_get = config_get,
|
.config_get = config_get,
|
||||||
.config_set = config_set,
|
.config_set = config_set,
|
||||||
.config_list = config_list,
|
.config_list = config_list,
|
||||||
|
|
|
@ -71,15 +71,11 @@ struct per_channel_config {
|
||||||
gboolean output_enabled_set;
|
gboolean output_enabled_set;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Private, per-device-instance driver context. */
|
|
||||||
struct dev_context {
|
struct dev_context {
|
||||||
/* Model-specific information */
|
|
||||||
const struct pps_model *model;
|
const struct pps_model *model;
|
||||||
|
|
||||||
/* Acquisition state */
|
|
||||||
gboolean acquisition_running;
|
gboolean acquisition_running;
|
||||||
|
|
||||||
/* Operational state */
|
|
||||||
gboolean config_dirty;
|
gboolean config_dirty;
|
||||||
struct per_channel_config *config;
|
struct per_channel_config *config;
|
||||||
/* Blocking write timeout for packet. */
|
/* Blocking write timeout for packet. */
|
||||||
|
@ -91,7 +87,6 @@ struct dev_context {
|
||||||
int channel_mode_set;
|
int channel_mode_set;
|
||||||
gboolean over_current_protection_set;
|
gboolean over_current_protection_set;
|
||||||
|
|
||||||
/* Temporary state across callbacks */
|
|
||||||
uint8_t packet[PACKET_SIZE];
|
uint8_t packet[PACKET_SIZE];
|
||||||
int packet_size;
|
int packet_size;
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,11 @@
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <sys/timerfd.h>
|
#include <sys/timerfd.h>
|
||||||
|
|
||||||
|
static const uint32_t drvopts[] = {
|
||||||
|
SR_CONF_THERMOMETER,
|
||||||
|
SR_CONF_POWERMETER,
|
||||||
|
};
|
||||||
|
|
||||||
static const uint32_t devopts[] = {
|
static const uint32_t devopts[] = {
|
||||||
SR_CONF_CONTINUOUS,
|
SR_CONF_CONTINUOUS,
|
||||||
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
|
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
|
||||||
|
@ -126,27 +131,8 @@ err_out:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_open(struct sr_dev_inst *sdi)
|
|
||||||
{
|
|
||||||
(void)sdi;
|
|
||||||
|
|
||||||
sdi->status = SR_ST_ACTIVE;
|
|
||||||
|
|
||||||
return SR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dev_close(struct sr_dev_inst *sdi)
|
|
||||||
{
|
|
||||||
(void)sdi;
|
|
||||||
|
|
||||||
sdi->status = SR_ST_INACTIVE;
|
|
||||||
|
|
||||||
return SR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int config_get(uint32_t key, GVariant **data,
|
static int config_get(uint32_t key, GVariant **data,
|
||||||
const struct sr_dev_inst *sdi,
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
const struct sr_channel_group *cg)
|
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -156,11 +142,11 @@ static int config_get(uint32_t key, GVariant **data,
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
ret = SR_OK;
|
ret = SR_OK;
|
||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case SR_CONF_LIMIT_SAMPLES:
|
case SR_CONF_LIMIT_SAMPLES:
|
||||||
case SR_CONF_LIMIT_MSEC:
|
case SR_CONF_LIMIT_MSEC:
|
||||||
ret = sr_sw_limits_config_get(&devc->limits, key, data);
|
return sr_sw_limits_config_get(&devc->limits, key, data);
|
||||||
break;
|
|
||||||
case SR_CONF_SAMPLERATE:
|
case SR_CONF_SAMPLERATE:
|
||||||
*data = g_variant_new_uint64(devc->samplerate);
|
*data = g_variant_new_uint64(devc->samplerate);
|
||||||
break;
|
break;
|
||||||
|
@ -186,30 +172,22 @@ static int config_get(uint32_t key, GVariant **data,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_set(uint32_t key, GVariant *data,
|
static int config_set(uint32_t key, GVariant *data,
|
||||||
const struct sr_dev_inst *sdi,
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
const struct sr_channel_group *cg)
|
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
uint64_t samplerate;
|
uint64_t samplerate;
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
ret = SR_OK;
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case SR_CONF_LIMIT_SAMPLES:
|
case SR_CONF_LIMIT_SAMPLES:
|
||||||
case SR_CONF_LIMIT_MSEC:
|
case SR_CONF_LIMIT_MSEC:
|
||||||
ret = sr_sw_limits_config_set(&devc->limits, key, data);
|
return sr_sw_limits_config_set(&devc->limits, key, data);
|
||||||
break;
|
|
||||||
case SR_CONF_SAMPLERATE:
|
case SR_CONF_SAMPLERATE:
|
||||||
samplerate = g_variant_get_uint64(data);
|
samplerate = g_variant_get_uint64(data);
|
||||||
if (samplerate > MAX_SAMPLE_RATE) {
|
if (samplerate > MAX_SAMPLE_RATE) {
|
||||||
sr_err("Maximum sample rate is %d", MAX_SAMPLE_RATE);
|
sr_err("Maximum sample rate is %d", MAX_SAMPLE_RATE);
|
||||||
ret = SR_ERR_SAMPLERATE;
|
return SR_ERR_SAMPLERATE;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
devc->samplerate = samplerate;
|
devc->samplerate = samplerate;
|
||||||
bl_acme_maybe_set_update_interval(sdi, samplerate);
|
bl_acme_maybe_set_update_interval(sdi, samplerate);
|
||||||
|
@ -217,46 +195,30 @@ static int config_set(uint32_t key, GVariant *data,
|
||||||
case SR_CONF_PROBE_FACTOR:
|
case SR_CONF_PROBE_FACTOR:
|
||||||
if (!cg)
|
if (!cg)
|
||||||
return SR_ERR_CHANNEL_GROUP;
|
return SR_ERR_CHANNEL_GROUP;
|
||||||
ret = bl_acme_set_shunt(cg, g_variant_get_uint64(data));
|
return bl_acme_set_shunt(cg, g_variant_get_uint64(data));
|
||||||
break;
|
|
||||||
case SR_CONF_POWER_OFF:
|
case SR_CONF_POWER_OFF:
|
||||||
if (!cg)
|
if (!cg)
|
||||||
return SR_ERR_CHANNEL_GROUP;
|
return SR_ERR_CHANNEL_GROUP;
|
||||||
ret = bl_acme_set_power_off(cg, g_variant_get_boolean(data));
|
return bl_acme_set_power_off(cg, g_variant_get_boolean(data));
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
ret = SR_ERR_NA;
|
return SR_ERR_NA;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_list(uint32_t key, GVariant **data,
|
static int config_list(uint32_t key, GVariant **data,
|
||||||
const struct sr_dev_inst *sdi,
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
const struct sr_channel_group *cg)
|
|
||||||
{
|
{
|
||||||
uint32_t devopts_cg[MAX_DEVOPTS_CG];
|
uint32_t devopts_cg[MAX_DEVOPTS_CG];
|
||||||
GVariant *gvar;
|
int num_devopts_cg = 0;
|
||||||
GVariantBuilder gvb;
|
|
||||||
int ret, num_devopts_cg = 0;
|
|
||||||
|
|
||||||
(void)sdi;
|
|
||||||
(void)cg;
|
|
||||||
|
|
||||||
ret = SR_OK;
|
|
||||||
if (!cg) {
|
if (!cg) {
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case SR_CONF_DEVICE_OPTIONS:
|
case SR_CONF_DEVICE_OPTIONS:
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
return STD_CONFIG_LIST(key, data, sdi, cg, NO_OPTS, drvopts, devopts);
|
||||||
devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
|
|
||||||
break;
|
|
||||||
case SR_CONF_SAMPLERATE:
|
case SR_CONF_SAMPLERATE:
|
||||||
g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
|
*data = std_gvar_samplerates_steps(ARRAY_AND_SIZE(samplerates));
|
||||||
gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"),
|
|
||||||
samplerates, ARRAY_SIZE(samplerates), sizeof(uint64_t));
|
|
||||||
g_variant_builder_add(&gvb, "{sv}",
|
|
||||||
"samplerate-steps", gvar);
|
|
||||||
*data = g_variant_builder_end(&gvb);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return SR_ERR_NA;
|
return SR_ERR_NA;
|
||||||
|
@ -269,15 +231,14 @@ static int config_list(uint32_t key, GVariant **data,
|
||||||
if (bl_acme_probe_has_pws(cg))
|
if (bl_acme_probe_has_pws(cg))
|
||||||
devopts_cg[num_devopts_cg++] = HAS_POWER_OFF;
|
devopts_cg[num_devopts_cg++] = HAS_POWER_OFF;
|
||||||
|
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
*data = std_gvar_array_u32(devopts_cg, num_devopts_cg);
|
||||||
devopts_cg, num_devopts_cg, sizeof(uint32_t));
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return SR_ERR_NA;
|
return SR_ERR_NA;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dev_acquisition_close(const struct sr_dev_inst *sdi)
|
static void dev_acquisition_close(const struct sr_dev_inst *sdi)
|
||||||
|
@ -316,9 +277,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||||
.it_value = { 0, 0 }
|
.it_value = { 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
if (dev_acquisition_open(sdi))
|
if (dev_acquisition_open(sdi))
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
|
|
||||||
|
@ -360,9 +318,6 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi)
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
dev_acquisition_close(sdi);
|
dev_acquisition_close(sdi);
|
||||||
sr_session_source_remove_channel(sdi->session, devc->channel);
|
sr_session_source_remove_channel(sdi->session, devc->channel);
|
||||||
g_io_channel_shutdown(devc->channel, FALSE, NULL);
|
g_io_channel_shutdown(devc->channel, FALSE, NULL);
|
||||||
|
@ -385,11 +340,12 @@ static struct sr_dev_driver baylibre_acme_driver_info = {
|
||||||
.cleanup = std_cleanup,
|
.cleanup = std_cleanup,
|
||||||
.scan = scan,
|
.scan = scan,
|
||||||
.dev_list = std_dev_list,
|
.dev_list = std_dev_list,
|
||||||
|
.dev_clear = std_dev_clear,
|
||||||
.config_get = config_get,
|
.config_get = config_get,
|
||||||
.config_set = config_set,
|
.config_set = config_set,
|
||||||
.config_list = config_list,
|
.config_list = config_list,
|
||||||
.dev_open = dev_open,
|
.dev_open = std_dummy_dev_open,
|
||||||
.dev_close = dev_close,
|
.dev_close = std_dummy_dev_close,
|
||||||
.dev_acquisition_start = dev_acquisition_start,
|
.dev_acquisition_start = dev_acquisition_start,
|
||||||
.dev_acquisition_stop = dev_acquisition_stop,
|
.dev_acquisition_stop = dev_acquisition_stop,
|
||||||
.context = NULL,
|
.context = NULL,
|
||||||
|
|
|
@ -166,8 +166,10 @@ SR_PRIV gboolean bl_acme_detect_probe(unsigned int addr,
|
||||||
probe_name_path(addr, path);
|
probe_name_path(addr, path);
|
||||||
status = g_file_get_contents(path->str, &buf, &size, &err);
|
status = g_file_get_contents(path->str, &buf, &size, &err);
|
||||||
if (!status) {
|
if (!status) {
|
||||||
sr_dbg("Name for probe %d can't be read: %s",
|
/* Don't log "No such file or directory" messages. */
|
||||||
prb_num, err->message);
|
if (err->code != G_FILE_ERROR_NOENT)
|
||||||
|
sr_dbg("Name for probe %d can't be read (%d): %s",
|
||||||
|
prb_num, err->code, err->message);
|
||||||
g_string_free(path, TRUE);
|
g_string_free(path, TRUE);
|
||||||
g_error_free(err);
|
g_error_free(err);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -793,7 +795,7 @@ SR_PRIV int bl_acme_receive_data(int fd, int revents, void *cb_data)
|
||||||
sr_sw_limits_update_samples_read(&devc->limits, 1);
|
sr_sw_limits_update_samples_read(&devc->limits, 1);
|
||||||
|
|
||||||
if (sr_sw_limits_check(&devc->limits)) {
|
if (sr_sw_limits_check(&devc->limits)) {
|
||||||
sdi->driver->dev_acquisition_stop(sdi);
|
sr_dev_acquisition_stop(sdi);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,6 @@ enum probe_type {
|
||||||
PROBE_TEMP,
|
PROBE_TEMP,
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Private, per-device-instance driver context. */
|
|
||||||
struct dev_context {
|
struct dev_context {
|
||||||
uint64_t samplerate;
|
uint64_t samplerate;
|
||||||
struct sr_sw_limits limits;
|
struct sr_sw_limits limits;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of the libsigrok project.
|
* This file is part of the libsigrok project.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2014 Kumar Abhishek <abhishek@theembeddedkitchen.net>
|
* Copyright (C) 2014-2017 Kumar Abhishek <abhishek@theembeddedkitchen.net>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -21,24 +21,25 @@
|
||||||
#include "protocol.h"
|
#include "protocol.h"
|
||||||
#include "beaglelogic.h"
|
#include "beaglelogic.h"
|
||||||
|
|
||||||
/* Scan options */
|
|
||||||
static const uint32_t scanopts[] = {
|
static const uint32_t scanopts[] = {
|
||||||
|
SR_CONF_CONN,
|
||||||
SR_CONF_NUM_LOGIC_CHANNELS,
|
SR_CONF_NUM_LOGIC_CHANNELS,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Hardware capabilities */
|
static const uint32_t drvopts[] = {
|
||||||
static const uint32_t devopts[] = {
|
|
||||||
SR_CONF_LOGIC_ANALYZER,
|
SR_CONF_LOGIC_ANALYZER,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t devopts[] = {
|
||||||
SR_CONF_CONTINUOUS,
|
SR_CONF_CONTINUOUS,
|
||||||
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
|
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
|
||||||
SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET,
|
SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
|
||||||
SR_CONF_TRIGGER_MATCH | SR_CONF_LIST,
|
SR_CONF_TRIGGER_MATCH | SR_CONF_LIST,
|
||||||
SR_CONF_CAPTURE_RATIO | SR_CONF_GET | SR_CONF_SET,
|
SR_CONF_CAPTURE_RATIO | SR_CONF_GET | SR_CONF_SET,
|
||||||
SR_CONF_NUM_LOGIC_CHANNELS | SR_CONF_GET,
|
SR_CONF_NUM_LOGIC_CHANNELS | SR_CONF_GET,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Trigger matching capabilities */
|
static const int32_t trigger_matches[] = {
|
||||||
static const int32_t soft_trigger_matches[] = {
|
|
||||||
SR_TRIGGER_ZERO,
|
SR_TRIGGER_ZERO,
|
||||||
SR_TRIGGER_ONE,
|
SR_TRIGGER_ONE,
|
||||||
SR_TRIGGER_RISING,
|
SR_TRIGGER_RISING,
|
||||||
|
@ -58,67 +59,78 @@ static const uint64_t samplerates[] = {
|
||||||
SR_HZ(1),
|
SR_HZ(1),
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct dev_context *beaglelogic_devc_alloc(void)
|
|
||||||
{
|
|
||||||
struct dev_context *devc;
|
|
||||||
|
|
||||||
devc = g_malloc0(sizeof(struct dev_context));
|
|
||||||
|
|
||||||
/* Default non-zero values (if any) */
|
|
||||||
devc->fd = -1;
|
|
||||||
devc->limit_samples = (uint64_t)-1;
|
|
||||||
|
|
||||||
return devc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
{
|
{
|
||||||
GSList *l;
|
GSList *l;
|
||||||
struct sr_config *src;
|
struct sr_config *src;
|
||||||
struct sr_dev_inst *sdi;
|
struct sr_dev_inst *sdi;
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
|
const char *conn;
|
||||||
|
gchar **params;
|
||||||
int i, maxch;
|
int i, maxch;
|
||||||
|
|
||||||
/* Probe for /dev/beaglelogic */
|
maxch = NUM_CHANNELS;
|
||||||
if (!g_file_test(BEAGLELOGIC_DEV_NODE, G_FILE_TEST_EXISTS))
|
conn = NULL;
|
||||||
return NULL;
|
|
||||||
|
|
||||||
sdi = g_malloc0(sizeof(struct sr_dev_inst));
|
|
||||||
sdi->status = SR_ST_INACTIVE;
|
|
||||||
sdi->model = g_strdup("BeagleLogic");
|
|
||||||
sdi->version = g_strdup("1.0");
|
|
||||||
|
|
||||||
/* Unless explicitly specified, keep max channels to 8 only */
|
|
||||||
maxch = 8;
|
|
||||||
for (l = options; l; l = l->next) {
|
for (l = options; l; l = l->next) {
|
||||||
src = l->data;
|
src = l->data;
|
||||||
if (src->key == SR_CONF_NUM_LOGIC_CHANNELS)
|
if (src->key == SR_CONF_NUM_LOGIC_CHANNELS)
|
||||||
maxch = g_variant_get_int32(src->data);
|
maxch = g_variant_get_int32(src->data);
|
||||||
|
if (src->key == SR_CONF_CONN)
|
||||||
|
conn = g_variant_get_string(src->data, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We need to test for number of channels by opening the node */
|
/* Probe for /dev/beaglelogic if not connecting via TCP */
|
||||||
devc = beaglelogic_devc_alloc();
|
if (!conn) {
|
||||||
|
params = NULL;
|
||||||
if (beaglelogic_open_nonblock(devc) != SR_OK) {
|
if (!g_file_test(BEAGLELOGIC_DEV_NODE, G_FILE_TEST_EXISTS))
|
||||||
g_free(devc);
|
return NULL;
|
||||||
sr_dev_inst_free(sdi);
|
} else {
|
||||||
|
params = g_strsplit(conn, "/", 0);
|
||||||
|
if (!params || !params[1] || !params[2]) {
|
||||||
|
sr_err("Invalid Parameters.");
|
||||||
|
g_strfreev(params);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (g_ascii_strncasecmp(params[0], "tcp", 3)) {
|
||||||
|
sr_err("Only TCP (tcp-raw) protocol is currently supported.");
|
||||||
|
g_strfreev(params);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (maxch > 8) {
|
|
||||||
maxch = NUM_CHANNELS;
|
|
||||||
devc->sampleunit = BL_SAMPLEUNIT_16_BITS;
|
|
||||||
} else {
|
|
||||||
maxch = 8;
|
|
||||||
devc->sampleunit = BL_SAMPLEUNIT_8_BITS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
beaglelogic_set_sampleunit(devc);
|
maxch = (maxch > 8) ? NUM_CHANNELS : 8;
|
||||||
beaglelogic_close(devc);
|
|
||||||
|
|
||||||
/* Signal */
|
sdi = g_new0(struct sr_dev_inst, 1);
|
||||||
|
sdi->status = SR_ST_INACTIVE;
|
||||||
|
sdi->model = g_strdup("BeagleLogic");
|
||||||
|
sdi->version = g_strdup("1.0");
|
||||||
|
|
||||||
|
devc = g_malloc0(sizeof(struct dev_context));
|
||||||
|
|
||||||
|
/* Default non-zero values (if any) */
|
||||||
|
devc->fd = -1;
|
||||||
|
devc->limit_samples = 10000000;
|
||||||
|
devc->tcp_buffer = 0;
|
||||||
|
|
||||||
|
if (!conn) {
|
||||||
|
devc->beaglelogic = &beaglelogic_native_ops;
|
||||||
sr_info("BeagleLogic device found at "BEAGLELOGIC_DEV_NODE);
|
sr_info("BeagleLogic device found at "BEAGLELOGIC_DEV_NODE);
|
||||||
|
} else {
|
||||||
|
devc->read_timeout = 1000 * 1000;
|
||||||
|
devc->beaglelogic = &beaglelogic_tcp_ops;
|
||||||
|
devc->address = g_strdup(params[1]);
|
||||||
|
devc->port = g_strdup(params[2]);
|
||||||
|
g_strfreev(params);
|
||||||
|
|
||||||
|
if (devc->beaglelogic->open(devc) != SR_OK)
|
||||||
|
goto err_free;
|
||||||
|
if (beaglelogic_tcp_detect(devc) != SR_OK)
|
||||||
|
goto err_free;
|
||||||
|
if (devc->beaglelogic->close(devc) != SR_OK)
|
||||||
|
goto err_free;
|
||||||
|
sr_info("BeagleLogic device found at %s : %s",
|
||||||
|
devc->address, devc->port);
|
||||||
|
}
|
||||||
|
|
||||||
/* Fill the channels */
|
/* Fill the channels */
|
||||||
for (i = 0; i < maxch; i++)
|
for (i = 0; i < maxch; i++)
|
||||||
|
@ -128,6 +140,16 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
sdi->priv = devc;
|
sdi->priv = devc;
|
||||||
|
|
||||||
return std_scan_complete(di, g_slist_append(NULL, sdi));
|
return std_scan_complete(di, g_slist_append(NULL, sdi));
|
||||||
|
|
||||||
|
err_free:
|
||||||
|
g_free(sdi->model);
|
||||||
|
g_free(sdi->version);
|
||||||
|
g_free(devc->address);
|
||||||
|
g_free(devc->port);
|
||||||
|
g_free(devc);
|
||||||
|
g_free(sdi);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_open(struct sr_dev_inst *sdi)
|
static int dev_open(struct sr_dev_inst *sdi)
|
||||||
|
@ -135,30 +157,39 @@ static int dev_open(struct sr_dev_inst *sdi)
|
||||||
struct dev_context *devc = sdi->priv;
|
struct dev_context *devc = sdi->priv;
|
||||||
|
|
||||||
/* Open BeagleLogic */
|
/* Open BeagleLogic */
|
||||||
if (beaglelogic_open_nonblock(devc))
|
if (devc->beaglelogic->open(devc))
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
|
|
||||||
/* Set fd and local attributes */
|
/* Set fd and local attributes */
|
||||||
|
if (devc->beaglelogic == &beaglelogic_tcp_ops)
|
||||||
|
devc->pollfd.fd = devc->socket;
|
||||||
|
else
|
||||||
devc->pollfd.fd = devc->fd;
|
devc->pollfd.fd = devc->fd;
|
||||||
devc->pollfd.events = G_IO_IN;
|
devc->pollfd.events = G_IO_IN;
|
||||||
devc->pollfd.revents = 0;
|
devc->pollfd.revents = 0;
|
||||||
|
|
||||||
/* Get the default attributes */
|
/* Get the default attributes */
|
||||||
beaglelogic_get_samplerate(devc);
|
devc->beaglelogic->get_samplerate(devc);
|
||||||
beaglelogic_get_sampleunit(devc);
|
devc->beaglelogic->get_sampleunit(devc);
|
||||||
beaglelogic_get_triggerflags(devc);
|
devc->beaglelogic->get_buffersize(devc);
|
||||||
beaglelogic_get_buffersize(devc);
|
devc->beaglelogic->get_bufunitsize(devc);
|
||||||
beaglelogic_get_bufunitsize(devc);
|
|
||||||
|
/* Set the triggerflags to default for continuous capture unless we
|
||||||
|
* explicitly limit samples using SR_CONF_LIMIT_SAMPLES */
|
||||||
|
devc->triggerflags = BL_TRIGGERFLAGS_CONTINUOUS;
|
||||||
|
devc->beaglelogic->set_triggerflags(devc);
|
||||||
|
|
||||||
/* Map the kernel capture FIFO for reads, saves 1 level of memcpy */
|
/* Map the kernel capture FIFO for reads, saves 1 level of memcpy */
|
||||||
if (beaglelogic_mmap(devc) != SR_OK) {
|
if (devc->beaglelogic == &beaglelogic_native_ops) {
|
||||||
|
if (devc->beaglelogic->mmap(devc) != SR_OK) {
|
||||||
sr_err("Unable to map capture buffer");
|
sr_err("Unable to map capture buffer");
|
||||||
beaglelogic_close(devc);
|
devc->beaglelogic->close(devc);
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
devc->tcp_buffer = g_malloc(TCP_BUFFER_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
/* We're good to go now */
|
|
||||||
sdi->status = SR_ST_ACTIVE;
|
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,17 +197,28 @@ static int dev_close(struct sr_dev_inst *sdi)
|
||||||
{
|
{
|
||||||
struct dev_context *devc = sdi->priv;
|
struct dev_context *devc = sdi->priv;
|
||||||
|
|
||||||
if (sdi->status == SR_ST_ACTIVE) {
|
|
||||||
/* Close the memory mapping and the file */
|
/* Close the memory mapping and the file */
|
||||||
beaglelogic_munmap(devc);
|
if (devc->beaglelogic == &beaglelogic_native_ops)
|
||||||
beaglelogic_close(devc);
|
devc->beaglelogic->munmap(devc);
|
||||||
}
|
devc->beaglelogic->close(devc);
|
||||||
sdi->status = SR_ST_INACTIVE;
|
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
|
static void clear_helper(struct dev_context *devc)
|
||||||
const struct sr_channel_group *cg)
|
{
|
||||||
|
g_free(devc->tcp_buffer);
|
||||||
|
g_free(devc->address);
|
||||||
|
g_free(devc->port);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dev_clear(const struct sr_dev_driver *di)
|
||||||
|
{
|
||||||
|
return std_dev_clear_with_callback(di, (std_dev_clear_callback)clear_helper);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
struct dev_context *devc = sdi->priv;
|
||||||
|
|
||||||
|
@ -202,21 +244,18 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
|
static int config_set(uint32_t key, GVariant *data,
|
||||||
const struct sr_channel_group *cg)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
struct dev_context *devc = sdi->priv;
|
struct dev_context *devc = sdi->priv;
|
||||||
uint64_t tmp_u64;
|
uint64_t tmp_u64;
|
||||||
|
|
||||||
(void)cg;
|
(void)cg;
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case SR_CONF_SAMPLERATE:
|
case SR_CONF_SAMPLERATE:
|
||||||
devc->cur_samplerate = g_variant_get_uint64(data);
|
devc->cur_samplerate = g_variant_get_uint64(data);
|
||||||
return beaglelogic_set_samplerate(devc);
|
return devc->beaglelogic->set_samplerate(devc);
|
||||||
case SR_CONF_LIMIT_SAMPLES:
|
case SR_CONF_LIMIT_SAMPLES:
|
||||||
tmp_u64 = g_variant_get_uint64(data);
|
tmp_u64 = g_variant_get_uint64(data);
|
||||||
devc->limit_samples = tmp_u64;
|
devc->limit_samples = tmp_u64;
|
||||||
|
@ -228,17 +267,15 @@ static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sd
|
||||||
sr_warn("Insufficient buffer space has been allocated.");
|
sr_warn("Insufficient buffer space has been allocated.");
|
||||||
sr_warn("Please use \'echo <size in bytes> > "\
|
sr_warn("Please use \'echo <size in bytes> > "\
|
||||||
BEAGLELOGIC_SYSFS_ATTR(memalloc) \
|
BEAGLELOGIC_SYSFS_ATTR(memalloc) \
|
||||||
"\' as root to increase the buffer size, this"\
|
"\' to increase the buffer size, this"\
|
||||||
" capture is now truncated to %d Msamples",
|
" capture is now truncated to %d Msamples",
|
||||||
devc->buffersize /
|
devc->buffersize /
|
||||||
(SAMPLEUNIT_TO_BYTES(devc->sampleunit) * 1000000));
|
(SAMPLEUNIT_TO_BYTES(devc->sampleunit) * 1000000));
|
||||||
}
|
}
|
||||||
return beaglelogic_set_triggerflags(devc);
|
return devc->beaglelogic->set_triggerflags(devc);
|
||||||
case SR_CONF_CAPTURE_RATIO:
|
case SR_CONF_CAPTURE_RATIO:
|
||||||
devc->capture_ratio = g_variant_get_uint64(data);
|
devc->capture_ratio = g_variant_get_uint64(data);
|
||||||
if (devc->capture_ratio > 100)
|
break;
|
||||||
return SR_ERR;
|
|
||||||
return SR_OK;
|
|
||||||
default:
|
default:
|
||||||
return SR_ERR_NA;
|
return SR_ERR_NA;
|
||||||
}
|
}
|
||||||
|
@ -246,43 +283,24 @@ static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sd
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
|
static int config_list(uint32_t key, GVariant **data,
|
||||||
const struct sr_channel_group *cg)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
int ret;
|
|
||||||
GVariant *gvar;
|
|
||||||
GVariantBuilder gvb;
|
|
||||||
|
|
||||||
(void)sdi;
|
|
||||||
(void)cg;
|
|
||||||
|
|
||||||
ret = SR_OK;
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case SR_CONF_SCAN_OPTIONS:
|
case SR_CONF_SCAN_OPTIONS:
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
|
|
||||||
break;
|
|
||||||
case SR_CONF_DEVICE_OPTIONS:
|
case SR_CONF_DEVICE_OPTIONS:
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
|
||||||
devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
|
|
||||||
break;
|
|
||||||
case SR_CONF_SAMPLERATE:
|
case SR_CONF_SAMPLERATE:
|
||||||
g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
|
*data = std_gvar_samplerates_steps(ARRAY_AND_SIZE(samplerates));
|
||||||
gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"),
|
|
||||||
samplerates, ARRAY_SIZE(samplerates), sizeof(uint64_t));
|
|
||||||
g_variant_builder_add(&gvb, "{sv}", "samplerate-steps", gvar);
|
|
||||||
*data = g_variant_builder_end(&gvb);
|
|
||||||
break;
|
break;
|
||||||
case SR_CONF_TRIGGER_MATCH:
|
case SR_CONF_TRIGGER_MATCH:
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
|
*data = std_gvar_array_i32(ARRAY_AND_SIZE(trigger_matches));
|
||||||
soft_trigger_matches, ARRAY_SIZE(soft_trigger_matches),
|
|
||||||
sizeof(int32_t));
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return SR_ERR_NA;
|
return SR_ERR_NA;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get a sane timeout for poll() */
|
/* get a sane timeout for poll() */
|
||||||
|
@ -292,25 +310,33 @@ static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *
|
||||||
static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||||
{
|
{
|
||||||
struct dev_context *devc = sdi->priv;
|
struct dev_context *devc = sdi->priv;
|
||||||
|
GSList *l;
|
||||||
struct sr_trigger *trigger;
|
struct sr_trigger *trigger;
|
||||||
|
struct sr_channel *channel;
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
/* Clear capture state */
|
/* Clear capture state */
|
||||||
devc->bytes_read = 0;
|
devc->bytes_read = 0;
|
||||||
devc->offset = 0;
|
devc->offset = 0;
|
||||||
|
|
||||||
/* Configure channels */
|
/* Configure channels */
|
||||||
devc->sampleunit = g_slist_length(sdi->channels) > 8 ?
|
devc->sampleunit = BL_SAMPLEUNIT_8_BITS;
|
||||||
BL_SAMPLEUNIT_16_BITS : BL_SAMPLEUNIT_8_BITS;
|
|
||||||
beaglelogic_set_sampleunit(devc);
|
for (l = sdi->channels; l; l = l->next) {
|
||||||
|
channel = l->data;
|
||||||
|
if (channel->index >= 8 && channel->enabled)
|
||||||
|
devc->sampleunit = BL_SAMPLEUNIT_16_BITS;
|
||||||
|
}
|
||||||
|
devc->beaglelogic->set_sampleunit(devc);
|
||||||
|
|
||||||
|
/* If continuous sampling, set the limit_samples to max possible value */
|
||||||
|
if (devc->triggerflags == BL_TRIGGERFLAGS_CONTINUOUS)
|
||||||
|
devc->limit_samples = UINT64_MAX;
|
||||||
|
|
||||||
/* Configure triggers & send header packet */
|
/* Configure triggers & send header packet */
|
||||||
if ((trigger = sr_session_trigger_get(sdi->session))) {
|
if ((trigger = sr_session_trigger_get(sdi->session))) {
|
||||||
int pre_trigger_samples = 0;
|
int pre_trigger_samples = 0;
|
||||||
if (devc->limit_samples > 0)
|
if (devc->limit_samples > 0)
|
||||||
pre_trigger_samples = devc->capture_ratio * devc->limit_samples/100;
|
pre_trigger_samples = (devc->capture_ratio * devc->limit_samples) / 100;
|
||||||
devc->stl = soft_trigger_logic_new(sdi, trigger, pre_trigger_samples);
|
devc->stl = soft_trigger_logic_new(sdi, trigger, pre_trigger_samples);
|
||||||
if (!devc->stl)
|
if (!devc->stl)
|
||||||
return SR_ERR_MALLOC;
|
return SR_ERR_MALLOC;
|
||||||
|
@ -320,9 +346,14 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||||
std_session_send_df_header(sdi);
|
std_session_send_df_header(sdi);
|
||||||
|
|
||||||
/* Trigger and add poll on file */
|
/* Trigger and add poll on file */
|
||||||
beaglelogic_start(devc);
|
devc->beaglelogic->start(devc);
|
||||||
|
if (devc->beaglelogic == &beaglelogic_native_ops)
|
||||||
sr_session_source_add_pollfd(sdi->session, &devc->pollfd,
|
sr_session_source_add_pollfd(sdi->session, &devc->pollfd,
|
||||||
BUFUNIT_TIMEOUT_MS(devc), beaglelogic_receive_data,
|
BUFUNIT_TIMEOUT_MS(devc), beaglelogic_native_receive_data,
|
||||||
|
(void *)sdi);
|
||||||
|
else
|
||||||
|
sr_session_source_add_pollfd(sdi->session, &devc->pollfd,
|
||||||
|
BUFUNIT_TIMEOUT_MS(devc), beaglelogic_tcp_receive_data,
|
||||||
(void *)sdi);
|
(void *)sdi);
|
||||||
|
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
|
@ -332,14 +363,14 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi)
|
||||||
{
|
{
|
||||||
struct dev_context *devc = sdi->priv;
|
struct dev_context *devc = sdi->priv;
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
/* Execute a stop on BeagleLogic */
|
/* Execute a stop on BeagleLogic */
|
||||||
beaglelogic_stop(devc);
|
devc->beaglelogic->stop(devc);
|
||||||
|
|
||||||
/* lseek to offset 0, flushes the cache */
|
/* Flush the cache */
|
||||||
|
if (devc->beaglelogic == &beaglelogic_native_ops)
|
||||||
lseek(devc->fd, 0, SEEK_SET);
|
lseek(devc->fd, 0, SEEK_SET);
|
||||||
|
else
|
||||||
|
beaglelogic_tcp_drain(devc);
|
||||||
|
|
||||||
/* Remove session source and send EOT packet */
|
/* Remove session source and send EOT packet */
|
||||||
sr_session_source_remove_pollfd(sdi->session, &devc->pollfd);
|
sr_session_source_remove_pollfd(sdi->session, &devc->pollfd);
|
||||||
|
@ -356,6 +387,7 @@ static struct sr_dev_driver beaglelogic_driver_info = {
|
||||||
.cleanup = std_cleanup,
|
.cleanup = std_cleanup,
|
||||||
.scan = scan,
|
.scan = scan,
|
||||||
.dev_list = std_dev_list,
|
.dev_list = std_dev_list,
|
||||||
|
.dev_clear = dev_clear,
|
||||||
.config_get = config_get,
|
.config_get = config_get,
|
||||||
.config_set = config_set,
|
.config_set = config_set,
|
||||||
.config_list = config_list,
|
.config_list = config_list,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of the libsigrok project.
|
* This file is part of the libsigrok project.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2014 Kumar Abhishek <abhishek@theembeddedkitchen.net>
|
* Copyright (C) 2014-2017 Kumar Abhishek <abhishek@theembeddedkitchen.net>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -47,12 +47,14 @@
|
||||||
#define IOCTL_BL_GET_TRIGGER_FLAGS _IOR('k', 0x23, uint32_t)
|
#define IOCTL_BL_GET_TRIGGER_FLAGS _IOR('k', 0x23, uint32_t)
|
||||||
#define IOCTL_BL_SET_TRIGGER_FLAGS _IOW('k', 0x23, uint32_t)
|
#define IOCTL_BL_SET_TRIGGER_FLAGS _IOW('k', 0x23, uint32_t)
|
||||||
|
|
||||||
|
#define IOCTL_BL_GET_CUR_INDEX _IOR('k', 0x24, uint32_t)
|
||||||
#define IOCTL_BL_CACHE_INVALIDATE _IO('k', 0x25)
|
#define IOCTL_BL_CACHE_INVALIDATE _IO('k', 0x25)
|
||||||
|
|
||||||
#define IOCTL_BL_GET_BUFFER_SIZE _IOR('k', 0x26, uint32_t)
|
#define IOCTL_BL_GET_BUFFER_SIZE _IOR('k', 0x26, uint32_t)
|
||||||
#define IOCTL_BL_SET_BUFFER_SIZE _IOW('k', 0x26, uint32_t)
|
#define IOCTL_BL_SET_BUFFER_SIZE _IOW('k', 0x26, uint32_t)
|
||||||
|
|
||||||
#define IOCTL_BL_GET_BUFUNIT_SIZE _IOR('k', 0x27, uint32_t)
|
#define IOCTL_BL_GET_BUFUNIT_SIZE _IOR('k', 0x27, uint32_t)
|
||||||
|
#define IOCTL_BL_SET_BUFUNIT_SIZE _IOW('k', 0x27, uint32_t)
|
||||||
|
|
||||||
#define IOCTL_BL_FILL_TEST_PATTERN _IO('k', 0x28)
|
#define IOCTL_BL_FILL_TEST_PATTERN _IO('k', 0x28)
|
||||||
|
|
||||||
|
@ -90,120 +92,41 @@ enum beaglelogic_sampleunit {
|
||||||
* SR_OK or SR_ERR
|
* SR_OK or SR_ERR
|
||||||
*/
|
*/
|
||||||
|
|
||||||
SR_PRIV int beaglelogic_open_nonblock(struct dev_context *devc);
|
struct beaglelogic_ops {
|
||||||
SR_PRIV int beaglelogic_close(struct dev_context *devc);
|
int (*open)(struct dev_context *devc);
|
||||||
|
int (*close)(struct dev_context *devc);
|
||||||
|
|
||||||
SR_PRIV int beaglelogic_get_buffersize(struct dev_context *devc);
|
int (*get_buffersize)(struct dev_context *devc);
|
||||||
SR_PRIV int beaglelogic_set_buffersize(struct dev_context *devc);
|
int (*set_buffersize)(struct dev_context *devc);
|
||||||
|
|
||||||
SR_PRIV int beaglelogic_get_samplerate(struct dev_context *devc);
|
int (*get_samplerate)(struct dev_context *devc);
|
||||||
SR_PRIV int beaglelogic_set_samplerate(struct dev_context *devc);
|
int (*set_samplerate)(struct dev_context *devc);
|
||||||
|
|
||||||
SR_PRIV int beaglelogic_get_sampleunit(struct dev_context *devc);
|
int (*get_sampleunit)(struct dev_context *devc);
|
||||||
SR_PRIV int beaglelogic_set_sampleunit(struct dev_context *devc);
|
int (*set_sampleunit)(struct dev_context *devc);
|
||||||
|
|
||||||
SR_PRIV int beaglelogic_get_triggerflags(struct dev_context *devc);
|
int (*get_triggerflags)(struct dev_context *devc);
|
||||||
SR_PRIV int beaglelogic_set_triggerflags(struct dev_context *devc);
|
int (*set_triggerflags)(struct dev_context *devc);
|
||||||
|
|
||||||
/* Start and stop the capture operation */
|
/* Start and stop the capture operation */
|
||||||
SR_PRIV int beaglelogic_start(struct dev_context *devc);
|
int (*start)(struct dev_context *devc);
|
||||||
SR_PRIV int beaglelogic_stop(struct dev_context *devc);
|
int (*stop)(struct dev_context *devc);
|
||||||
|
|
||||||
/* Get the last error size */
|
/* Get the last error size */
|
||||||
SR_PRIV int beaglelogic_getlasterror(struct dev_context *devc);
|
int (*get_lasterror)(struct dev_context *devc);
|
||||||
|
|
||||||
/* Gets the unit size of the capture buffer (usually 4 or 8 MB) */
|
/* Gets the unit size of the capture buffer (usually 4 or 8 MB) */
|
||||||
SR_PRIV int beaglelogic_get_bufunitsize(struct dev_context *devc);
|
int (*get_bufunitsize)(struct dev_context *devc);
|
||||||
|
int (*set_bufunitsize)(struct dev_context *devc);
|
||||||
|
|
||||||
SR_PRIV int beaglelogic_mmap(struct dev_context *devc);
|
int (*mmap)(struct dev_context *devc);
|
||||||
SR_PRIV int beaglelogic_munmap(struct dev_context *devc);
|
int (*munmap)(struct dev_context *devc);
|
||||||
|
};
|
||||||
|
|
||||||
/* Sources */
|
SR_PRIV extern const struct beaglelogic_ops beaglelogic_native_ops;
|
||||||
SR_PRIV inline int beaglelogic_open_nonblock(struct dev_context *devc) {
|
SR_PRIV extern const struct beaglelogic_ops beaglelogic_tcp_ops;
|
||||||
devc->fd = open(BEAGLELOGIC_DEV_NODE, O_RDONLY | O_NONBLOCK);
|
|
||||||
return (devc->fd == -1 ? SR_ERR : SR_OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
SR_PRIV inline int beaglelogic_close(struct dev_context *devc) {
|
SR_PRIV int beaglelogic_tcp_detect(struct dev_context *devc);
|
||||||
return close(devc->fd);
|
SR_PRIV int beaglelogic_tcp_drain(struct dev_context *devc);
|
||||||
}
|
|
||||||
|
|
||||||
SR_PRIV inline int beaglelogic_get_buffersize(struct dev_context *devc) {
|
|
||||||
return ioctl(devc->fd, IOCTL_BL_GET_BUFFER_SIZE, &devc->buffersize);
|
|
||||||
}
|
|
||||||
|
|
||||||
SR_PRIV inline int beaglelogic_set_buffersize(struct dev_context *devc) {
|
|
||||||
return ioctl(devc->fd, IOCTL_BL_SET_BUFFER_SIZE, devc->buffersize);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This is treated differently as it gets a uint64_t while a uint32_t is read */
|
|
||||||
SR_PRIV inline int beaglelogic_get_samplerate(struct dev_context *devc) {
|
|
||||||
uint32_t arg, err;
|
|
||||||
err = ioctl(devc->fd, IOCTL_BL_GET_SAMPLE_RATE, &arg);
|
|
||||||
devc->cur_samplerate = arg;
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
SR_PRIV inline int beaglelogic_set_samplerate(struct dev_context *devc) {
|
|
||||||
return ioctl(devc->fd, IOCTL_BL_SET_SAMPLE_RATE,
|
|
||||||
(uint32_t)devc->cur_samplerate);
|
|
||||||
}
|
|
||||||
|
|
||||||
SR_PRIV inline int beaglelogic_get_sampleunit(struct dev_context *devc) {
|
|
||||||
return ioctl(devc->fd, IOCTL_BL_GET_SAMPLE_UNIT, &devc->sampleunit);
|
|
||||||
}
|
|
||||||
|
|
||||||
SR_PRIV inline int beaglelogic_set_sampleunit(struct dev_context *devc) {
|
|
||||||
return ioctl(devc->fd, IOCTL_BL_SET_SAMPLE_UNIT, devc->sampleunit);
|
|
||||||
}
|
|
||||||
|
|
||||||
SR_PRIV inline int beaglelogic_get_triggerflags(struct dev_context *devc) {
|
|
||||||
return ioctl(devc->fd, IOCTL_BL_GET_TRIGGER_FLAGS, &devc->triggerflags);
|
|
||||||
}
|
|
||||||
|
|
||||||
SR_PRIV inline int beaglelogic_set_triggerflags(struct dev_context *devc) {
|
|
||||||
return ioctl(devc->fd, IOCTL_BL_SET_TRIGGER_FLAGS, devc->triggerflags);
|
|
||||||
}
|
|
||||||
|
|
||||||
SR_PRIV int beaglelogic_getlasterror(struct dev_context *devc) {
|
|
||||||
int fd;
|
|
||||||
char buf[16];
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if ((fd = open(BEAGLELOGIC_SYSFS_ATTR(lasterror), O_RDONLY)) == -1)
|
|
||||||
return SR_ERR;
|
|
||||||
|
|
||||||
if ((ret = read(fd, buf, 16)) < 0)
|
|
||||||
return SR_ERR;
|
|
||||||
|
|
||||||
close(fd);
|
|
||||||
devc->last_error = strtoul(buf, NULL, 10);
|
|
||||||
|
|
||||||
return SR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
SR_PRIV inline int beaglelogic_start(struct dev_context *devc) {
|
|
||||||
return ioctl(devc->fd, IOCTL_BL_START);
|
|
||||||
}
|
|
||||||
|
|
||||||
SR_PRIV inline int beaglelogic_stop(struct dev_context *devc) {
|
|
||||||
return ioctl(devc->fd, IOCTL_BL_STOP);
|
|
||||||
}
|
|
||||||
|
|
||||||
SR_PRIV int beaglelogic_get_bufunitsize(struct dev_context *devc) {
|
|
||||||
return ioctl(devc->fd, IOCTL_BL_GET_BUFUNIT_SIZE, &devc->bufunitsize);
|
|
||||||
}
|
|
||||||
|
|
||||||
SR_PRIV int beaglelogic_mmap(struct dev_context *devc) {
|
|
||||||
if (!devc->buffersize)
|
|
||||||
beaglelogic_get_buffersize(devc);
|
|
||||||
devc->sample_buf = mmap(NULL, devc->buffersize,
|
|
||||||
PROT_READ, MAP_SHARED, devc->fd, 0);
|
|
||||||
return (devc->sample_buf == MAP_FAILED ? -1 : SR_OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
SR_PRIV int beaglelogic_munmap(struct dev_context *devc) {
|
|
||||||
return munmap(devc->sample_buf, devc->buffersize);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,153 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the libsigrok project.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014-2017 Kumar Abhishek <abhishek@theembeddedkitchen.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 "protocol.h"
|
||||||
|
#include "beaglelogic.h"
|
||||||
|
|
||||||
|
static int beaglelogic_open_nonblock(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
devc->fd = open(BEAGLELOGIC_DEV_NODE, O_RDONLY | O_NONBLOCK);
|
||||||
|
|
||||||
|
return ((devc->fd == -1) ? SR_ERR : SR_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int beaglelogic_close(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
return close(devc->fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int beaglelogic_get_buffersize(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
return ioctl(devc->fd, IOCTL_BL_GET_BUFFER_SIZE, &devc->buffersize);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int beaglelogic_set_buffersize(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
return ioctl(devc->fd, IOCTL_BL_SET_BUFFER_SIZE, devc->buffersize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is treated differently as it gets a uint64_t while a uint32_t is read */
|
||||||
|
static int beaglelogic_get_samplerate(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
uint32_t arg, err;
|
||||||
|
|
||||||
|
err = ioctl(devc->fd, IOCTL_BL_GET_SAMPLE_RATE, &arg);
|
||||||
|
devc->cur_samplerate = arg;
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int beaglelogic_set_samplerate(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
return ioctl(devc->fd, IOCTL_BL_SET_SAMPLE_RATE,
|
||||||
|
(uint32_t)devc->cur_samplerate);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int beaglelogic_get_sampleunit(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
return ioctl(devc->fd, IOCTL_BL_GET_SAMPLE_UNIT, &devc->sampleunit);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int beaglelogic_set_sampleunit(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
return ioctl(devc->fd, IOCTL_BL_SET_SAMPLE_UNIT, devc->sampleunit);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int beaglelogic_get_triggerflags(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
return ioctl(devc->fd, IOCTL_BL_GET_TRIGGER_FLAGS, &devc->triggerflags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int beaglelogic_set_triggerflags(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
return ioctl(devc->fd, IOCTL_BL_SET_TRIGGER_FLAGS, devc->triggerflags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int beaglelogic_get_lasterror(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
char buf[16];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if ((fd = open(BEAGLELOGIC_SYSFS_ATTR(lasterror), O_RDONLY)) == -1)
|
||||||
|
return SR_ERR;
|
||||||
|
|
||||||
|
if ((ret = read(fd, buf, 16)) < 0)
|
||||||
|
return SR_ERR;
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
devc->last_error = strtoul(buf, NULL, 10);
|
||||||
|
|
||||||
|
return SR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int beaglelogic_start(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
return ioctl(devc->fd, IOCTL_BL_START);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int beaglelogic_stop(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
return ioctl(devc->fd, IOCTL_BL_STOP);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int beaglelogic_get_bufunitsize(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
return ioctl(devc->fd, IOCTL_BL_GET_BUFUNIT_SIZE, &devc->bufunitsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int beaglelogic_set_bufunitsize(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
return ioctl(devc->fd, IOCTL_BL_SET_BUFUNIT_SIZE, devc->bufunitsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int beaglelogic_mmap(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
if (!devc->buffersize)
|
||||||
|
beaglelogic_get_buffersize(devc);
|
||||||
|
devc->sample_buf = mmap(NULL, devc->buffersize,
|
||||||
|
PROT_READ, MAP_SHARED, devc->fd, 0);
|
||||||
|
|
||||||
|
return ((devc->sample_buf == MAP_FAILED) ? -1 : SR_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int beaglelogic_munmap(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
return munmap(devc->sample_buf, devc->buffersize);
|
||||||
|
}
|
||||||
|
|
||||||
|
SR_PRIV const struct beaglelogic_ops beaglelogic_native_ops = {
|
||||||
|
.open = beaglelogic_open_nonblock,
|
||||||
|
.close = beaglelogic_close,
|
||||||
|
.get_buffersize = beaglelogic_get_buffersize,
|
||||||
|
.set_buffersize = beaglelogic_set_buffersize,
|
||||||
|
.get_samplerate = beaglelogic_get_samplerate,
|
||||||
|
.set_samplerate = beaglelogic_set_samplerate,
|
||||||
|
.get_sampleunit = beaglelogic_get_sampleunit,
|
||||||
|
.set_sampleunit = beaglelogic_set_sampleunit,
|
||||||
|
.get_triggerflags = beaglelogic_get_triggerflags,
|
||||||
|
.set_triggerflags = beaglelogic_set_triggerflags,
|
||||||
|
.start = beaglelogic_start,
|
||||||
|
.stop = beaglelogic_stop,
|
||||||
|
.get_lasterror = beaglelogic_get_lasterror,
|
||||||
|
.get_bufunitsize = beaglelogic_get_bufunitsize,
|
||||||
|
.set_bufunitsize = beaglelogic_set_bufunitsize,
|
||||||
|
.mmap = beaglelogic_mmap,
|
||||||
|
.munmap = beaglelogic_munmap,
|
||||||
|
};
|
|
@ -0,0 +1,430 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the libsigrok project.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Kumar Abhishek <abhishek@theembeddedkitchen.net>
|
||||||
|
* Portions of the code are adapted from scpi_tcp.c and scpi.c, their
|
||||||
|
* copyright notices are listed below:
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 Martin Ling <martin-sigrok@earth.li>
|
||||||
|
* Copyright (C) 2013 poljar (Damir Jelić) <poljarinho@gmail.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
|
||||||
|
* 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>
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define _WIN32_WINNT 0x0501
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
#endif
|
||||||
|
#include <glib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#ifndef _WIN32
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#endif
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "protocol.h"
|
||||||
|
#include "beaglelogic.h"
|
||||||
|
|
||||||
|
static int beaglelogic_tcp_open(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
struct addrinfo hints;
|
||||||
|
struct addrinfo *results, *res;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
hints.ai_family = AF_UNSPEC;
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
hints.ai_protocol = IPPROTO_TCP;
|
||||||
|
|
||||||
|
err = getaddrinfo(devc->address, devc->port, &hints, &results);
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
sr_err("Address lookup failed: %s:%s: %s", devc->address,
|
||||||
|
devc->port, gai_strerror(err));
|
||||||
|
return SR_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (res = results; res; res = res->ai_next) {
|
||||||
|
if ((devc->socket = socket(res->ai_family, res->ai_socktype,
|
||||||
|
res->ai_protocol)) < 0)
|
||||||
|
continue;
|
||||||
|
if (connect(devc->socket, res->ai_addr, res->ai_addrlen) != 0) {
|
||||||
|
close(devc->socket);
|
||||||
|
devc->socket = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
freeaddrinfo(results);
|
||||||
|
|
||||||
|
if (devc->socket < 0) {
|
||||||
|
sr_err("Failed to connect to %s:%s: %s", devc->address,
|
||||||
|
devc->port, g_strerror(errno));
|
||||||
|
return SR_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int beaglelogic_tcp_send_cmd(struct dev_context *devc,
|
||||||
|
const char *format, ...)
|
||||||
|
{
|
||||||
|
int len, out;
|
||||||
|
va_list args, args_copy;
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
va_start(args, format);
|
||||||
|
va_copy(args_copy, args);
|
||||||
|
len = vsnprintf(NULL, 0, format, args_copy);
|
||||||
|
va_end(args_copy);
|
||||||
|
|
||||||
|
buf = g_malloc0(len + 2);
|
||||||
|
vsprintf(buf, format, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
if (buf[len - 1] != '\n')
|
||||||
|
buf[len] = '\n';
|
||||||
|
|
||||||
|
out = send(devc->socket, buf, strlen(buf), 0);
|
||||||
|
|
||||||
|
if (out < 0) {
|
||||||
|
sr_err("Send error: %s", g_strerror(errno));
|
||||||
|
g_free(buf);
|
||||||
|
return SR_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out < (int)strlen(buf)) {
|
||||||
|
sr_dbg("Only sent %d/%zu bytes of command: '%s'.", out,
|
||||||
|
strlen(buf), buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
sr_spew("Sent command: '%s'.", buf);
|
||||||
|
|
||||||
|
g_free(buf);
|
||||||
|
|
||||||
|
return SR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int beaglelogic_tcp_read_data(struct dev_context *devc, char *buf,
|
||||||
|
int maxlen)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
|
||||||
|
len = recv(devc->socket, buf, maxlen, 0);
|
||||||
|
|
||||||
|
if (len < 0) {
|
||||||
|
sr_err("Receive error: %s", g_strerror(errno));
|
||||||
|
return SR_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
SR_PRIV int beaglelogic_tcp_drain(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
char *buf = g_malloc(1024);
|
||||||
|
fd_set rset;
|
||||||
|
int ret, len = 0;
|
||||||
|
struct timeval tv;
|
||||||
|
|
||||||
|
FD_ZERO(&rset);
|
||||||
|
FD_SET(devc->socket, &rset);
|
||||||
|
|
||||||
|
/* 25ms timeout */
|
||||||
|
tv.tv_sec = 0;
|
||||||
|
tv.tv_usec = 25 * 1000;
|
||||||
|
|
||||||
|
do {
|
||||||
|
ret = select(devc->socket + 1, &rset, NULL, NULL, &tv);
|
||||||
|
if (ret > 0)
|
||||||
|
len += beaglelogic_tcp_read_data(devc, buf, 1024);
|
||||||
|
} while (ret > 0);
|
||||||
|
|
||||||
|
sr_spew("Drained %d bytes of data.", len);
|
||||||
|
|
||||||
|
g_free(buf);
|
||||||
|
|
||||||
|
return SR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int beaglelogic_tcp_get_string(struct dev_context *devc, const char *cmd,
|
||||||
|
char **tcp_resp)
|
||||||
|
{
|
||||||
|
GString *response = g_string_sized_new(1024);
|
||||||
|
int len;
|
||||||
|
gint64 timeout;
|
||||||
|
|
||||||
|
*tcp_resp = NULL;
|
||||||
|
if (cmd) {
|
||||||
|
if (beaglelogic_tcp_send_cmd(devc, cmd) != SR_OK)
|
||||||
|
return SR_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
timeout = g_get_monotonic_time() + devc->read_timeout;
|
||||||
|
len = beaglelogic_tcp_read_data(devc, response->str,
|
||||||
|
response->allocated_len);
|
||||||
|
|
||||||
|
if (len < 0) {
|
||||||
|
g_string_free(response, TRUE);
|
||||||
|
return SR_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len > 0)
|
||||||
|
g_string_set_size(response, len);
|
||||||
|
|
||||||
|
if (g_get_monotonic_time() > timeout) {
|
||||||
|
sr_err("Timed out waiting for response.");
|
||||||
|
g_string_free(response, TRUE);
|
||||||
|
return SR_ERR_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove trailing newline if present */
|
||||||
|
if (response->len >= 1 && response->str[response->len - 1] == '\n')
|
||||||
|
g_string_truncate(response, response->len - 1);
|
||||||
|
|
||||||
|
/* Remove trailing carriage return if present */
|
||||||
|
if (response->len >= 1 && response->str[response->len - 1] == '\r')
|
||||||
|
g_string_truncate(response, response->len - 1);
|
||||||
|
|
||||||
|
sr_spew("Got response: '%.70s', length %" G_GSIZE_FORMAT ".",
|
||||||
|
response->str, response->len);
|
||||||
|
|
||||||
|
*tcp_resp = g_string_free(response, FALSE);
|
||||||
|
|
||||||
|
return SR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int beaglelogic_tcp_get_int(struct dev_context *devc,
|
||||||
|
const char *cmd, int *response)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
char *resp = NULL;
|
||||||
|
|
||||||
|
ret = beaglelogic_tcp_get_string(devc, cmd, &resp);
|
||||||
|
if (!resp && ret != SR_OK)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (sr_atoi(resp, response) == SR_OK)
|
||||||
|
ret = SR_OK;
|
||||||
|
else
|
||||||
|
ret = SR_ERR_DATA;
|
||||||
|
|
||||||
|
g_free(resp);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
SR_PRIV int beaglelogic_tcp_detect(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
char *resp = NULL;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = beaglelogic_tcp_get_string(devc, "version", &resp);
|
||||||
|
if (ret == SR_OK && !g_ascii_strncasecmp(resp, "BeagleLogic", 11))
|
||||||
|
ret = SR_OK;
|
||||||
|
else
|
||||||
|
ret = SR_ERR;
|
||||||
|
|
||||||
|
g_free(resp);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int beaglelogic_open(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
return beaglelogic_tcp_open(devc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int beaglelogic_close(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
if (close(devc->socket) < 0)
|
||||||
|
return SR_ERR;
|
||||||
|
|
||||||
|
return SR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int beaglelogic_get_buffersize(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
return beaglelogic_tcp_get_int(devc, "memalloc",
|
||||||
|
(int *)&devc->buffersize);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int beaglelogic_set_buffersize(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
char *resp;
|
||||||
|
|
||||||
|
beaglelogic_tcp_send_cmd(devc, "memalloc %lu", devc->buffersize);
|
||||||
|
ret = beaglelogic_tcp_get_string(devc, NULL, &resp);
|
||||||
|
if (ret == SR_OK && !g_ascii_strncasecmp(resp, "ok", 2))
|
||||||
|
ret = SR_OK;
|
||||||
|
else
|
||||||
|
ret = SR_ERR;
|
||||||
|
|
||||||
|
g_free(resp);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int beaglelogic_get_samplerate(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
int arg, err;
|
||||||
|
|
||||||
|
err = beaglelogic_tcp_get_int(devc, "samplerate", &arg);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
devc->cur_samplerate = arg;
|
||||||
|
return SR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int beaglelogic_set_samplerate(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
char *resp;
|
||||||
|
|
||||||
|
beaglelogic_tcp_send_cmd(devc, "samplerate %lu",
|
||||||
|
(uint32_t)devc->cur_samplerate);
|
||||||
|
ret = beaglelogic_tcp_get_string(devc, NULL, &resp);
|
||||||
|
if (ret == SR_OK && !g_ascii_strncasecmp(resp, "ok", 2))
|
||||||
|
ret = SR_OK;
|
||||||
|
else
|
||||||
|
ret = SR_ERR;
|
||||||
|
|
||||||
|
g_free(resp);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int beaglelogic_get_sampleunit(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
return beaglelogic_tcp_get_int(devc, "sampleunit",
|
||||||
|
(int *)&devc->sampleunit);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int beaglelogic_set_sampleunit(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
char *resp;
|
||||||
|
|
||||||
|
beaglelogic_tcp_send_cmd(devc, "sampleunit %lu", devc->sampleunit);
|
||||||
|
ret = beaglelogic_tcp_get_string(devc, NULL, &resp);
|
||||||
|
if (ret == SR_OK && !g_ascii_strncasecmp(resp, "ok", 2))
|
||||||
|
ret = SR_OK;
|
||||||
|
else
|
||||||
|
ret = SR_ERR;
|
||||||
|
|
||||||
|
g_free(resp);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int beaglelogic_get_triggerflags(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
return beaglelogic_tcp_get_int(devc, "triggerflags",
|
||||||
|
(int *)&devc->triggerflags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int beaglelogic_set_triggerflags(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
char *resp;
|
||||||
|
|
||||||
|
beaglelogic_tcp_send_cmd(devc, "triggerflags %lu", devc->triggerflags);
|
||||||
|
ret = beaglelogic_tcp_get_string(devc, NULL, &resp);
|
||||||
|
if (ret == SR_OK && !g_ascii_strncasecmp(resp, "ok", 2))
|
||||||
|
ret = SR_OK;
|
||||||
|
else
|
||||||
|
ret = SR_ERR;
|
||||||
|
|
||||||
|
g_free(resp);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int beaglelogic_get_lasterror(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
devc->last_error = 0;
|
||||||
|
|
||||||
|
return SR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int beaglelogic_start(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
beaglelogic_tcp_drain(devc);
|
||||||
|
|
||||||
|
return beaglelogic_tcp_send_cmd(devc, "get");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int beaglelogic_stop(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
return beaglelogic_tcp_send_cmd(devc, "close");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int beaglelogic_get_bufunitsize(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
return beaglelogic_tcp_get_int(devc, "bufunitsize",
|
||||||
|
(int *)&devc->bufunitsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int beaglelogic_set_bufunitsize(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
char *resp;
|
||||||
|
|
||||||
|
beaglelogic_tcp_send_cmd(devc, "bufunitsize %ld", devc->bufunitsize);
|
||||||
|
ret = beaglelogic_tcp_get_string(devc, NULL, &resp);
|
||||||
|
if (ret == SR_OK && !g_ascii_strncasecmp(resp, "ok", 2))
|
||||||
|
ret = SR_OK;
|
||||||
|
else
|
||||||
|
ret = SR_ERR;
|
||||||
|
|
||||||
|
g_free(resp);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dummy(struct dev_context *devc)
|
||||||
|
{
|
||||||
|
(void)devc;
|
||||||
|
|
||||||
|
return SR_ERR_NA;
|
||||||
|
}
|
||||||
|
|
||||||
|
SR_PRIV const struct beaglelogic_ops beaglelogic_tcp_ops = {
|
||||||
|
.open = beaglelogic_open,
|
||||||
|
.close = beaglelogic_close,
|
||||||
|
.get_buffersize = beaglelogic_get_buffersize,
|
||||||
|
.set_buffersize = beaglelogic_set_buffersize,
|
||||||
|
.get_samplerate = beaglelogic_get_samplerate,
|
||||||
|
.set_samplerate = beaglelogic_set_samplerate,
|
||||||
|
.get_sampleunit = beaglelogic_get_sampleunit,
|
||||||
|
.set_sampleunit = beaglelogic_set_sampleunit,
|
||||||
|
.get_triggerflags = beaglelogic_get_triggerflags,
|
||||||
|
.set_triggerflags = beaglelogic_set_triggerflags,
|
||||||
|
.start = beaglelogic_start,
|
||||||
|
.stop = beaglelogic_stop,
|
||||||
|
.get_lasterror = beaglelogic_get_lasterror,
|
||||||
|
.get_bufunitsize = beaglelogic_get_bufunitsize,
|
||||||
|
.set_bufunitsize = beaglelogic_set_bufunitsize,
|
||||||
|
.mmap = dummy,
|
||||||
|
.munmap = dummy,
|
||||||
|
};
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of the libsigrok project.
|
* This file is part of the libsigrok project.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2014 Kumar Abhishek <abhishek@theembeddedkitchen.net>
|
* Copyright (C) 2014-2017 Kumar Abhishek <abhishek@theembeddedkitchen.net>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -21,7 +21,16 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define _WIN32_WINNT 0x0501
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
#else
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#endif
|
||||||
|
#include <errno.h>
|
||||||
#include "protocol.h"
|
#include "protocol.h"
|
||||||
|
#include "beaglelogic.h"
|
||||||
|
|
||||||
/* Define data packet size independent of packet (bufunitsize bytes) size
|
/* Define data packet size independent of packet (bufunitsize bytes) size
|
||||||
* from the BeagleLogic kernel module */
|
* from the BeagleLogic kernel module */
|
||||||
|
@ -32,7 +41,7 @@
|
||||||
* kernel buffers appropriately. It is up to the application which is
|
* kernel buffers appropriately. It is up to the application which is
|
||||||
* using libsigrok to decide how to deal with the data.
|
* using libsigrok to decide how to deal with the data.
|
||||||
*/
|
*/
|
||||||
SR_PRIV int beaglelogic_receive_data(int fd, int revents, void *cb_data)
|
SR_PRIV int beaglelogic_native_receive_data(int fd, int revents, void *cb_data)
|
||||||
{
|
{
|
||||||
const struct sr_dev_inst *sdi;
|
const struct sr_dev_inst *sdi;
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
|
@ -90,7 +99,7 @@ SR_PRIV int beaglelogic_receive_data(int fd, int revents, void *cb_data)
|
||||||
if ((devc->offset += packetsize) >= devc->buffersize) {
|
if ((devc->offset += packetsize) >= devc->buffersize) {
|
||||||
/* One shot capture, we abort and settle with less than
|
/* One shot capture, we abort and settle with less than
|
||||||
* the required number of samples */
|
* the required number of samples */
|
||||||
if (devc->triggerflags)
|
if (devc->triggerflags == BL_TRIGGERFLAGS_CONTINUOUS)
|
||||||
devc->offset = 0;
|
devc->offset = 0;
|
||||||
else
|
else
|
||||||
packetsize = 0;
|
packetsize = 0;
|
||||||
|
@ -107,3 +116,90 @@ SR_PRIV int beaglelogic_receive_data(int fd, int revents, void *cb_data)
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SR_PRIV int beaglelogic_tcp_receive_data(int fd, int revents, void *cb_data)
|
||||||
|
{
|
||||||
|
const struct sr_dev_inst *sdi;
|
||||||
|
struct dev_context *devc;
|
||||||
|
struct sr_datafeed_packet packet;
|
||||||
|
struct sr_datafeed_logic logic;
|
||||||
|
|
||||||
|
int len;
|
||||||
|
int pre_trigger_samples;
|
||||||
|
int trigger_offset;
|
||||||
|
uint32_t packetsize;
|
||||||
|
uint64_t bytes_remaining;
|
||||||
|
|
||||||
|
if (!(sdi = cb_data) || !(devc = sdi->priv))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
packetsize = TCP_BUFFER_SIZE;
|
||||||
|
logic.unitsize = SAMPLEUNIT_TO_BYTES(devc->sampleunit);
|
||||||
|
|
||||||
|
if (revents == G_IO_IN) {
|
||||||
|
sr_info("In callback G_IO_IN");
|
||||||
|
|
||||||
|
len = recv(fd, devc->tcp_buffer, TCP_BUFFER_SIZE, 0);
|
||||||
|
if (len < 0) {
|
||||||
|
sr_err("Receive error: %s", g_strerror(errno));
|
||||||
|
return SR_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
packetsize = len;
|
||||||
|
|
||||||
|
bytes_remaining = (devc->limit_samples * logic.unitsize) -
|
||||||
|
devc->bytes_read;
|
||||||
|
|
||||||
|
/* Configure data packet */
|
||||||
|
packet.type = SR_DF_LOGIC;
|
||||||
|
packet.payload = &logic;
|
||||||
|
logic.data = devc->tcp_buffer;
|
||||||
|
logic.length = MIN(packetsize, bytes_remaining);
|
||||||
|
|
||||||
|
if (devc->trigger_fired) {
|
||||||
|
/* Send the incoming transfer to the session bus. */
|
||||||
|
sr_session_send(sdi, &packet);
|
||||||
|
} else {
|
||||||
|
/* Check for trigger */
|
||||||
|
trigger_offset = soft_trigger_logic_check(devc->stl,
|
||||||
|
logic.data, packetsize, &pre_trigger_samples);
|
||||||
|
if (trigger_offset > -1) {
|
||||||
|
devc->bytes_read += pre_trigger_samples * logic.unitsize;
|
||||||
|
trigger_offset *= logic.unitsize;
|
||||||
|
logic.length = MIN(packetsize - trigger_offset,
|
||||||
|
bytes_remaining);
|
||||||
|
logic.data += trigger_offset;
|
||||||
|
|
||||||
|
sr_session_send(sdi, &packet);
|
||||||
|
|
||||||
|
devc->trigger_fired = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update byte count and offset (roll over if needed) */
|
||||||
|
devc->bytes_read += logic.length;
|
||||||
|
if ((devc->offset += packetsize) >= devc->buffersize) {
|
||||||
|
/* One shot capture, we abort and settle with less than
|
||||||
|
* the required number of samples */
|
||||||
|
if (devc->triggerflags == BL_TRIGGERFLAGS_CONTINUOUS)
|
||||||
|
devc->offset = 0;
|
||||||
|
else
|
||||||
|
packetsize = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* EOF Received or we have reached the limit */
|
||||||
|
if (devc->bytes_read >= devc->limit_samples * logic.unitsize ||
|
||||||
|
packetsize == 0) {
|
||||||
|
/* Send EOA Packet, stop polling */
|
||||||
|
std_session_send_df_end(sdi);
|
||||||
|
devc->beaglelogic->stop(devc);
|
||||||
|
|
||||||
|
/* Drain the receive buffer */
|
||||||
|
beaglelogic_tcp_drain(devc);
|
||||||
|
|
||||||
|
sr_session_source_remove_pollfd(sdi->session, &devc->pollfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of the libsigrok project.
|
* This file is part of the libsigrok project.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2014 Kumar Abhishek <abhishek@theembeddedkitchen.net>
|
* Copyright (C) 2014-2017 Kumar Abhishek <abhishek@theembeddedkitchen.net>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -32,12 +32,23 @@
|
||||||
|
|
||||||
#define SAMPLEUNIT_TO_BYTES(x) ((x) == 1 ? 1 : 2)
|
#define SAMPLEUNIT_TO_BYTES(x) ((x) == 1 ? 1 : 2)
|
||||||
|
|
||||||
|
#define TCP_BUFFER_SIZE (128 * 1024)
|
||||||
|
|
||||||
/** Private, per-device-instance driver context. */
|
/** Private, per-device-instance driver context. */
|
||||||
struct dev_context {
|
struct dev_context {
|
||||||
/* Model-specific information */
|
|
||||||
int max_channels;
|
int max_channels;
|
||||||
uint32_t fw_ver;
|
uint32_t fw_ver;
|
||||||
|
|
||||||
|
/* Operations */
|
||||||
|
const struct beaglelogic_ops *beaglelogic;
|
||||||
|
|
||||||
|
/* TCP Settings */
|
||||||
|
char *address;
|
||||||
|
char *port;
|
||||||
|
int socket;
|
||||||
|
unsigned int read_timeout;
|
||||||
|
unsigned char *tcp_buffer;
|
||||||
|
|
||||||
/* Acquisition settings: see beaglelogic.h */
|
/* Acquisition settings: see beaglelogic.h */
|
||||||
uint64_t cur_samplerate;
|
uint64_t cur_samplerate;
|
||||||
uint64_t limit_samples;
|
uint64_t limit_samples;
|
||||||
|
@ -49,7 +60,6 @@ struct dev_context {
|
||||||
uint32_t bufunitsize;
|
uint32_t bufunitsize;
|
||||||
uint32_t buffersize;
|
uint32_t buffersize;
|
||||||
|
|
||||||
/* Operational state */
|
|
||||||
int fd;
|
int fd;
|
||||||
GPollFD pollfd;
|
GPollFD pollfd;
|
||||||
int last_error;
|
int last_error;
|
||||||
|
@ -64,6 +74,7 @@ struct dev_context {
|
||||||
gboolean trigger_fired;
|
gboolean trigger_fired;
|
||||||
};
|
};
|
||||||
|
|
||||||
SR_PRIV int beaglelogic_receive_data(int fd, int revents, void *cb_data);
|
SR_PRIV int beaglelogic_native_receive_data(int fd, int revents, void *cb_data);
|
||||||
|
SR_PRIV int beaglelogic_tcp_receive_data(int fd, int revents, void *cb_data);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -26,8 +26,11 @@ static const uint32_t scanopts[] = {
|
||||||
SR_CONF_CONN,
|
SR_CONF_CONN,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint32_t devopts[] = {
|
static const uint32_t drvopts[] = {
|
||||||
SR_CONF_MULTIMETER,
|
SR_CONF_MULTIMETER,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t devopts[] = {
|
||||||
SR_CONF_CONTINUOUS,
|
SR_CONF_CONTINUOUS,
|
||||||
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
|
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
|
||||||
SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET,
|
SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET,
|
||||||
|
@ -95,12 +98,9 @@ static int dev_open(struct sr_dev_inst *sdi)
|
||||||
usb = sdi->conn;
|
usb = sdi->conn;
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
if ((ret = sr_usb_open(drvc->sr_ctx->libusb_ctx, usb)) == SR_OK)
|
if ((ret = sr_usb_open(drvc->sr_ctx->libusb_ctx, usb)) < 0)
|
||||||
sdi->status = SR_ST_ACTIVE;
|
|
||||||
else
|
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
|
|
||||||
/* Detach kernel drivers which grabbed this device (if any). */
|
|
||||||
if (libusb_kernel_driver_active(usb->devhdl, 0) == 1) {
|
if (libusb_kernel_driver_active(usb->devhdl, 0) == 1) {
|
||||||
ret = libusb_detach_kernel_driver(usb->devhdl, 0);
|
ret = libusb_detach_kernel_driver(usb->devhdl, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@ -109,20 +109,15 @@ static int dev_open(struct sr_dev_inst *sdi)
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
}
|
}
|
||||||
devc->detached_kernel_driver = 1;
|
devc->detached_kernel_driver = 1;
|
||||||
sr_dbg("Successfully detached kernel driver.");
|
|
||||||
} else {
|
|
||||||
sr_dbg("No need to detach a kernel driver.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Claim interface 0. */
|
|
||||||
if ((ret = libusb_claim_interface(usb->devhdl, 0)) < 0) {
|
if ((ret = libusb_claim_interface(usb->devhdl, 0)) < 0) {
|
||||||
sr_err("Failed to claim interface 0: %s.",
|
sr_err("Failed to claim interface 0: %s.",
|
||||||
libusb_error_name(ret));
|
libusb_error_name(ret));
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
}
|
}
|
||||||
sr_dbg("Successfully claimed interface 0.");
|
|
||||||
|
|
||||||
return ret;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_close(struct sr_dev_inst *sdi)
|
static int dev_close(struct sr_dev_inst *sdi)
|
||||||
|
@ -131,36 +126,30 @@ static int dev_close(struct sr_dev_inst *sdi)
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
usb = sdi->conn;
|
usb = sdi->conn;
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
|
if (!usb->devhdl)
|
||||||
|
return SR_OK;
|
||||||
|
|
||||||
if ((ret = libusb_release_interface(usb->devhdl, 0)))
|
if ((ret = libusb_release_interface(usb->devhdl, 0)))
|
||||||
sr_err("Failed to release interface 0: %s.\n", libusb_error_name(ret));
|
sr_err("Failed to release interface 0: %s.\n", libusb_error_name(ret));
|
||||||
else
|
|
||||||
sr_dbg("Successfully released interface 0.\n");
|
|
||||||
|
|
||||||
if (!ret && devc->detached_kernel_driver) {
|
if (!ret && devc->detached_kernel_driver) {
|
||||||
if ((ret = libusb_attach_kernel_driver(usb->devhdl, 0))) {
|
if ((ret = libusb_attach_kernel_driver(usb->devhdl, 0)))
|
||||||
sr_err("Failed to attach kernel driver: %s.\n",
|
sr_err("Failed to attach kernel driver: %s.\n",
|
||||||
libusb_error_name(ret));
|
libusb_error_name(ret));
|
||||||
} else {
|
else
|
||||||
devc->detached_kernel_driver = 0;
|
devc->detached_kernel_driver = 0;
|
||||||
sr_dbg("Successfully attached kernel driver.\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
libusb_close(usb->devhdl);
|
libusb_close(usb->devhdl);
|
||||||
|
|
||||||
sdi->status = SR_ST_INACTIVE;
|
return (ret == 0) ? SR_OK : SR_ERR;
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
|
static int config_get(uint32_t key, GVariant **data,
|
||||||
const struct sr_channel_group *cg)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
struct dev_context *devc = sdi->priv;
|
struct dev_context *devc = sdi->priv;
|
||||||
|
|
||||||
|
@ -169,50 +158,28 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s
|
||||||
return sr_sw_limits_config_get(&devc->sw_limits, key, data);
|
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,
|
static int config_set(uint32_t key, GVariant *data,
|
||||||
const struct sr_channel_group *cg)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
|
|
||||||
(void)cg;
|
(void)cg;
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
return sr_sw_limits_config_set(&devc->sw_limits, key, data);
|
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,
|
static int config_list(uint32_t key, GVariant **data,
|
||||||
const struct sr_channel_group *cg)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
(void)sdi;
|
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
|
||||||
(void)cg;
|
|
||||||
|
|
||||||
switch (key) {
|
|
||||||
case SR_CONF_SCAN_OPTIONS:
|
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
|
|
||||||
break;
|
|
||||||
case SR_CONF_DEVICE_OPTIONS:
|
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return SR_ERR_NA;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SR_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
sr_sw_limits_acquisition_start(&devc->sw_limits);
|
sr_sw_limits_acquisition_start(&devc->sw_limits);
|
||||||
|
@ -227,9 +194,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||||
|
|
||||||
static int dev_acquisition_stop(struct sr_dev_inst *sdi)
|
static int dev_acquisition_stop(struct sr_dev_inst *sdi)
|
||||||
{
|
{
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
std_session_send_df_end(sdi);
|
std_session_send_df_end(sdi);
|
||||||
|
|
||||||
sr_session_source_remove(sdi->session, -1);
|
sr_session_source_remove(sdi->session, -1);
|
||||||
|
@ -245,7 +209,7 @@ static struct sr_dev_driver brymen_bm86x_driver_info = {
|
||||||
.cleanup = std_cleanup,
|
.cleanup = std_cleanup,
|
||||||
.scan = scan,
|
.scan = scan,
|
||||||
.dev_list = std_dev_list,
|
.dev_list = std_dev_list,
|
||||||
.dev_clear = NULL,
|
.dev_clear = std_dev_clear,
|
||||||
.config_get = config_get,
|
.config_get = config_get,
|
||||||
.config_set = config_set,
|
.config_set = config_set,
|
||||||
.config_list = config_list,
|
.config_list = config_list,
|
||||||
|
|
|
@ -99,8 +99,10 @@ static void brymen_bm86x_parse(unsigned char *buf, float *floatval,
|
||||||
if (buf[8] & 0x01) {
|
if (buf[8] & 0x01) {
|
||||||
analog[0].meaning->mq = SR_MQ_VOLTAGE;
|
analog[0].meaning->mq = SR_MQ_VOLTAGE;
|
||||||
analog[0].meaning->unit = SR_UNIT_VOLT;
|
analog[0].meaning->unit = SR_UNIT_VOLT;
|
||||||
if (!strcmp(str, "diod"))
|
if (!strcmp(str, "diod")) {
|
||||||
analog[0].meaning->mqflags |= SR_MQFLAG_DIODE;
|
analog[0].meaning->mqflags |= SR_MQFLAG_DIODE;
|
||||||
|
analog[0].meaning->mqflags |= SR_MQFLAG_DC;
|
||||||
|
}
|
||||||
} else if (buf[14] & 0x80) {
|
} else if (buf[14] & 0x80) {
|
||||||
analog[0].meaning->mq = SR_MQ_CURRENT;
|
analog[0].meaning->mq = SR_MQ_CURRENT;
|
||||||
analog[0].meaning->unit = SR_UNIT_AMPERE;
|
analog[0].meaning->unit = SR_UNIT_AMPERE;
|
||||||
|
@ -214,6 +216,8 @@ static void brymen_bm86x_handle_packet(const struct sr_dev_inst *sdi,
|
||||||
struct sr_analog_encoding encoding[2];
|
struct sr_analog_encoding encoding[2];
|
||||||
struct sr_analog_meaning meaning[2];
|
struct sr_analog_meaning meaning[2];
|
||||||
struct sr_analog_spec spec[2];
|
struct sr_analog_spec spec[2];
|
||||||
|
struct sr_channel *channel;
|
||||||
|
int sent_ch1, sent_ch2;
|
||||||
float floatval[2];
|
float floatval[2];
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
@ -223,30 +227,35 @@ static void brymen_bm86x_handle_packet(const struct sr_dev_inst *sdi,
|
||||||
sr_analog_init(&analog[1], &encoding[1], &meaning[1], &spec[1], 0);
|
sr_analog_init(&analog[1], &encoding[1], &meaning[1], &spec[1], 0);
|
||||||
|
|
||||||
brymen_bm86x_parse(buf, floatval, analog);
|
brymen_bm86x_parse(buf, floatval, analog);
|
||||||
|
sent_ch1 = sent_ch2 = 0;
|
||||||
|
|
||||||
if (analog[0].meaning->mq != 0) {
|
channel = sdi->channels->data;
|
||||||
|
if (analog[0].meaning->mq != 0 && channel->enabled) {
|
||||||
/* Got a measurement. */
|
/* Got a measurement. */
|
||||||
|
sent_ch1 = 1;
|
||||||
analog[0].num_samples = 1;
|
analog[0].num_samples = 1;
|
||||||
analog[0].data = &floatval[0];
|
analog[0].data = &floatval[0];
|
||||||
analog[0].meaning->channels = g_slist_append(NULL, sdi->channels->data);
|
analog[0].meaning->channels = g_slist_append(NULL, channel);
|
||||||
packet.type = SR_DF_ANALOG;
|
packet.type = SR_DF_ANALOG;
|
||||||
packet.payload = &analog[0];
|
packet.payload = &analog[0];
|
||||||
sr_session_send(sdi, &packet);
|
sr_session_send(sdi, &packet);
|
||||||
g_slist_free(analog[0].meaning->channels);
|
g_slist_free(analog[0].meaning->channels);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (analog[1].meaning->mq != 0) {
|
channel = sdi->channels->next->data;
|
||||||
|
if (analog[1].meaning->mq != 0 && channel->enabled) {
|
||||||
/* Got a measurement. */
|
/* Got a measurement. */
|
||||||
|
sent_ch2 = 1;
|
||||||
analog[1].num_samples = 1;
|
analog[1].num_samples = 1;
|
||||||
analog[1].data = &floatval[1];
|
analog[1].data = &floatval[1];
|
||||||
analog[1].meaning->channels = g_slist_append(NULL, sdi->channels->next->data);
|
analog[1].meaning->channels = g_slist_append(NULL, channel);
|
||||||
packet.type = SR_DF_ANALOG;
|
packet.type = SR_DF_ANALOG;
|
||||||
packet.payload = &analog[1];
|
packet.payload = &analog[1];
|
||||||
sr_session_send(sdi, &packet);
|
sr_session_send(sdi, &packet);
|
||||||
g_slist_free(analog[1].meaning->channels);
|
g_slist_free(analog[1].meaning->channels);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (analog[0].meaning->mq != 0 || analog[1].meaning->mq != 0)
|
if (sent_ch1 || sent_ch2)
|
||||||
sr_sw_limits_update_samples_read(&devc->sw_limits, 1);
|
sr_sw_limits_update_samples_read(&devc->sw_limits, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -344,7 +353,7 @@ SR_PRIV int brymen_bm86x_receive_data(int fd, int revents, void *cb_data)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if (sr_sw_limits_check(&devc->sw_limits))
|
if (sr_sw_limits_check(&devc->sw_limits))
|
||||||
sdi->driver->dev_acquisition_stop(sdi);
|
sr_dev_acquisition_stop(sdi);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,15 +27,9 @@
|
||||||
|
|
||||||
#define LOG_PREFIX "brymen-bm86x"
|
#define LOG_PREFIX "brymen-bm86x"
|
||||||
|
|
||||||
/** Private, per-device-instance driver context. */
|
|
||||||
struct dev_context {
|
struct dev_context {
|
||||||
/* Acquisition settings */
|
|
||||||
struct sr_sw_limits sw_limits;
|
struct sr_sw_limits sw_limits;
|
||||||
|
int detached_kernel_driver; /**< Whether kernel driver was detached or not */
|
||||||
/* Operational state */
|
|
||||||
int detached_kernel_driver;/**< Whether kernel driver was detached or not */
|
|
||||||
|
|
||||||
/* Temporary state across callbacks */
|
|
||||||
int interrupt_pending;
|
int interrupt_pending;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -25,8 +25,11 @@ static const uint32_t scanopts[] = {
|
||||||
SR_CONF_SERIALCOMM,
|
SR_CONF_SERIALCOMM,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint32_t devopts[] = {
|
static const uint32_t drvopts[] = {
|
||||||
SR_CONF_MULTIMETER,
|
SR_CONF_MULTIMETER,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t devopts[] = {
|
||||||
SR_CONF_CONTINUOUS,
|
SR_CONF_CONTINUOUS,
|
||||||
SR_CONF_LIMIT_SAMPLES | SR_CONF_SET,
|
SR_CONF_LIMIT_SAMPLES | SR_CONF_SET,
|
||||||
SR_CONF_LIMIT_MSEC | SR_CONF_SET,
|
SR_CONF_LIMIT_MSEC | SR_CONF_SET,
|
||||||
|
@ -58,7 +61,7 @@ static GSList *brymen_scan(struct sr_dev_driver *di, const char *conn,
|
||||||
goto scan_cleanup;
|
goto scan_cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = 128;
|
len = sizeof(buf);
|
||||||
ret = brymen_stream_detect(serial, buf, &len, brymen_packet_length,
|
ret = brymen_stream_detect(serial, buf, &len, brymen_packet_length,
|
||||||
brymen_packet_is_valid, 1000, 9600);
|
brymen_packet_is_valid, 1000, 9600);
|
||||||
if (ret != SR_OK)
|
if (ret != SR_OK)
|
||||||
|
@ -107,52 +110,30 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
if (!conn)
|
if (!conn)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (serialcomm) {
|
if (serialcomm)
|
||||||
/* Use the provided comm specs. */
|
|
||||||
devices = brymen_scan(di, conn, serialcomm);
|
devices = brymen_scan(di, conn, serialcomm);
|
||||||
} else {
|
else
|
||||||
/* But 9600/8n1 should work all of the time. */
|
|
||||||
devices = brymen_scan(di, conn, "9600/8n1/dtr=1/rts=1");
|
devices = brymen_scan(di, conn, "9600/8n1/dtr=1/rts=1");
|
||||||
}
|
|
||||||
|
|
||||||
return devices;
|
return devices;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
|
static int config_set(uint32_t key, GVariant *data,
|
||||||
const struct sr_channel_group *cg)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
|
|
||||||
(void)cg;
|
(void)cg;
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
return sr_sw_limits_config_set(&devc->sw_limits, key, data);
|
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,
|
static int config_list(uint32_t key, GVariant **data,
|
||||||
const struct sr_channel_group *cg)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
(void)sdi;
|
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
|
||||||
(void)cg;
|
|
||||||
|
|
||||||
switch (key) {
|
|
||||||
case SR_CONF_SCAN_OPTIONS:
|
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
|
|
||||||
break;
|
|
||||||
case SR_CONF_DEVICE_OPTIONS:
|
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return SR_ERR_NA;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SR_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||||
|
@ -160,15 +141,11 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
struct sr_serial_dev_inst *serial;
|
struct sr_serial_dev_inst *serial;
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
sr_sw_limits_acquisition_start(&devc->sw_limits);
|
sr_sw_limits_acquisition_start(&devc->sw_limits);
|
||||||
std_session_send_df_header(sdi);
|
std_session_send_df_header(sdi);
|
||||||
|
|
||||||
/* Poll every 50ms, or whenever some data comes in. */
|
|
||||||
serial = sdi->conn;
|
serial = sdi->conn;
|
||||||
serial_source_add(sdi->session, serial, G_IO_IN, 50,
|
serial_source_add(sdi->session, serial, G_IO_IN, 50,
|
||||||
brymen_dmm_receive_data, (void *)sdi);
|
brymen_dmm_receive_data, (void *)sdi);
|
||||||
|
@ -184,7 +161,7 @@ static struct sr_dev_driver brymen_bm857_driver_info = {
|
||||||
.cleanup = std_cleanup,
|
.cleanup = std_cleanup,
|
||||||
.scan = scan,
|
.scan = scan,
|
||||||
.dev_list = std_dev_list,
|
.dev_list = std_dev_list,
|
||||||
.dev_clear = NULL,
|
.dev_clear = std_dev_clear,
|
||||||
.config_get = NULL,
|
.config_get = NULL,
|
||||||
.config_set = config_set,
|
.config_set = config_set,
|
||||||
.config_list = config_list,
|
.config_list = config_list,
|
||||||
|
|
|
@ -276,7 +276,7 @@ SR_PRIV int brymen_parse(const uint8_t *buf, float *floatval,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags.is_diode)
|
if (flags.is_diode)
|
||||||
analog->meaning->mqflags |= SR_MQFLAG_DIODE;
|
analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
|
||||||
/* We can have both AC+DC in a single measurement. */
|
/* We can have both AC+DC in a single measurement. */
|
||||||
if (flags.is_ac)
|
if (flags.is_ac)
|
||||||
analog->meaning->mqflags |= SR_MQFLAG_AC;
|
analog->meaning->mqflags |= SR_MQFLAG_AC;
|
||||||
|
|
|
@ -143,7 +143,7 @@ SR_PRIV int brymen_dmm_receive_data(int fd, int revents, void *cb_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sr_sw_limits_check(&devc->sw_limits))
|
if (sr_sw_limits_check(&devc->sw_limits))
|
||||||
sdi->driver->dev_acquisition_stop(sdi);
|
sr_dev_acquisition_stop(sdi);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,6 @@ enum packet_len_status {
|
||||||
PACKET_INVALID_HEADER,
|
PACKET_INVALID_HEADER,
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Private, per-device-instance driver context. */
|
|
||||||
struct dev_context {
|
struct dev_context {
|
||||||
struct sr_sw_limits sw_limits;
|
struct sr_sw_limits sw_limits;
|
||||||
|
|
||||||
|
|
|
@ -125,11 +125,10 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
return std_scan_complete(di, devices);
|
return std_scan_complete(di, devices);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
|
static int config_get(uint32_t key, GVariant **data,
|
||||||
const struct sr_channel_group *cg)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
GVariant *range[2];
|
|
||||||
uint64_t low, high;
|
uint64_t low, high;
|
||||||
int tmp, ret;
|
int tmp, ret;
|
||||||
|
|
||||||
|
@ -139,7 +138,9 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s
|
||||||
return SR_ERR_ARG;
|
return SR_ERR_ARG;
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
ret = SR_OK;
|
ret = SR_OK;
|
||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case SR_CONF_LIMIT_SAMPLES:
|
case SR_CONF_LIMIT_SAMPLES:
|
||||||
*data = g_variant_new_uint64(devc->limit_samples);
|
*data = g_variant_new_uint64(devc->limit_samples);
|
||||||
|
@ -175,11 +176,8 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s
|
||||||
*data = g_variant_new_boolean(tmp == SR_MQFLAG_MIN);
|
*data = g_variant_new_boolean(tmp == SR_MQFLAG_MIN);
|
||||||
break;
|
break;
|
||||||
case SR_CONF_SPL_MEASUREMENT_RANGE:
|
case SR_CONF_SPL_MEASUREMENT_RANGE:
|
||||||
if ((ret = cem_dt_885x_meas_range_get(sdi, &low, &high)) == SR_OK) {
|
if ((ret = cem_dt_885x_meas_range_get(sdi, &low, &high)) == SR_OK)
|
||||||
range[0] = g_variant_new_uint64(low);
|
*data = std_gvar_tuple_u64(low, high);
|
||||||
range[1] = g_variant_new_uint64(high);
|
|
||||||
*data = g_variant_new_tuple(range, 2);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case SR_CONF_POWER_OFF:
|
case SR_CONF_POWER_OFF:
|
||||||
*data = g_variant_new_boolean(FALSE);
|
*data = g_variant_new_boolean(FALSE);
|
||||||
|
@ -197,148 +195,83 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
|
static int config_set(uint32_t key, GVariant *data,
|
||||||
const struct sr_channel_group *cg)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
uint64_t tmp_u64, low, high;
|
int tmp, idx;
|
||||||
unsigned int i;
|
|
||||||
int tmp, ret;
|
|
||||||
const char *tmp_str;
|
|
||||||
|
|
||||||
(void)cg;
|
(void)cg;
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
ret = SR_OK;
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case SR_CONF_LIMIT_SAMPLES:
|
case SR_CONF_LIMIT_SAMPLES:
|
||||||
tmp_u64 = g_variant_get_uint64(data);
|
devc->limit_samples = g_variant_get_uint64(data);
|
||||||
devc->limit_samples = tmp_u64;
|
|
||||||
ret = SR_OK;
|
|
||||||
break;
|
break;
|
||||||
case SR_CONF_DATALOG:
|
case SR_CONF_DATALOG:
|
||||||
ret = cem_dt_885x_recording_set(sdi, g_variant_get_boolean(data));
|
return cem_dt_885x_recording_set(sdi, g_variant_get_boolean(data));
|
||||||
break;
|
|
||||||
case SR_CONF_SPL_WEIGHT_FREQ:
|
case SR_CONF_SPL_WEIGHT_FREQ:
|
||||||
tmp_str = g_variant_get_string(data, NULL);
|
if ((idx = std_str_idx(data, ARRAY_AND_SIZE(weight_freq))) < 0)
|
||||||
if (!strcmp(tmp_str, "A"))
|
|
||||||
ret = cem_dt_885x_weight_freq_set(sdi,
|
|
||||||
SR_MQFLAG_SPL_FREQ_WEIGHT_A);
|
|
||||||
else if (!strcmp(tmp_str, "C"))
|
|
||||||
ret = cem_dt_885x_weight_freq_set(sdi,
|
|
||||||
SR_MQFLAG_SPL_FREQ_WEIGHT_C);
|
|
||||||
else
|
|
||||||
return SR_ERR_ARG;
|
return SR_ERR_ARG;
|
||||||
break;
|
return cem_dt_885x_weight_freq_set(sdi, (weight_freq[idx][0] == 'A') ?
|
||||||
|
SR_MQFLAG_SPL_FREQ_WEIGHT_A : SR_MQFLAG_SPL_FREQ_WEIGHT_C);
|
||||||
case SR_CONF_SPL_WEIGHT_TIME:
|
case SR_CONF_SPL_WEIGHT_TIME:
|
||||||
tmp_str = g_variant_get_string(data, NULL);
|
if ((idx = std_str_idx(data, ARRAY_AND_SIZE(weight_time))) < 0)
|
||||||
if (!strcmp(tmp_str, "F"))
|
|
||||||
ret = cem_dt_885x_weight_time_set(sdi,
|
|
||||||
SR_MQFLAG_SPL_TIME_WEIGHT_F);
|
|
||||||
else if (!strcmp(tmp_str, "S"))
|
|
||||||
ret = cem_dt_885x_weight_time_set(sdi,
|
|
||||||
SR_MQFLAG_SPL_TIME_WEIGHT_S);
|
|
||||||
else
|
|
||||||
return SR_ERR_ARG;
|
return SR_ERR_ARG;
|
||||||
break;
|
return cem_dt_885x_weight_time_set(sdi, (weight_time[idx][0] == 'F') ?
|
||||||
|
SR_MQFLAG_SPL_TIME_WEIGHT_F : SR_MQFLAG_SPL_TIME_WEIGHT_S);
|
||||||
case SR_CONF_HOLD_MAX:
|
case SR_CONF_HOLD_MAX:
|
||||||
tmp = g_variant_get_boolean(data) ? SR_MQFLAG_MAX : 0;
|
tmp = g_variant_get_boolean(data) ? SR_MQFLAG_MAX : 0;
|
||||||
ret = cem_dt_885x_holdmode_set(sdi, tmp);
|
return cem_dt_885x_holdmode_set(sdi, tmp);
|
||||||
break;
|
|
||||||
case SR_CONF_HOLD_MIN:
|
case SR_CONF_HOLD_MIN:
|
||||||
tmp = g_variant_get_boolean(data) ? SR_MQFLAG_MIN : 0;
|
tmp = g_variant_get_boolean(data) ? SR_MQFLAG_MIN : 0;
|
||||||
ret = cem_dt_885x_holdmode_set(sdi, tmp);
|
return cem_dt_885x_holdmode_set(sdi, tmp);
|
||||||
break;
|
|
||||||
case SR_CONF_SPL_MEASUREMENT_RANGE:
|
case SR_CONF_SPL_MEASUREMENT_RANGE:
|
||||||
g_variant_get(data, "(tt)", &low, &high);
|
if ((idx = std_u64_tuple_idx(data, ARRAY_AND_SIZE(meas_ranges))) < 0)
|
||||||
ret = SR_ERR_ARG;
|
return SR_ERR_ARG;
|
||||||
for (i = 0; i < ARRAY_SIZE(meas_ranges); i++) {
|
return cem_dt_885x_meas_range_set(sdi, meas_ranges[idx][0], meas_ranges[idx][1]);
|
||||||
if (meas_ranges[i][0] == low && meas_ranges[i][1] == high) {
|
|
||||||
ret = cem_dt_885x_meas_range_set(sdi, low, high);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SR_CONF_POWER_OFF:
|
case SR_CONF_POWER_OFF:
|
||||||
if (g_variant_get_boolean(data))
|
if (g_variant_get_boolean(data))
|
||||||
ret = cem_dt_885x_power_off(sdi);
|
return cem_dt_885x_power_off(sdi);
|
||||||
break;
|
break;
|
||||||
case SR_CONF_DATA_SOURCE:
|
case SR_CONF_DATA_SOURCE:
|
||||||
tmp_str = g_variant_get_string(data, NULL);
|
if ((idx = std_str_idx(data, ARRAY_AND_SIZE(data_sources))) < 0)
|
||||||
if (!strcmp(tmp_str, "Live"))
|
return SR_ERR_ARG;
|
||||||
devc->cur_data_source = DATA_SOURCE_LIVE;
|
devc->cur_data_source = idx;
|
||||||
else if (!strcmp(tmp_str, "Memory"))
|
devc->enable_data_source_memory = (idx == DATA_SOURCE_MEMORY);
|
||||||
devc->cur_data_source = DATA_SOURCE_MEMORY;
|
|
||||||
else
|
|
||||||
return SR_ERR;
|
|
||||||
devc->enable_data_source_memory = devc->cur_data_source == DATA_SOURCE_MEMORY;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret = SR_ERR_NA;
|
return SR_ERR_NA;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
|
static int config_list(uint32_t key, GVariant **data,
|
||||||
const struct sr_channel_group *cg)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
GVariant *tuple, *range[2];
|
|
||||||
GVariantBuilder gvb;
|
|
||||||
unsigned int i;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
(void)cg;
|
|
||||||
|
|
||||||
ret = SR_OK;
|
|
||||||
if (!sdi) {
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case SR_CONF_SCAN_OPTIONS:
|
case SR_CONF_SCAN_OPTIONS:
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
|
|
||||||
break;
|
|
||||||
case SR_CONF_DEVICE_OPTIONS:
|
case SR_CONF_DEVICE_OPTIONS:
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
|
||||||
drvopts, ARRAY_SIZE(drvopts), sizeof(uint32_t));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return SR_ERR_NA;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch (key) {
|
|
||||||
case SR_CONF_DEVICE_OPTIONS:
|
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
|
|
||||||
break;
|
|
||||||
case SR_CONF_SPL_WEIGHT_FREQ:
|
case SR_CONF_SPL_WEIGHT_FREQ:
|
||||||
*data = g_variant_new_strv(weight_freq, ARRAY_SIZE(weight_freq));
|
*data = g_variant_new_strv(ARRAY_AND_SIZE(weight_freq));
|
||||||
break;
|
break;
|
||||||
case SR_CONF_SPL_WEIGHT_TIME:
|
case SR_CONF_SPL_WEIGHT_TIME:
|
||||||
*data = g_variant_new_strv(weight_time, ARRAY_SIZE(weight_time));
|
*data = g_variant_new_strv(ARRAY_AND_SIZE(weight_time));
|
||||||
break;
|
break;
|
||||||
case SR_CONF_SPL_MEASUREMENT_RANGE:
|
case SR_CONF_SPL_MEASUREMENT_RANGE:
|
||||||
g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
|
*data = std_gvar_tuple_array(ARRAY_AND_SIZE(meas_ranges));
|
||||||
for (i = 0; i < ARRAY_SIZE(meas_ranges); i++) {
|
|
||||||
range[0] = g_variant_new_uint64(meas_ranges[i][0]);
|
|
||||||
range[1] = g_variant_new_uint64(meas_ranges[i][1]);
|
|
||||||
tuple = g_variant_new_tuple(range, 2);
|
|
||||||
g_variant_builder_add_value(&gvb, tuple);
|
|
||||||
}
|
|
||||||
*data = g_variant_builder_end(&gvb);
|
|
||||||
break;
|
break;
|
||||||
case SR_CONF_DATA_SOURCE:
|
case SR_CONF_DATA_SOURCE:
|
||||||
*data = g_variant_new_strv(data_sources, ARRAY_SIZE(data_sources));
|
*data = g_variant_new_strv(ARRAY_AND_SIZE(data_sources));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return SR_ERR_NA;
|
return SR_ERR_NA;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||||
|
@ -346,9 +279,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
struct sr_serial_dev_inst *serial;
|
struct sr_serial_dev_inst *serial;
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
devc->state = ST_INIT;
|
devc->state = ST_INIT;
|
||||||
devc->num_samples = 0;
|
devc->num_samples = 0;
|
||||||
|
@ -356,7 +286,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||||
|
|
||||||
std_session_send_df_header(sdi);
|
std_session_send_df_header(sdi);
|
||||||
|
|
||||||
/* Poll every 100ms, or whenever some data comes in. */
|
|
||||||
serial = sdi->conn;
|
serial = sdi->conn;
|
||||||
serial_source_add(sdi->session, serial, G_IO_IN, 150,
|
serial_source_add(sdi->session, serial, G_IO_IN, 150,
|
||||||
cem_dt_885x_receive_data, (void *)sdi);
|
cem_dt_885x_receive_data, (void *)sdi);
|
||||||
|
@ -372,7 +301,7 @@ static struct sr_dev_driver cem_dt_885x_driver_info = {
|
||||||
.cleanup = std_cleanup,
|
.cleanup = std_cleanup,
|
||||||
.scan = scan,
|
.scan = scan,
|
||||||
.dev_list = std_dev_list,
|
.dev_list = std_dev_list,
|
||||||
.dev_clear = NULL,
|
.dev_clear = std_dev_clear,
|
||||||
.config_get = config_get,
|
.config_get = config_get,
|
||||||
.config_set = config_set,
|
.config_set = config_set,
|
||||||
.config_list = config_list,
|
.config_list = config_list,
|
||||||
|
|
|
@ -147,7 +147,7 @@ static void process_mset(const struct sr_dev_inst *sdi)
|
||||||
|
|
||||||
devc->num_samples++;
|
devc->num_samples++;
|
||||||
if (devc->limit_samples && devc->num_samples >= devc->limit_samples)
|
if (devc->limit_samples && devc->num_samples >= devc->limit_samples)
|
||||||
sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi);
|
sr_dev_acquisition_stop((struct sr_dev_inst *)sdi);
|
||||||
break;
|
break;
|
||||||
case TOKEN_RECORDING_ON:
|
case TOKEN_RECORDING_ON:
|
||||||
devc->recording = TRUE;
|
devc->recording = TRUE;
|
||||||
|
@ -208,7 +208,7 @@ static void send_data(const struct sr_dev_inst *sdi, unsigned char *data,
|
||||||
|
|
||||||
devc->num_samples += analog.num_samples;
|
devc->num_samples += analog.num_samples;
|
||||||
if (devc->limit_samples && devc->num_samples >= devc->limit_samples)
|
if (devc->limit_samples && devc->num_samples >= devc->limit_samples)
|
||||||
sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi);
|
sr_dev_acquisition_stop((struct sr_dev_inst *)sdi);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -321,7 +321,7 @@ static void process_byte(const struct sr_dev_inst *sdi, const unsigned char c,
|
||||||
* records. Otherwise the frontend would have no
|
* records. Otherwise the frontend would have no
|
||||||
* way to tell where stored data ends and live
|
* way to tell where stored data ends and live
|
||||||
* measurements begin. */
|
* measurements begin. */
|
||||||
sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi);
|
sr_dev_acquisition_stop((struct sr_dev_inst *)sdi);
|
||||||
} else if (c == RECORD_DATA) {
|
} else if (c == RECORD_DATA) {
|
||||||
devc->buf_len = 0;
|
devc->buf_len = 0;
|
||||||
devc->state = ST_GET_LOG_RECORD_DATA;
|
devc->state = ST_GET_LOG_RECORD_DATA;
|
||||||
|
@ -400,7 +400,7 @@ SR_PRIV int cem_dt_885x_receive_data(int fd, int revents, void *cb_data)
|
||||||
} else {
|
} else {
|
||||||
/* Tell device to start transferring from memory. */
|
/* Tell device to start transferring from memory. */
|
||||||
cmd = CMD_TRANSFER_MEMORY;
|
cmd = CMD_TRANSFER_MEMORY;
|
||||||
serial_write_nonblocking(serial, &cmd, 1);
|
serial_write_blocking(serial, &cmd, 1, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -456,7 +456,7 @@ static int cem_dt_885x_toggle(const struct sr_dev_inst *sdi, uint8_t cmd,
|
||||||
* only thing to do is wait for the token that will confirm
|
* only thing to do is wait for the token that will confirm
|
||||||
* whether the command worked or not, and resend if needed. */
|
* whether the command worked or not, and resend if needed. */
|
||||||
while (TRUE) {
|
while (TRUE) {
|
||||||
if (serial_write_nonblocking(serial, (const void *)&cmd, 1) != 1)
|
if (serial_write_blocking(serial, (const void *)&cmd, 1, 0) < 0)
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
if (wait_for_token(sdi, tokens, timeout) == SR_ERR)
|
if (wait_for_token(sdi, tokens, timeout) == SR_ERR)
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
|
@ -817,7 +817,7 @@ SR_PRIV int cem_dt_885x_power_off(const struct sr_dev_inst *sdi)
|
||||||
cmd = CMD_TOGGLE_POWER_OFF;
|
cmd = CMD_TOGGLE_POWER_OFF;
|
||||||
while (TRUE) {
|
while (TRUE) {
|
||||||
serial_flush(serial);
|
serial_flush(serial);
|
||||||
if (serial_write_nonblocking(serial, (const void *)&cmd, 1) != 1)
|
if (serial_write_blocking(serial, (const void *)&cmd, 1, 0) < 0)
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
/* It never takes more than 23ms for the next token to arrive. */
|
/* It never takes more than 23ms for the next token to arrive. */
|
||||||
g_usleep(25 * 1000);
|
g_usleep(25 * 1000);
|
||||||
|
|
|
@ -87,23 +87,18 @@ enum {
|
||||||
DATA_SOURCE_MEMORY,
|
DATA_SOURCE_MEMORY,
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Private, per-device-instance driver context. */
|
|
||||||
struct dev_context {
|
struct dev_context {
|
||||||
/* Device state */
|
|
||||||
enum sr_mqflag cur_mqflags;
|
enum sr_mqflag cur_mqflags;
|
||||||
int recording;
|
int recording;
|
||||||
int cur_meas_range;
|
int cur_meas_range;
|
||||||
int cur_data_source;
|
int cur_data_source;
|
||||||
|
|
||||||
/* Acquisition settings */
|
|
||||||
uint64_t limit_samples;
|
uint64_t limit_samples;
|
||||||
|
|
||||||
/* Operational state */
|
|
||||||
int state;
|
int state;
|
||||||
uint64_t num_samples;
|
uint64_t num_samples;
|
||||||
gboolean enable_data_source_memory;
|
gboolean enable_data_source_memory;
|
||||||
|
|
||||||
/* Temporary state across callbacks */
|
|
||||||
unsigned char cmd;
|
unsigned char cmd;
|
||||||
unsigned char token;
|
unsigned char token;
|
||||||
int buf_len;
|
int buf_len;
|
||||||
|
|
|
@ -109,55 +109,30 @@ static GSList *scan(GSList *options, int idx)
|
||||||
if (!conn)
|
if (!conn)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (serialcomm) {
|
if (serialcomm)
|
||||||
/* Use the provided comm specs. */
|
|
||||||
devices = center_scan(conn, serialcomm, idx);
|
devices = center_scan(conn, serialcomm, idx);
|
||||||
} else {
|
else
|
||||||
/* Try the default. */
|
|
||||||
devices = center_scan(conn, center_devs[idx].conn, idx);
|
devices = center_scan(conn, center_devs[idx].conn, idx);
|
||||||
}
|
|
||||||
|
|
||||||
return std_scan_complete(center_devs[idx].di, devices);
|
return std_scan_complete(center_devs[idx].di, devices);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
|
static int config_set(uint32_t key, GVariant *data,
|
||||||
const struct sr_channel_group *cg)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
|
|
||||||
(void)cg;
|
(void)cg;
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
return sr_sw_limits_config_set(&devc->sw_limits, key, data);
|
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,
|
static int config_list(uint32_t key, GVariant **data,
|
||||||
const struct sr_channel_group *cg)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
(void)cg;
|
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
|
||||||
|
|
||||||
switch (key) {
|
|
||||||
case SR_CONF_SCAN_OPTIONS:
|
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
|
|
||||||
break;
|
|
||||||
case SR_CONF_DEVICE_OPTIONS:
|
|
||||||
if (!sdi)
|
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
drvopts, ARRAY_SIZE(drvopts), sizeof(uint32_t));
|
|
||||||
else
|
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return SR_ERR_NA;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SR_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_acquisition_start(const struct sr_dev_inst *sdi, int idx)
|
static int dev_acquisition_start(const struct sr_dev_inst *sdi, int idx)
|
||||||
|
@ -165,16 +140,12 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi, int idx)
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
struct sr_serial_dev_inst *serial;
|
struct sr_serial_dev_inst *serial;
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
sr_sw_limits_acquisition_start(&devc->sw_limits);
|
sr_sw_limits_acquisition_start(&devc->sw_limits);
|
||||||
|
|
||||||
std_session_send_df_header(sdi);
|
std_session_send_df_header(sdi);
|
||||||
|
|
||||||
/* Poll every 500ms, or whenever some data comes in. */
|
|
||||||
serial = sdi->conn;
|
serial = sdi->conn;
|
||||||
serial_source_add(sdi->session, serial, G_IO_IN, 500,
|
serial_source_add(sdi->session, serial, G_IO_IN, 500,
|
||||||
center_devs[idx].receive_data, (void *)sdi);
|
center_devs[idx].receive_data, (void *)sdi);
|
||||||
|
@ -202,6 +173,7 @@ static struct sr_dev_driver ID##_driver_info = { \
|
||||||
.cleanup = std_cleanup, \
|
.cleanup = std_cleanup, \
|
||||||
.scan = scan_##ID_UPPER, \
|
.scan = scan_##ID_UPPER, \
|
||||||
.dev_list = std_dev_list, \
|
.dev_list = std_dev_list, \
|
||||||
|
.dev_clear = std_dev_clear, \
|
||||||
.config_get = NULL, \
|
.config_get = NULL, \
|
||||||
.config_set = config_set, \
|
.config_set = config_set, \
|
||||||
.config_list = config_list, \
|
.config_list = config_list, \
|
||||||
|
|
|
@ -177,7 +177,7 @@ static gboolean handle_new_data(struct sr_dev_inst *sdi, int idx)
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
struct sr_serial_dev_inst *serial;
|
struct sr_serial_dev_inst *serial;
|
||||||
int len, i, offset = 0, ret = FALSE;
|
int len, offset, ret = FALSE;
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
serial = sdi->conn;
|
serial = sdi->conn;
|
||||||
|
@ -193,6 +193,7 @@ static gboolean handle_new_data(struct sr_dev_inst *sdi, int idx)
|
||||||
devc->buflen += len;
|
devc->buflen += len;
|
||||||
|
|
||||||
/* Now look for packets in that data. */
|
/* Now look for packets in that data. */
|
||||||
|
offset = 0;
|
||||||
while ((devc->buflen - offset) >= center_devs[idx].packet_size) {
|
while ((devc->buflen - offset) >= center_devs[idx].packet_size) {
|
||||||
if (center_devs[idx].packet_valid(devc->buf + offset)) {
|
if (center_devs[idx].packet_valid(devc->buf + offset)) {
|
||||||
handle_packet(devc->buf + offset, sdi, idx);
|
handle_packet(devc->buf + offset, sdi, idx);
|
||||||
|
@ -204,8 +205,8 @@ static gboolean handle_new_data(struct sr_dev_inst *sdi, int idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we have any data left, move it to the beginning of our buffer. */
|
/* If we have any data left, move it to the beginning of our buffer. */
|
||||||
for (i = 0; i < devc->buflen - offset; i++)
|
if (offset < devc->buflen)
|
||||||
devc->buf[i] = devc->buf[offset + i];
|
memmove(devc->buf, devc->buf + offset, devc->buflen - offset);
|
||||||
devc->buflen -= offset;
|
devc->buflen -= offset;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -243,7 +244,7 @@ static int receive_data(int fd, int revents, int idx, void *cb_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sr_sw_limits_check(&devc->sw_limits))
|
if (sr_sw_limits_check(&devc->sw_limits))
|
||||||
sdi->driver->dev_acquisition_stop(sdi);
|
sr_dev_acquisition_stop(sdi);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,6 @@ extern SR_PRIV const struct center_dev_info center_devs[];
|
||||||
|
|
||||||
#define SERIAL_BUFSIZE 256
|
#define SERIAL_BUFSIZE 256
|
||||||
|
|
||||||
/** Private, per-device-instance driver context. */
|
|
||||||
struct dev_context {
|
struct dev_context {
|
||||||
struct sr_sw_limits sw_limits;
|
struct sr_sw_limits sw_limits;
|
||||||
|
|
||||||
|
|
|
@ -20,14 +20,14 @@
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include "protocol.h"
|
#include "protocol.h"
|
||||||
|
|
||||||
static const uint32_t drvopts[] = {
|
|
||||||
SR_CONF_LOGIC_ANALYZER,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint32_t scanopts[] = {
|
static const uint32_t scanopts[] = {
|
||||||
SR_CONF_CONN,
|
SR_CONF_CONN,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const uint32_t drvopts[] = {
|
||||||
|
SR_CONF_LOGIC_ANALYZER,
|
||||||
|
};
|
||||||
|
|
||||||
static const uint32_t devopts[] = {
|
static const uint32_t devopts[] = {
|
||||||
SR_CONF_LIMIT_MSEC | SR_CONF_SET,
|
SR_CONF_LIMIT_MSEC | SR_CONF_SET,
|
||||||
SR_CONF_LIMIT_SAMPLES | SR_CONF_SET | SR_CONF_LIST,
|
SR_CONF_LIMIT_SAMPLES | SR_CONF_SET | SR_CONF_LIST,
|
||||||
|
@ -43,21 +43,15 @@ static const int32_t trigger_matches[] = {
|
||||||
SR_TRIGGER_FALLING,
|
SR_TRIGGER_FALLING,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int dev_acquisition_stop(struct sr_dev_inst *sdi);
|
static void clear_helper(struct dev_context *devc)
|
||||||
|
|
||||||
static void clear_helper(void *priv)
|
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
|
||||||
|
|
||||||
devc = priv;
|
|
||||||
|
|
||||||
ftdi_free(devc->ftdic);
|
ftdi_free(devc->ftdic);
|
||||||
g_free(devc->final_buf);
|
g_free(devc->final_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_clear(const struct sr_dev_driver *di)
|
static int dev_clear(const struct sr_dev_driver *di)
|
||||||
{
|
{
|
||||||
return std_dev_clear(di, clear_helper);
|
return std_dev_clear_with_callback(di, (std_dev_clear_callback)clear_helper);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_device(int model, struct libusb_device_descriptor *des,
|
static int add_device(int model, struct libusb_device_descriptor *des,
|
||||||
|
@ -71,7 +65,6 @@ static int add_device(int model, struct libusb_device_descriptor *des,
|
||||||
|
|
||||||
ret = SR_OK;
|
ret = SR_OK;
|
||||||
|
|
||||||
/* Allocate memory for our private device context. */
|
|
||||||
devc = g_malloc0(sizeof(struct dev_context));
|
devc = g_malloc0(sizeof(struct dev_context));
|
||||||
|
|
||||||
/* Set some sane defaults. */
|
/* Set some sane defaults. */
|
||||||
|
@ -103,7 +96,6 @@ static int add_device(int model, struct libusb_device_descriptor *des,
|
||||||
/* We now know the device, set its max. samplerate as default. */
|
/* We now know the device, set its max. samplerate as default. */
|
||||||
devc->cur_samplerate = devc->prof->max_samplerate;
|
devc->cur_samplerate = devc->prof->max_samplerate;
|
||||||
|
|
||||||
/* Register the device with libsigrok. */
|
|
||||||
sdi = g_malloc0(sizeof(struct sr_dev_inst));
|
sdi = g_malloc0(sizeof(struct sr_dev_inst));
|
||||||
sdi->status = SR_ST_INACTIVE;
|
sdi->status = SR_ST_INACTIVE;
|
||||||
sdi->vendor = g_strdup("ChronoVu");
|
sdi->vendor = g_strdup("ChronoVu");
|
||||||
|
@ -200,18 +192,17 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
usb_get_port_path(devlist[i], connection_id, sizeof(connection_id));
|
|
||||||
|
|
||||||
libusb_close(hdl);
|
libusb_close(hdl);
|
||||||
|
|
||||||
if (!strcmp(product, "ChronoVu LA8")) {
|
if (usb_get_port_path(devlist[i], connection_id, sizeof(connection_id)) < 0)
|
||||||
model = 0;
|
|
||||||
} else if (!strcmp(product, "ChronoVu LA16")) {
|
|
||||||
model = 1;
|
|
||||||
} else {
|
|
||||||
sr_spew("Unknown iProduct string '%s'.", product);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
if (!strcmp(product, "ChronoVu LA8"))
|
||||||
|
model = 0;
|
||||||
|
else if (!strcmp(product, "ChronoVu LA16"))
|
||||||
|
model = 1;
|
||||||
|
else
|
||||||
|
continue; /* Unknown iProduct string, ignore. */
|
||||||
|
|
||||||
sr_dbg("Found %s (%04x:%04x, %d.%d, %s).",
|
sr_dbg("Found %s (%04x:%04x, %d.%d, %s).",
|
||||||
product, des.idVendor, des.idProduct,
|
product, des.idVendor, des.idProduct,
|
||||||
|
@ -237,7 +228,6 @@ static int dev_open(struct sr_dev_inst *sdi)
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
/* Allocate memory for the FTDI context and initialize it. */
|
|
||||||
if (!(devc->ftdic = ftdi_new())) {
|
if (!(devc->ftdic = ftdi_new())) {
|
||||||
sr_err("Failed to initialize libftdi.");
|
sr_err("Failed to initialize libftdi.");
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
|
@ -246,43 +236,33 @@ static int dev_open(struct sr_dev_inst *sdi)
|
||||||
sr_dbg("Opening %s device (%04x:%04x).", devc->prof->modelname,
|
sr_dbg("Opening %s device (%04x:%04x).", devc->prof->modelname,
|
||||||
devc->usb_vid, devc->usb_pid);
|
devc->usb_vid, devc->usb_pid);
|
||||||
|
|
||||||
/* Open the device. */
|
|
||||||
if ((ret = ftdi_usb_open_desc(devc->ftdic, devc->usb_vid,
|
if ((ret = ftdi_usb_open_desc(devc->ftdic, devc->usb_vid,
|
||||||
devc->usb_pid, devc->prof->iproduct, NULL)) < 0) {
|
devc->usb_pid, devc->prof->iproduct, NULL)) < 0) {
|
||||||
sr_err("Failed to open FTDI device (%d): %s.",
|
sr_err("Failed to open FTDI device (%d): %s.",
|
||||||
ret, ftdi_get_error_string(devc->ftdic));
|
ret, ftdi_get_error_string(devc->ftdic));
|
||||||
goto err_ftdi_free;
|
goto err_ftdi_free;
|
||||||
}
|
}
|
||||||
sr_dbg("Device opened successfully.");
|
|
||||||
|
|
||||||
/* Purge RX/TX buffers in the FTDI chip. */
|
|
||||||
if ((ret = ftdi_usb_purge_buffers(devc->ftdic)) < 0) {
|
if ((ret = ftdi_usb_purge_buffers(devc->ftdic)) < 0) {
|
||||||
sr_err("Failed to purge FTDI buffers (%d): %s.",
|
sr_err("Failed to purge FTDI buffers (%d): %s.",
|
||||||
ret, ftdi_get_error_string(devc->ftdic));
|
ret, ftdi_get_error_string(devc->ftdic));
|
||||||
goto err_ftdi_free;
|
goto err_ftdi_free;
|
||||||
}
|
}
|
||||||
sr_dbg("FTDI buffers purged successfully.");
|
|
||||||
|
|
||||||
/* Enable flow control in the FTDI chip. */
|
|
||||||
if ((ret = ftdi_setflowctrl(devc->ftdic, SIO_RTS_CTS_HS)) < 0) {
|
if ((ret = ftdi_setflowctrl(devc->ftdic, SIO_RTS_CTS_HS)) < 0) {
|
||||||
sr_err("Failed to enable FTDI flow control (%d): %s.",
|
sr_err("Failed to enable FTDI flow control (%d): %s.",
|
||||||
ret, ftdi_get_error_string(devc->ftdic));
|
ret, ftdi_get_error_string(devc->ftdic));
|
||||||
goto err_ftdi_free;
|
goto err_ftdi_free;
|
||||||
}
|
}
|
||||||
sr_dbg("FTDI flow control enabled successfully.");
|
|
||||||
|
|
||||||
/* Wait 100ms. */
|
|
||||||
g_usleep(100 * 1000);
|
g_usleep(100 * 1000);
|
||||||
|
|
||||||
sdi->status = SR_ST_ACTIVE;
|
|
||||||
|
|
||||||
if (ret == SR_OK)
|
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
|
|
||||||
err_ftdi_free:
|
err_ftdi_free:
|
||||||
ftdi_free(devc->ftdic); /* Close device (if open), free FTDI context. */
|
ftdi_free(devc->ftdic); /* Close device (if open), free FTDI context. */
|
||||||
devc->ftdic = NULL;
|
devc->ftdic = NULL;
|
||||||
return ret;
|
return SR_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_close(struct sr_dev_inst *sdi)
|
static int dev_close(struct sr_dev_inst *sdi)
|
||||||
|
@ -290,25 +270,23 @@ static int dev_close(struct sr_dev_inst *sdi)
|
||||||
int ret;
|
int ret;
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_OK;
|
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
if (devc->ftdic && (ret = ftdi_usb_close(devc->ftdic)) < 0)
|
if (!devc->ftdic)
|
||||||
|
return SR_ERR_BUG;
|
||||||
|
|
||||||
|
if ((ret = ftdi_usb_close(devc->ftdic)) < 0)
|
||||||
sr_err("Failed to close FTDI device (%d): %s.",
|
sr_err("Failed to close FTDI device (%d): %s.",
|
||||||
ret, ftdi_get_error_string(devc->ftdic));
|
ret, ftdi_get_error_string(devc->ftdic));
|
||||||
sdi->status = SR_ST_INACTIVE;
|
|
||||||
|
|
||||||
return SR_OK;
|
return (ret == 0) ? SR_OK : SR_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
|
static int config_get(uint32_t key, GVariant **data,
|
||||||
const struct sr_channel_group *cg)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
struct sr_usb_dev_inst *usb;
|
struct sr_usb_dev_inst *usb;
|
||||||
char str[128];
|
|
||||||
|
|
||||||
(void)cg;
|
(void)cg;
|
||||||
|
|
||||||
|
@ -316,8 +294,7 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s
|
||||||
case SR_CONF_CONN:
|
case SR_CONF_CONN:
|
||||||
if (!sdi || !(usb = sdi->conn))
|
if (!sdi || !(usb = sdi->conn))
|
||||||
return SR_ERR_ARG;
|
return SR_ERR_ARG;
|
||||||
snprintf(str, 128, "%d.%d", usb->bus, usb->address);
|
*data = g_variant_new_printf("%d.%d", usb->bus, usb->address);
|
||||||
*data = g_variant_new_string(str);
|
|
||||||
break;
|
break;
|
||||||
case SR_CONF_SAMPLERATE:
|
case SR_CONF_SAMPLERATE:
|
||||||
if (!sdi)
|
if (!sdi)
|
||||||
|
@ -332,16 +309,13 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
|
static int config_set(uint32_t key, GVariant *data,
|
||||||
const struct sr_channel_group *cg)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
|
|
||||||
(void)cg;
|
(void)cg;
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
|
@ -350,13 +324,9 @@ static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sd
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
break;
|
break;
|
||||||
case SR_CONF_LIMIT_MSEC:
|
case SR_CONF_LIMIT_MSEC:
|
||||||
if (g_variant_get_uint64(data) == 0)
|
|
||||||
return SR_ERR_ARG;
|
|
||||||
devc->limit_msec = g_variant_get_uint64(data);
|
devc->limit_msec = g_variant_get_uint64(data);
|
||||||
break;
|
break;
|
||||||
case SR_CONF_LIMIT_SAMPLES:
|
case SR_CONF_LIMIT_SAMPLES:
|
||||||
if (g_variant_get_uint64(data) == 0)
|
|
||||||
return SR_ERR_ARG;
|
|
||||||
devc->limit_samples = g_variant_get_uint64(data);
|
devc->limit_samples = g_variant_get_uint64(data);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -366,57 +336,30 @@ static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sd
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
|
static int config_list(uint32_t key, GVariant **data,
|
||||||
const struct sr_channel_group *cg)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
GVariant *gvar, *grange[2];
|
|
||||||
GVariantBuilder gvb;
|
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
|
|
||||||
(void)cg;
|
devc = (sdi) ? sdi->priv : NULL;
|
||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case SR_CONF_SCAN_OPTIONS:
|
case SR_CONF_SCAN_OPTIONS:
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
|
|
||||||
break;
|
|
||||||
case SR_CONF_DEVICE_OPTIONS:
|
case SR_CONF_DEVICE_OPTIONS:
|
||||||
if (!sdi)
|
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
drvopts, ARRAY_SIZE(drvopts), sizeof(uint32_t));
|
|
||||||
else
|
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
|
|
||||||
break;
|
|
||||||
case SR_CONF_SAMPLERATE:
|
case SR_CONF_SAMPLERATE:
|
||||||
if (!sdi)
|
|
||||||
return SR_ERR_BUG;
|
|
||||||
devc = sdi->priv;
|
|
||||||
cv_fill_samplerates_if_needed(sdi);
|
cv_fill_samplerates_if_needed(sdi);
|
||||||
g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
|
*data = std_gvar_samplerates(ARRAY_AND_SIZE(devc->samplerates));
|
||||||
gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"),
|
|
||||||
devc->samplerates,
|
|
||||||
ARRAY_SIZE(devc->samplerates),
|
|
||||||
sizeof(uint64_t));
|
|
||||||
g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar);
|
|
||||||
*data = g_variant_builder_end(&gvb);
|
|
||||||
break;
|
break;
|
||||||
case SR_CONF_LIMIT_SAMPLES:
|
case SR_CONF_LIMIT_SAMPLES:
|
||||||
if (!sdi || !sdi->priv || !(devc = sdi->priv) || !devc->prof)
|
if (!devc || !devc->prof)
|
||||||
return SR_ERR_BUG;
|
return SR_ERR_BUG;
|
||||||
grange[0] = g_variant_new_uint64(0);
|
*data = std_gvar_tuple_u64(0, (devc->prof->model == CHRONOVU_LA8) ? MAX_NUM_SAMPLES : MAX_NUM_SAMPLES / 2);
|
||||||
if (devc->prof->model == CHRONOVU_LA8)
|
|
||||||
grange[1] = g_variant_new_uint64(MAX_NUM_SAMPLES);
|
|
||||||
else
|
|
||||||
grange[1] = g_variant_new_uint64(MAX_NUM_SAMPLES / 2);
|
|
||||||
*data = g_variant_new_tuple(grange, 2);
|
|
||||||
break;
|
break;
|
||||||
case SR_CONF_TRIGGER_MATCH:
|
case SR_CONF_TRIGGER_MATCH:
|
||||||
if (!sdi || !sdi->priv || !(devc = sdi->priv) || !devc->prof)
|
if (!devc || !devc->prof)
|
||||||
return SR_ERR_BUG;
|
return SR_ERR_BUG;
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
|
*data = std_gvar_array_i32(trigger_matches, devc->prof->num_trigger_matches);
|
||||||
trigger_matches, devc->prof->num_trigger_matches,
|
|
||||||
sizeof(int32_t));
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return SR_ERR_NA;
|
return SR_ERR_NA;
|
||||||
|
@ -452,7 +395,7 @@ static int receive_data(int fd, int revents, void *cb_data)
|
||||||
/* Get one block of data. */
|
/* Get one block of data. */
|
||||||
if ((ret = cv_read_block(devc)) < 0) {
|
if ((ret = cv_read_block(devc)) < 0) {
|
||||||
sr_err("Failed to read data block: %d.", ret);
|
sr_err("Failed to read data block: %d.", ret);
|
||||||
dev_acquisition_stop(sdi);
|
sr_dev_acquisition_stop(sdi);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -475,7 +418,7 @@ static int receive_data(int fd, int revents, void *cb_data)
|
||||||
for (i = 0; i < NUM_BLOCKS; i++)
|
for (i = 0; i < NUM_BLOCKS; i++)
|
||||||
cv_send_block_to_session_bus(sdi, i);
|
cv_send_block_to_session_bus(sdi, i);
|
||||||
|
|
||||||
dev_acquisition_stop(sdi);
|
sr_dev_acquisition_stop(sdi);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -486,9 +429,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||||
uint8_t buf[8];
|
uint8_t buf[8];
|
||||||
int bytes_to_write, bytes_written;
|
int bytes_to_write, bytes_written;
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
if (!devc->ftdic) {
|
if (!devc->ftdic) {
|
||||||
|
@ -534,8 +474,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
sr_dbg("Hardware acquisition started successfully.");
|
|
||||||
|
|
||||||
std_session_send_df_header(sdi);
|
std_session_send_df_header(sdi);
|
||||||
|
|
||||||
/* Time when we should be done (for detecting trigger timeouts). */
|
/* Time when we should be done (for detecting trigger timeouts). */
|
||||||
|
@ -552,7 +490,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||||
|
|
||||||
static int dev_acquisition_stop(struct sr_dev_inst *sdi)
|
static int dev_acquisition_stop(struct sr_dev_inst *sdi)
|
||||||
{
|
{
|
||||||
sr_dbg("Stopping acquisition.");
|
|
||||||
sr_session_source_remove(sdi->session, -1);
|
sr_session_source_remove(sdi->session, -1);
|
||||||
std_session_send_df_end(sdi);
|
std_session_send_df_end(sdi);
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
#include <libsigrok/libsigrok.h>
|
#include <libsigrok/libsigrok.h>
|
||||||
#include "libsigrok-internal.h"
|
#include "libsigrok-internal.h"
|
||||||
|
|
||||||
#define LOG_PREFIX "la8/la16"
|
#define LOG_PREFIX "chronovu-la"
|
||||||
|
|
||||||
#define SDRAM_SIZE (8 * 1024 * 1024)
|
#define SDRAM_SIZE (8 * 1024 * 1024)
|
||||||
#define MAX_NUM_SAMPLES SDRAM_SIZE
|
#define MAX_NUM_SAMPLES SDRAM_SIZE
|
||||||
|
@ -44,28 +44,18 @@ enum {
|
||||||
struct cv_profile {
|
struct cv_profile {
|
||||||
int model;
|
int model;
|
||||||
const char *modelname;
|
const char *modelname;
|
||||||
const char *iproduct; /* USB iProduct string */
|
const char *iproduct;
|
||||||
unsigned int num_channels;
|
unsigned int num_channels;
|
||||||
uint64_t max_samplerate;
|
uint64_t max_samplerate;
|
||||||
const int num_trigger_matches;
|
const int num_trigger_matches;
|
||||||
float trigger_constant;
|
float trigger_constant;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Private, per-device-instance driver context. */
|
|
||||||
struct dev_context {
|
struct dev_context {
|
||||||
/** Device profile struct for this device. */
|
|
||||||
const struct cv_profile *prof;
|
const struct cv_profile *prof;
|
||||||
|
|
||||||
/** FTDI device context (used by libftdi). */
|
|
||||||
struct ftdi_context *ftdic;
|
struct ftdi_context *ftdic;
|
||||||
|
|
||||||
/** The currently configured samplerate of the device. */
|
|
||||||
uint64_t cur_samplerate;
|
uint64_t cur_samplerate;
|
||||||
|
|
||||||
/** The current sampling limit (in ms). */
|
|
||||||
uint64_t limit_msec;
|
uint64_t limit_msec;
|
||||||
|
|
||||||
/** The current sampling limit (in number of samples). */
|
|
||||||
uint64_t limit_samples;
|
uint64_t limit_samples;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -124,7 +114,6 @@ struct dev_context {
|
||||||
uint64_t samplerates[255];
|
uint64_t samplerates[255];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* protocol.c */
|
|
||||||
extern SR_PRIV const char *cv_channel_names[];
|
extern SR_PRIV const char *cv_channel_names[];
|
||||||
extern const struct cv_profile cv_profiles[];
|
extern const struct cv_profile cv_profiles[];
|
||||||
SR_PRIV void cv_fill_samplerates_if_needed(const struct sr_dev_inst *sdi);
|
SR_PRIV void cv_fill_samplerates_if_needed(const struct sr_dev_inst *sdi);
|
||||||
|
|
|
@ -35,8 +35,11 @@ static const uint32_t scanopts[] = {
|
||||||
SR_CONF_SERIALCOMM,
|
SR_CONF_SERIALCOMM,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint32_t devopts[] = {
|
static const uint32_t drvopts[] = {
|
||||||
SR_CONF_SOUNDLEVELMETER,
|
SR_CONF_SOUNDLEVELMETER,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t devopts[] = {
|
||||||
SR_CONF_CONTINUOUS,
|
SR_CONF_CONTINUOUS,
|
||||||
SR_CONF_LIMIT_SAMPLES | SR_CONF_SET,
|
SR_CONF_LIMIT_SAMPLES | SR_CONF_SET,
|
||||||
SR_CONF_LIMIT_MSEC | SR_CONF_SET,
|
SR_CONF_LIMIT_MSEC | SR_CONF_SET,
|
||||||
|
@ -81,41 +84,22 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
return std_scan_complete(di, g_slist_append(NULL, sdi));
|
return std_scan_complete(di, g_slist_append(NULL, sdi));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
|
static int config_set(uint32_t key, GVariant *data,
|
||||||
const struct sr_channel_group *cg)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
|
|
||||||
(void)cg;
|
(void)cg;
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
return sr_sw_limits_config_set(&devc->limits, key, data);
|
return sr_sw_limits_config_set(&devc->limits, key, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
|
static int config_list(uint32_t key, GVariant **data,
|
||||||
const struct sr_channel_group *cg)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
(void)sdi;
|
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
|
||||||
(void)cg;
|
|
||||||
|
|
||||||
switch (key) {
|
|
||||||
case SR_CONF_SCAN_OPTIONS:
|
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
|
|
||||||
break;
|
|
||||||
case SR_CONF_DEVICE_OPTIONS:
|
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return SR_ERR_NA;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SR_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||||
|
@ -123,13 +107,9 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||||
struct dev_context *devc = sdi->priv;
|
struct dev_context *devc = sdi->priv;
|
||||||
struct sr_serial_dev_inst *serial;
|
struct sr_serial_dev_inst *serial;
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
sr_sw_limits_acquisition_start(&devc->limits);
|
sr_sw_limits_acquisition_start(&devc->limits);
|
||||||
std_session_send_df_header(sdi);
|
std_session_send_df_header(sdi);
|
||||||
|
|
||||||
/* Poll every 150ms, or whenever some data comes in. */
|
|
||||||
serial = sdi->conn;
|
serial = sdi->conn;
|
||||||
serial_source_add(sdi->session, serial, G_IO_IN, 150,
|
serial_source_add(sdi->session, serial, G_IO_IN, 150,
|
||||||
colead_slm_receive_data, (void *)sdi);
|
colead_slm_receive_data, (void *)sdi);
|
||||||
|
@ -145,7 +125,7 @@ static struct sr_dev_driver colead_slm_driver_info = {
|
||||||
.cleanup = std_cleanup,
|
.cleanup = std_cleanup,
|
||||||
.scan = scan,
|
.scan = scan,
|
||||||
.dev_list = std_dev_list,
|
.dev_list = std_dev_list,
|
||||||
.dev_clear = NULL,
|
.dev_clear = std_dev_clear,
|
||||||
.config_get = NULL,
|
.config_get = NULL,
|
||||||
.config_set = config_set,
|
.config_set = config_set,
|
||||||
.config_list = config_list,
|
.config_list = config_list,
|
||||||
|
|
|
@ -177,7 +177,7 @@ static void process_packet(const struct sr_dev_inst *sdi)
|
||||||
sr_sw_limits_update_samples_read(&devc->limits, 1);
|
sr_sw_limits_update_samples_read(&devc->limits, 1);
|
||||||
|
|
||||||
if (sr_sw_limits_check(&devc->limits))
|
if (sr_sw_limits_check(&devc->limits))
|
||||||
sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi);
|
sr_dev_acquisition_stop((struct sr_dev_inst *)sdi);
|
||||||
}
|
}
|
||||||
|
|
||||||
SR_PRIV int colead_slm_receive_data(int fd, int revents, void *cb_data)
|
SR_PRIV int colead_slm_receive_data(int fd, int revents, void *cb_data)
|
||||||
|
@ -202,7 +202,7 @@ SR_PRIV int colead_slm_receive_data(int fd, int revents, void *cb_data)
|
||||||
|
|
||||||
serial = sdi->conn;
|
serial = sdi->conn;
|
||||||
if (devc->state == IDLE) {
|
if (devc->state == IDLE) {
|
||||||
if (serial_read_nonblocking(serial, buf, 128) != 1 || buf[0] != 0x10)
|
if (serial_read_nonblocking(serial, buf, sizeof(buf)) != 1 || buf[0] != 0x10)
|
||||||
/* Nothing there, or caught the tail end of a previous packet,
|
/* Nothing there, or caught the tail end of a previous packet,
|
||||||
* or some garbage. Unless it's a single "data ready" byte,
|
* or some garbage. Unless it's a single "data ready" byte,
|
||||||
* we don't want it. */
|
* we don't want it. */
|
||||||
|
|
|
@ -31,7 +31,6 @@ enum {
|
||||||
COMMAND_SENT,
|
COMMAND_SENT,
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Private, per-device-instance driver context. */
|
|
||||||
struct dev_context {
|
struct dev_context {
|
||||||
struct sr_sw_limits limits;
|
struct sr_sw_limits limits;
|
||||||
|
|
||||||
|
|
|
@ -17,14 +17,6 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
*
|
|
||||||
* <em>Conrad DIGI 35 CPU</em> power supply driver
|
|
||||||
*
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include "protocol.h"
|
#include "protocol.h"
|
||||||
|
|
||||||
|
@ -35,15 +27,19 @@ static const uint32_t scanopts[] = {
|
||||||
SR_CONF_SERIALCOMM,
|
SR_CONF_SERIALCOMM,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint32_t devopts[] = {
|
static const uint32_t drvopts[] = {
|
||||||
SR_CONF_POWER_SUPPLY,
|
SR_CONF_POWER_SUPPLY,
|
||||||
SR_CONF_VOLTAGE | SR_CONF_SET,
|
};
|
||||||
SR_CONF_CURRENT | SR_CONF_SET,
|
|
||||||
|
static const uint32_t devopts[] = {
|
||||||
|
SR_CONF_VOLTAGE_TARGET | SR_CONF_SET | SR_CONF_LIST,
|
||||||
|
SR_CONF_CURRENT_LIMIT | SR_CONF_SET | SR_CONF_LIST,
|
||||||
SR_CONF_OVER_CURRENT_PROTECTION_ENABLED | SR_CONF_SET,
|
SR_CONF_OVER_CURRENT_PROTECTION_ENABLED | SR_CONF_SET,
|
||||||
};
|
};
|
||||||
|
|
||||||
static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
{
|
{
|
||||||
|
struct dev_context *devc;
|
||||||
struct sr_dev_inst *sdi;
|
struct sr_dev_inst *sdi;
|
||||||
struct sr_config *src;
|
struct sr_config *src;
|
||||||
struct sr_serial_dev_inst *serial;
|
struct sr_serial_dev_inst *serial;
|
||||||
|
@ -88,91 +84,66 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
sdi->status = SR_ST_INACTIVE;
|
sdi->status = SR_ST_INACTIVE;
|
||||||
sdi->vendor = g_strdup("Conrad");
|
sdi->vendor = g_strdup("Conrad");
|
||||||
sdi->model = g_strdup("DIGI 35 CPU");
|
sdi->model = g_strdup("DIGI 35 CPU");
|
||||||
|
devc = g_malloc0(sizeof(struct dev_context));
|
||||||
|
sr_sw_limits_init(&devc->limits);
|
||||||
|
sdi->inst_type = SR_INST_SERIAL;
|
||||||
sdi->conn = serial;
|
sdi->conn = serial;
|
||||||
sdi->priv = NULL;
|
sdi->priv = devc;
|
||||||
sr_channel_new(sdi, 0, SR_CHANNEL_ANALOG, TRUE, "CH1");
|
sr_channel_new(sdi, 0, SR_CHANNEL_ANALOG, TRUE, "CH1");
|
||||||
|
|
||||||
return std_scan_complete(di, g_slist_append(NULL, sdi));
|
return std_scan_complete(di, g_slist_append(NULL, sdi));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
|
static int config_set(uint32_t key, GVariant *data,
|
||||||
const struct sr_channel_group *cg)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
int ret;
|
|
||||||
double dblval;
|
double dblval;
|
||||||
|
|
||||||
(void)cg;
|
(void)cg;
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case SR_CONF_VOLTAGE:
|
case SR_CONF_VOLTAGE_TARGET:
|
||||||
dblval = g_variant_get_double(data);
|
dblval = g_variant_get_double(data);
|
||||||
if ((dblval < 0.0) || (dblval > 35.0)) {
|
if ((dblval < 0.0) || (dblval > 35.0)) {
|
||||||
sr_err("Voltage out of range (0 - 35.0)!");
|
sr_err("Voltage out of range (0 - 35.0)!");
|
||||||
return SR_ERR_ARG;
|
return SR_ERR_ARG;
|
||||||
}
|
}
|
||||||
ret = send_msg1(sdi, 'V', (int) (dblval * 10 + 0.5));
|
return send_msg1(sdi, 'V', (int) (dblval * 10 + 0.5));
|
||||||
break;
|
case SR_CONF_CURRENT_LIMIT:
|
||||||
case SR_CONF_CURRENT:
|
|
||||||
dblval = g_variant_get_double(data);
|
dblval = g_variant_get_double(data);
|
||||||
if ((dblval < 0.01) || (dblval > 2.55)) {
|
if ((dblval < 0.00) || (dblval > 2.55)) {
|
||||||
sr_err("Current out of range (0 - 2.55)!");
|
sr_err("Current out of range (0 - 2.55)!");
|
||||||
return SR_ERR_ARG;
|
return SR_ERR_ARG;
|
||||||
}
|
}
|
||||||
ret = send_msg1(sdi, 'C', (int) (dblval * 100 + 0.5));
|
return send_msg1(sdi, 'C', (int) (dblval * 100 + 0.5));
|
||||||
break;
|
|
||||||
case SR_CONF_OVER_CURRENT_PROTECTION_ENABLED:
|
case SR_CONF_OVER_CURRENT_PROTECTION_ENABLED:
|
||||||
if (g_variant_get_boolean(data))
|
if (g_variant_get_boolean(data))
|
||||||
ret = send_msg1(sdi, 'V', 900);
|
return send_msg1(sdi, 'V', 900);
|
||||||
else /* Constant current mode */
|
else /* Constant current mode */
|
||||||
ret = send_msg1(sdi, 'V', 901);
|
return send_msg1(sdi, 'V', 901);
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ret = SR_ERR_NA;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
|
|
||||||
const struct sr_channel_group *cg)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
(void)sdi;
|
|
||||||
(void)cg;
|
|
||||||
|
|
||||||
ret = SR_OK;
|
|
||||||
switch (key) {
|
|
||||||
case SR_CONF_SCAN_OPTIONS:
|
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
|
|
||||||
break;
|
|
||||||
case SR_CONF_DEVICE_OPTIONS:
|
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
return SR_ERR_NA;
|
return SR_ERR_NA;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
|
||||||
{
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_acquisition_stop(struct sr_dev_inst *sdi)
|
static int config_list(uint32_t key, GVariant **data,
|
||||||
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
switch (key) {
|
||||||
return SR_ERR_DEV_CLOSED;
|
case SR_CONF_SCAN_OPTIONS:
|
||||||
|
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, 35.0, 0.1);
|
||||||
|
break;
|
||||||
|
case SR_CONF_CURRENT_LIMIT:
|
||||||
|
*data = std_gvar_min_max_step(0.0, 2.55, 0.01);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return SR_ERR_NA;
|
||||||
|
}
|
||||||
|
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
@ -185,14 +156,14 @@ static struct sr_dev_driver conrad_digi_35_cpu_driver_info = {
|
||||||
.cleanup = std_cleanup,
|
.cleanup = std_cleanup,
|
||||||
.scan = scan,
|
.scan = scan,
|
||||||
.dev_list = std_dev_list,
|
.dev_list = std_dev_list,
|
||||||
.dev_clear = NULL,
|
.dev_clear = std_dev_clear,
|
||||||
.config_get = NULL,
|
.config_get = NULL,
|
||||||
.config_set = config_set,
|
.config_set = config_set,
|
||||||
.config_list = config_list,
|
.config_list = config_list,
|
||||||
.dev_open = std_serial_dev_open,
|
.dev_open = std_serial_dev_open,
|
||||||
.dev_close = std_serial_dev_close,
|
.dev_close = std_serial_dev_close,
|
||||||
.dev_acquisition_start = dev_acquisition_start,
|
.dev_acquisition_start = std_dummy_dev_acquisition_start,
|
||||||
.dev_acquisition_stop = dev_acquisition_stop,
|
.dev_acquisition_stop = std_dummy_dev_acquisition_stop,
|
||||||
.context = NULL,
|
.context = NULL,
|
||||||
};
|
};
|
||||||
SR_REGISTER_DEV_DRIVER(conrad_digi_35_cpu_driver_info);
|
SR_REGISTER_DEV_DRIVER(conrad_digi_35_cpu_driver_info);
|
||||||
|
|
|
@ -17,12 +17,6 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* <em>Conrad DIGI 35 CPU</em> power supply driver
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include "protocol.h"
|
#include "protocol.h"
|
||||||
|
|
||||||
|
|
|
@ -17,14 +17,6 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
*
|
|
||||||
* <em>Conrad DIGI 35 CPU</em> power supply driver
|
|
||||||
*
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef LIBSIGROK_HARDWARE_CONRAD_DIGI_35_CPU_PROTOCOL_H
|
#ifndef LIBSIGROK_HARDWARE_CONRAD_DIGI_35_CPU_PROTOCOL_H
|
||||||
#define LIBSIGROK_HARDWARE_CONRAD_DIGI_35_CPU_PROTOCOL_H
|
#define LIBSIGROK_HARDWARE_CONRAD_DIGI_35_CPU_PROTOCOL_H
|
||||||
|
|
||||||
|
@ -36,6 +28,10 @@
|
||||||
|
|
||||||
#define LOG_PREFIX "conrad-digi-35-cpu"
|
#define LOG_PREFIX "conrad-digi-35-cpu"
|
||||||
|
|
||||||
|
struct dev_context {
|
||||||
|
struct sr_sw_limits limits;
|
||||||
|
};
|
||||||
|
|
||||||
SR_PRIV int send_msg1(const struct sr_dev_inst *sdi, char cmd, int param);
|
SR_PRIV int send_msg1(const struct sr_dev_inst *sdi, char cmd, int param);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -29,11 +29,9 @@
|
||||||
#include "protocol.h"
|
#include "protocol.h"
|
||||||
|
|
||||||
#define DEFAULT_NUM_LOGIC_CHANNELS 8
|
#define DEFAULT_NUM_LOGIC_CHANNELS 8
|
||||||
#define DEFAULT_ENABLED_LOGIC_CHANNELS 8
|
|
||||||
#define DEFAULT_LOGIC_PATTERN PATTERN_SIGROK
|
#define DEFAULT_LOGIC_PATTERN PATTERN_SIGROK
|
||||||
|
|
||||||
#define DEFAULT_NUM_ANALOG_CHANNELS 4
|
#define DEFAULT_NUM_ANALOG_CHANNELS 4
|
||||||
#define DEFAULT_ENABLED_ANALOG_CHANNELS 4
|
|
||||||
#define DEFAULT_ANALOG_AMPLITUDE 10
|
#define DEFAULT_ANALOG_AMPLITUDE 10
|
||||||
|
|
||||||
/* Note: No spaces allowed because of sigrok-cli. */
|
/* Note: No spaces allowed because of sigrok-cli. */
|
||||||
|
@ -46,6 +44,13 @@ static const char *logic_pattern_str[] = {
|
||||||
"all-low",
|
"all-low",
|
||||||
"all-high",
|
"all-high",
|
||||||
"squid",
|
"squid",
|
||||||
|
"graycode",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t scanopts[] = {
|
||||||
|
SR_CONF_NUM_LOGIC_CHANNELS,
|
||||||
|
SR_CONF_NUM_ANALOG_CHANNELS,
|
||||||
|
SR_CONF_LIMIT_FRAMES,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint32_t drvopts[] = {
|
static const uint32_t drvopts[] = {
|
||||||
|
@ -54,18 +59,16 @@ static const uint32_t drvopts[] = {
|
||||||
SR_CONF_OSCILLOSCOPE,
|
SR_CONF_OSCILLOSCOPE,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint32_t scanopts[] = {
|
|
||||||
SR_CONF_NUM_LOGIC_CHANNELS,
|
|
||||||
SR_CONF_NUM_ANALOG_CHANNELS,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint32_t devopts[] = {
|
static const uint32_t devopts[] = {
|
||||||
SR_CONF_CONTINUOUS,
|
SR_CONF_CONTINUOUS,
|
||||||
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
|
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
|
||||||
SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET,
|
SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET,
|
||||||
|
SR_CONF_LIMIT_FRAMES | SR_CONF_GET | SR_CONF_SET,
|
||||||
SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
|
SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
|
||||||
SR_CONF_AVERAGING | SR_CONF_GET | SR_CONF_SET,
|
SR_CONF_AVERAGING | SR_CONF_GET | SR_CONF_SET,
|
||||||
SR_CONF_AVG_SAMPLES | SR_CONF_GET | SR_CONF_SET,
|
SR_CONF_AVG_SAMPLES | SR_CONF_GET | SR_CONF_SET,
|
||||||
|
SR_CONF_TRIGGER_MATCH | SR_CONF_LIST,
|
||||||
|
SR_CONF_CAPTURE_RATIO | SR_CONF_GET | SR_CONF_SET,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint32_t devopts_cg_logic[] = {
|
static const uint32_t devopts_cg_logic[] = {
|
||||||
|
@ -81,6 +84,14 @@ static const uint32_t devopts_cg_analog_channel[] = {
|
||||||
SR_CONF_AMPLITUDE | SR_CONF_GET | SR_CONF_SET,
|
SR_CONF_AMPLITUDE | SR_CONF_GET | SR_CONF_SET,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const int32_t trigger_matches[] = {
|
||||||
|
SR_TRIGGER_ZERO,
|
||||||
|
SR_TRIGGER_ONE,
|
||||||
|
SR_TRIGGER_RISING,
|
||||||
|
SR_TRIGGER_FALLING,
|
||||||
|
SR_TRIGGER_EDGE,
|
||||||
|
};
|
||||||
|
|
||||||
static const uint64_t samplerates[] = {
|
static const uint64_t samplerates[] = {
|
||||||
SR_HZ(1),
|
SR_HZ(1),
|
||||||
SR_GHZ(1),
|
SR_GHZ(1),
|
||||||
|
@ -97,11 +108,12 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
struct analog_gen *ag;
|
struct analog_gen *ag;
|
||||||
GSList *l;
|
GSList *l;
|
||||||
int num_logic_channels, num_analog_channels, pattern, i;
|
int num_logic_channels, num_analog_channels, pattern, i;
|
||||||
|
uint64_t limit_frames;
|
||||||
char channel_name[16];
|
char channel_name[16];
|
||||||
gboolean enabled;
|
|
||||||
|
|
||||||
num_logic_channels = DEFAULT_NUM_LOGIC_CHANNELS;
|
num_logic_channels = DEFAULT_NUM_LOGIC_CHANNELS;
|
||||||
num_analog_channels = DEFAULT_NUM_ANALOG_CHANNELS;
|
num_analog_channels = DEFAULT_NUM_ANALOG_CHANNELS;
|
||||||
|
limit_frames = DEFAULT_LIMIT_FRAMES;
|
||||||
for (l = options; l; l = l->next) {
|
for (l = options; l; l = l->next) {
|
||||||
src = l->data;
|
src = l->data;
|
||||||
switch (src->key) {
|
switch (src->key) {
|
||||||
|
@ -111,6 +123,9 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
case SR_CONF_NUM_ANALOG_CHANNELS:
|
case SR_CONF_NUM_ANALOG_CHANNELS:
|
||||||
num_analog_channels = g_variant_get_int32(src->data);
|
num_analog_channels = g_variant_get_int32(src->data);
|
||||||
break;
|
break;
|
||||||
|
case SR_CONF_LIMIT_FRAMES:
|
||||||
|
limit_frames = g_variant_get_uint64(src->data);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,8 +137,14 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
devc->cur_samplerate = SR_KHZ(200);
|
devc->cur_samplerate = SR_KHZ(200);
|
||||||
devc->num_logic_channels = num_logic_channels;
|
devc->num_logic_channels = num_logic_channels;
|
||||||
devc->logic_unitsize = (devc->num_logic_channels + 7) / 8;
|
devc->logic_unitsize = (devc->num_logic_channels + 7) / 8;
|
||||||
|
devc->all_logic_channels_mask = 1UL << 0;
|
||||||
|
devc->all_logic_channels_mask <<= devc->num_logic_channels;
|
||||||
|
devc->all_logic_channels_mask--;
|
||||||
devc->logic_pattern = DEFAULT_LOGIC_PATTERN;
|
devc->logic_pattern = DEFAULT_LOGIC_PATTERN;
|
||||||
devc->num_analog_channels = num_analog_channels;
|
devc->num_analog_channels = num_analog_channels;
|
||||||
|
devc->limit_frames = limit_frames;
|
||||||
|
devc->capture_ratio = 20;
|
||||||
|
devc->stl = NULL;
|
||||||
|
|
||||||
if (num_logic_channels > 0) {
|
if (num_logic_channels > 0) {
|
||||||
/* Logic channels, all in one channel group. */
|
/* Logic channels, all in one channel group. */
|
||||||
|
@ -131,14 +152,14 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
cg->name = g_strdup("Logic");
|
cg->name = g_strdup("Logic");
|
||||||
for (i = 0; i < num_logic_channels; i++) {
|
for (i = 0; i < num_logic_channels; i++) {
|
||||||
sprintf(channel_name, "D%d", i);
|
sprintf(channel_name, "D%d", i);
|
||||||
enabled = (i < DEFAULT_ENABLED_LOGIC_CHANNELS) ? TRUE : FALSE;
|
ch = sr_channel_new(sdi, i, SR_CHANNEL_LOGIC, TRUE, channel_name);
|
||||||
ch = sr_channel_new(sdi, i, SR_CHANNEL_LOGIC, enabled, channel_name);
|
|
||||||
cg->channels = g_slist_append(cg->channels, ch);
|
cg->channels = g_slist_append(cg->channels, ch);
|
||||||
}
|
}
|
||||||
sdi->channel_groups = g_slist_append(NULL, cg);
|
sdi->channel_groups = g_slist_append(NULL, cg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Analog channels, channel groups and pattern generators. */
|
/* 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) {
|
if (num_analog_channels > 0) {
|
||||||
pattern = 0;
|
pattern = 0;
|
||||||
/* An "Analog" channel group with all analog channels in it. */
|
/* An "Analog" channel group with all analog channels in it. */
|
||||||
|
@ -146,12 +167,10 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
acg->name = g_strdup("Analog");
|
acg->name = g_strdup("Analog");
|
||||||
sdi->channel_groups = g_slist_append(sdi->channel_groups, acg);
|
sdi->channel_groups = g_slist_append(sdi->channel_groups, acg);
|
||||||
|
|
||||||
devc->ch_ag = g_hash_table_new(g_direct_hash, g_direct_equal);
|
|
||||||
for (i = 0; i < num_analog_channels; i++) {
|
for (i = 0; i < num_analog_channels; i++) {
|
||||||
snprintf(channel_name, 16, "A%d", i);
|
snprintf(channel_name, 16, "A%d", i);
|
||||||
enabled = (i < DEFAULT_ENABLED_ANALOG_CHANNELS) ? TRUE : FALSE;
|
|
||||||
ch = sr_channel_new(sdi, i + num_logic_channels, SR_CHANNEL_ANALOG,
|
ch = sr_channel_new(sdi, i + num_logic_channels, SR_CHANNEL_ANALOG,
|
||||||
enabled, channel_name);
|
TRUE, channel_name);
|
||||||
acg->channels = g_slist_append(acg->channels, ch);
|
acg->channels = g_slist_append(acg->channels, ch);
|
||||||
|
|
||||||
/* Every analog channel gets its own channel group as well. */
|
/* Every analog channel gets its own channel group as well. */
|
||||||
|
@ -162,6 +181,7 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
|
|
||||||
/* Every channel gets a generator struct. */
|
/* Every channel gets a generator struct. */
|
||||||
ag = g_malloc(sizeof(struct analog_gen));
|
ag = g_malloc(sizeof(struct analog_gen));
|
||||||
|
ag->ch = ch;
|
||||||
ag->amplitude = DEFAULT_ANALOG_AMPLITUDE;
|
ag->amplitude = DEFAULT_ANALOG_AMPLITUDE;
|
||||||
sr_analog_init(&ag->packet, &ag->encoding, &ag->meaning, &ag->spec, 2);
|
sr_analog_init(&ag->packet, &ag->encoding, &ag->meaning, &ag->spec, 2);
|
||||||
ag->packet.meaning->channels = cg->channels;
|
ag->packet.meaning->channels = cg->channels;
|
||||||
|
@ -184,43 +204,25 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
return std_scan_complete(di, g_slist_append(NULL, sdi));
|
return std_scan_complete(di, g_slist_append(NULL, sdi));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_open(struct sr_dev_inst *sdi)
|
static void clear_helper(struct dev_context *devc)
|
||||||
{
|
{
|
||||||
sdi->status = SR_ST_ACTIVE;
|
|
||||||
|
|
||||||
return SR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dev_close(struct sr_dev_inst *sdi)
|
|
||||||
{
|
|
||||||
sdi->status = SR_ST_INACTIVE;
|
|
||||||
|
|
||||||
return SR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void clear_helper(void *priv)
|
|
||||||
{
|
|
||||||
struct dev_context *devc;
|
|
||||||
GHashTableIter iter;
|
GHashTableIter iter;
|
||||||
void *value;
|
void *value;
|
||||||
|
|
||||||
devc = priv;
|
|
||||||
|
|
||||||
/* Analog generators. */
|
/* Analog generators. */
|
||||||
g_hash_table_iter_init(&iter, devc->ch_ag);
|
g_hash_table_iter_init(&iter, devc->ch_ag);
|
||||||
while (g_hash_table_iter_next(&iter, NULL, &value))
|
while (g_hash_table_iter_next(&iter, NULL, &value))
|
||||||
g_free(value);
|
g_free(value);
|
||||||
g_hash_table_unref(devc->ch_ag);
|
g_hash_table_unref(devc->ch_ag);
|
||||||
g_free(devc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_clear(const struct sr_dev_driver *di)
|
static int dev_clear(const struct sr_dev_driver *di)
|
||||||
{
|
{
|
||||||
return std_dev_clear(di, clear_helper);
|
return std_dev_clear_with_callback(di, (std_dev_clear_callback)clear_helper);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
|
static int config_get(uint32_t key, GVariant **data,
|
||||||
const struct sr_channel_group *cg)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
struct sr_channel *ch;
|
struct sr_channel *ch;
|
||||||
|
@ -241,6 +243,9 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s
|
||||||
case SR_CONF_LIMIT_MSEC:
|
case SR_CONF_LIMIT_MSEC:
|
||||||
*data = g_variant_new_uint64(devc->limit_msec);
|
*data = g_variant_new_uint64(devc->limit_msec);
|
||||||
break;
|
break;
|
||||||
|
case SR_CONF_LIMIT_FRAMES:
|
||||||
|
*data = g_variant_new_uint64(devc->limit_frames);
|
||||||
|
break;
|
||||||
case SR_CONF_AVERAGING:
|
case SR_CONF_AVERAGING:
|
||||||
*data = g_variant_new_boolean(devc->avg);
|
*data = g_variant_new_boolean(devc->avg);
|
||||||
break;
|
break;
|
||||||
|
@ -272,6 +277,9 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s
|
||||||
ag = g_hash_table_lookup(devc->ch_ag, ch);
|
ag = g_hash_table_lookup(devc->ch_ag, ch);
|
||||||
*data = g_variant_new_double(ag->amplitude);
|
*data = g_variant_new_double(ag->amplitude);
|
||||||
break;
|
break;
|
||||||
|
case SR_CONF_CAPTURE_RATIO:
|
||||||
|
*data = g_variant_new_uint64(devc->capture_ratio);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return SR_ERR_NA;
|
return SR_ERR_NA;
|
||||||
}
|
}
|
||||||
|
@ -279,23 +287,17 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
|
static int config_set(uint32_t key, GVariant *data,
|
||||||
const struct sr_channel_group *cg)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
struct analog_gen *ag;
|
struct analog_gen *ag;
|
||||||
struct sr_channel *ch;
|
struct sr_channel *ch;
|
||||||
GSList *l;
|
GSList *l;
|
||||||
int logic_pattern, analog_pattern, ret;
|
int logic_pattern, analog_pattern;
|
||||||
unsigned int i;
|
|
||||||
const char *stropt;
|
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
ret = SR_OK;
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case SR_CONF_SAMPLERATE:
|
case SR_CONF_SAMPLERATE:
|
||||||
devc->cur_samplerate = g_variant_get_uint64(data);
|
devc->cur_samplerate = g_variant_get_uint64(data);
|
||||||
|
@ -308,6 +310,9 @@ static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sd
|
||||||
devc->limit_msec = g_variant_get_uint64(data);
|
devc->limit_msec = g_variant_get_uint64(data);
|
||||||
devc->limit_samples = 0;
|
devc->limit_samples = 0;
|
||||||
break;
|
break;
|
||||||
|
case SR_CONF_LIMIT_FRAMES:
|
||||||
|
devc->limit_frames = g_variant_get_uint64(data);
|
||||||
|
break;
|
||||||
case SR_CONF_AVERAGING:
|
case SR_CONF_AVERAGING:
|
||||||
devc->avg = g_variant_get_boolean(data);
|
devc->avg = g_variant_get_boolean(data);
|
||||||
sr_dbg("%s averaging", devc->avg ? "Enabling" : "Disabling");
|
sr_dbg("%s averaging", devc->avg ? "Enabling" : "Disabling");
|
||||||
|
@ -319,21 +324,9 @@ static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sd
|
||||||
case SR_CONF_PATTERN_MODE:
|
case SR_CONF_PATTERN_MODE:
|
||||||
if (!cg)
|
if (!cg)
|
||||||
return SR_ERR_CHANNEL_GROUP;
|
return SR_ERR_CHANNEL_GROUP;
|
||||||
stropt = g_variant_get_string(data, NULL);
|
logic_pattern = std_str_idx(data, ARRAY_AND_SIZE(logic_pattern_str));
|
||||||
logic_pattern = analog_pattern = -1;
|
analog_pattern = std_str_idx(data, ARRAY_AND_SIZE(analog_pattern_str));
|
||||||
for (i = 0; i < ARRAY_SIZE(logic_pattern_str); i++) {
|
if (logic_pattern < 0 && analog_pattern < 0)
|
||||||
if (!strcmp(stropt, logic_pattern_str[i])) {
|
|
||||||
logic_pattern = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (i = 0; i < ARRAY_SIZE(analog_pattern_str); i++) {
|
|
||||||
if (!strcmp(stropt, analog_pattern_str[i])) {
|
|
||||||
analog_pattern = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (logic_pattern == -1 && analog_pattern == -1)
|
|
||||||
return SR_ERR_ARG;
|
return SR_ERR_ARG;
|
||||||
for (l = cg->channels; l; l = l->next) {
|
for (l = cg->channels; l; l = l->next) {
|
||||||
ch = l->data;
|
ch = l->data;
|
||||||
|
@ -370,47 +363,31 @@ static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sd
|
||||||
ag->amplitude = g_variant_get_double(data);
|
ag->amplitude = g_variant_get_double(data);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case SR_CONF_CAPTURE_RATIO:
|
||||||
|
devc->capture_ratio = g_variant_get_uint64(data);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ret = SR_ERR_NA;
|
return SR_ERR_NA;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
|
static int config_list(uint32_t key, GVariant **data,
|
||||||
const struct sr_channel_group *cg)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
struct sr_channel *ch;
|
struct sr_channel *ch;
|
||||||
GVariant *gvar;
|
|
||||||
GVariantBuilder gvb;
|
|
||||||
|
|
||||||
if (key == SR_CONF_SCAN_OPTIONS) {
|
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
|
|
||||||
return SR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key == SR_CONF_DEVICE_OPTIONS && !sdi) {
|
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
drvopts, ARRAY_SIZE(drvopts), sizeof(uint32_t));
|
|
||||||
return SR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!sdi)
|
|
||||||
return SR_ERR_ARG;
|
|
||||||
|
|
||||||
if (!cg) {
|
if (!cg) {
|
||||||
switch (key) {
|
switch (key) {
|
||||||
|
case SR_CONF_SCAN_OPTIONS:
|
||||||
case SR_CONF_DEVICE_OPTIONS:
|
case SR_CONF_DEVICE_OPTIONS:
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
|
||||||
devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
|
|
||||||
break;
|
|
||||||
case SR_CONF_SAMPLERATE:
|
case SR_CONF_SAMPLERATE:
|
||||||
g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
|
*data = std_gvar_samplerates_steps(ARRAY_AND_SIZE(samplerates));
|
||||||
gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), samplerates,
|
break;
|
||||||
ARRAY_SIZE(samplerates), sizeof(uint64_t));
|
case SR_CONF_TRIGGER_MATCH:
|
||||||
g_variant_builder_add(&gvb, "{sv}", "samplerate-steps", gvar);
|
*data = std_gvar_array_i32(ARRAY_AND_SIZE(trigger_matches));
|
||||||
*data = g_variant_builder_end(&gvb);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return SR_ERR_NA;
|
return SR_ERR_NA;
|
||||||
|
@ -420,18 +397,12 @@ static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case SR_CONF_DEVICE_OPTIONS:
|
case SR_CONF_DEVICE_OPTIONS:
|
||||||
if (ch->type == SR_CHANNEL_LOGIC)
|
if (ch->type == SR_CHANNEL_LOGIC)
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
*data = std_gvar_array_u32(ARRAY_AND_SIZE(devopts_cg_logic));
|
||||||
devopts_cg_logic, ARRAY_SIZE(devopts_cg_logic),
|
|
||||||
sizeof(uint32_t));
|
|
||||||
else if (ch->type == SR_CHANNEL_ANALOG) {
|
else if (ch->type == SR_CHANNEL_ANALOG) {
|
||||||
if (strcmp(cg->name, "Analog") == 0)
|
if (strcmp(cg->name, "Analog") == 0)
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
*data = std_gvar_array_u32(ARRAY_AND_SIZE(devopts_cg_analog_group));
|
||||||
devopts_cg_analog_group, ARRAY_SIZE(devopts_cg_analog_group),
|
|
||||||
sizeof(uint32_t));
|
|
||||||
else
|
else
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
*data = std_gvar_array_u32(ARRAY_AND_SIZE(devopts_cg_analog_channel));
|
||||||
devopts_cg_analog_channel, ARRAY_SIZE(devopts_cg_analog_channel),
|
|
||||||
sizeof(uint32_t));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return SR_ERR_BUG;
|
return SR_ERR_BUG;
|
||||||
|
@ -442,11 +413,9 @@ static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *
|
||||||
return SR_ERR_NA;
|
return SR_ERR_NA;
|
||||||
|
|
||||||
if (ch->type == SR_CHANNEL_LOGIC)
|
if (ch->type == SR_CHANNEL_LOGIC)
|
||||||
*data = g_variant_new_strv(logic_pattern_str,
|
*data = g_variant_new_strv(ARRAY_AND_SIZE(logic_pattern_str));
|
||||||
ARRAY_SIZE(logic_pattern_str));
|
|
||||||
else if (ch->type == SR_CHANNEL_ANALOG)
|
else if (ch->type == SR_CHANNEL_ANALOG)
|
||||||
*data = g_variant_new_strv(analog_pattern_str,
|
*data = g_variant_new_strv(ARRAY_AND_SIZE(analog_pattern_str));
|
||||||
ARRAY_SIZE(analog_pattern_str));
|
|
||||||
else
|
else
|
||||||
return SR_ERR_BUG;
|
return SR_ERR_BUG;
|
||||||
break;
|
break;
|
||||||
|
@ -461,15 +430,82 @@ static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *
|
||||||
static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
|
GSList *l;
|
||||||
|
struct sr_channel *ch;
|
||||||
|
int bitpos;
|
||||||
|
uint8_t mask;
|
||||||
GHashTableIter iter;
|
GHashTableIter iter;
|
||||||
void *value;
|
void *value;
|
||||||
|
struct sr_trigger *trigger;
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
devc->sent_samples = 0;
|
devc->sent_samples = 0;
|
||||||
|
devc->sent_frame_samples = 0;
|
||||||
|
|
||||||
|
/* Setup triggers */
|
||||||
|
if ((trigger = sr_session_trigger_get(sdi->session))) {
|
||||||
|
int pre_trigger_samples = 0;
|
||||||
|
if (devc->limit_samples > 0)
|
||||||
|
pre_trigger_samples = (devc->capture_ratio * devc->limit_samples) / 100;
|
||||||
|
devc->stl = soft_trigger_logic_new(sdi, trigger, pre_trigger_samples);
|
||||||
|
if (!devc->stl)
|
||||||
|
return SR_ERR_MALLOC;
|
||||||
|
|
||||||
|
/* Disable all analog channels since using them when there are logic
|
||||||
|
* triggers set up would require having pre-trigger sample buffers
|
||||||
|
* for analog sample data.
|
||||||
|
*/
|
||||||
|
for (l = sdi->channels; l; l = l->next) {
|
||||||
|
ch = l->data;
|
||||||
|
if (ch->type == SR_CHANNEL_ANALOG)
|
||||||
|
ch->enabled = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
devc->trigger_fired = FALSE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine the numbers of logic and analog channels that are
|
||||||
|
* involved in the acquisition. Determine an offset and a mask to
|
||||||
|
* remove excess logic data content before datafeed submission.
|
||||||
|
*/
|
||||||
|
devc->enabled_logic_channels = 0;
|
||||||
|
devc->enabled_analog_channels = 0;
|
||||||
|
for (l = sdi->channels; l; l = l->next) {
|
||||||
|
ch = l->data;
|
||||||
|
if (!ch->enabled)
|
||||||
|
continue;
|
||||||
|
if (ch->type == SR_CHANNEL_ANALOG) {
|
||||||
|
devc->enabled_analog_channels++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ch->type != SR_CHANNEL_LOGIC)
|
||||||
|
continue;
|
||||||
|
/*
|
||||||
|
* TODO: Need we create a channel map here, such that the
|
||||||
|
* session datafeed packets will have a dense representation
|
||||||
|
* of the enabled channels' data? For example store channels
|
||||||
|
* D3 and D5 in bit positions 0 and 1 respectively, when all
|
||||||
|
* other channels are disabled? The current implementation
|
||||||
|
* generates a sparse layout, might provide data for logic
|
||||||
|
* channels that are disabled while it might suppress data
|
||||||
|
* from enabled channels at the same time.
|
||||||
|
*/
|
||||||
|
devc->enabled_logic_channels++;
|
||||||
|
}
|
||||||
|
devc->first_partial_logic_index = devc->enabled_logic_channels / 8;
|
||||||
|
bitpos = devc->enabled_logic_channels % 8;
|
||||||
|
mask = (1 << bitpos) - 1;
|
||||||
|
devc->first_partial_logic_mask = mask;
|
||||||
|
sr_dbg("num logic %zu, partial off %zu, mask 0x%02x.",
|
||||||
|
devc->enabled_logic_channels,
|
||||||
|
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);
|
g_hash_table_iter_init(&iter, devc->ch_ag);
|
||||||
while (g_hash_table_iter_next(&iter, NULL, &value))
|
while (g_hash_table_iter_next(&iter, NULL, &value))
|
||||||
demo_generate_analog_pattern(value, devc->cur_samplerate);
|
demo_generate_analog_pattern(value, devc->cur_samplerate);
|
||||||
|
@ -479,6 +515,9 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||||
|
|
||||||
std_session_send_df_header(sdi);
|
std_session_send_df_header(sdi);
|
||||||
|
|
||||||
|
if (devc->limit_frames > 0)
|
||||||
|
std_session_send_frame_begin(sdi);
|
||||||
|
|
||||||
/* We use this timestamp to decide how many more samples to send. */
|
/* We use this timestamp to decide how many more samples to send. */
|
||||||
devc->start_us = g_get_monotonic_time();
|
devc->start_us = g_get_monotonic_time();
|
||||||
devc->spent_us = 0;
|
devc->spent_us = 0;
|
||||||
|
@ -489,10 +528,21 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||||
|
|
||||||
static int dev_acquisition_stop(struct sr_dev_inst *sdi)
|
static int dev_acquisition_stop(struct sr_dev_inst *sdi)
|
||||||
{
|
{
|
||||||
sr_dbg("Stopping acquisition.");
|
struct dev_context *devc;
|
||||||
|
|
||||||
sr_session_source_remove(sdi->session, -1);
|
sr_session_source_remove(sdi->session, -1);
|
||||||
|
|
||||||
|
devc = sdi->priv;
|
||||||
|
if (devc->limit_frames > 0)
|
||||||
|
std_session_send_frame_end(sdi);
|
||||||
|
|
||||||
std_session_send_df_end(sdi);
|
std_session_send_df_end(sdi);
|
||||||
|
|
||||||
|
if (devc->stl) {
|
||||||
|
soft_trigger_logic_free(devc->stl);
|
||||||
|
devc->stl = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -508,8 +558,8 @@ static struct sr_dev_driver demo_driver_info = {
|
||||||
.config_get = config_get,
|
.config_get = config_get,
|
||||||
.config_set = config_set,
|
.config_set = config_set,
|
||||||
.config_list = config_list,
|
.config_list = config_list,
|
||||||
.dev_open = dev_open,
|
.dev_open = std_dummy_dev_open,
|
||||||
.dev_close = dev_close,
|
.dev_close = std_dummy_dev_close,
|
||||||
.dev_acquisition_start = dev_acquisition_start,
|
.dev_acquisition_start = dev_acquisition_start,
|
||||||
.dev_acquisition_stop = dev_acquisition_stop,
|
.dev_acquisition_stop = dev_acquisition_stop,
|
||||||
.context = NULL,
|
.context = NULL,
|
||||||
|
|
|
@ -245,6 +245,19 @@ SR_PRIV void demo_generate_analog_pattern(struct analog_gen *ag, uint64_t sample
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint64_t encode_number_to_gray(uint64_t nr)
|
||||||
|
{
|
||||||
|
return nr ^ (nr >> 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_logic_data(uint64_t bits, uint8_t *data, size_t len)
|
||||||
|
{
|
||||||
|
while (len--) {
|
||||||
|
*data++ = bits & 0xff;
|
||||||
|
bits >>= 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void logic_generator(struct sr_dev_inst *sdi, uint64_t size)
|
static void logic_generator(struct sr_dev_inst *sdi, uint64_t size)
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
|
@ -253,6 +266,7 @@ static void logic_generator(struct sr_dev_inst *sdi, uint64_t size)
|
||||||
uint8_t *sample;
|
uint8_t *sample;
|
||||||
const uint8_t *image_col;
|
const uint8_t *image_col;
|
||||||
size_t col_count, col_height;
|
size_t col_count, col_height;
|
||||||
|
uint64_t gray;
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
|
@ -273,9 +287,8 @@ static void logic_generator(struct sr_dev_inst *sdi, uint64_t size)
|
||||||
break;
|
break;
|
||||||
case PATTERN_INC:
|
case PATTERN_INC:
|
||||||
for (i = 0; i < size; i++) {
|
for (i = 0; i < size; i++) {
|
||||||
for (j = 0; j < devc->logic_unitsize; j++) {
|
for (j = 0; j < devc->logic_unitsize; j++)
|
||||||
devc->logic_data[i + j] = devc->step;
|
devc->logic_data[i + j] = devc->step;
|
||||||
}
|
|
||||||
devc->step++;
|
devc->step++;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -327,12 +340,49 @@ static void logic_generator(struct sr_dev_inst *sdi, uint64_t size)
|
||||||
devc->step %= col_count;
|
devc->step %= col_count;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case PATTERN_GRAYCODE:
|
||||||
|
for (i = 0; i < size; i += devc->logic_unitsize) {
|
||||||
|
devc->step++;
|
||||||
|
devc->step &= devc->all_logic_channels_mask;
|
||||||
|
gray = encode_number_to_gray(devc->step);
|
||||||
|
gray &= devc->all_logic_channels_mask;
|
||||||
|
set_logic_data(gray, &devc->logic_data[i], devc->logic_unitsize);
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
sr_err("Unknown pattern: %d.", devc->logic_pattern);
|
sr_err("Unknown pattern: %d.", devc->logic_pattern);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fixup a memory image of generated logic data before it gets sent to
|
||||||
|
* the session's datafeed. Mask out content from disabled channels.
|
||||||
|
*
|
||||||
|
* TODO: Need we apply a channel map, and enforce a dense representation
|
||||||
|
* of the enabled channels' data?
|
||||||
|
*/
|
||||||
|
static void logic_fixup_feed(struct dev_context *devc,
|
||||||
|
struct sr_datafeed_logic *logic)
|
||||||
|
{
|
||||||
|
size_t fp_off;
|
||||||
|
uint8_t fp_mask;
|
||||||
|
size_t off, idx;
|
||||||
|
uint8_t *sample;
|
||||||
|
|
||||||
|
fp_off = devc->first_partial_logic_index;
|
||||||
|
fp_mask = devc->first_partial_logic_mask;
|
||||||
|
if (fp_off == logic->unitsize)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (off = 0; off < logic->length; off += logic->unitsize) {
|
||||||
|
sample = logic->data + off;
|
||||||
|
sample[fp_off] &= fp_mask;
|
||||||
|
for (idx = fp_off + 1; idx < logic->unitsize; idx++)
|
||||||
|
sample[idx] = 0x00;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void send_analog_packet(struct analog_gen *ag,
|
static void send_analog_packet(struct analog_gen *ag,
|
||||||
struct sr_dev_inst *sdi, uint64_t *analog_sent,
|
struct sr_dev_inst *sdi, uint64_t *analog_sent,
|
||||||
uint64_t analog_pos, uint64_t analog_todo)
|
uint64_t analog_pos, uint64_t analog_todo)
|
||||||
|
@ -343,13 +393,16 @@ static void send_analog_packet(struct analog_gen *ag,
|
||||||
int ag_pattern_pos;
|
int ag_pattern_pos;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
|
if (!ag->ch || !ag->ch->enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
packet.type = SR_DF_ANALOG;
|
packet.type = SR_DF_ANALOG;
|
||||||
packet.payload = &ag->packet;
|
packet.payload = &ag->packet;
|
||||||
|
|
||||||
if (!devc->avg) {
|
if (!devc->avg) {
|
||||||
ag_pattern_pos = analog_pos % ag->num_samples;
|
ag_pattern_pos = analog_pos % ag->num_samples;
|
||||||
sending_now = MIN(analog_todo, ag->num_samples-ag_pattern_pos);
|
sending_now = MIN(analog_todo, ag->num_samples - ag_pattern_pos);
|
||||||
ag->packet.data = ag->pattern_data + ag_pattern_pos;
|
ag->packet.data = ag->pattern_data + ag_pattern_pos;
|
||||||
ag->packet.num_samples = sending_now;
|
ag->packet.num_samples = sending_now;
|
||||||
sr_session_send(sdi, &packet);
|
sr_session_send(sdi, &packet);
|
||||||
|
@ -358,7 +411,7 @@ static void send_analog_packet(struct analog_gen *ag,
|
||||||
*analog_sent = MAX(*analog_sent, sending_now);
|
*analog_sent = MAX(*analog_sent, sending_now);
|
||||||
} else {
|
} else {
|
||||||
ag_pattern_pos = analog_pos % ag->num_samples;
|
ag_pattern_pos = analog_pos % ag->num_samples;
|
||||||
to_avg = MIN(analog_todo, ag->num_samples-ag_pattern_pos);
|
to_avg = MIN(analog_todo, ag->num_samples - ag_pattern_pos);
|
||||||
|
|
||||||
for (i = 0; i < to_avg; i++) {
|
for (i = 0; i < to_avg; i++) {
|
||||||
ag->avg_val = (ag->avg_val +
|
ag->avg_val = (ag->avg_val +
|
||||||
|
@ -366,8 +419,7 @@ static void send_analog_packet(struct analog_gen *ag,
|
||||||
ag_pattern_pos + i)) / 2;
|
ag_pattern_pos + i)) / 2;
|
||||||
ag->num_avgs++;
|
ag->num_avgs++;
|
||||||
/* Time to send averaged data? */
|
/* Time to send averaged data? */
|
||||||
if (devc->avg_samples > 0 &&
|
if ((devc->avg_samples > 0) && (ag->num_avgs >= devc->avg_samples))
|
||||||
ag->num_avgs >= devc->avg_samples)
|
|
||||||
goto do_send;
|
goto do_send;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -403,6 +455,8 @@ SR_PRIV int demo_prepare_data(int fd, int revents, void *cb_data)
|
||||||
void *value;
|
void *value;
|
||||||
uint64_t samples_todo, logic_done, analog_done, analog_sent, sending_now;
|
uint64_t samples_todo, logic_done, analog_done, analog_sent, sending_now;
|
||||||
int64_t elapsed_us, limit_us, todo_us;
|
int64_t elapsed_us, limit_us, todo_us;
|
||||||
|
int64_t trigger_offset;
|
||||||
|
int pre_trigger_samples;
|
||||||
|
|
||||||
(void)fd;
|
(void)fd;
|
||||||
(void)revents;
|
(void)revents;
|
||||||
|
@ -414,7 +468,7 @@ SR_PRIV int demo_prepare_data(int fd, int revents, void *cb_data)
|
||||||
if (devc->cur_samplerate <= 0
|
if (devc->cur_samplerate <= 0
|
||||||
|| (devc->num_logic_channels <= 0
|
|| (devc->num_logic_channels <= 0
|
||||||
&& devc->num_analog_channels <= 0)) {
|
&& devc->num_analog_channels <= 0)) {
|
||||||
sdi->driver->dev_acquisition_stop(sdi);
|
sr_dev_acquisition_stop(sdi);
|
||||||
return G_SOURCE_CONTINUE;
|
return G_SOURCE_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -429,12 +483,25 @@ SR_PRIV int demo_prepare_data(int fd, int revents, void *cb_data)
|
||||||
/* How many samples are outstanding since the last round? */
|
/* How many samples are outstanding since the last round? */
|
||||||
samples_todo = (todo_us * devc->cur_samplerate + G_USEC_PER_SEC - 1)
|
samples_todo = (todo_us * devc->cur_samplerate + G_USEC_PER_SEC - 1)
|
||||||
/ G_USEC_PER_SEC;
|
/ G_USEC_PER_SEC;
|
||||||
|
|
||||||
if (devc->limit_samples > 0) {
|
if (devc->limit_samples > 0) {
|
||||||
if (devc->limit_samples < devc->sent_samples)
|
if (devc->limit_samples < devc->sent_samples)
|
||||||
samples_todo = 0;
|
samples_todo = 0;
|
||||||
else if (devc->limit_samples - devc->sent_samples < samples_todo)
|
else if (devc->limit_samples - devc->sent_samples < samples_todo)
|
||||||
samples_todo = devc->limit_samples - devc->sent_samples;
|
samples_todo = devc->limit_samples - devc->sent_samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (samples_todo == 0)
|
||||||
|
return G_SOURCE_CONTINUE;
|
||||||
|
|
||||||
|
if (devc->limit_frames) {
|
||||||
|
/* Never send more samples than a frame can fit... */
|
||||||
|
samples_todo = MIN(samples_todo, SAMPLES_PER_FRAME);
|
||||||
|
/* ...or than we need to finish the current frame. */
|
||||||
|
samples_todo = MIN(samples_todo,
|
||||||
|
SAMPLES_PER_FRAME - devc->sent_frame_samples);
|
||||||
|
}
|
||||||
|
|
||||||
/* Calculate the actual time covered by this run back from the sample
|
/* Calculate the actual time covered by this run back from the sample
|
||||||
* count, rounded towards zero. This avoids getting stuck on a too-low
|
* count, rounded towards zero. This avoids getting stuck on a too-low
|
||||||
* time delta with no samples being sent due to round-off.
|
* time delta with no samples being sent due to round-off.
|
||||||
|
@ -442,7 +509,12 @@ SR_PRIV int demo_prepare_data(int fd, int revents, void *cb_data)
|
||||||
todo_us = samples_todo * G_USEC_PER_SEC / devc->cur_samplerate;
|
todo_us = samples_todo * G_USEC_PER_SEC / devc->cur_samplerate;
|
||||||
|
|
||||||
logic_done = devc->num_logic_channels > 0 ? 0 : samples_todo;
|
logic_done = devc->num_logic_channels > 0 ? 0 : samples_todo;
|
||||||
|
if (!devc->enabled_logic_channels)
|
||||||
|
logic_done = samples_todo;
|
||||||
|
|
||||||
analog_done = devc->num_analog_channels > 0 ? 0 : samples_todo;
|
analog_done = devc->num_analog_channels > 0 ? 0 : samples_todo;
|
||||||
|
if (!devc->enabled_analog_channels)
|
||||||
|
analog_done = samples_todo;
|
||||||
|
|
||||||
while (logic_done < samples_todo || analog_done < samples_todo) {
|
while (logic_done < samples_todo || analog_done < samples_todo) {
|
||||||
/* Logic */
|
/* Logic */
|
||||||
|
@ -450,14 +522,48 @@ SR_PRIV int demo_prepare_data(int fd, int revents, void *cb_data)
|
||||||
sending_now = MIN(samples_todo - logic_done,
|
sending_now = MIN(samples_todo - logic_done,
|
||||||
LOGIC_BUFSIZE / devc->logic_unitsize);
|
LOGIC_BUFSIZE / devc->logic_unitsize);
|
||||||
logic_generator(sdi, sending_now * devc->logic_unitsize);
|
logic_generator(sdi, sending_now * devc->logic_unitsize);
|
||||||
|
/* Check for trigger and send pre-trigger data if needed */
|
||||||
|
if (devc->stl && (!devc->trigger_fired)) {
|
||||||
|
trigger_offset = soft_trigger_logic_check(devc->stl,
|
||||||
|
devc->logic_data, sending_now * devc->logic_unitsize,
|
||||||
|
&pre_trigger_samples);
|
||||||
|
if (trigger_offset > -1) {
|
||||||
|
devc->trigger_fired = TRUE;
|
||||||
|
logic_done = pre_trigger_samples;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
trigger_offset = 0;
|
||||||
|
|
||||||
|
/* Send logic samples if needed */
|
||||||
packet.type = SR_DF_LOGIC;
|
packet.type = SR_DF_LOGIC;
|
||||||
packet.payload = &logic;
|
packet.payload = &logic;
|
||||||
logic.length = sending_now * devc->logic_unitsize;
|
|
||||||
logic.unitsize = devc->logic_unitsize;
|
logic.unitsize = devc->logic_unitsize;
|
||||||
|
|
||||||
|
if (devc->stl) {
|
||||||
|
if (devc->trigger_fired && (trigger_offset < (int)sending_now)) {
|
||||||
|
/* Send after-trigger data */
|
||||||
|
logic.length = (sending_now - trigger_offset) * devc->logic_unitsize;
|
||||||
|
logic.data = devc->logic_data + trigger_offset * devc->logic_unitsize;
|
||||||
|
logic_fixup_feed(devc, &logic);
|
||||||
|
sr_session_send(sdi, &packet);
|
||||||
|
logic_done += sending_now - trigger_offset;
|
||||||
|
/* End acquisition */
|
||||||
|
sr_dbg("Triggered, stopping acquisition.");
|
||||||
|
sr_dev_acquisition_stop(sdi);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
/* Send nothing */
|
||||||
|
logic_done += sending_now;
|
||||||
|
}
|
||||||
|
} else if (!devc->stl) {
|
||||||
|
/* No trigger defined, send logic samples */
|
||||||
|
logic.length = sending_now * devc->logic_unitsize;
|
||||||
logic.data = devc->logic_data;
|
logic.data = devc->logic_data;
|
||||||
|
logic_fixup_feed(devc, &logic);
|
||||||
sr_session_send(sdi, &packet);
|
sr_session_send(sdi, &packet);
|
||||||
logic_done += sending_now;
|
logic_done += sending_now;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Analog, one channel at a time */
|
/* Analog, one channel at a time */
|
||||||
if (analog_done < samples_todo) {
|
if (analog_done < samples_todo) {
|
||||||
|
@ -472,21 +578,27 @@ SR_PRIV int demo_prepare_data(int fd, int revents, void *cb_data)
|
||||||
analog_done += analog_sent;
|
analog_done += analog_sent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* At this point, both logic_done and analog_done should be
|
|
||||||
* exactly equal to samples_todo, or else.
|
uint64_t min = MIN(logic_done, analog_done);
|
||||||
*/
|
devc->sent_samples += min;
|
||||||
if (logic_done != samples_todo || analog_done != samples_todo) {
|
devc->sent_frame_samples += min;
|
||||||
sr_err("BUG: Sample count mismatch.");
|
|
||||||
return G_SOURCE_REMOVE;
|
|
||||||
}
|
|
||||||
devc->sent_samples += samples_todo;
|
|
||||||
devc->spent_us += todo_us;
|
devc->spent_us += todo_us;
|
||||||
|
|
||||||
|
if (devc->limit_frames && devc->sent_frame_samples >= SAMPLES_PER_FRAME) {
|
||||||
|
std_session_send_frame_end(sdi);
|
||||||
|
devc->sent_frame_samples = 0;
|
||||||
|
devc->limit_frames--;
|
||||||
|
if (!devc->limit_frames) {
|
||||||
|
sr_dbg("Requested number of frames reached.");
|
||||||
|
sr_dev_acquisition_stop(sdi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ((devc->limit_samples > 0 && devc->sent_samples >= devc->limit_samples)
|
if ((devc->limit_samples > 0 && devc->sent_samples >= devc->limit_samples)
|
||||||
|| (limit_us > 0 && devc->spent_us >= limit_us)) {
|
|| (limit_us > 0 && devc->spent_us >= limit_us)) {
|
||||||
|
|
||||||
/* If we're averaging everything - now is the time to send data */
|
/* If we're averaging everything - now is the time to send data */
|
||||||
if (devc->avg_samples == 0) {
|
if (devc->avg && devc->avg_samples == 0) {
|
||||||
g_hash_table_iter_init(&iter, devc->ch_ag);
|
g_hash_table_iter_init(&iter, devc->ch_ag);
|
||||||
while (g_hash_table_iter_next(&iter, NULL, &value)) {
|
while (g_hash_table_iter_next(&iter, NULL, &value)) {
|
||||||
ag = value;
|
ag = value;
|
||||||
|
@ -498,7 +610,10 @@ SR_PRIV int demo_prepare_data(int fd, int revents, void *cb_data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sr_dbg("Requested number of samples reached.");
|
sr_dbg("Requested number of samples reached.");
|
||||||
sdi->driver->dev_acquisition_stop(sdi);
|
sr_dev_acquisition_stop(sdi);
|
||||||
|
} else if (devc->limit_frames) {
|
||||||
|
if (devc->sent_frame_samples == 0)
|
||||||
|
std_session_send_frame_begin(sdi);
|
||||||
}
|
}
|
||||||
|
|
||||||
return G_SOURCE_CONTINUE;
|
return G_SOURCE_CONTINUE;
|
||||||
|
|
|
@ -33,31 +33,12 @@
|
||||||
#define LOGIC_BUFSIZE 4096
|
#define LOGIC_BUFSIZE 4096
|
||||||
/* Size of the analog pattern space per channel. */
|
/* Size of the analog pattern space per channel. */
|
||||||
#define ANALOG_BUFSIZE 4096
|
#define ANALOG_BUFSIZE 4096
|
||||||
|
/* This is a development feature: it starts a new frame every n samples. */
|
||||||
/* Private, per-device-instance driver context. */
|
#define SAMPLES_PER_FRAME 1000UL
|
||||||
struct dev_context {
|
#define DEFAULT_LIMIT_FRAMES 0
|
||||||
uint64_t cur_samplerate;
|
|
||||||
uint64_t limit_samples;
|
|
||||||
uint64_t limit_msec;
|
|
||||||
uint64_t sent_samples;
|
|
||||||
int64_t start_us;
|
|
||||||
int64_t spent_us;
|
|
||||||
uint64_t step;
|
|
||||||
/* Logic */
|
|
||||||
int32_t num_logic_channels;
|
|
||||||
unsigned int logic_unitsize;
|
|
||||||
/* There is only ever one logic channel group, so its pattern goes here. */
|
|
||||||
uint8_t logic_pattern;
|
|
||||||
unsigned char logic_data[LOGIC_BUFSIZE];
|
|
||||||
/* Analog */
|
|
||||||
int32_t num_analog_channels;
|
|
||||||
GHashTable *ch_ag;
|
|
||||||
gboolean avg; /* True if averaging is enabled */
|
|
||||||
uint64_t avg_samples;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Logic patterns we can generate. */
|
/* Logic patterns we can generate. */
|
||||||
enum {
|
enum logic_pattern_type {
|
||||||
/**
|
/**
|
||||||
* Spells "sigrok" across 8 channels using '0's (with '1's as
|
* Spells "sigrok" across 8 channels using '0's (with '1's as
|
||||||
* "background") when displayed using the 'bits' output format.
|
* "background") when displayed using the 'bits' output format.
|
||||||
|
@ -97,19 +78,51 @@ enum {
|
||||||
* something that can get recognized.
|
* something that can get recognized.
|
||||||
*/
|
*/
|
||||||
PATTERN_SQUID,
|
PATTERN_SQUID,
|
||||||
|
|
||||||
|
/** Gray encoded data, like rotary encoder signals. */
|
||||||
|
PATTERN_GRAYCODE,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Analog patterns we can generate. */
|
/* Analog patterns we can generate. */
|
||||||
enum {
|
enum analog_pattern_type {
|
||||||
/**
|
|
||||||
* Square wave.
|
|
||||||
*/
|
|
||||||
PATTERN_SQUARE,
|
PATTERN_SQUARE,
|
||||||
PATTERN_SINE,
|
PATTERN_SINE,
|
||||||
PATTERN_TRIANGLE,
|
PATTERN_TRIANGLE,
|
||||||
PATTERN_SAWTOOTH,
|
PATTERN_SAWTOOTH,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct dev_context {
|
||||||
|
uint64_t cur_samplerate;
|
||||||
|
uint64_t limit_samples;
|
||||||
|
uint64_t limit_msec;
|
||||||
|
uint64_t limit_frames;
|
||||||
|
uint64_t sent_samples;
|
||||||
|
uint64_t sent_frame_samples; /* Number of samples that were sent for current frame. */
|
||||||
|
int64_t start_us;
|
||||||
|
int64_t spent_us;
|
||||||
|
uint64_t step;
|
||||||
|
/* Logic */
|
||||||
|
int32_t num_logic_channels;
|
||||||
|
size_t logic_unitsize;
|
||||||
|
uint64_t all_logic_channels_mask;
|
||||||
|
/* There is only ever one logic channel group, so its pattern goes here. */
|
||||||
|
enum logic_pattern_type logic_pattern;
|
||||||
|
uint8_t logic_data[LOGIC_BUFSIZE];
|
||||||
|
/* Analog */
|
||||||
|
int32_t num_analog_channels;
|
||||||
|
GHashTable *ch_ag;
|
||||||
|
gboolean avg; /* True if averaging is enabled */
|
||||||
|
uint64_t avg_samples;
|
||||||
|
size_t enabled_logic_channels;
|
||||||
|
size_t enabled_analog_channels;
|
||||||
|
size_t first_partial_logic_index;
|
||||||
|
uint8_t first_partial_logic_mask;
|
||||||
|
/* Triggers */
|
||||||
|
uint64_t capture_ratio;
|
||||||
|
gboolean trigger_fired;
|
||||||
|
struct soft_trigger_logic *stl;
|
||||||
|
};
|
||||||
|
|
||||||
static const char *analog_pattern_str[] = {
|
static const char *analog_pattern_str[] = {
|
||||||
"square",
|
"square",
|
||||||
"sine",
|
"sine",
|
||||||
|
@ -118,7 +131,8 @@ static const char *analog_pattern_str[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct analog_gen {
|
struct analog_gen {
|
||||||
int pattern;
|
struct sr_channel *ch;
|
||||||
|
enum analog_pattern_type pattern;
|
||||||
float amplitude;
|
float amplitude;
|
||||||
float pattern_data[ANALOG_BUFSIZE];
|
float pattern_data[ANALOG_BUFSIZE];
|
||||||
unsigned int num_samples;
|
unsigned int num_samples;
|
||||||
|
@ -127,7 +141,7 @@ struct analog_gen {
|
||||||
struct sr_analog_meaning meaning;
|
struct sr_analog_meaning meaning;
|
||||||
struct sr_analog_spec spec;
|
struct sr_analog_spec spec;
|
||||||
float avg_val; /* Average value */
|
float avg_val; /* Average value */
|
||||||
unsigned num_avgs; /* Number of samples averaged */
|
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 analog_gen *ag, uint64_t sample_rate);
|
||||||
|
|
|
@ -0,0 +1,565 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the libsigrok project.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
|
||||||
|
* Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
|
||||||
|
*
|
||||||
|
* 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 "protocol.h"
|
||||||
|
|
||||||
|
static const struct dslogic_profile supported_device[] = {
|
||||||
|
/* DreamSourceLab DSLogic */
|
||||||
|
{ 0x2a0e, 0x0001, "DreamSourceLab", "DSLogic", NULL,
|
||||||
|
"dreamsourcelab-dslogic-fx2.fw",
|
||||||
|
0, "DreamSourceLab", "DSLogic", 256 * 1024 * 1024},
|
||||||
|
/* DreamSourceLab DSCope */
|
||||||
|
{ 0x2a0e, 0x0002, "DreamSourceLab", "DSCope", NULL,
|
||||||
|
"dreamsourcelab-dscope-fx2.fw",
|
||||||
|
0, "DreamSourceLab", "DSCope", 256 * 1024 * 1024},
|
||||||
|
/* DreamSourceLab DSLogic Pro */
|
||||||
|
{ 0x2a0e, 0x0003, "DreamSourceLab", "DSLogic Pro", NULL,
|
||||||
|
"dreamsourcelab-dslogic-pro-fx2.fw",
|
||||||
|
0, "DreamSourceLab", "DSLogic", 256 * 1024 * 1024},
|
||||||
|
/* DreamSourceLab DSLogic Plus */
|
||||||
|
{ 0x2a0e, 0x0020, "DreamSourceLab", "DSLogic Plus", NULL,
|
||||||
|
"dreamsourcelab-dslogic-plus-fx2.fw",
|
||||||
|
0, "DreamSourceLab", "DSLogic", 256 * 1024 * 1024},
|
||||||
|
/* DreamSourceLab DSLogic Basic */
|
||||||
|
{ 0x2a0e, 0x0021, "DreamSourceLab", "DSLogic Basic", NULL,
|
||||||
|
"dreamsourcelab-dslogic-basic-fx2.fw",
|
||||||
|
0, "DreamSourceLab", "DSLogic", 256 * 1024},
|
||||||
|
|
||||||
|
ALL_ZERO
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t scanopts[] = {
|
||||||
|
SR_CONF_CONN,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t drvopts[] = {
|
||||||
|
SR_CONF_LOGIC_ANALYZER,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t devopts[] = {
|
||||||
|
SR_CONF_CONTINUOUS | SR_CONF_SET | SR_CONF_GET,
|
||||||
|
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
|
||||||
|
SR_CONF_VOLTAGE_THRESHOLD | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
|
||||||
|
SR_CONF_CONN | SR_CONF_GET,
|
||||||
|
SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
|
||||||
|
SR_CONF_TRIGGER_MATCH | SR_CONF_LIST,
|
||||||
|
SR_CONF_CAPTURE_RATIO | SR_CONF_GET | SR_CONF_SET,
|
||||||
|
SR_CONF_EXTERNAL_CLOCK | SR_CONF_GET | SR_CONF_SET,
|
||||||
|
SR_CONF_CLOCK_EDGE | 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,
|
||||||
|
SR_TRIGGER_EDGE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *signal_edges[] = {
|
||||||
|
[DS_EDGE_RISING] = "rising",
|
||||||
|
[DS_EDGE_FALLING] = "falling",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const double thresholds[][2] = {
|
||||||
|
{ 0.7, 1.4 },
|
||||||
|
{ 1.4, 3.6 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint64_t samplerates[] = {
|
||||||
|
SR_KHZ(10),
|
||||||
|
SR_KHZ(20),
|
||||||
|
SR_KHZ(50),
|
||||||
|
SR_KHZ(100),
|
||||||
|
SR_KHZ(200),
|
||||||
|
SR_KHZ(500),
|
||||||
|
SR_MHZ(1),
|
||||||
|
SR_MHZ(2),
|
||||||
|
SR_MHZ(5),
|
||||||
|
SR_MHZ(10),
|
||||||
|
SR_MHZ(20),
|
||||||
|
SR_MHZ(25),
|
||||||
|
SR_MHZ(50),
|
||||||
|
SR_MHZ(100),
|
||||||
|
SR_MHZ(200),
|
||||||
|
SR_MHZ(400),
|
||||||
|
};
|
||||||
|
|
||||||
|
static gboolean is_plausible(const struct libusb_device_descriptor *des)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; supported_device[i].vid; i++) {
|
||||||
|
if (des->idVendor != supported_device[i].vid)
|
||||||
|
continue;
|
||||||
|
if (des->idProduct == supported_device[i].pid)
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
|
{
|
||||||
|
struct drv_context *drvc;
|
||||||
|
struct dev_context *devc;
|
||||||
|
struct sr_dev_inst *sdi;
|
||||||
|
struct sr_usb_dev_inst *usb;
|
||||||
|
struct sr_channel *ch;
|
||||||
|
struct sr_channel_group *cg;
|
||||||
|
struct sr_config *src;
|
||||||
|
const struct dslogic_profile *prof;
|
||||||
|
GSList *l, *devices, *conn_devices;
|
||||||
|
gboolean has_firmware;
|
||||||
|
struct libusb_device_descriptor des;
|
||||||
|
libusb_device **devlist;
|
||||||
|
struct libusb_device_handle *hdl;
|
||||||
|
int ret, i, j;
|
||||||
|
const char *conn;
|
||||||
|
char manufacturer[64], product[64], serial_num[64], connection_id[64];
|
||||||
|
char channel_name[16];
|
||||||
|
|
||||||
|
drvc = di->context;
|
||||||
|
|
||||||
|
conn = 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (conn)
|
||||||
|
conn_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn);
|
||||||
|
else
|
||||||
|
conn_devices = NULL;
|
||||||
|
|
||||||
|
/* Find all DSLogic compatible devices and upload firmware to them. */
|
||||||
|
devices = NULL;
|
||||||
|
libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
|
||||||
|
for (i = 0; devlist[i]; i++) {
|
||||||
|
if (conn) {
|
||||||
|
usb = NULL;
|
||||||
|
for (l = conn_devices; l; l = l->next) {
|
||||||
|
usb = l->data;
|
||||||
|
if (usb->bus == libusb_get_bus_number(devlist[i])
|
||||||
|
&& usb->address == libusb_get_device_address(devlist[i]))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!l)
|
||||||
|
/* This device matched none of the ones that
|
||||||
|
* matched the conn specification. */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
libusb_get_device_descriptor(devlist[i], &des);
|
||||||
|
|
||||||
|
if (!is_plausible(&des))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((ret = libusb_open(devlist[i], &hdl)) < 0) {
|
||||||
|
sr_warn("Failed to open potential device with "
|
||||||
|
"VID:PID %04x:%04x: %s.", des.idVendor,
|
||||||
|
des.idProduct, libusb_error_name(ret));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (des.iManufacturer == 0) {
|
||||||
|
manufacturer[0] = '\0';
|
||||||
|
} else if ((ret = libusb_get_string_descriptor_ascii(hdl,
|
||||||
|
des.iManufacturer, (unsigned char *) manufacturer,
|
||||||
|
sizeof(manufacturer))) < 0) {
|
||||||
|
sr_warn("Failed to get manufacturer string descriptor: %s.",
|
||||||
|
libusb_error_name(ret));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (des.iProduct == 0) {
|
||||||
|
product[0] = '\0';
|
||||||
|
} else if ((ret = libusb_get_string_descriptor_ascii(hdl,
|
||||||
|
des.iProduct, (unsigned char *) product,
|
||||||
|
sizeof(product))) < 0) {
|
||||||
|
sr_warn("Failed to get product string descriptor: %s.",
|
||||||
|
libusb_error_name(ret));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (des.iSerialNumber == 0) {
|
||||||
|
serial_num[0] = '\0';
|
||||||
|
} else if ((ret = libusb_get_string_descriptor_ascii(hdl,
|
||||||
|
des.iSerialNumber, (unsigned char *) serial_num,
|
||||||
|
sizeof(serial_num))) < 0) {
|
||||||
|
sr_warn("Failed to get serial number string descriptor: %s.",
|
||||||
|
libusb_error_name(ret));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
libusb_close(hdl);
|
||||||
|
|
||||||
|
if (usb_get_port_path(devlist[i], connection_id, sizeof(connection_id)) < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
prof = NULL;
|
||||||
|
for (j = 0; supported_device[j].vid; j++) {
|
||||||
|
if (des.idVendor == supported_device[j].vid &&
|
||||||
|
des.idProduct == supported_device[j].pid) {
|
||||||
|
prof = &supported_device[j];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!prof)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
sdi = g_malloc0(sizeof(struct sr_dev_inst));
|
||||||
|
sdi->status = SR_ST_INITIALIZING;
|
||||||
|
sdi->vendor = g_strdup(prof->vendor);
|
||||||
|
sdi->model = g_strdup(prof->model);
|
||||||
|
sdi->version = g_strdup(prof->model_version);
|
||||||
|
sdi->serial_num = g_strdup(serial_num);
|
||||||
|
sdi->connection_id = g_strdup(connection_id);
|
||||||
|
|
||||||
|
/* Logic channels, all in one channel group. */
|
||||||
|
cg = g_malloc0(sizeof(struct sr_channel_group));
|
||||||
|
cg->name = g_strdup("Logic");
|
||||||
|
for (j = 0; j < NUM_CHANNELS; j++) {
|
||||||
|
sprintf(channel_name, "%d", j);
|
||||||
|
ch = sr_channel_new(sdi, j, SR_CHANNEL_LOGIC,
|
||||||
|
TRUE, channel_name);
|
||||||
|
cg->channels = g_slist_append(cg->channels, ch);
|
||||||
|
}
|
||||||
|
sdi->channel_groups = g_slist_append(NULL, cg);
|
||||||
|
|
||||||
|
devc = dslogic_dev_new();
|
||||||
|
devc->profile = prof;
|
||||||
|
sdi->priv = devc;
|
||||||
|
devices = g_slist_append(devices, sdi);
|
||||||
|
|
||||||
|
devc->samplerates = samplerates;
|
||||||
|
devc->num_samplerates = ARRAY_SIZE(samplerates);
|
||||||
|
has_firmware = usb_match_manuf_prod(devlist[i], "DreamSourceLab", "USB-based Instrument");
|
||||||
|
|
||||||
|
if (has_firmware) {
|
||||||
|
/* Already has the firmware, so fix the new address. */
|
||||||
|
sr_dbg("Found a DSLogic device.");
|
||||||
|
sdi->status = SR_ST_INACTIVE;
|
||||||
|
sdi->inst_type = SR_INST_USB;
|
||||||
|
sdi->conn = sr_usb_dev_inst_new(libusb_get_bus_number(devlist[i]),
|
||||||
|
libusb_get_device_address(devlist[i]), NULL);
|
||||||
|
} else {
|
||||||
|
if (ezusb_upload_firmware(drvc->sr_ctx, devlist[i],
|
||||||
|
USB_CONFIGURATION, prof->firmware) == SR_OK) {
|
||||||
|
/* Store when this device's FW was updated. */
|
||||||
|
devc->fw_updated = g_get_monotonic_time();
|
||||||
|
} else {
|
||||||
|
sr_err("Firmware upload failed for "
|
||||||
|
"device %d.%d (logical), name %s.",
|
||||||
|
libusb_get_bus_number(devlist[i]),
|
||||||
|
libusb_get_device_address(devlist[i]),
|
||||||
|
prof->firmware);
|
||||||
|
}
|
||||||
|
sdi->inst_type = SR_INST_USB;
|
||||||
|
sdi->conn = sr_usb_dev_inst_new(libusb_get_bus_number(devlist[i]),
|
||||||
|
0xff, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
libusb_free_device_list(devlist, 1);
|
||||||
|
g_slist_free_full(conn_devices, (GDestroyNotify)sr_usb_dev_inst_free);
|
||||||
|
|
||||||
|
return std_scan_complete(di, devices);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dev_open(struct sr_dev_inst *sdi)
|
||||||
|
{
|
||||||
|
struct sr_dev_driver *di = sdi->driver;
|
||||||
|
struct sr_usb_dev_inst *usb;
|
||||||
|
struct dev_context *devc;
|
||||||
|
int ret;
|
||||||
|
int64_t timediff_us, timediff_ms;
|
||||||
|
|
||||||
|
devc = sdi->priv;
|
||||||
|
usb = sdi->conn;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the firmware was recently uploaded, wait up to MAX_RENUM_DELAY_MS
|
||||||
|
* milliseconds for the FX2 to renumerate.
|
||||||
|
*/
|
||||||
|
ret = SR_ERR;
|
||||||
|
if (devc->fw_updated > 0) {
|
||||||
|
sr_info("Waiting for device to reset.");
|
||||||
|
/* Takes >= 300ms for the FX2 to be gone from the USB bus. */
|
||||||
|
g_usleep(300 * 1000);
|
||||||
|
timediff_ms = 0;
|
||||||
|
while (timediff_ms < MAX_RENUM_DELAY_MS) {
|
||||||
|
if ((ret = dslogic_dev_open(sdi, di)) == SR_OK)
|
||||||
|
break;
|
||||||
|
g_usleep(100 * 1000);
|
||||||
|
|
||||||
|
timediff_us = g_get_monotonic_time() - devc->fw_updated;
|
||||||
|
timediff_ms = timediff_us / 1000;
|
||||||
|
sr_spew("Waited %" PRIi64 "ms.", timediff_ms);
|
||||||
|
}
|
||||||
|
if (ret != SR_OK) {
|
||||||
|
sr_err("Device failed to renumerate.");
|
||||||
|
return SR_ERR;
|
||||||
|
}
|
||||||
|
sr_info("Device came back after %" PRIi64 "ms.", timediff_ms);
|
||||||
|
} else {
|
||||||
|
sr_info("Firmware upload was not needed.");
|
||||||
|
ret = dslogic_dev_open(sdi, di);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret != SR_OK) {
|
||||||
|
sr_err("Unable to open device.");
|
||||||
|
return SR_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE);
|
||||||
|
if (ret != 0) {
|
||||||
|
switch (ret) {
|
||||||
|
case LIBUSB_ERROR_BUSY:
|
||||||
|
sr_err("Unable to claim USB interface. Another "
|
||||||
|
"program or driver has already claimed it.");
|
||||||
|
break;
|
||||||
|
case LIBUSB_ERROR_NO_DEVICE:
|
||||||
|
sr_err("Device has been disconnected.");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sr_err("Unable to claim interface: %s.",
|
||||||
|
libusb_error_name(ret));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SR_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ((ret = dslogic_fpga_firmware_upload(sdi)) != SR_OK)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (devc->cur_samplerate == 0) {
|
||||||
|
/* Samplerate hasn't been set; default to the slowest one. */
|
||||||
|
devc->cur_samplerate = devc->samplerates[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (devc->cur_threshold == 0.0) {
|
||||||
|
devc->cur_threshold = thresholds[1][0];
|
||||||
|
return dslogic_set_voltage_threshold(sdi, devc->cur_threshold);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dev_close(struct sr_dev_inst *sdi)
|
||||||
|
{
|
||||||
|
struct sr_usb_dev_inst *usb;
|
||||||
|
|
||||||
|
usb = sdi->conn;
|
||||||
|
|
||||||
|
if (!usb->devhdl)
|
||||||
|
return SR_ERR_BUG;
|
||||||
|
|
||||||
|
sr_info("Closing device on %d.%d (logical) / %s (physical) interface %d.",
|
||||||
|
usb->bus, usb->address, sdi->connection_id, USB_INTERFACE);
|
||||||
|
libusb_release_interface(usb->devhdl, USB_INTERFACE);
|
||||||
|
libusb_close(usb->devhdl);
|
||||||
|
usb->devhdl = 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;
|
||||||
|
int idx;
|
||||||
|
|
||||||
|
(void)cg;
|
||||||
|
|
||||||
|
if (!sdi)
|
||||||
|
return SR_ERR_ARG;
|
||||||
|
|
||||||
|
devc = sdi->priv;
|
||||||
|
|
||||||
|
switch (key) {
|
||||||
|
case SR_CONF_CONN:
|
||||||
|
if (!sdi->conn)
|
||||||
|
return SR_ERR_ARG;
|
||||||
|
usb = sdi->conn;
|
||||||
|
if (usb->address == 255)
|
||||||
|
/* Device still needs to re-enumerate after firmware
|
||||||
|
* upload, so we don't know its (future) address. */
|
||||||
|
return SR_ERR;
|
||||||
|
*data = g_variant_new_printf("%d.%d", usb->bus, usb->address);
|
||||||
|
break;
|
||||||
|
case SR_CONF_VOLTAGE_THRESHOLD:
|
||||||
|
if (!strcmp(devc->profile->model, "DSLogic")) {
|
||||||
|
if ((idx = std_double_tuple_idx_d0(devc->cur_threshold,
|
||||||
|
ARRAY_AND_SIZE(thresholds))) < 0)
|
||||||
|
return SR_ERR_BUG;
|
||||||
|
*data = std_gvar_tuple_double(thresholds[idx][0],
|
||||||
|
thresholds[idx][1]);
|
||||||
|
} else {
|
||||||
|
*data = std_gvar_tuple_double(devc->cur_threshold, devc->cur_threshold);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SR_CONF_LIMIT_SAMPLES:
|
||||||
|
*data = g_variant_new_uint64(devc->limit_samples);
|
||||||
|
break;
|
||||||
|
case SR_CONF_SAMPLERATE:
|
||||||
|
*data = g_variant_new_uint64(devc->cur_samplerate);
|
||||||
|
break;
|
||||||
|
case SR_CONF_CAPTURE_RATIO:
|
||||||
|
*data = g_variant_new_uint64(devc->capture_ratio);
|
||||||
|
break;
|
||||||
|
case SR_CONF_EXTERNAL_CLOCK:
|
||||||
|
*data = g_variant_new_boolean(devc->external_clock);
|
||||||
|
break;
|
||||||
|
case SR_CONF_CONTINUOUS:
|
||||||
|
*data = g_variant_new_boolean(devc->continuous_mode);
|
||||||
|
break;
|
||||||
|
case SR_CONF_CLOCK_EDGE:
|
||||||
|
idx = devc->clock_edge;
|
||||||
|
if (idx >= (int)ARRAY_SIZE(signal_edges))
|
||||||
|
return SR_ERR_BUG;
|
||||||
|
*data = g_variant_new_string(signal_edges[0]);
|
||||||
|
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;
|
||||||
|
gdouble low, high;
|
||||||
|
|
||||||
|
(void)cg;
|
||||||
|
|
||||||
|
if (!sdi)
|
||||||
|
return SR_ERR_ARG;
|
||||||
|
|
||||||
|
devc = sdi->priv;
|
||||||
|
|
||||||
|
switch (key) {
|
||||||
|
case SR_CONF_SAMPLERATE:
|
||||||
|
if ((idx = std_u64_idx(data, devc->samplerates, devc->num_samplerates)) < 0)
|
||||||
|
return SR_ERR_ARG;
|
||||||
|
devc->cur_samplerate = devc->samplerates[idx];
|
||||||
|
break;
|
||||||
|
case SR_CONF_LIMIT_SAMPLES:
|
||||||
|
devc->limit_samples = g_variant_get_uint64(data);
|
||||||
|
break;
|
||||||
|
case SR_CONF_CAPTURE_RATIO:
|
||||||
|
devc->capture_ratio = g_variant_get_uint64(data);
|
||||||
|
break;
|
||||||
|
case SR_CONF_VOLTAGE_THRESHOLD:
|
||||||
|
if (!strcmp(devc->profile->model, "DSLogic")) {
|
||||||
|
if ((idx = std_double_tuple_idx(data, ARRAY_AND_SIZE(thresholds))) < 0)
|
||||||
|
return SR_ERR_ARG;
|
||||||
|
devc->cur_threshold = thresholds[idx][0];
|
||||||
|
return dslogic_fpga_firmware_upload(sdi);
|
||||||
|
} else {
|
||||||
|
g_variant_get(data, "(dd)", &low, &high);
|
||||||
|
return dslogic_set_voltage_threshold(sdi, (low + high) / 2.0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SR_CONF_EXTERNAL_CLOCK:
|
||||||
|
devc->external_clock = g_variant_get_boolean(data);
|
||||||
|
break;
|
||||||
|
case SR_CONF_CONTINUOUS:
|
||||||
|
devc->continuous_mode = g_variant_get_boolean(data);
|
||||||
|
break;
|
||||||
|
case SR_CONF_CLOCK_EDGE:
|
||||||
|
if ((idx = std_str_idx(data, ARRAY_AND_SIZE(signal_edges))) < 0)
|
||||||
|
return SR_ERR_ARG;
|
||||||
|
devc->clock_edge = 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)
|
||||||
|
{
|
||||||
|
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_VOLTAGE_THRESHOLD:
|
||||||
|
if (!devc || !devc->profile)
|
||||||
|
return SR_ERR_ARG;
|
||||||
|
if (!strcmp(devc->profile->model, "DSLogic"))
|
||||||
|
*data = std_gvar_thresholds(ARRAY_AND_SIZE(thresholds));
|
||||||
|
else
|
||||||
|
*data = std_gvar_min_max_step_thresholds(0.0, 5.0, 0.1);
|
||||||
|
break;
|
||||||
|
case SR_CONF_SAMPLERATE:
|
||||||
|
if (!devc)
|
||||||
|
return SR_ERR_ARG;
|
||||||
|
*data = std_gvar_samplerates(devc->samplerates, devc->num_samplerates);
|
||||||
|
break;
|
||||||
|
case SR_CONF_TRIGGER_MATCH:
|
||||||
|
*data = std_gvar_array_i32(ARRAY_AND_SIZE(trigger_matches));
|
||||||
|
break;
|
||||||
|
case SR_CONF_CLOCK_EDGE:
|
||||||
|
*data = g_variant_new_strv(ARRAY_AND_SIZE(signal_edges));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return SR_ERR_NA;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct sr_dev_driver dreamsourcelab_dslogic_driver_info = {
|
||||||
|
.name = "dreamsourcelab-dslogic",
|
||||||
|
.longname = "DreamSourceLab DSLogic",
|
||||||
|
.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 = dslogic_acquisition_start,
|
||||||
|
.dev_acquisition_stop = dslogic_acquisition_stop,
|
||||||
|
.context = NULL,
|
||||||
|
};
|
||||||
|
SR_REGISTER_DEV_DRIVER(dreamsourcelab_dslogic_driver_info);
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,152 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the libsigrok project.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
|
||||||
|
* Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
|
||||||
|
*
|
||||||
|
* 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_DREAMSOURCELAB_DSLOGIC_PROTOCOL_H
|
||||||
|
#define LIBSIGROK_HARDWARE_DREAMSOURCELAB_DSLOGIC_PROTOCOL_H
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <libusb.h>
|
||||||
|
#include <libsigrok/libsigrok.h>
|
||||||
|
#include "libsigrok-internal.h"
|
||||||
|
|
||||||
|
#define LOG_PREFIX "dreamsourcelab-dslogic"
|
||||||
|
|
||||||
|
#define USB_INTERFACE 0
|
||||||
|
#define USB_CONFIGURATION 1
|
||||||
|
|
||||||
|
#define MAX_RENUM_DELAY_MS 3000
|
||||||
|
#define NUM_SIMUL_TRANSFERS 32
|
||||||
|
#define MAX_EMPTY_TRANSFERS (NUM_SIMUL_TRANSFERS * 2)
|
||||||
|
|
||||||
|
#define NUM_CHANNELS 16
|
||||||
|
#define NUM_TRIGGER_STAGES 16
|
||||||
|
|
||||||
|
#define DSLOGIC_REQUIRED_VERSION_MAJOR 1
|
||||||
|
|
||||||
|
/* 6 delay states of up to 256 clock ticks */
|
||||||
|
#define MAX_SAMPLE_DELAY (6 * 256)
|
||||||
|
|
||||||
|
#define DSLOGIC_FPGA_FIRMWARE_5V "dreamsourcelab-dslogic-fpga-5v.fw"
|
||||||
|
#define DSLOGIC_FPGA_FIRMWARE_3V3 "dreamsourcelab-dslogic-fpga-3v3.fw"
|
||||||
|
#define DSCOPE_FPGA_FIRMWARE "dreamsourcelab-dscope-fpga.fw"
|
||||||
|
#define DSLOGIC_PRO_FPGA_FIRMWARE "dreamsourcelab-dslogic-pro-fpga.fw"
|
||||||
|
#define DSLOGIC_PLUS_FPGA_FIRMWARE "dreamsourcelab-dslogic-plus-fpga.fw"
|
||||||
|
#define DSLOGIC_BASIC_FPGA_FIRMWARE "dreamsourcelab-dslogic-basic-fpga.fw"
|
||||||
|
|
||||||
|
enum dslogic_operation_modes {
|
||||||
|
DS_OP_NORMAL,
|
||||||
|
DS_OP_INTERNAL_TEST,
|
||||||
|
DS_OP_EXTERNAL_TEST,
|
||||||
|
DS_OP_LOOPBACK_TEST,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum dslogic_edge_modes {
|
||||||
|
DS_EDGE_RISING,
|
||||||
|
DS_EDGE_FALLING,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dslogic_version {
|
||||||
|
uint8_t major;
|
||||||
|
uint8_t minor;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dslogic_mode {
|
||||||
|
uint8_t flags;
|
||||||
|
uint8_t sample_delay_h;
|
||||||
|
uint8_t sample_delay_l;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dslogic_trigger_pos {
|
||||||
|
uint32_t check_id;
|
||||||
|
uint32_t real_pos;
|
||||||
|
uint32_t ram_saddr;
|
||||||
|
uint32_t remain_cnt_l;
|
||||||
|
uint32_t remain_cnt_h;
|
||||||
|
uint32_t status;
|
||||||
|
uint8_t first_block[488];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dslogic_profile {
|
||||||
|
uint16_t vid;
|
||||||
|
uint16_t pid;
|
||||||
|
|
||||||
|
const char *vendor;
|
||||||
|
const char *model;
|
||||||
|
const char *model_version;
|
||||||
|
|
||||||
|
const char *firmware;
|
||||||
|
|
||||||
|
uint32_t dev_caps;
|
||||||
|
|
||||||
|
const char *usb_manufacturer;
|
||||||
|
const char *usb_product;
|
||||||
|
|
||||||
|
/* Memory depth in bits. */
|
||||||
|
uint64_t mem_depth;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dev_context {
|
||||||
|
const struct dslogic_profile *profile;
|
||||||
|
/*
|
||||||
|
* Since we can't keep track of a DSLogic device after upgrading
|
||||||
|
* the firmware (it renumerates into a different device address
|
||||||
|
* after the upgrade) this is like a global lock. No device will open
|
||||||
|
* until a proper delay after the last device was upgraded.
|
||||||
|
*/
|
||||||
|
int64_t fw_updated;
|
||||||
|
|
||||||
|
const uint64_t *samplerates;
|
||||||
|
int num_samplerates;
|
||||||
|
|
||||||
|
uint64_t cur_samplerate;
|
||||||
|
uint64_t limit_samples;
|
||||||
|
uint64_t capture_ratio;
|
||||||
|
|
||||||
|
gboolean acq_aborted;
|
||||||
|
|
||||||
|
unsigned int sent_samples;
|
||||||
|
int submitted_transfers;
|
||||||
|
int empty_transfer_count;
|
||||||
|
|
||||||
|
unsigned int num_transfers;
|
||||||
|
struct libusb_transfer **transfers;
|
||||||
|
struct sr_context *ctx;
|
||||||
|
|
||||||
|
uint16_t *deinterleave_buffer;
|
||||||
|
|
||||||
|
uint16_t mode;
|
||||||
|
uint32_t trigger_pos;
|
||||||
|
gboolean external_clock;
|
||||||
|
gboolean continuous_mode;
|
||||||
|
int clock_edge;
|
||||||
|
double cur_threshold;
|
||||||
|
};
|
||||||
|
|
||||||
|
SR_PRIV int dslogic_fpga_firmware_upload(const struct sr_dev_inst *sdi);
|
||||||
|
SR_PRIV int dslogic_set_voltage_threshold(const struct sr_dev_inst *sdi, double threshold);
|
||||||
|
SR_PRIV int dslogic_dev_open(struct sr_dev_inst *sdi, struct sr_dev_driver *di);
|
||||||
|
SR_PRIV struct dev_context *dslogic_dev_new(void);
|
||||||
|
SR_PRIV int dslogic_acquisition_start(const struct sr_dev_inst *sdi);
|
||||||
|
SR_PRIV int dslogic_acquisition_stop(struct sr_dev_inst *sdi);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,243 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the libsigrok project.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Bert Vermeulen <bert@biot.com>
|
||||||
|
* Copyright (C) 2017 John Chajecki <subs@qcontinuum.plus.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
|
||||||
|
* 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 <glib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <libsigrok/libsigrok.h>
|
||||||
|
#include "libsigrok-internal.h"
|
||||||
|
#include "scpi.h"
|
||||||
|
#include "protocol.h"
|
||||||
|
|
||||||
|
static const uint32_t scanopts[] = {
|
||||||
|
SR_CONF_CONN,
|
||||||
|
SR_CONF_SERIALCOMM,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t drvopts[] = {
|
||||||
|
SR_CONF_MULTIMETER,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t devopts[] = {
|
||||||
|
SR_CONF_CONTINUOUS,
|
||||||
|
SR_CONF_LIMIT_SAMPLES | SR_CONF_SET,
|
||||||
|
SR_CONF_LIMIT_MSEC | SR_CONF_SET,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Vendor, model, number of channels, poll period */
|
||||||
|
static const struct fluke_scpi_dmm_model supported_models[] = {
|
||||||
|
{ "FLUKE", "45", 2, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct sr_dev_driver fluke_45_driver_info;
|
||||||
|
|
||||||
|
static struct sr_dev_inst *probe_device(struct sr_scpi_dev_inst *scpi)
|
||||||
|
{
|
||||||
|
struct dev_context *devc;
|
||||||
|
struct sr_dev_inst *sdi;
|
||||||
|
struct sr_scpi_hw_info *hw_info;
|
||||||
|
const struct scpi_command *cmdset = fluke_45_cmdset;
|
||||||
|
unsigned int i;
|
||||||
|
const struct fluke_scpi_dmm_model *model = NULL;
|
||||||
|
gchar *channel_name;
|
||||||
|
char *response;
|
||||||
|
|
||||||
|
sdi = g_malloc0(sizeof(struct sr_dev_inst));
|
||||||
|
sdi->conn = scpi;
|
||||||
|
|
||||||
|
/* Test for serial port ECHO enabled. */
|
||||||
|
sr_scpi_get_string(scpi, "ECHO-TEST", &response);
|
||||||
|
if (strcmp(response, "ECHO-TEST") == 0) {
|
||||||
|
sr_err("Serial port ECHO is ON. Please turn it OFF!");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get device IDN. */
|
||||||
|
if (sr_scpi_get_hw_id(scpi, &hw_info) != SR_OK) {
|
||||||
|
sr_info("Couldn't get IDN response, retrying.");
|
||||||
|
sr_scpi_close(scpi);
|
||||||
|
sr_scpi_open(scpi);
|
||||||
|
if (sr_scpi_get_hw_id(scpi, &hw_info) != SR_OK) {
|
||||||
|
sr_info("Couldn't get IDN response.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check IDN. */
|
||||||
|
for (i = 0; i < ARRAY_SIZE(supported_models); i++) {
|
||||||
|
if (!g_ascii_strcasecmp(hw_info->manufacturer,
|
||||||
|
supported_models[i].vendor) &&
|
||||||
|
!strcmp(hw_info->model, supported_models[i].model)) {
|
||||||
|
model = &supported_models[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!model) {
|
||||||
|
sr_scpi_hw_info_free(hw_info);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set up device parameters. */
|
||||||
|
sdi->vendor = g_strdup(model->vendor);
|
||||||
|
sdi->model = g_strdup(model->model);
|
||||||
|
sdi->version = g_strdup(hw_info->firmware_version);
|
||||||
|
sdi->serial_num = g_strdup(hw_info->serial_number);
|
||||||
|
sdi->conn = scpi;
|
||||||
|
sdi->driver = &fluke_45_driver_info;
|
||||||
|
sdi->inst_type = SR_INST_SCPI;
|
||||||
|
|
||||||
|
devc = g_malloc0(sizeof(struct dev_context));
|
||||||
|
devc->num_channels = model->num_channels;
|
||||||
|
devc->cmdset = cmdset;
|
||||||
|
|
||||||
|
/* Create channels. */
|
||||||
|
for (i = 0; i < devc->num_channels; i++) {
|
||||||
|
channel_name = g_strdup_printf("P%d", i + 1);
|
||||||
|
sr_channel_new(sdi, 0, SR_CHANNEL_ANALOG, TRUE, channel_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
sdi->priv = devc;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
if ((ret = sr_scpi_open(scpi) < 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;
|
||||||
|
|
||||||
|
return sr_scpi_close(scpi);
|
||||||
|
}
|
||||||
|
|
||||||
|
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->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 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->limits, key, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||||
|
{
|
||||||
|
struct sr_scpi_dev_inst *scpi;
|
||||||
|
struct dev_context *devc;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
scpi = sdi->conn;
|
||||||
|
devc = sdi->priv;
|
||||||
|
|
||||||
|
sr_sw_limits_acquisition_start(&devc->limits);
|
||||||
|
std_session_send_df_header(sdi);
|
||||||
|
|
||||||
|
if ((ret = sr_scpi_source_add(sdi->session, scpi, G_IO_IN, 10,
|
||||||
|
fl45_scpi_receive_data, (void *)sdi)) != SR_OK)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return SR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dev_acquisition_stop(struct sr_dev_inst *sdi)
|
||||||
|
{
|
||||||
|
struct sr_scpi_dev_inst *scpi;
|
||||||
|
double d;
|
||||||
|
|
||||||
|
scpi = sdi->conn;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A requested value is certainly on the way. Retrieve it now,
|
||||||
|
* to avoid leaving the device in a state where it's not expecting
|
||||||
|
* commands.
|
||||||
|
*/
|
||||||
|
sr_scpi_get_double(scpi, NULL, &d);
|
||||||
|
sr_scpi_source_remove(sdi->session, scpi);
|
||||||
|
|
||||||
|
std_session_send_df_end(sdi);
|
||||||
|
|
||||||
|
return SR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct sr_dev_driver fluke_45_driver_info = {
|
||||||
|
.name = "fluke-45",
|
||||||
|
.longname = "Fluke 45",
|
||||||
|
.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(fluke_45_driver_info);
|
|
@ -0,0 +1,349 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the libsigrok project.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Bert Vermeulen <bert@biot.com>
|
||||||
|
* Copyright (C) 2017 John Chajecki <subs@qcontinuum.plus.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
|
||||||
|
* 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 <stdio.h>
|
||||||
|
#include <config.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <glib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <scpi.h>
|
||||||
|
#include <libsigrok/libsigrok.h>
|
||||||
|
#include "libsigrok-internal.h"
|
||||||
|
#include "protocol.h"
|
||||||
|
|
||||||
|
/* Get the current state of the meter and sets analog object parameters. */
|
||||||
|
SR_PRIV int fl45_get_status(const struct sr_dev_inst *sdi,
|
||||||
|
struct sr_datafeed_analog *analog, int idx)
|
||||||
|
{
|
||||||
|
struct dev_context *devc;
|
||||||
|
char *cmd, *func;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = 0;
|
||||||
|
|
||||||
|
/* Command string to read current function. */
|
||||||
|
cmd = g_strdup_printf("FUNC%d?", idx + 1);
|
||||||
|
sr_dbg("Sent command: %s.", cmd);
|
||||||
|
|
||||||
|
if (!(devc = sdi->priv))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
/* Default settings. */
|
||||||
|
analog[idx].meaning->mq = 0;
|
||||||
|
analog[idx].meaning->unit = 0;
|
||||||
|
analog[idx].meaning->mqflags = 0;
|
||||||
|
|
||||||
|
/* Get a response to the FUNC? command. */
|
||||||
|
res = fl45_scpi_get_response(sdi, cmd);
|
||||||
|
if (res == SR_ERR)
|
||||||
|
return res;
|
||||||
|
sr_dbg("Response to FUNC: %s.", devc->response);
|
||||||
|
|
||||||
|
/* Set up analog mq, unit and flags. */
|
||||||
|
if (res == SR_OK && devc->response != NULL) {
|
||||||
|
func = devc->response;
|
||||||
|
if (strcmp(func, "AAC") == 0) {
|
||||||
|
analog[idx].meaning->mq = SR_MQ_CURRENT;
|
||||||
|
analog[idx].meaning->unit = SR_UNIT_AMPERE;
|
||||||
|
analog[idx].meaning->mqflags = SR_MQFLAG_AC;
|
||||||
|
} else if (strcmp(func, "AACDC") == 0) {
|
||||||
|
analog[idx].meaning->mq = SR_MQ_CURRENT;
|
||||||
|
analog[idx].meaning->unit = SR_UNIT_AMPERE;
|
||||||
|
analog[idx].meaning->mqflags = SR_MQFLAG_AC;
|
||||||
|
} else if (strcmp(func, "ADC") == 0) {
|
||||||
|
analog[idx].meaning->mq = SR_MQ_CURRENT;
|
||||||
|
analog[idx].meaning->unit = SR_UNIT_AMPERE;
|
||||||
|
analog[idx].meaning->mqflags = SR_MQFLAG_DC;
|
||||||
|
} else if (strcmp(func, "CONT") == 0) {
|
||||||
|
analog[idx].meaning->mq = SR_MQ_CONTINUITY;
|
||||||
|
analog->meaning->unit = SR_UNIT_BOOLEAN;
|
||||||
|
} else if (strcmp(func, "DIODE") == 0) {
|
||||||
|
analog[idx].meaning->mq = SR_MQ_VOLTAGE;
|
||||||
|
analog[idx].meaning->unit = SR_UNIT_VOLT;
|
||||||
|
analog[idx].meaning->mqflags = SR_MQFLAG_DIODE;
|
||||||
|
} else if (strcmp(func, "FREQ") == 0) {
|
||||||
|
analog[idx].meaning->mq = SR_MQ_FREQUENCY;
|
||||||
|
analog[idx].meaning->unit = SR_UNIT_HERTZ;
|
||||||
|
} else if (strcmp(func, "OHMS") == 0) {
|
||||||
|
analog[idx].meaning->mq = SR_MQ_RESISTANCE;
|
||||||
|
analog[idx].meaning->unit = SR_UNIT_OHM;
|
||||||
|
} else if (strcmp(func, "VAC") == 0) {
|
||||||
|
analog[idx].meaning->mq = SR_MQ_VOLTAGE;
|
||||||
|
analog[idx].meaning->unit = SR_UNIT_VOLT;
|
||||||
|
analog[idx].meaning->mqflags = SR_MQFLAG_AC;
|
||||||
|
} else if (strcmp(func, "VACDC") == 0) {
|
||||||
|
analog[idx].meaning->mq = SR_MQ_VOLTAGE;
|
||||||
|
analog[idx].meaning->unit = SR_UNIT_VOLT;
|
||||||
|
analog[idx].meaning->mqflags |= SR_MQFLAG_AC;
|
||||||
|
analog[idx].meaning->mqflags |= SR_MQFLAG_DC;
|
||||||
|
} else if (strcmp(func, "VDC") == 0) {
|
||||||
|
analog[idx].meaning->mq = SR_MQ_VOLTAGE;
|
||||||
|
analog[idx].meaning->unit = SR_UNIT_VOLT;
|
||||||
|
analog[idx].meaning->mqflags = SR_MQFLAG_DC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Is the meter in autorange mode? */
|
||||||
|
res = fl45_scpi_get_response(sdi, "AUTO?");
|
||||||
|
if (res == SR_ERR)
|
||||||
|
return res;
|
||||||
|
sr_dbg("Response to AUTO: %s.", devc->response);
|
||||||
|
if (res == SR_OK && devc->response != NULL) {
|
||||||
|
if (strcmp(devc->response, "1") == 0)
|
||||||
|
analog[idx].meaning->mqflags |= SR_MQFLAG_AUTORANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
SR_PRIV int fl45_get_modifiers(const struct sr_dev_inst *sdi,
|
||||||
|
struct sr_datafeed_analog *analog, int idx)
|
||||||
|
{
|
||||||
|
struct dev_context *devc;
|
||||||
|
int res, mod;
|
||||||
|
|
||||||
|
if (!(devc = sdi->priv))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
/* Get modifier value. */
|
||||||
|
res = fl45_scpi_get_response(sdi, "MOD?");
|
||||||
|
if (res == SR_ERR)
|
||||||
|
return res;
|
||||||
|
sr_dbg("Response to MOD: %s.", devc->response);
|
||||||
|
if (res == SR_OK && devc->response != NULL) {
|
||||||
|
mod = atoi(devc->response);
|
||||||
|
if (mod & 0x01) {
|
||||||
|
analog[idx].meaning->mqflags |= SR_MQFLAG_MIN;
|
||||||
|
sr_dbg("MIN bit set: %s.", "1");
|
||||||
|
}
|
||||||
|
if (mod & 0x02) {
|
||||||
|
analog[idx].meaning->mqflags |= SR_MQFLAG_MAX;
|
||||||
|
sr_dbg("MAX bit set: %s.", "2");
|
||||||
|
}
|
||||||
|
if (mod & 0x04) {
|
||||||
|
analog[idx].meaning->mqflags |= SR_MQFLAG_HOLD;
|
||||||
|
sr_dbg("HOLD bit set: %s.", "4");
|
||||||
|
}
|
||||||
|
if (mod & 0x08) {
|
||||||
|
sr_dbg("dB bit set: %s.", "8");
|
||||||
|
analog[idx].meaning->mq = SR_MQ_POWER_FACTOR;
|
||||||
|
analog[idx].meaning->unit = SR_UNIT_DECIBEL_MW;
|
||||||
|
analog[idx].meaning->mqflags = 0;
|
||||||
|
analog[idx].encoding->digits = 2;
|
||||||
|
analog[idx].spec->spec_digits = 2;
|
||||||
|
}
|
||||||
|
if (mod & 0x10) {
|
||||||
|
sr_dbg("dB Power mod bit set: %s.", "16");
|
||||||
|
analog[idx].meaning->mq = SR_MQ_POWER;
|
||||||
|
analog[idx].meaning->unit = SR_UNIT_DECIBEL_SPL;
|
||||||
|
analog[idx].meaning->mqflags = 0;
|
||||||
|
analog[idx].encoding->digits = 2;
|
||||||
|
analog[idx].spec->spec_digits = 2;
|
||||||
|
}
|
||||||
|
if (mod & 0x20) {
|
||||||
|
sr_dbg("REL bit set: %s.", "32");
|
||||||
|
analog[idx].meaning->mqflags |= SR_MQFLAG_HOLD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_reading_dd(char *reading, size_t size)
|
||||||
|
{
|
||||||
|
int pe, pd, digits;
|
||||||
|
unsigned int i;
|
||||||
|
char expstr[3];
|
||||||
|
char *eptr;
|
||||||
|
long exp;
|
||||||
|
|
||||||
|
/* Calculate required precision. */
|
||||||
|
|
||||||
|
pe = pd = digits = 0;
|
||||||
|
|
||||||
|
/* Get positions for '.' end 'E'. */
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
if (reading[i] == '.')
|
||||||
|
pd = i;
|
||||||
|
if (reading[i] == 'E') {
|
||||||
|
pe = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
digits = (pe - pd) - 1;
|
||||||
|
|
||||||
|
/* Get exponent element. */
|
||||||
|
expstr[0] = reading[pe + 1];
|
||||||
|
expstr[1] = reading[pe + 2];
|
||||||
|
expstr[2] = '\0';
|
||||||
|
errno = 0;
|
||||||
|
exp = strtol(expstr, &eptr, 10);
|
||||||
|
if (errno != 0)
|
||||||
|
return 2;
|
||||||
|
/* A negative exponent increses digits, a positive one reduces. */
|
||||||
|
exp = exp * (-1);
|
||||||
|
|
||||||
|
/* Adjust digits taking into account exponent. */
|
||||||
|
digits = digits + exp;
|
||||||
|
|
||||||
|
return digits;
|
||||||
|
}
|
||||||
|
|
||||||
|
SR_PRIV int fl45_scpi_receive_data(int fd, int revents, void *cb_data)
|
||||||
|
{
|
||||||
|
struct sr_dev_inst *sdi;
|
||||||
|
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;
|
||||||
|
char *reading;
|
||||||
|
float fv;
|
||||||
|
int res, digits;
|
||||||
|
unsigned int i;
|
||||||
|
int sent_ch[2];
|
||||||
|
|
||||||
|
(void)fd;
|
||||||
|
(void)revents;
|
||||||
|
|
||||||
|
if (!(sdi = cb_data))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
if (!(devc = sdi->priv))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
res = 0;
|
||||||
|
sent_ch[0] = sent_ch[1] = 0;
|
||||||
|
|
||||||
|
/* Process the list of channels. */
|
||||||
|
for (i = 0; i < devc->num_channels; i++) {
|
||||||
|
/* Note: digits/spec_digits will be overridden later. */
|
||||||
|
sr_analog_init(&analog[i], &encoding[i], &meaning[i], &spec[i], 0);
|
||||||
|
|
||||||
|
/* Detect current meter function. */
|
||||||
|
res = fl45_get_status(sdi, analog, i);
|
||||||
|
|
||||||
|
/* Get channel data. */
|
||||||
|
if (i == 0)
|
||||||
|
channel = sdi->channels->data;
|
||||||
|
else
|
||||||
|
channel = sdi->channels->next->data;
|
||||||
|
|
||||||
|
/* Is channel enabled? */
|
||||||
|
if (analog[i].meaning->mq != 0 && channel->enabled) {
|
||||||
|
/* Then get a reading from it. */
|
||||||
|
if (i == 0)
|
||||||
|
res = fl45_scpi_get_response(sdi, "VAL1?");
|
||||||
|
if (i == 1)
|
||||||
|
res = fl45_scpi_get_response(sdi, "VAL2?");
|
||||||
|
/* Note: Fluke 45 sends all data in text strings. */
|
||||||
|
reading = devc->response;
|
||||||
|
|
||||||
|
/* Deal with OL reading. */
|
||||||
|
if (strcmp(reading, "+1E+9") == 0) {
|
||||||
|
fv = INFINITY;
|
||||||
|
sr_dbg("Reading OL (infinity): %s.",
|
||||||
|
devc->response);
|
||||||
|
} else if (res == SR_OK && reading != NULL) {
|
||||||
|
/* Convert reading to float. */
|
||||||
|
sr_dbg("Meter reading string: %s.", reading);
|
||||||
|
res = sr_atof_ascii(reading, &fv);
|
||||||
|
digits = get_reading_dd(reading, strlen(reading));
|
||||||
|
analog[i].encoding->digits = digits;
|
||||||
|
analog[i].spec->spec_digits = digits;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
sr_dbg("Invalid float string: '%s'.", reading);
|
||||||
|
return SR_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Are we on a little or big endian system? */
|
||||||
|
#ifdef WORDS_BIGENDIAN
|
||||||
|
analog[i].encoding->is_bigendian = TRUE;
|
||||||
|
#else
|
||||||
|
analog[i].encoding->is_bigendian = FALSE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Apply any modifiers. */
|
||||||
|
res = fl45_get_modifiers(sdi, analog, i);
|
||||||
|
|
||||||
|
/* Channal flag. */
|
||||||
|
sent_ch[i] = 1;
|
||||||
|
|
||||||
|
/* Set up analog object. */
|
||||||
|
analog[i].num_samples = 1;
|
||||||
|
analog[i].data = &fv;
|
||||||
|
analog[i].meaning->channels = g_slist_append(NULL, channel);
|
||||||
|
|
||||||
|
packet.type = SR_DF_ANALOG;
|
||||||
|
packet.payload = &analog[i];
|
||||||
|
|
||||||
|
sr_session_send(sdi, &packet);
|
||||||
|
|
||||||
|
g_slist_free(analog[i].meaning->channels);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update appropriate channel limits. */
|
||||||
|
if (sent_ch[0] || sent_ch[1])
|
||||||
|
sr_sw_limits_update_samples_read(&devc->limits, 1);
|
||||||
|
|
||||||
|
/* Are we done collecting samples? */
|
||||||
|
if (sr_sw_limits_check(&devc->limits))
|
||||||
|
sr_dev_acquisition_stop(sdi);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
SR_PRIV int fl45_scpi_get_response(const struct sr_dev_inst *sdi, char *cmd)
|
||||||
|
{
|
||||||
|
struct dev_context *devc;
|
||||||
|
devc = sdi->priv;
|
||||||
|
|
||||||
|
/* Attempt to get a SCPI reponse. */
|
||||||
|
if (sr_scpi_get_string(sdi->conn, cmd, &devc->response) != SR_OK)
|
||||||
|
return SR_ERR;
|
||||||
|
|
||||||
|
/* Deal with RS232 '=>' prompt. */
|
||||||
|
if (strcmp(devc->response, "=>") == 0) {
|
||||||
|
/*
|
||||||
|
* If the response is a prompt then ignore and read the next
|
||||||
|
* response in the buffer.
|
||||||
|
*/
|
||||||
|
devc->response = NULL;
|
||||||
|
/* Now attempt to read again. */
|
||||||
|
if (sr_scpi_get_string(sdi->conn, NULL, &devc->response) != SR_OK)
|
||||||
|
return SR_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NULL RS232 error prompts. */
|
||||||
|
if (strcmp(devc->response, "!>") == 0
|
||||||
|
|| (strcmp(devc->response, "?>") == 0)) {
|
||||||
|
/* Unable to execute CMD. */
|
||||||
|
devc->response = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SR_OK;
|
||||||
|
}
|
|
@ -0,0 +1,200 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the libsigrok project.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Bert Vermeulen <bert@biot.com>
|
||||||
|
* Copyright (C) 2017 John Chajecki <subs@qcontinuum.plus.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
|
||||||
|
* 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_FLUKE_45_PROTOCOL_H
|
||||||
|
#define LIBSIGROK_HARDWARE_FLUKE_45_PROTOCOL_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <scpi.h>
|
||||||
|
|
||||||
|
#define LOG_PREFIX "fluke-45"
|
||||||
|
|
||||||
|
#define FLUKEDMM_BUFSIZE 256
|
||||||
|
|
||||||
|
/* Always USB-serial, 1ms is plenty. */
|
||||||
|
#define SERIAL_WRITE_TIMEOUT_MS 1
|
||||||
|
|
||||||
|
enum data_format {
|
||||||
|
/* Fluke 45 uses IEEE488v2. */
|
||||||
|
FORMAT_IEEE488_2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum dmm_scpi_cmds {
|
||||||
|
SCPI_CMD_CLS,
|
||||||
|
SCPI_CMD_RST,
|
||||||
|
SCPI_CMD_REMS,
|
||||||
|
SCPI_CMD_RWLS,
|
||||||
|
SCPI_CMD_LOCS,
|
||||||
|
SCPI_CMD_LWLS,
|
||||||
|
SCPI_CMD_REMOTE,
|
||||||
|
SCPI_CMD_LOCAL,
|
||||||
|
SCPI_CMD_SET_ACVOLTAGE,
|
||||||
|
SCPI_CMD_SET_ACDCVOLTAGE,
|
||||||
|
SCPI_CMD_SET_DCVOLTAGE,
|
||||||
|
SCPI_CMD_SET_ACCURRENT,
|
||||||
|
SCPI_CMD_SET_ACDCCURRENT,
|
||||||
|
SCPI_CMD_SET_DCCURRENT,
|
||||||
|
SCPI_CMD_SET_FREQUENCY,
|
||||||
|
SCPI_CMD_SET_RESISTANCE,
|
||||||
|
SCPI_CMD_SET_CONTINUITY,
|
||||||
|
SCPI_CMD_SET_DIODE,
|
||||||
|
SCPI_CMD_SET_AUTO,
|
||||||
|
SCPI_CMD_GET_AUTO,
|
||||||
|
SCPI_CMD_SET_FIXED,
|
||||||
|
SCPI_CMD_SET_RANGE,
|
||||||
|
SCPI_CMD_GET_RANGE_D1,
|
||||||
|
SCPI_CMD_GET_RANGE_D2,
|
||||||
|
SCPI_CMD_SET_DB,
|
||||||
|
SCPI_CMD_SET_DBCLR,
|
||||||
|
SCPI_CMD_SET_DBPOWER,
|
||||||
|
SCPI_CMD_SET_DBREF,
|
||||||
|
SCPI_CMD_GET_DBREF,
|
||||||
|
SCPI_CMD_SET_HOLD,
|
||||||
|
SCPI_CMD_SET_HOLDCLR,
|
||||||
|
SCPI_CMD_SET_MAX,
|
||||||
|
SCPI_CMD_SET_MIN,
|
||||||
|
SCPI_CMD_SET_MMCLR,
|
||||||
|
SCPI_CMD_SET_REL,
|
||||||
|
SCPI_CMD_SET_RELCLR,
|
||||||
|
SCPI_CMD_GET_MEAS_DD,
|
||||||
|
SCPI_CMD_GET_MEAS_D1,
|
||||||
|
SCPI_CMD_GET_MEAS_D2,
|
||||||
|
SCPI_CMD_GET_RATE,
|
||||||
|
SCPI_CMD_SET_RATE,
|
||||||
|
SCPI_CMD_SET_TRIGGER,
|
||||||
|
SCPI_CMD_GET_TRIGGER,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct scpi_command fluke_45_cmdset[] = {
|
||||||
|
{ SCPI_CMD_CLS, "*CLS" },
|
||||||
|
{ SCPI_CMD_RST, "*RST" },
|
||||||
|
{ SCPI_CMD_REMS, "*REMS" },
|
||||||
|
{ SCPI_CMD_RWLS, "*RWLS" },
|
||||||
|
{ SCPI_CMD_LOCS, "LOCS" },
|
||||||
|
{ SCPI_CMD_LWLS, "LWLS" },
|
||||||
|
{ SCPI_CMD_REMOTE, "REMS" },
|
||||||
|
{ SCPI_CMD_LOCAL, "LOCS" },
|
||||||
|
{ SCPI_CMD_SET_ACVOLTAGE, "VAC" },
|
||||||
|
{ SCPI_CMD_SET_ACDCVOLTAGE, "VACDC" },
|
||||||
|
{ SCPI_CMD_SET_DCVOLTAGE, "VDC" },
|
||||||
|
{ SCPI_CMD_SET_ACCURRENT, "AAC" },
|
||||||
|
{ SCPI_CMD_SET_ACDCCURRENT, "AACDC" },
|
||||||
|
{ SCPI_CMD_SET_DCCURRENT, "ADC" },
|
||||||
|
{ SCPI_CMD_SET_FREQUENCY, "FREQ" },
|
||||||
|
{ SCPI_CMD_SET_RESISTANCE, "OHMS" },
|
||||||
|
{ SCPI_CMD_SET_CONTINUITY, "CONT" },
|
||||||
|
{ SCPI_CMD_SET_DIODE, "DIODE" },
|
||||||
|
{ SCPI_CMD_SET_AUTO, "AUTO" },
|
||||||
|
{ SCPI_CMD_GET_AUTO, "AUTO?" },
|
||||||
|
{ SCPI_CMD_SET_FIXED, "FIXED" },
|
||||||
|
{ SCPI_CMD_SET_RANGE, "RANGE" },
|
||||||
|
{ SCPI_CMD_GET_RANGE_D1, "RANGE1?" },
|
||||||
|
{ SCPI_CMD_GET_RANGE_D2, "RANGE2?" },
|
||||||
|
{ SCPI_CMD_SET_DB, "DB" },
|
||||||
|
{ SCPI_CMD_SET_DBCLR, "DBCLR" },
|
||||||
|
{ SCPI_CMD_SET_DBPOWER, "DBPOWER" },
|
||||||
|
{ SCPI_CMD_SET_DBREF, "DBREF" },
|
||||||
|
{ SCPI_CMD_GET_DBREF, "DBREF?" },
|
||||||
|
{ SCPI_CMD_SET_HOLD, "HOLD" },
|
||||||
|
{ SCPI_CMD_SET_HOLDCLR, "HOLDCLR" },
|
||||||
|
{ SCPI_CMD_SET_MAX, "MAX" },
|
||||||
|
{ SCPI_CMD_SET_MIN, "MIN" },
|
||||||
|
{ SCPI_CMD_SET_MMCLR, "MMCLR" },
|
||||||
|
{ SCPI_CMD_SET_REL, "REL" },
|
||||||
|
{ SCPI_CMD_SET_RELCLR, "RELCLR" },
|
||||||
|
{ SCPI_CMD_GET_MEAS_DD, "MEAS?" },
|
||||||
|
{ SCPI_CMD_GET_MEAS_D1, "MEAS1?" },
|
||||||
|
{ SCPI_CMD_GET_MEAS_D2, "MEAS2?" },
|
||||||
|
{ SCPI_CMD_SET_RATE, "RATE" },
|
||||||
|
{ SCPI_CMD_GET_RATE, "RATE?" },
|
||||||
|
{ SCPI_CMD_SET_TRIGGER, "TRIGGER" },
|
||||||
|
{ SCPI_CMD_GET_TRIGGER, "TRIGGER?" },
|
||||||
|
ALL_ZERO
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fluke_scpi_dmm_model {
|
||||||
|
const char *vendor;
|
||||||
|
const char *model;
|
||||||
|
int num_channels;
|
||||||
|
int poll_period; /* How often to poll, in ms. */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct channel_spec {
|
||||||
|
const char *name;
|
||||||
|
/* Min, max, programming resolution, spec digits, encoding digits. */
|
||||||
|
double voltage[5];
|
||||||
|
double current[5];
|
||||||
|
double resistance[5];
|
||||||
|
double capacitance[5];
|
||||||
|
double conductance[5];
|
||||||
|
double diode[5];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct channel_group_spec {
|
||||||
|
const char *name;
|
||||||
|
uint64_t channel_index_mask;
|
||||||
|
uint64_t features;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dmm_channel {
|
||||||
|
enum sr_mq mq;
|
||||||
|
unsigned int hw_output_idx;
|
||||||
|
const char *hwname;
|
||||||
|
int digits;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dmm_channel_instance {
|
||||||
|
enum sr_mq mq;
|
||||||
|
int command;
|
||||||
|
const char *prefix;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dmm_channel_group {
|
||||||
|
uint64_t features;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dev_context {
|
||||||
|
struct sr_sw_limits limits;
|
||||||
|
unsigned int num_channels;
|
||||||
|
const struct scpi_command *cmdset;
|
||||||
|
char *response;
|
||||||
|
const char *mode1;
|
||||||
|
const char *mode2;
|
||||||
|
long range1;
|
||||||
|
long range2;
|
||||||
|
long autorng;
|
||||||
|
const char *rate;
|
||||||
|
long modifiers;
|
||||||
|
long trigmode;
|
||||||
|
};
|
||||||
|
|
||||||
|
int get_reading_dd(char *reading, size_t size);
|
||||||
|
|
||||||
|
SR_PRIV extern const struct fluke_scpi_dmm_model dmm_profiles[];
|
||||||
|
|
||||||
|
SR_PRIV int fl45_scpi_receive_data(int fd, int revents, void *cb_data);
|
||||||
|
SR_PRIV int fl45_scpi_get_response(const struct sr_dev_inst *sdi, char *cmd);
|
||||||
|
SR_PRIV int fl45_get_status(const struct sr_dev_inst *sdi,
|
||||||
|
struct sr_datafeed_analog *analog, int idx);
|
||||||
|
SR_PRIV int fl45_get_modifiers(const struct sr_dev_inst *sdi,
|
||||||
|
struct sr_datafeed_analog *analog, int idx);
|
||||||
|
|
||||||
|
#endif
|
|
@ -32,8 +32,11 @@ static const uint32_t scanopts[] = {
|
||||||
SR_CONF_SERIALCOMM,
|
SR_CONF_SERIALCOMM,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint32_t devopts[] = {
|
static const uint32_t drvopts[] = {
|
||||||
SR_CONF_MULTIMETER,
|
SR_CONF_MULTIMETER,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t devopts[] = {
|
||||||
SR_CONF_CONTINUOUS,
|
SR_CONF_CONTINUOUS,
|
||||||
SR_CONF_LIMIT_SAMPLES | SR_CONF_SET,
|
SR_CONF_LIMIT_SAMPLES | SR_CONF_SET,
|
||||||
SR_CONF_LIMIT_MSEC | SR_CONF_SET,
|
SR_CONF_LIMIT_MSEC | SR_CONF_SET,
|
||||||
|
@ -87,7 +90,7 @@ static GSList *fluke_scan(struct sr_dev_driver *di, const char *conn,
|
||||||
|
|
||||||
/* Response is first a CMD_ACK byte (ASCII '0' for OK,
|
/* Response is first a CMD_ACK byte (ASCII '0' for OK,
|
||||||
* or '1' to signify an error. */
|
* or '1' to signify an error. */
|
||||||
len = 128;
|
len = sizeof(buf);
|
||||||
serial_readline(serial, &b, &len, 150);
|
serial_readline(serial, &b, &len, 150);
|
||||||
if (len != 1)
|
if (len != 1)
|
||||||
continue;
|
continue;
|
||||||
|
@ -95,7 +98,7 @@ static GSList *fluke_scan(struct sr_dev_driver *di, const char *conn,
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* If CMD_ACK was OK, ID string follows. */
|
/* If CMD_ACK was OK, ID string follows. */
|
||||||
len = 128;
|
len = sizeof(buf);
|
||||||
serial_readline(serial, &b, &len, 850);
|
serial_readline(serial, &b, &len, 850);
|
||||||
if (len < 10)
|
if (len < 10)
|
||||||
continue;
|
continue;
|
||||||
|
@ -179,41 +182,22 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
return devices;
|
return devices;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
|
static int config_set(uint32_t key, GVariant *data,
|
||||||
const struct sr_channel_group *cg)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
|
|
||||||
(void)cg;
|
(void)cg;
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
return sr_sw_limits_config_set(&devc->limits, key, data);
|
return sr_sw_limits_config_set(&devc->limits, key, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
|
static int config_list(uint32_t key, GVariant **data,
|
||||||
const struct sr_channel_group *cg)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
(void)sdi;
|
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
|
||||||
(void)cg;
|
|
||||||
|
|
||||||
switch (key) {
|
|
||||||
case SR_CONF_SCAN_OPTIONS:
|
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
|
|
||||||
break;
|
|
||||||
case SR_CONF_DEVICE_OPTIONS:
|
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return SR_ERR_NA;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SR_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||||
|
@ -221,15 +205,11 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
struct sr_serial_dev_inst *serial;
|
struct sr_serial_dev_inst *serial;
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
sr_sw_limits_acquisition_start(&devc->limits);
|
sr_sw_limits_acquisition_start(&devc->limits);
|
||||||
std_session_send_df_header(sdi);
|
std_session_send_df_header(sdi);
|
||||||
|
|
||||||
/* Poll every 100ms, or whenever some data comes in. */
|
|
||||||
serial = sdi->conn;
|
serial = sdi->conn;
|
||||||
serial_source_add(sdi->session, serial, G_IO_IN, 50,
|
serial_source_add(sdi->session, serial, G_IO_IN, 50,
|
||||||
fluke_receive_data, (void *)sdi);
|
fluke_receive_data, (void *)sdi);
|
||||||
|
@ -252,7 +232,7 @@ static struct sr_dev_driver flukedmm_driver_info = {
|
||||||
.cleanup = std_cleanup,
|
.cleanup = std_cleanup,
|
||||||
.scan = scan,
|
.scan = scan,
|
||||||
.dev_list = std_dev_list,
|
.dev_list = std_dev_list,
|
||||||
.dev_clear = NULL,
|
.dev_clear = std_dev_clear,
|
||||||
.config_get = NULL,
|
.config_get = NULL,
|
||||||
.config_set = config_set,
|
.config_set = config_set,
|
||||||
.config_list = config_list,
|
.config_list = config_list,
|
||||||
|
|
|
@ -324,7 +324,7 @@ static void handle_qm_19x_meta(const struct sr_dev_inst *sdi, char **tokens)
|
||||||
else if (meas_char == 3)
|
else if (meas_char == 3)
|
||||||
devc->mqflags |= SR_MQFLAG_DC | SR_MQFLAG_AC;
|
devc->mqflags |= SR_MQFLAG_DC | SR_MQFLAG_AC;
|
||||||
else if (meas_char == 15)
|
else if (meas_char == 15)
|
||||||
devc->mqflags |= SR_MQFLAG_DIODE;
|
devc->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
devc->mq = SR_MQ_CURRENT;
|
devc->mq = SR_MQ_CURRENT;
|
||||||
|
@ -526,7 +526,7 @@ SR_PRIV int fluke_receive_data(int fd, int revents, void *cb_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sr_sw_limits_check(&devc->limits)) {
|
if (sr_sw_limits_check(&devc->limits)) {
|
||||||
sdi->driver->dev_acquisition_stop(sdi);
|
sr_dev_acquisition_stop(sdi);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,12 +46,10 @@ struct flukedmm_profile {
|
||||||
int timeout;
|
int timeout;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Private, per-device-instance driver context. */
|
|
||||||
struct dev_context {
|
struct dev_context {
|
||||||
const struct flukedmm_profile *profile;
|
const struct flukedmm_profile *profile;
|
||||||
struct sr_sw_limits limits;
|
struct sr_sw_limits limits;
|
||||||
|
|
||||||
/* Runtime. */
|
|
||||||
char buf[FLUKEDMM_BUFSIZE];
|
char buf[FLUKEDMM_BUFSIZE];
|
||||||
int buflen;
|
int buflen;
|
||||||
int64_t cmd_sent_at;
|
int64_t cmd_sent_at;
|
||||||
|
|
|
@ -28,8 +28,11 @@ static const uint32_t scanopts[] = {
|
||||||
SR_CONF_CONN,
|
SR_CONF_CONN,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint32_t devopts[] = {
|
static const uint32_t drvopts[] = {
|
||||||
SR_CONF_LOGIC_ANALYZER,
|
SR_CONF_LOGIC_ANALYZER,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t devopts[] = {
|
||||||
SR_CONF_CONTINUOUS,
|
SR_CONF_CONTINUOUS,
|
||||||
SR_CONF_LIMIT_SAMPLES | SR_CONF_SET,
|
SR_CONF_LIMIT_SAMPLES | SR_CONF_SET,
|
||||||
SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
|
SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
|
||||||
|
@ -47,14 +50,8 @@ static const struct ftdi_chip_desc ft2232h_desc = {
|
||||||
.product = 0x6010,
|
.product = 0x6010,
|
||||||
.samplerate_div = 20,
|
.samplerate_div = 20,
|
||||||
.channel_names = {
|
.channel_names = {
|
||||||
"ADBUS0",
|
"ADBUS0", "ADBUS1", "ADBUS2", "ADBUS3",
|
||||||
"ADBUS1",
|
"ADBUS4", "ADBUS5", "ADBUS6", "ADBUS7",
|
||||||
"ADBUS2",
|
|
||||||
"ADBUS3",
|
|
||||||
"ADBUS4",
|
|
||||||
"ADBUS5",
|
|
||||||
"ADBUS6",
|
|
||||||
"ADBUS7",
|
|
||||||
/* TODO: BDBUS[0..7] channels. */
|
/* TODO: BDBUS[0..7] channels. */
|
||||||
NULL
|
NULL
|
||||||
}
|
}
|
||||||
|
@ -65,14 +62,7 @@ static const struct ftdi_chip_desc ft232r_desc = {
|
||||||
.product = 0x6001,
|
.product = 0x6001,
|
||||||
.samplerate_div = 30,
|
.samplerate_div = 30,
|
||||||
.channel_names = {
|
.channel_names = {
|
||||||
"TXD",
|
"TXD", "RXD", "RTS#", "CTS#", "DTR#", "DSR#", "DCD#", "RI#",
|
||||||
"RXD",
|
|
||||||
"RTS#",
|
|
||||||
"CTS#",
|
|
||||||
"DTR#",
|
|
||||||
"DSR#",
|
|
||||||
"DCD#",
|
|
||||||
"RI#",
|
|
||||||
NULL
|
NULL
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -108,7 +98,6 @@ static void scan_device(struct ftdi_context *ftdic,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate memory for our private device context. */
|
|
||||||
devc = g_malloc0(sizeof(struct dev_context));
|
devc = g_malloc0(sizeof(struct dev_context));
|
||||||
|
|
||||||
/* Allocate memory for the incoming data. */
|
/* Allocate memory for the incoming data. */
|
||||||
|
@ -135,7 +124,6 @@ static void scan_device(struct ftdi_context *ftdic,
|
||||||
}
|
}
|
||||||
sr_dbg("Found an FTDI device: %s.", model);
|
sr_dbg("Found an FTDI device: %s.", model);
|
||||||
|
|
||||||
/* Register the device with libsigrok. */
|
|
||||||
sdi = g_malloc0(sizeof(struct sr_dev_inst));
|
sdi = g_malloc0(sizeof(struct sr_dev_inst));
|
||||||
sdi->status = SR_ST_INACTIVE;
|
sdi->status = SR_ST_INACTIVE;
|
||||||
sdi->vendor = vendor;
|
sdi->vendor = vendor;
|
||||||
|
@ -178,8 +166,6 @@ static GSList *scan_all(struct ftdi_context *ftdic, GSList *options)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
sr_dbg("Number of FTDI devices found: %d", ret);
|
|
||||||
|
|
||||||
curdev = devlist;
|
curdev = devlist;
|
||||||
while (curdev) {
|
while (curdev) {
|
||||||
scan_device(ftdic, curdev->dev, &devices);
|
scan_device(ftdic, curdev->dev, &devices);
|
||||||
|
@ -213,7 +199,6 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate memory for the FTDI context (ftdic) and initialize it. */
|
|
||||||
ftdic = ftdi_new();
|
ftdic = ftdi_new();
|
||||||
if (!ftdic) {
|
if (!ftdic) {
|
||||||
sr_err("Failed to initialize libftdi.");
|
sr_err("Failed to initialize libftdi.");
|
||||||
|
@ -242,18 +227,14 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
return std_scan_complete(di, devices);
|
return std_scan_complete(di, devices);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clear_helper(void *priv)
|
static void clear_helper(struct dev_context *devc)
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
|
||||||
|
|
||||||
devc = priv;
|
|
||||||
g_free(devc->data_buf);
|
g_free(devc->data_buf);
|
||||||
g_free(devc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_clear(const struct sr_dev_driver *di)
|
static int dev_clear(const struct sr_dev_driver *di)
|
||||||
{
|
{
|
||||||
return std_dev_clear(di, clear_helper);
|
return std_dev_clear_with_callback(di, (std_dev_clear_callback)clear_helper);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_open(struct sr_dev_inst *sdi)
|
static int dev_open(struct sr_dev_inst *sdi)
|
||||||
|
@ -276,23 +257,19 @@ static int dev_open(struct sr_dev_inst *sdi)
|
||||||
goto err_ftdi_free;
|
goto err_ftdi_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Purge RX/TX buffers in the FTDI chip. */
|
|
||||||
ret = ftdi_usb_purge_buffers(devc->ftdic);
|
ret = ftdi_usb_purge_buffers(devc->ftdic);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
sr_err("Failed to purge FTDI RX/TX buffers (%d): %s.",
|
sr_err("Failed to purge FTDI RX/TX buffers (%d): %s.",
|
||||||
ret, ftdi_get_error_string(devc->ftdic));
|
ret, ftdi_get_error_string(devc->ftdic));
|
||||||
goto err_dev_open_close_ftdic;
|
goto err_dev_open_close_ftdic;
|
||||||
}
|
}
|
||||||
sr_dbg("FTDI chip buffers purged successfully.");
|
|
||||||
|
|
||||||
/* Reset the FTDI bitmode. */
|
|
||||||
ret = ftdi_set_bitmode(devc->ftdic, 0x00, BITMODE_RESET);
|
ret = ftdi_set_bitmode(devc->ftdic, 0x00, BITMODE_RESET);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
sr_err("Failed to reset the FTDI chip bitmode (%d): %s.",
|
sr_err("Failed to reset the FTDI chip bitmode (%d): %s.",
|
||||||
ret, ftdi_get_error_string(devc->ftdic));
|
ret, ftdi_get_error_string(devc->ftdic));
|
||||||
goto err_dev_open_close_ftdic;
|
goto err_dev_open_close_ftdic;
|
||||||
}
|
}
|
||||||
sr_dbg("FTDI chip bitmode reset successfully.");
|
|
||||||
|
|
||||||
ret = ftdi_set_bitmode(devc->ftdic, 0x00, BITMODE_BITBANG);
|
ret = ftdi_set_bitmode(devc->ftdic, 0x00, BITMODE_BITBANG);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@ -300,15 +277,15 @@ static int dev_open(struct sr_dev_inst *sdi)
|
||||||
ret, ftdi_get_error_string(devc->ftdic));
|
ret, ftdi_get_error_string(devc->ftdic));
|
||||||
goto err_dev_open_close_ftdic;
|
goto err_dev_open_close_ftdic;
|
||||||
}
|
}
|
||||||
sr_dbg("FTDI chip bitbang mode entered successfully.");
|
|
||||||
|
|
||||||
sdi->status = SR_ST_ACTIVE;
|
|
||||||
|
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
|
|
||||||
err_dev_open_close_ftdic:
|
err_dev_open_close_ftdic:
|
||||||
ftdi_usb_close(devc->ftdic);
|
ftdi_usb_close(devc->ftdic);
|
||||||
|
|
||||||
err_ftdi_free:
|
err_ftdi_free:
|
||||||
ftdi_free(devc->ftdic);
|
ftdi_free(devc->ftdic);
|
||||||
|
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,13 +295,12 @@ static int dev_close(struct sr_dev_inst *sdi)
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
if (devc->ftdic) {
|
if (!devc->ftdic)
|
||||||
|
return SR_ERR_BUG;
|
||||||
|
|
||||||
ftdi_usb_close(devc->ftdic);
|
ftdi_usb_close(devc->ftdic);
|
||||||
ftdi_free(devc->ftdic);
|
ftdi_free(devc->ftdic);
|
||||||
devc->ftdic = NULL;
|
devc->ftdic = NULL;
|
||||||
}
|
|
||||||
|
|
||||||
sdi->status = SR_ST_INACTIVE;
|
|
||||||
|
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
@ -332,16 +308,13 @@ static int dev_close(struct sr_dev_inst *sdi)
|
||||||
static int config_get(uint32_t key, GVariant **data,
|
static int config_get(uint32_t key, GVariant **data,
|
||||||
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
int ret;
|
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
struct sr_usb_dev_inst *usb;
|
struct sr_usb_dev_inst *usb;
|
||||||
char str[128];
|
|
||||||
|
|
||||||
(void)cg;
|
(void)cg;
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
ret = SR_OK;
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case SR_CONF_SAMPLERATE:
|
case SR_CONF_SAMPLERATE:
|
||||||
*data = g_variant_new_uint64(devc->cur_samplerate);
|
*data = g_variant_new_uint64(devc->cur_samplerate);
|
||||||
|
@ -350,40 +323,32 @@ static int config_get(uint32_t key, GVariant **data,
|
||||||
if (!sdi || !sdi->conn)
|
if (!sdi || !sdi->conn)
|
||||||
return SR_ERR_ARG;
|
return SR_ERR_ARG;
|
||||||
usb = sdi->conn;
|
usb = sdi->conn;
|
||||||
snprintf(str, 128, "%d.%d", usb->bus, usb->address);
|
*data = g_variant_new_printf("%d.%d", usb->bus, usb->address);
|
||||||
*data = g_variant_new_string(str);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return SR_ERR_NA;
|
return SR_ERR_NA;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_set(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)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
int ret;
|
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
uint64_t value;
|
uint64_t value;
|
||||||
|
|
||||||
(void)cg;
|
(void)cg;
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
ret = SR_OK;
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case SR_CONF_LIMIT_MSEC:
|
case SR_CONF_LIMIT_MSEC:
|
||||||
value = g_variant_get_uint64(data);
|
value = g_variant_get_uint64(data);
|
||||||
/* TODO: Implement. */
|
/* TODO: Implement. */
|
||||||
ret = SR_ERR_NA;
|
(void)value;
|
||||||
break;
|
return SR_ERR_NA;
|
||||||
case SR_CONF_LIMIT_SAMPLES:
|
case SR_CONF_LIMIT_SAMPLES:
|
||||||
if (g_variant_get_uint64(data) == 0)
|
|
||||||
return SR_ERR_ARG;
|
|
||||||
devc->limit_samples = g_variant_get_uint64(data);
|
devc->limit_samples = g_variant_get_uint64(data);
|
||||||
break;
|
break;
|
||||||
case SR_CONF_SAMPLERATE:
|
case SR_CONF_SAMPLERATE:
|
||||||
|
@ -393,44 +358,27 @@ static int config_set(uint32_t key, GVariant *data,
|
||||||
devc->cur_samplerate = value;
|
devc->cur_samplerate = value;
|
||||||
return ftdi_la_set_samplerate(devc);
|
return ftdi_la_set_samplerate(devc);
|
||||||
default:
|
default:
|
||||||
ret = SR_ERR_NA;
|
return SR_ERR_NA;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_list(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)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
int ret;
|
|
||||||
GVariant *gvar;
|
|
||||||
GVariantBuilder gvb;
|
|
||||||
|
|
||||||
(void)sdi;
|
|
||||||
(void)cg;
|
|
||||||
|
|
||||||
ret = SR_OK;
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case SR_CONF_SCAN_OPTIONS:
|
case SR_CONF_SCAN_OPTIONS:
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
|
|
||||||
break;
|
|
||||||
case SR_CONF_DEVICE_OPTIONS:
|
case SR_CONF_DEVICE_OPTIONS:
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
|
||||||
devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
|
|
||||||
break;
|
|
||||||
case SR_CONF_SAMPLERATE:
|
case SR_CONF_SAMPLERATE:
|
||||||
g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
|
*data = std_gvar_samplerates_steps(ARRAY_AND_SIZE(samplerates));
|
||||||
gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"),
|
|
||||||
samplerates, ARRAY_SIZE(samplerates), sizeof(uint64_t));
|
|
||||||
g_variant_builder_add(&gvb, "{sv}", "samplerate-steps", gvar);
|
|
||||||
*data = g_variant_builder_end(&gvb);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return SR_ERR_NA;
|
return SR_ERR_NA;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||||
|
@ -439,9 +387,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
if (!devc->ftdic)
|
if (!devc->ftdic)
|
||||||
return SR_ERR_BUG;
|
return SR_ERR_BUG;
|
||||||
|
|
||||||
|
@ -462,10 +407,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||||
|
|
||||||
static int dev_acquisition_stop(struct sr_dev_inst *sdi)
|
static int dev_acquisition_stop(struct sr_dev_inst *sdi)
|
||||||
{
|
{
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
sr_dbg("Stopping acquisition.");
|
|
||||||
sr_session_source_remove(sdi->session, -1);
|
sr_session_source_remove(sdi->session, -1);
|
||||||
|
|
||||||
std_session_send_df_end(sdi);
|
std_session_send_df_end(sdi);
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
#include <ftdi.h>
|
#include <ftdi.h>
|
||||||
#include "protocol.h"
|
#include "protocol.h"
|
||||||
|
|
||||||
|
@ -79,7 +80,7 @@ SR_PRIV int ftdi_la_receive_data(int fd, int revents, void *cb_data)
|
||||||
if (bytes_read < 0) {
|
if (bytes_read < 0) {
|
||||||
sr_err("Failed to read FTDI data (%d): %s.",
|
sr_err("Failed to read FTDI data (%d): %s.",
|
||||||
bytes_read, ftdi_get_error_string(devc->ftdic));
|
bytes_read, ftdi_get_error_string(devc->ftdic));
|
||||||
sdi->driver->dev_acquisition_stop(sdi);
|
sr_dev_acquisition_stop(sdi);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
if (bytes_read == 0) {
|
if (bytes_read == 0) {
|
||||||
|
@ -94,7 +95,7 @@ SR_PRIV int ftdi_la_receive_data(int fd, int revents, void *cb_data)
|
||||||
if (devc->limit_samples && (n >= devc->limit_samples)) {
|
if (devc->limit_samples && (n >= devc->limit_samples)) {
|
||||||
send_samples(sdi, devc->limit_samples - devc->samples_sent);
|
send_samples(sdi, devc->limit_samples - devc->samples_sent);
|
||||||
sr_info("Requested number of samples reached.");
|
sr_info("Requested number of samples reached.");
|
||||||
sdi->driver->dev_acquisition_stop(sdi);
|
sr_dev_acquisition_stop(sdi);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
} else {
|
} else {
|
||||||
send_samples(sdi, devc->bytes_received);
|
send_samples(sdi, devc->bytes_received);
|
||||||
|
|
|
@ -36,7 +36,6 @@ struct ftdi_chip_desc {
|
||||||
char *channel_names[];
|
char *channel_names[];
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Private, per-device-instance driver context. */
|
|
||||||
struct dev_context {
|
struct dev_context {
|
||||||
struct ftdi_context *ftdic;
|
struct ftdi_context *ftdic;
|
||||||
const struct ftdi_chip_desc *desc;
|
const struct ftdi_chip_desc *desc;
|
||||||
|
|
|
@ -20,21 +20,27 @@
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include "protocol.h"
|
#include "protocol.h"
|
||||||
#include "dslogic.h"
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
static const struct fx2lafw_profile supported_fx2[] = {
|
static const struct fx2lafw_profile supported_fx2[] = {
|
||||||
/*
|
/*
|
||||||
* CWAV USBee AX
|
* CWAV USBee AX
|
||||||
* EE Electronics ESLA201A
|
* ARMFLY AX-Pro (clone of the CWAV USBee AX)
|
||||||
* ARMFLY AX-Pro
|
* ARMFLY Mini-Logic (clone of the CWAV USBee AX)
|
||||||
|
* EE Electronics ESLA201A (clone of the CWAV USBee AX)
|
||||||
|
* HT USBee-AxPro (clone of the CWAV USBee AX)
|
||||||
|
* MCU123 USBee AX Pro clone (clone of the CWAV USBee AX)
|
||||||
|
* Noname LHT00SU1 (clone of the CWAV USBee AX)
|
||||||
|
* XZL_Studio AX (clone of the CWAV USBee AX)
|
||||||
*/
|
*/
|
||||||
{ 0x08a9, 0x0014, "CWAV", "USBee AX", NULL,
|
{ 0x08a9, 0x0014, "CWAV", "USBee AX", NULL,
|
||||||
"fx2lafw-cwav-usbeeax.fw",
|
"fx2lafw-cwav-usbeeax.fw",
|
||||||
DEV_CAPS_AX_ANALOG, NULL, NULL},
|
DEV_CAPS_AX_ANALOG, NULL, NULL},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CWAV USBee DX
|
* CWAV USBee DX
|
||||||
* XZL-Studio DX
|
* HT USBee-DxPro (clone of the CWAV USBee DX), not yet supported!
|
||||||
|
* XZL-Studio DX (clone of the CWAV USBee DX)
|
||||||
*/
|
*/
|
||||||
{ 0x08a9, 0x0015, "CWAV", "USBee DX", NULL,
|
{ 0x08a9, 0x0015, "CWAV", "USBee DX", NULL,
|
||||||
"fx2lafw-cwav-usbeedx.fw",
|
"fx2lafw-cwav-usbeedx.fw",
|
||||||
|
@ -54,38 +60,14 @@ static const struct fx2lafw_profile supported_fx2[] = {
|
||||||
"fx2lafw-cwav-usbeezx.fw",
|
"fx2lafw-cwav-usbeezx.fw",
|
||||||
0, NULL, NULL},
|
0, NULL, NULL},
|
||||||
|
|
||||||
/* DreamSourceLab DSLogic (before FW upload) */
|
|
||||||
{ 0x2a0e, 0x0001, "DreamSourceLab", "DSLogic", NULL,
|
|
||||||
"dreamsourcelab-dslogic-fx2.fw",
|
|
||||||
DEV_CAPS_16BIT | DEV_CAPS_DSLOGIC_FW, NULL, NULL},
|
|
||||||
/* DreamSourceLab DSLogic (after FW upload) */
|
|
||||||
{ 0x2a0e, 0x0001, "DreamSourceLab", "DSLogic", NULL,
|
|
||||||
"dreamsourcelab-dslogic-fx2.fw",
|
|
||||||
DEV_CAPS_16BIT | DEV_CAPS_DSLOGIC_FW, "DreamSourceLab", "DSLogic"},
|
|
||||||
|
|
||||||
/* DreamSourceLab DSCope (before FW upload) */
|
|
||||||
{ 0x2a0e, 0x0002, "DreamSourceLab", "DSCope", NULL,
|
|
||||||
"dreamsourcelab-dscope-fx2.fw",
|
|
||||||
DEV_CAPS_16BIT | DEV_CAPS_DSLOGIC_FW, NULL, NULL},
|
|
||||||
/* DreamSourceLab DSCope (after FW upload) */
|
|
||||||
{ 0x2a0e, 0x0002, "DreamSourceLab", "DSCope", NULL,
|
|
||||||
"dreamsourcelab-dscope-fx2.fw",
|
|
||||||
DEV_CAPS_16BIT | DEV_CAPS_DSLOGIC_FW, "DreamSourceLab", "DSCope"},
|
|
||||||
|
|
||||||
/* DreamSourceLab DSLogic Pro (before FW upload) */
|
|
||||||
{ 0x2a0e, 0x0003, "DreamSourceLab", "DSLogic Pro", NULL,
|
|
||||||
"dreamsourcelab-dslogic-pro-fx2.fw",
|
|
||||||
DEV_CAPS_16BIT | DEV_CAPS_DSLOGIC_FW, NULL, NULL},
|
|
||||||
/* DreamSourceLab DSLogic Pro (after FW upload) */
|
|
||||||
{ 0x2a0e, 0x0003, "DreamSourceLab", "DSLogic Pro", NULL,
|
|
||||||
"dreamsourcelab-dslogic-pro-fx2.fw",
|
|
||||||
DEV_CAPS_16BIT | DEV_CAPS_DSLOGIC_FW, "DreamSourceLab", "DSLogic"},
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Saleae Logic
|
* Saleae Logic
|
||||||
* EE Electronics ESLA100
|
* EE Electronics ESLA100 (clone of the Saleae Logic)
|
||||||
* Robomotic MiniLogic
|
* Hantek 6022BL in LA mode (clone of the Saleae Logic)
|
||||||
* Robomotic BugLogic 3
|
* Instrustar ISDS205X in LA mode (clone of the Saleae Logic)
|
||||||
|
* Robomotic MiniLogic (clone of the Saleae Logic)
|
||||||
|
* Robomotic BugLogic 3 (clone of the Saleae Logic)
|
||||||
|
* MCU123 Saleae Logic clone (clone of the Saleae Logic)
|
||||||
*/
|
*/
|
||||||
{ 0x0925, 0x3881, "Saleae", "Logic", NULL,
|
{ 0x0925, 0x3881, "Saleae", "Logic", NULL,
|
||||||
"fx2lafw-saleae-logic.fw",
|
"fx2lafw-saleae-logic.fw",
|
||||||
|
@ -95,6 +77,7 @@ static const struct fx2lafw_profile supported_fx2[] = {
|
||||||
* Default Cypress FX2 without EEPROM, e.g.:
|
* Default Cypress FX2 without EEPROM, e.g.:
|
||||||
* Lcsoft Mini Board
|
* Lcsoft Mini Board
|
||||||
* Braintechnology USB Interface V2.x
|
* Braintechnology USB Interface V2.x
|
||||||
|
* fx2grok-tiny
|
||||||
*/
|
*/
|
||||||
{ 0x04B4, 0x8613, "Cypress", "FX2", NULL,
|
{ 0x04B4, 0x8613, "Cypress", "FX2", NULL,
|
||||||
"fx2lafw-cypress-fx2.fw",
|
"fx2lafw-cypress-fx2.fw",
|
||||||
|
@ -109,6 +92,7 @@ static const struct fx2lafw_profile supported_fx2[] = {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* sigrok FX2 based 8-channel logic analyzer
|
* sigrok FX2 based 8-channel logic analyzer
|
||||||
|
* fx2grok-flat (before and after renumeration)
|
||||||
*/
|
*/
|
||||||
{ 0x1d50, 0x608c, "sigrok", "FX2 LA (8ch)", NULL,
|
{ 0x1d50, 0x608c, "sigrok", "FX2 LA (8ch)", NULL,
|
||||||
"fx2lafw-sigrok-fx2-8ch.fw",
|
"fx2lafw-sigrok-fx2-8ch.fw",
|
||||||
|
@ -121,17 +105,24 @@ static const struct fx2lafw_profile supported_fx2[] = {
|
||||||
"fx2lafw-sigrok-fx2-16ch.fw",
|
"fx2lafw-sigrok-fx2-16ch.fw",
|
||||||
DEV_CAPS_16BIT, NULL, NULL },
|
DEV_CAPS_16BIT, NULL, NULL },
|
||||||
|
|
||||||
ALL_ZERO
|
/*
|
||||||
};
|
* usb-c-grok
|
||||||
|
*/
|
||||||
|
{ 0x1d50, 0x608f, "sigrok", "usb-c-grok", NULL,
|
||||||
|
"fx2lafw-usb-c-grok.fw",
|
||||||
|
0, NULL, NULL},
|
||||||
|
|
||||||
static const uint32_t drvopts[] = {
|
ALL_ZERO
|
||||||
SR_CONF_LOGIC_ANALYZER,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint32_t scanopts[] = {
|
static const uint32_t scanopts[] = {
|
||||||
SR_CONF_CONN,
|
SR_CONF_CONN,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const uint32_t drvopts[] = {
|
||||||
|
SR_CONF_LOGIC_ANALYZER,
|
||||||
|
};
|
||||||
|
|
||||||
static const uint32_t devopts[] = {
|
static const uint32_t devopts[] = {
|
||||||
SR_CONF_CONTINUOUS,
|
SR_CONF_CONTINUOUS,
|
||||||
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
|
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
|
||||||
|
@ -141,19 +132,7 @@ static const uint32_t devopts[] = {
|
||||||
SR_CONF_CAPTURE_RATIO | SR_CONF_GET | SR_CONF_SET,
|
SR_CONF_CAPTURE_RATIO | SR_CONF_GET | SR_CONF_SET,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint32_t dslogic_devopts[] = {
|
static const int32_t trigger_matches[] = {
|
||||||
SR_CONF_CONTINUOUS | SR_CONF_SET | SR_CONF_GET,
|
|
||||||
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
|
|
||||||
SR_CONF_VOLTAGE_THRESHOLD | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
|
|
||||||
SR_CONF_CONN | SR_CONF_GET,
|
|
||||||
SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
|
|
||||||
SR_CONF_TRIGGER_MATCH | SR_CONF_LIST,
|
|
||||||
SR_CONF_CAPTURE_RATIO | SR_CONF_GET | SR_CONF_SET,
|
|
||||||
SR_CONF_EXTERNAL_CLOCK | SR_CONF_GET | SR_CONF_SET,
|
|
||||||
SR_CONF_CLOCK_EDGE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const int32_t soft_trigger_matches[] = {
|
|
||||||
SR_TRIGGER_ZERO,
|
SR_TRIGGER_ZERO,
|
||||||
SR_TRIGGER_ONE,
|
SR_TRIGGER_ONE,
|
||||||
SR_TRIGGER_RISING,
|
SR_TRIGGER_RISING,
|
||||||
|
@ -161,21 +140,6 @@ static const int32_t soft_trigger_matches[] = {
|
||||||
SR_TRIGGER_EDGE,
|
SR_TRIGGER_EDGE,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Names assigned to available edge slope choices. */
|
|
||||||
static const char *const signal_edge_names[] = {
|
|
||||||
[DS_EDGE_RISING] = "rising",
|
|
||||||
[DS_EDGE_FALLING] = "falling",
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct {
|
|
||||||
int range;
|
|
||||||
gdouble low;
|
|
||||||
gdouble high;
|
|
||||||
} volt_thresholds[] = {
|
|
||||||
{ DS_VOLTAGE_RANGE_18_33_V, 0.7, 1.4 },
|
|
||||||
{ DS_VOLTAGE_RANGE_5_V, 1.4, 3.6 },
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint64_t samplerates[] = {
|
static const uint64_t samplerates[] = {
|
||||||
SR_KHZ(20),
|
SR_KHZ(20),
|
||||||
SR_KHZ(25),
|
SR_KHZ(25),
|
||||||
|
@ -195,25 +159,6 @@ static const uint64_t samplerates[] = {
|
||||||
SR_MHZ(24),
|
SR_MHZ(24),
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint64_t dslogic_samplerates[] = {
|
|
||||||
SR_KHZ(10),
|
|
||||||
SR_KHZ(20),
|
|
||||||
SR_KHZ(50),
|
|
||||||
SR_KHZ(100),
|
|
||||||
SR_KHZ(200),
|
|
||||||
SR_KHZ(500),
|
|
||||||
SR_MHZ(1),
|
|
||||||
SR_MHZ(2),
|
|
||||||
SR_MHZ(5),
|
|
||||||
SR_MHZ(10),
|
|
||||||
SR_MHZ(20),
|
|
||||||
SR_MHZ(25),
|
|
||||||
SR_MHZ(50),
|
|
||||||
SR_MHZ(100),
|
|
||||||
SR_MHZ(200),
|
|
||||||
SR_MHZ(400),
|
|
||||||
};
|
|
||||||
|
|
||||||
static gboolean is_plausible(const struct libusb_device_descriptor *des)
|
static gboolean is_plausible(const struct libusb_device_descriptor *des)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -325,10 +270,11 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
usb_get_port_path(devlist[i], connection_id, sizeof(connection_id));
|
|
||||||
|
|
||||||
libusb_close(hdl);
|
libusb_close(hdl);
|
||||||
|
|
||||||
|
if (usb_get_port_path(devlist[i], connection_id, sizeof(connection_id)) < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
prof = NULL;
|
prof = NULL;
|
||||||
for (j = 0; supported_fx2[j].vid; j++) {
|
for (j = 0; supported_fx2[j].vid; j++) {
|
||||||
if (des.idVendor == supported_fx2[j].vid &&
|
if (des.idVendor == supported_fx2[j].vid &&
|
||||||
|
@ -342,7 +288,6 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Skip if the device was not found. */
|
|
||||||
if (!prof)
|
if (!prof)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -386,21 +331,10 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
sdi->priv = devc;
|
sdi->priv = devc;
|
||||||
devices = g_slist_append(devices, sdi);
|
devices = g_slist_append(devices, sdi);
|
||||||
|
|
||||||
if (!strcmp(prof->model, "DSLogic")
|
|
||||||
|| !strcmp(prof->model, "DSLogic Pro")
|
|
||||||
|| !strcmp(prof->model, "DSCope")) {
|
|
||||||
devc->dslogic = TRUE;
|
|
||||||
devc->samplerates = dslogic_samplerates;
|
|
||||||
devc->num_samplerates = ARRAY_SIZE(dslogic_samplerates);
|
|
||||||
has_firmware = match_manuf_prod(devlist[i], "DreamSourceLab", "DSLogic")
|
|
||||||
|| match_manuf_prod(devlist[i], "DreamSourceLab", "DSCope");
|
|
||||||
} else {
|
|
||||||
devc->dslogic = FALSE;
|
|
||||||
devc->samplerates = samplerates;
|
devc->samplerates = samplerates;
|
||||||
devc->num_samplerates = ARRAY_SIZE(samplerates);
|
devc->num_samplerates = ARRAY_SIZE(samplerates);
|
||||||
has_firmware = match_manuf_prod(devlist[i],
|
has_firmware = usb_match_manuf_prod(devlist[i],
|
||||||
"sigrok", "fx2lafw");
|
"sigrok", "fx2lafw");
|
||||||
}
|
|
||||||
|
|
||||||
if (has_firmware) {
|
if (has_firmware) {
|
||||||
/* Already has the firmware, so fix the new address. */
|
/* Already has the firmware, so fix the new address. */
|
||||||
|
@ -411,14 +345,16 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
libusb_get_device_address(devlist[i]), NULL);
|
libusb_get_device_address(devlist[i]), NULL);
|
||||||
} else {
|
} else {
|
||||||
if (ezusb_upload_firmware(drvc->sr_ctx, devlist[i],
|
if (ezusb_upload_firmware(drvc->sr_ctx, devlist[i],
|
||||||
USB_CONFIGURATION, prof->firmware) == SR_OK)
|
USB_CONFIGURATION, prof->firmware) == SR_OK) {
|
||||||
/* Store when this device's FW was updated. */
|
/* Store when this device's FW was updated. */
|
||||||
devc->fw_updated = g_get_monotonic_time();
|
devc->fw_updated = g_get_monotonic_time();
|
||||||
else
|
} else {
|
||||||
sr_err("Firmware upload failed for "
|
sr_err("Firmware upload failed for "
|
||||||
"device %d.%d (logical).",
|
"device %d.%d (logical), name %s.",
|
||||||
libusb_get_bus_number(devlist[i]),
|
libusb_get_bus_number(devlist[i]),
|
||||||
libusb_get_device_address(devlist[i]));
|
libusb_get_device_address(devlist[i]),
|
||||||
|
prof->firmware);
|
||||||
|
}
|
||||||
sdi->inst_type = SR_INST_USB;
|
sdi->inst_type = SR_INST_USB;
|
||||||
sdi->conn = sr_usb_dev_inst_new(libusb_get_bus_number(devlist[i]),
|
sdi->conn = sr_usb_dev_inst_new(libusb_get_bus_number(devlist[i]),
|
||||||
0xff, NULL);
|
0xff, NULL);
|
||||||
|
@ -430,18 +366,14 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
return std_scan_complete(di, devices);
|
return std_scan_complete(di, devices);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clear_dev_context(void *priv)
|
static void clear_helper(struct dev_context *devc)
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
|
||||||
|
|
||||||
devc = priv;
|
|
||||||
g_slist_free(devc->enabled_analog_channels);
|
g_slist_free(devc->enabled_analog_channels);
|
||||||
g_free(devc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_clear(const struct sr_dev_driver *di)
|
static int dev_clear(const struct sr_dev_driver *di)
|
||||||
{
|
{
|
||||||
return std_dev_clear(di, clear_dev_context);
|
return std_dev_clear_with_callback(di, (std_dev_clear_callback)clear_helper);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_open(struct sr_dev_inst *sdi)
|
static int dev_open(struct sr_dev_inst *sdi)
|
||||||
|
@ -449,7 +381,6 @@ static int dev_open(struct sr_dev_inst *sdi)
|
||||||
struct sr_dev_driver *di = sdi->driver;
|
struct sr_dev_driver *di = sdi->driver;
|
||||||
struct sr_usb_dev_inst *usb;
|
struct sr_usb_dev_inst *usb;
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
const char *fpga_firmware = NULL;
|
|
||||||
int ret;
|
int ret;
|
||||||
int64_t timediff_us, timediff_ms;
|
int64_t timediff_us, timediff_ms;
|
||||||
|
|
||||||
|
@ -509,21 +440,6 @@ static int dev_open(struct sr_dev_inst *sdi)
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (devc->dslogic) {
|
|
||||||
if (!strcmp(devc->profile->model, "DSLogic")) {
|
|
||||||
if (devc->dslogic_voltage_threshold == DS_VOLTAGE_RANGE_18_33_V)
|
|
||||||
fpga_firmware = DSLOGIC_FPGA_FIRMWARE_3V3;
|
|
||||||
else
|
|
||||||
fpga_firmware = DSLOGIC_FPGA_FIRMWARE_5V;
|
|
||||||
} else if (!strcmp(devc->profile->model, "DSLogic Pro")){
|
|
||||||
fpga_firmware = DSLOGIC_PRO_FPGA_FIRMWARE;
|
|
||||||
} else if (!strcmp(devc->profile->model, "DSCope")) {
|
|
||||||
fpga_firmware = DSCOPE_FPGA_FIRMWARE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((ret = dslogic_fpga_firmware_upload(sdi, fpga_firmware)) != SR_OK)
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
if (devc->cur_samplerate == 0) {
|
if (devc->cur_samplerate == 0) {
|
||||||
/* Samplerate hasn't been set; default to the slowest one. */
|
/* Samplerate hasn't been set; default to the slowest one. */
|
||||||
devc->cur_samplerate = devc->samplerates[0];
|
devc->cur_samplerate = devc->samplerates[0];
|
||||||
|
@ -539,14 +455,13 @@ static int dev_close(struct sr_dev_inst *sdi)
|
||||||
usb = sdi->conn;
|
usb = sdi->conn;
|
||||||
|
|
||||||
if (!usb->devhdl)
|
if (!usb->devhdl)
|
||||||
return SR_ERR;
|
return SR_ERR_BUG;
|
||||||
|
|
||||||
sr_info("fx2lafw: Closing device on %d.%d (logical) / %s (physical) interface %d.",
|
sr_info("Closing device on %d.%d (logical) / %s (physical) interface %d.",
|
||||||
usb->bus, usb->address, sdi->connection_id, USB_INTERFACE);
|
usb->bus, usb->address, sdi->connection_id, USB_INTERFACE);
|
||||||
libusb_release_interface(usb->devhdl, USB_INTERFACE);
|
libusb_release_interface(usb->devhdl, USB_INTERFACE);
|
||||||
libusb_close(usb->devhdl);
|
libusb_close(usb->devhdl);
|
||||||
usb->devhdl = NULL;
|
usb->devhdl = NULL;
|
||||||
sdi->status = SR_ST_INACTIVE;
|
|
||||||
|
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
@ -556,9 +471,6 @@ static int config_get(uint32_t key, GVariant **data,
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
struct sr_usb_dev_inst *usb;
|
struct sr_usb_dev_inst *usb;
|
||||||
GVariant *range[2];
|
|
||||||
unsigned int i;
|
|
||||||
char str[128];
|
|
||||||
|
|
||||||
(void)cg;
|
(void)cg;
|
||||||
|
|
||||||
|
@ -576,18 +488,7 @@ static int config_get(uint32_t key, GVariant **data,
|
||||||
/* Device still needs to re-enumerate after firmware
|
/* Device still needs to re-enumerate after firmware
|
||||||
* upload, so we don't know its (future) address. */
|
* upload, so we don't know its (future) address. */
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
snprintf(str, 128, "%d.%d", usb->bus, usb->address);
|
*data = g_variant_new_printf("%d.%d", usb->bus, usb->address);
|
||||||
*data = g_variant_new_string(str);
|
|
||||||
break;
|
|
||||||
case SR_CONF_VOLTAGE_THRESHOLD:
|
|
||||||
for (i = 0; i < ARRAY_SIZE(volt_thresholds); i++) {
|
|
||||||
if (volt_thresholds[i].range != devc->dslogic_voltage_threshold)
|
|
||||||
continue;
|
|
||||||
range[0] = g_variant_new_double(volt_thresholds[i].low);
|
|
||||||
range[1] = g_variant_new_double(volt_thresholds[i].high);
|
|
||||||
*data = g_variant_new_tuple(range, 2);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case SR_CONF_LIMIT_SAMPLES:
|
case SR_CONF_LIMIT_SAMPLES:
|
||||||
*data = g_variant_new_uint64(devc->limit_samples);
|
*data = g_variant_new_uint64(devc->limit_samples);
|
||||||
|
@ -598,18 +499,6 @@ static int config_get(uint32_t key, GVariant **data,
|
||||||
case SR_CONF_CAPTURE_RATIO:
|
case SR_CONF_CAPTURE_RATIO:
|
||||||
*data = g_variant_new_uint64(devc->capture_ratio);
|
*data = g_variant_new_uint64(devc->capture_ratio);
|
||||||
break;
|
break;
|
||||||
case SR_CONF_EXTERNAL_CLOCK:
|
|
||||||
*data = g_variant_new_boolean(devc->dslogic_external_clock);
|
|
||||||
break;
|
|
||||||
case SR_CONF_CONTINUOUS:
|
|
||||||
*data = g_variant_new_boolean(devc->dslogic_continuous_mode);
|
|
||||||
break;
|
|
||||||
case SR_CONF_CLOCK_EDGE:
|
|
||||||
i = devc->dslogic_clock_edge;
|
|
||||||
if (i >= ARRAY_SIZE(signal_edge_names))
|
|
||||||
return SR_ERR_BUG;
|
|
||||||
*data = g_variant_new_string(signal_edge_names[0]);
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
return SR_ERR_NA;
|
return SR_ERR_NA;
|
||||||
}
|
}
|
||||||
|
@ -617,166 +506,58 @@ static int config_get(uint32_t key, GVariant **data,
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Helper for mapping a string-typed configuration value to an index
|
|
||||||
* within a table of possible values.
|
|
||||||
*/
|
|
||||||
static int lookup_index(GVariant *value, const char *const *table, int len)
|
|
||||||
{
|
|
||||||
const char *entry;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
entry = g_variant_get_string(value, NULL);
|
|
||||||
if (!entry)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
/* Linear search is fine for very small tables. */
|
|
||||||
for (i = 0; i < len; i++) {
|
|
||||||
if (strcmp(entry, table[i]) == 0)
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int config_set(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)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
uint64_t arg;
|
int idx;
|
||||||
int i, ret;
|
|
||||||
gdouble low, high;
|
|
||||||
|
|
||||||
(void)cg;
|
(void)cg;
|
||||||
|
|
||||||
if (!sdi)
|
if (!sdi)
|
||||||
return SR_ERR_ARG;
|
return SR_ERR_ARG;
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR;
|
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
ret = SR_OK;
|
|
||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case SR_CONF_SAMPLERATE:
|
case SR_CONF_SAMPLERATE:
|
||||||
arg = g_variant_get_uint64(data);
|
if ((idx = std_u64_idx(data, devc->samplerates, devc->num_samplerates)) < 0)
|
||||||
for (i = 0; i < devc->num_samplerates; i++) {
|
return SR_ERR_ARG;
|
||||||
if (devc->samplerates[i] == arg) {
|
devc->cur_samplerate = devc->samplerates[idx];
|
||||||
devc->cur_samplerate = arg;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (i == devc->num_samplerates)
|
|
||||||
ret = SR_ERR_ARG;
|
|
||||||
break;
|
break;
|
||||||
case SR_CONF_LIMIT_SAMPLES:
|
case SR_CONF_LIMIT_SAMPLES:
|
||||||
devc->limit_samples = g_variant_get_uint64(data);
|
devc->limit_samples = g_variant_get_uint64(data);
|
||||||
break;
|
break;
|
||||||
case SR_CONF_CAPTURE_RATIO:
|
case SR_CONF_CAPTURE_RATIO:
|
||||||
devc->capture_ratio = g_variant_get_uint64(data);
|
devc->capture_ratio = g_variant_get_uint64(data);
|
||||||
ret = (devc->capture_ratio > 100) ? SR_ERR : SR_OK;
|
|
||||||
break;
|
|
||||||
case SR_CONF_VOLTAGE_THRESHOLD:
|
|
||||||
g_variant_get(data, "(dd)", &low, &high);
|
|
||||||
ret = SR_ERR_ARG;
|
|
||||||
for (i = 0; (unsigned int)i < ARRAY_SIZE(volt_thresholds); i++) {
|
|
||||||
if (fabs(volt_thresholds[i].low - low) < 0.1 &&
|
|
||||||
fabs(volt_thresholds[i].high - high) < 0.1) {
|
|
||||||
devc->dslogic_voltage_threshold = volt_thresholds[i].range;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!strcmp(devc->profile->model, "DSLogic")) {
|
|
||||||
if (devc->dslogic_voltage_threshold == DS_VOLTAGE_RANGE_5_V)
|
|
||||||
ret = dslogic_fpga_firmware_upload(sdi, DSLOGIC_FPGA_FIRMWARE_5V);
|
|
||||||
else
|
|
||||||
ret = dslogic_fpga_firmware_upload(sdi, DSLOGIC_FPGA_FIRMWARE_3V3);
|
|
||||||
} else if (!strcmp(devc->profile->model, "DSLogic Pro")) {
|
|
||||||
ret = dslogic_fpga_firmware_upload(sdi, DSLOGIC_PRO_FPGA_FIRMWARE);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SR_CONF_EXTERNAL_CLOCK:
|
|
||||||
devc->dslogic_external_clock = g_variant_get_boolean(data);
|
|
||||||
break;
|
|
||||||
case SR_CONF_CONTINUOUS:
|
|
||||||
devc->dslogic_continuous_mode = g_variant_get_boolean(data);
|
|
||||||
break;
|
|
||||||
case SR_CONF_CLOCK_EDGE:
|
|
||||||
i = lookup_index(data, signal_edge_names,
|
|
||||||
ARRAY_SIZE(signal_edge_names));
|
|
||||||
if (i < 0)
|
|
||||||
return SR_ERR_ARG;
|
|
||||||
devc->dslogic_clock_edge = i;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret = SR_ERR_NA;
|
return SR_ERR_NA;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_list(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)
|
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
GVariant *gvar, *range[2];
|
|
||||||
GVariantBuilder gvb;
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
(void)cg;
|
devc = (sdi) ? sdi->priv : NULL;
|
||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case SR_CONF_SCAN_OPTIONS:
|
case SR_CONF_SCAN_OPTIONS:
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
|
|
||||||
break;
|
|
||||||
case SR_CONF_DEVICE_OPTIONS:
|
case SR_CONF_DEVICE_OPTIONS:
|
||||||
if (!sdi) {
|
if (cg)
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
drvopts, ARRAY_SIZE(drvopts), sizeof(uint32_t));
|
|
||||||
} else {
|
|
||||||
devc = sdi->priv;
|
|
||||||
if (!devc->dslogic)
|
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
|
|
||||||
else
|
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
|
|
||||||
dslogic_devopts, ARRAY_SIZE(dslogic_devopts), sizeof(uint32_t));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SR_CONF_VOLTAGE_THRESHOLD:
|
|
||||||
if (!sdi->priv)
|
|
||||||
return SR_ERR_ARG;
|
|
||||||
devc = sdi->priv;
|
|
||||||
if (!devc->dslogic)
|
|
||||||
return SR_ERR_NA;
|
return SR_ERR_NA;
|
||||||
g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
|
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
|
||||||
for (i = 0; i < ARRAY_SIZE(volt_thresholds); i++) {
|
|
||||||
range[0] = g_variant_new_double(volt_thresholds[i].low);
|
|
||||||
range[1] = g_variant_new_double(volt_thresholds[i].high);
|
|
||||||
gvar = g_variant_new_tuple(range, 2);
|
|
||||||
g_variant_builder_add_value(&gvb, gvar);
|
|
||||||
}
|
|
||||||
*data = g_variant_builder_end(&gvb);
|
|
||||||
break;
|
|
||||||
case SR_CONF_SAMPLERATE:
|
case SR_CONF_SAMPLERATE:
|
||||||
devc = sdi->priv;
|
if (!devc)
|
||||||
g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
|
return SR_ERR_NA;
|
||||||
gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), devc->samplerates,
|
*data = std_gvar_samplerates(devc->samplerates, devc->num_samplerates);
|
||||||
devc->num_samplerates, sizeof(uint64_t));
|
|
||||||
g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar);
|
|
||||||
*data = g_variant_builder_end(&gvb);
|
|
||||||
break;
|
break;
|
||||||
case SR_CONF_TRIGGER_MATCH:
|
case SR_CONF_TRIGGER_MATCH:
|
||||||
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
|
*data = std_gvar_array_i32(ARRAY_AND_SIZE(trigger_matches));
|
||||||
soft_trigger_matches, ARRAY_SIZE(soft_trigger_matches),
|
|
||||||
sizeof(int32_t));
|
|
||||||
break;
|
|
||||||
case SR_CONF_CLOCK_EDGE:
|
|
||||||
*data = g_variant_new_strv(signal_edge_names,
|
|
||||||
ARRAY_SIZE(signal_edge_names));
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return SR_ERR_NA;
|
return SR_ERR_NA;
|
||||||
|
@ -785,294 +566,8 @@ static int config_list(uint32_t key, GVariant **data,
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int receive_data(int fd, int revents, void *cb_data)
|
|
||||||
{
|
|
||||||
struct timeval tv;
|
|
||||||
struct drv_context *drvc;
|
|
||||||
|
|
||||||
(void)fd;
|
|
||||||
(void)revents;
|
|
||||||
|
|
||||||
drvc = (struct drv_context *)cb_data;
|
|
||||||
|
|
||||||
tv.tv_sec = tv.tv_usec = 0;
|
|
||||||
libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int start_transfers(const struct sr_dev_inst *sdi)
|
|
||||||
{
|
|
||||||
struct dev_context *devc;
|
|
||||||
struct sr_usb_dev_inst *usb;
|
|
||||||
struct sr_trigger *trigger;
|
|
||||||
struct libusb_transfer *transfer;
|
|
||||||
unsigned int i, num_transfers;
|
|
||||||
int endpoint, timeout, ret;
|
|
||||||
unsigned char *buf;
|
|
||||||
size_t size;
|
|
||||||
|
|
||||||
devc = sdi->priv;
|
|
||||||
usb = sdi->conn;
|
|
||||||
|
|
||||||
devc->sent_samples = 0;
|
|
||||||
devc->acq_aborted = FALSE;
|
|
||||||
devc->empty_transfer_count = 0;
|
|
||||||
|
|
||||||
if ((trigger = sr_session_trigger_get(sdi->session)) && !devc->dslogic) {
|
|
||||||
int pre_trigger_samples = 0;
|
|
||||||
if (devc->limit_samples > 0)
|
|
||||||
pre_trigger_samples = devc->capture_ratio * devc->limit_samples/100;
|
|
||||||
devc->stl = soft_trigger_logic_new(sdi, trigger, pre_trigger_samples);
|
|
||||||
if (!devc->stl)
|
|
||||||
return SR_ERR_MALLOC;
|
|
||||||
devc->trigger_fired = FALSE;
|
|
||||||
} else
|
|
||||||
devc->trigger_fired = TRUE;
|
|
||||||
|
|
||||||
num_transfers = fx2lafw_get_number_of_transfers(devc);
|
|
||||||
|
|
||||||
//if (devc->dslogic)
|
|
||||||
// num_transfers = dslogic_get_number_of_transfers(devc);
|
|
||||||
|
|
||||||
if (devc->dslogic) {
|
|
||||||
if (devc->cur_samplerate == SR_MHZ(100))
|
|
||||||
num_transfers = 16;
|
|
||||||
else if (devc->cur_samplerate == SR_MHZ(200))
|
|
||||||
num_transfers = 8;
|
|
||||||
else if (devc->cur_samplerate == SR_MHZ(400))
|
|
||||||
num_transfers = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
size = fx2lafw_get_buffer_size(devc);
|
|
||||||
devc->submitted_transfers = 0;
|
|
||||||
|
|
||||||
devc->transfers = g_try_malloc0(sizeof(*devc->transfers) * num_transfers);
|
|
||||||
if (!devc->transfers) {
|
|
||||||
sr_err("USB transfers malloc failed.");
|
|
||||||
return SR_ERR_MALLOC;
|
|
||||||
}
|
|
||||||
|
|
||||||
timeout = fx2lafw_get_timeout(devc);
|
|
||||||
endpoint = devc->dslogic ? 6 : 2;
|
|
||||||
devc->num_transfers = num_transfers;
|
|
||||||
for (i = 0; i < num_transfers; i++) {
|
|
||||||
if (!(buf = g_try_malloc(size))) {
|
|
||||||
sr_err("USB transfer buffer malloc failed.");
|
|
||||||
return SR_ERR_MALLOC;
|
|
||||||
}
|
|
||||||
transfer = libusb_alloc_transfer(0);
|
|
||||||
libusb_fill_bulk_transfer(transfer, usb->devhdl,
|
|
||||||
endpoint | LIBUSB_ENDPOINT_IN, buf, size,
|
|
||||||
fx2lafw_receive_transfer, (void *)sdi, timeout);
|
|
||||||
sr_info("submitting transfer: %d", i);
|
|
||||||
if ((ret = libusb_submit_transfer(transfer)) != 0) {
|
|
||||||
sr_err("Failed to submit transfer: %s.",
|
|
||||||
libusb_error_name(ret));
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
g_free(buf);
|
|
||||||
fx2lafw_abort_acquisition(devc);
|
|
||||||
return SR_ERR;
|
|
||||||
}
|
|
||||||
devc->transfers[i] = transfer;
|
|
||||||
devc->submitted_transfers++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If this device has analog channels and at least one of them is
|
|
||||||
* enabled, use mso_send_data_proc() to properly handle the analog
|
|
||||||
* data. Otherwise use la_send_data_proc().
|
|
||||||
*/
|
|
||||||
if (g_slist_length(devc->enabled_analog_channels) > 0)
|
|
||||||
devc->send_data_proc = mso_send_data_proc;
|
|
||||||
else
|
|
||||||
devc->send_data_proc = la_send_data_proc;
|
|
||||||
|
|
||||||
std_session_send_df_header(sdi);
|
|
||||||
|
|
||||||
return SR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void LIBUSB_CALL dslogic_trigger_receive(struct libusb_transfer *transfer)
|
|
||||||
{
|
|
||||||
const struct sr_dev_inst *sdi;
|
|
||||||
struct dslogic_trigger_pos *tpos;
|
|
||||||
struct dev_context *devc;
|
|
||||||
|
|
||||||
sdi = transfer->user_data;
|
|
||||||
devc = sdi->priv;
|
|
||||||
if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {
|
|
||||||
sr_dbg("Trigger transfer canceled.");
|
|
||||||
/* Terminate session. */
|
|
||||||
std_session_send_df_end(sdi);
|
|
||||||
usb_source_remove(sdi->session, devc->ctx);
|
|
||||||
devc->num_transfers = 0;
|
|
||||||
g_free(devc->transfers);
|
|
||||||
if (devc->stl) {
|
|
||||||
soft_trigger_logic_free(devc->stl);
|
|
||||||
devc->stl = NULL;
|
|
||||||
}
|
|
||||||
} else if (transfer->status == LIBUSB_TRANSFER_COMPLETED
|
|
||||||
&& transfer->actual_length == sizeof(struct dslogic_trigger_pos)) {
|
|
||||||
tpos = (struct dslogic_trigger_pos *)transfer->buffer;
|
|
||||||
sr_info("tpos real_pos %d ram_saddr %d cnt %d", tpos->real_pos,
|
|
||||||
tpos->ram_saddr, tpos->remain_cnt);
|
|
||||||
devc->trigger_pos = tpos->real_pos;
|
|
||||||
g_free(tpos);
|
|
||||||
start_transfers(sdi);
|
|
||||||
}
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dslogic_trigger_request(const struct sr_dev_inst *sdi)
|
|
||||||
{
|
|
||||||
struct sr_usb_dev_inst *usb;
|
|
||||||
struct libusb_transfer *transfer;
|
|
||||||
struct dslogic_trigger_pos *tpos;
|
|
||||||
struct dev_context *devc;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
usb = sdi->conn;
|
|
||||||
devc = sdi->priv;
|
|
||||||
|
|
||||||
if ((ret = dslogic_stop_acquisition(sdi)) != SR_OK)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
if ((ret = dslogic_fpga_configure(sdi)) != SR_OK)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/* If this is a DSLogic Pro, set the voltage threshold. */
|
|
||||||
if (!strcmp(devc->profile->model, "DSLogic Pro")){
|
|
||||||
if (devc->dslogic_voltage_threshold == DS_VOLTAGE_RANGE_18_33_V) {
|
|
||||||
dslogic_set_vth(sdi, 1.4);
|
|
||||||
} else {
|
|
||||||
dslogic_set_vth(sdi, 3.3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((ret = dslogic_start_acquisition(sdi)) != SR_OK)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
sr_dbg("Getting trigger.");
|
|
||||||
tpos = g_malloc(sizeof(struct dslogic_trigger_pos));
|
|
||||||
transfer = libusb_alloc_transfer(0);
|
|
||||||
libusb_fill_bulk_transfer(transfer, usb->devhdl, 6 | LIBUSB_ENDPOINT_IN,
|
|
||||||
(unsigned char *)tpos, sizeof(struct dslogic_trigger_pos),
|
|
||||||
dslogic_trigger_receive, (void *)sdi, 0);
|
|
||||||
if ((ret = libusb_submit_transfer(transfer)) < 0) {
|
|
||||||
sr_err("Failed to request trigger: %s.", libusb_error_name(ret));
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
g_free(tpos);
|
|
||||||
return SR_ERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
devc->transfers = g_try_malloc0(sizeof(*devc->transfers));
|
|
||||||
if (!devc->transfers) {
|
|
||||||
sr_err("USB trigger_pos transfer malloc failed.");
|
|
||||||
return SR_ERR_MALLOC;
|
|
||||||
}
|
|
||||||
devc->num_transfers = 1;
|
|
||||||
devc->submitted_transfers++;
|
|
||||||
devc->transfers[0] = transfer;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int configure_channels(const struct sr_dev_inst *sdi)
|
|
||||||
{
|
|
||||||
struct dev_context *devc;
|
|
||||||
const GSList *l;
|
|
||||||
int p;
|
|
||||||
struct sr_channel *ch;
|
|
||||||
uint32_t channel_mask = 0, num_analog = 0;
|
|
||||||
|
|
||||||
devc = sdi->priv;
|
|
||||||
|
|
||||||
g_slist_free(devc->enabled_analog_channels);
|
|
||||||
devc->enabled_analog_channels = NULL;
|
|
||||||
|
|
||||||
for (l = sdi->channels, p = 0; l; l = l->next, p++) {
|
|
||||||
ch = l->data;
|
|
||||||
if ((p <= NUM_CHANNELS) && (ch->type == SR_CHANNEL_ANALOG)
|
|
||||||
&& (ch->enabled)) {
|
|
||||||
num_analog++;
|
|
||||||
devc->enabled_analog_channels =
|
|
||||||
g_slist_append(devc->enabled_analog_channels, ch);
|
|
||||||
} else {
|
|
||||||
channel_mask |= ch->enabled << p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Use wide sampling if either any of the LA channels 8..15 is enabled,
|
|
||||||
* and/or at least one analog channel is enabled, and/or the device
|
|
||||||
* is running DSLogic firmware (not fx2lafw).
|
|
||||||
*/
|
|
||||||
devc->sample_wide = (channel_mask > 0xff
|
|
||||||
|| num_analog > 0
|
|
||||||
|| (devc->profile->dev_caps & DEV_CAPS_DSLOGIC_FW));
|
|
||||||
|
|
||||||
return SR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
|
||||||
{
|
|
||||||
struct sr_dev_driver *di;
|
|
||||||
struct drv_context *drvc;
|
|
||||||
struct dev_context *devc;
|
|
||||||
int timeout, ret;
|
|
||||||
size_t size;
|
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
|
||||||
return SR_ERR_DEV_CLOSED;
|
|
||||||
|
|
||||||
di = sdi->driver;
|
|
||||||
drvc = di->context;
|
|
||||||
devc = sdi->priv;
|
|
||||||
|
|
||||||
devc->ctx = drvc->sr_ctx;
|
|
||||||
devc->sent_samples = 0;
|
|
||||||
devc->empty_transfer_count = 0;
|
|
||||||
devc->acq_aborted = FALSE;
|
|
||||||
|
|
||||||
if (configure_channels(sdi) != SR_OK) {
|
|
||||||
sr_err("Failed to configure channels.");
|
|
||||||
return SR_ERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
timeout = fx2lafw_get_timeout(devc);
|
|
||||||
usb_source_add(sdi->session, devc->ctx, timeout, receive_data, drvc);
|
|
||||||
|
|
||||||
if (devc->dslogic) {
|
|
||||||
dslogic_trigger_request(sdi);
|
|
||||||
} else {
|
|
||||||
size = fx2lafw_get_buffer_size(devc);
|
|
||||||
/* Prepare for analog sampling. */
|
|
||||||
if (g_slist_length(devc->enabled_analog_channels) > 0) {
|
|
||||||
/* We need a buffer half the size of a transfer. */
|
|
||||||
devc->logic_buffer = g_try_malloc(size / 2);
|
|
||||||
devc->analog_buffer = g_try_malloc(
|
|
||||||
sizeof(float) * size / 2);
|
|
||||||
}
|
|
||||||
start_transfers(sdi);
|
|
||||||
if ((ret = fx2lafw_command_start_acquisition(sdi)) != SR_OK) {
|
|
||||||
fx2lafw_abort_acquisition(devc);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return SR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dev_acquisition_stop(struct sr_dev_inst *sdi)
|
static int dev_acquisition_stop(struct sr_dev_inst *sdi)
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
|
||||||
|
|
||||||
devc = sdi->priv;
|
|
||||||
|
|
||||||
if (devc->dslogic)
|
|
||||||
dslogic_stop_acquisition(sdi);
|
|
||||||
|
|
||||||
fx2lafw_abort_acquisition(sdi->priv);
|
fx2lafw_abort_acquisition(sdi->priv);
|
||||||
|
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
|
@ -1092,7 +587,7 @@ static struct sr_dev_driver fx2lafw_driver_info = {
|
||||||
.config_list = config_list,
|
.config_list = config_list,
|
||||||
.dev_open = dev_open,
|
.dev_open = dev_open,
|
||||||
.dev_close = dev_close,
|
.dev_close = dev_close,
|
||||||
.dev_acquisition_start = dev_acquisition_start,
|
.dev_acquisition_start = fx2lafw_start_acquisition,
|
||||||
.dev_acquisition_stop = dev_acquisition_stop,
|
.dev_acquisition_stop = dev_acquisition_stop,
|
||||||
.context = NULL,
|
.context = NULL,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,425 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of the libsigrok project.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
|
|
||||||
* Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
|
|
||||||
*
|
|
||||||
* 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 <glib.h>
|
|
||||||
#include <glib/gstdio.h>
|
|
||||||
#include "protocol.h"
|
|
||||||
#include "dslogic.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This should be larger than the FPGA bitstream image so that it'll get
|
|
||||||
* uploaded in one big operation. There seem to be issues when uploading
|
|
||||||
* it in chunks.
|
|
||||||
*/
|
|
||||||
#define FW_BUFSIZE (1024 * 1024)
|
|
||||||
|
|
||||||
#define FPGA_UPLOAD_DELAY (10 * 1000)
|
|
||||||
|
|
||||||
#define USB_TIMEOUT (3 * 1000)
|
|
||||||
|
|
||||||
SR_PRIV int dslogic_set_vth(const struct sr_dev_inst *sdi, double vth)
|
|
||||||
{
|
|
||||||
struct sr_usb_dev_inst *usb;
|
|
||||||
int ret;
|
|
||||||
uint8_t cmd;
|
|
||||||
|
|
||||||
usb = sdi->conn;
|
|
||||||
|
|
||||||
cmd = (vth / 5.0) * 255;
|
|
||||||
|
|
||||||
/* Send the control command. */
|
|
||||||
ret = libusb_control_transfer(usb->devhdl, LIBUSB_REQUEST_TYPE_VENDOR |
|
|
||||||
LIBUSB_ENDPOINT_OUT, DS_CMD_VTH, 0x0000, 0x0000,
|
|
||||||
(unsigned char *)&cmd, sizeof(cmd), 3000);
|
|
||||||
if (ret < 0) {
|
|
||||||
sr_err("Unable to send VTH command: %s.",
|
|
||||||
libusb_error_name(ret));
|
|
||||||
return SR_ERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
SR_PRIV int dslogic_fpga_firmware_upload(const struct sr_dev_inst *sdi,
|
|
||||||
const char *name)
|
|
||||||
{
|
|
||||||
uint64_t sum;
|
|
||||||
struct sr_resource bitstream;
|
|
||||||
struct drv_context *drvc;
|
|
||||||
struct sr_usb_dev_inst *usb;
|
|
||||||
unsigned char *buf;
|
|
||||||
ssize_t chunksize;
|
|
||||||
int transferred;
|
|
||||||
int result, ret;
|
|
||||||
uint8_t cmd[3];
|
|
||||||
|
|
||||||
drvc = sdi->driver->context;
|
|
||||||
usb = sdi->conn;
|
|
||||||
|
|
||||||
sr_dbg("Uploading FPGA firmware '%s'.", name);
|
|
||||||
|
|
||||||
result = sr_resource_open(drvc->sr_ctx, &bitstream,
|
|
||||||
SR_RESOURCE_FIRMWARE, name);
|
|
||||||
if (result != SR_OK)
|
|
||||||
return result;
|
|
||||||
|
|
||||||
/* Tell the device firmware is coming. */
|
|
||||||
memset(cmd, 0, sizeof(cmd));
|
|
||||||
if ((ret = libusb_control_transfer(usb->devhdl, LIBUSB_REQUEST_TYPE_VENDOR |
|
|
||||||
LIBUSB_ENDPOINT_OUT, DS_CMD_FPGA_FW, 0x0000, 0x0000,
|
|
||||||
(unsigned char *)&cmd, sizeof(cmd), USB_TIMEOUT)) < 0) {
|
|
||||||
sr_err("Failed to upload FPGA firmware: %s.", libusb_error_name(ret));
|
|
||||||
sr_resource_close(drvc->sr_ctx, &bitstream);
|
|
||||||
return SR_ERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Give the FX2 time to get ready for FPGA firmware upload. */
|
|
||||||
g_usleep(FPGA_UPLOAD_DELAY);
|
|
||||||
|
|
||||||
buf = g_malloc(FW_BUFSIZE);
|
|
||||||
sum = 0;
|
|
||||||
result = SR_OK;
|
|
||||||
while (1) {
|
|
||||||
chunksize = sr_resource_read(drvc->sr_ctx, &bitstream,
|
|
||||||
buf, FW_BUFSIZE);
|
|
||||||
if (chunksize < 0)
|
|
||||||
result = SR_ERR;
|
|
||||||
if (chunksize <= 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if ((ret = libusb_bulk_transfer(usb->devhdl, 2 | LIBUSB_ENDPOINT_OUT,
|
|
||||||
buf, chunksize, &transferred, USB_TIMEOUT)) < 0) {
|
|
||||||
sr_err("Unable to configure FPGA firmware: %s.",
|
|
||||||
libusb_error_name(ret));
|
|
||||||
result = SR_ERR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
sum += transferred;
|
|
||||||
sr_spew("Uploaded %" PRIu64 "/%" PRIu64 " bytes.",
|
|
||||||
sum, bitstream.size);
|
|
||||||
|
|
||||||
if (transferred != chunksize) {
|
|
||||||
sr_err("Short transfer while uploading FPGA firmware.");
|
|
||||||
result = SR_ERR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
g_free(buf);
|
|
||||||
sr_resource_close(drvc->sr_ctx, &bitstream);
|
|
||||||
|
|
||||||
if (result == SR_OK)
|
|
||||||
sr_dbg("FPGA firmware upload done.");
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
SR_PRIV int dslogic_start_acquisition(const struct sr_dev_inst *sdi)
|
|
||||||
{
|
|
||||||
struct dev_context *devc;
|
|
||||||
struct sr_usb_dev_inst *usb;
|
|
||||||
struct dslogic_mode mode;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
devc = sdi->priv;
|
|
||||||
mode.flags = DS_START_FLAGS_MODE_LA;
|
|
||||||
mode.sample_delay_h = mode.sample_delay_l = 0;
|
|
||||||
if (devc->sample_wide)
|
|
||||||
mode.flags |= DS_START_FLAGS_SAMPLE_WIDE;
|
|
||||||
|
|
||||||
usb = sdi->conn;
|
|
||||||
ret = libusb_control_transfer(usb->devhdl, LIBUSB_REQUEST_TYPE_VENDOR |
|
|
||||||
LIBUSB_ENDPOINT_OUT, DS_CMD_START, 0x0000, 0x0000,
|
|
||||||
(unsigned char *)&mode, sizeof(mode), USB_TIMEOUT);
|
|
||||||
if (ret < 0) {
|
|
||||||
sr_err("Failed to send start command: %s.", libusb_error_name(ret));
|
|
||||||
return SR_ERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
SR_PRIV int dslogic_stop_acquisition(const struct sr_dev_inst *sdi)
|
|
||||||
{
|
|
||||||
struct sr_usb_dev_inst *usb;
|
|
||||||
struct dslogic_mode mode;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
mode.flags = DS_START_FLAGS_STOP;
|
|
||||||
mode.sample_delay_h = mode.sample_delay_l = 0;
|
|
||||||
|
|
||||||
usb = sdi->conn;
|
|
||||||
ret = libusb_control_transfer(usb->devhdl, LIBUSB_REQUEST_TYPE_VENDOR |
|
|
||||||
LIBUSB_ENDPOINT_OUT, DS_CMD_START, 0x0000, 0x0000,
|
|
||||||
(unsigned char *)&mode, sizeof(struct dslogic_mode), USB_TIMEOUT);
|
|
||||||
if (ret < 0) {
|
|
||||||
sr_err("Failed to send stop command: %s.", libusb_error_name(ret));
|
|
||||||
return SR_ERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get the session trigger and configure the FPGA structure
|
|
||||||
* accordingly.
|
|
||||||
*/
|
|
||||||
static int dslogic_set_trigger(const struct sr_dev_inst *sdi,
|
|
||||||
struct dslogic_fpga_config *cfg)
|
|
||||||
{
|
|
||||||
struct sr_trigger *trigger;
|
|
||||||
struct sr_trigger_stage *stage;
|
|
||||||
struct sr_trigger_match *match;
|
|
||||||
struct dev_context *devc;
|
|
||||||
const GSList *l, *m;
|
|
||||||
int channelbit, i = 0;
|
|
||||||
uint16_t v16;
|
|
||||||
|
|
||||||
devc = sdi->priv;
|
|
||||||
|
|
||||||
cfg->trig_mask0[0] = 0xffff;
|
|
||||||
cfg->trig_mask1[0] = 0xffff;
|
|
||||||
|
|
||||||
cfg->trig_value0[0] = 0;
|
|
||||||
cfg->trig_value1[0] = 0;
|
|
||||||
|
|
||||||
cfg->trig_edge0[0] = 0;
|
|
||||||
cfg->trig_edge1[0] = 0;
|
|
||||||
|
|
||||||
cfg->trig_logic0[0] = 0;
|
|
||||||
cfg->trig_logic1[0] = 0;
|
|
||||||
|
|
||||||
cfg->trig_count0[0] = 0;
|
|
||||||
cfg->trig_count1[0] = 0;
|
|
||||||
|
|
||||||
cfg->trig_pos = 0;
|
|
||||||
cfg->trig_sda = 0;
|
|
||||||
cfg->trig_glb = 0;
|
|
||||||
cfg->trig_adp = cfg->count - cfg->trig_pos - 1;
|
|
||||||
|
|
||||||
for (i = 1; i < 16; i++) {
|
|
||||||
cfg->trig_mask0[i] = 0xff;
|
|
||||||
cfg->trig_mask1[i] = 0xff;
|
|
||||||
cfg->trig_value0[i] = 0;
|
|
||||||
cfg->trig_value1[i] = 0;
|
|
||||||
cfg->trig_edge0[i] = 0;
|
|
||||||
cfg->trig_edge1[i] = 0;
|
|
||||||
cfg->trig_count0[i] = 0;
|
|
||||||
cfg->trig_count1[i] = 0;
|
|
||||||
cfg->trig_logic0[i] = 2;
|
|
||||||
cfg->trig_logic1[i] = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg->trig_pos = (uint32_t)(devc->capture_ratio / 100.0 * devc->limit_samples);
|
|
||||||
sr_dbg("pos: %d", cfg->trig_pos);
|
|
||||||
|
|
||||||
sr_dbg("configuring trigger");
|
|
||||||
|
|
||||||
if (!(trigger = sr_session_trigger_get(sdi->session))) {
|
|
||||||
sr_dbg("No session trigger found");
|
|
||||||
return SR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (l = trigger->stages; l; l = l->next) {
|
|
||||||
stage = l->data;
|
|
||||||
for (m = stage->matches; m; m = m->next) {
|
|
||||||
match = m->data;
|
|
||||||
if (!match->channel->enabled)
|
|
||||||
/* Ignore disabled channels with a trigger. */
|
|
||||||
continue;
|
|
||||||
channelbit = 1 << (match->channel->index);
|
|
||||||
/* Simple trigger support (event). */
|
|
||||||
if (match->match == SR_TRIGGER_ONE) {
|
|
||||||
cfg->trig_mask0[0] &= ~channelbit;
|
|
||||||
cfg->trig_mask1[0] &= ~channelbit;
|
|
||||||
cfg->trig_value0[0] |= channelbit;
|
|
||||||
cfg->trig_value1[0] |= channelbit;
|
|
||||||
} else if (match->match == SR_TRIGGER_ZERO) {
|
|
||||||
cfg->trig_mask0[0] &= ~channelbit;
|
|
||||||
cfg->trig_mask1[0] &= ~channelbit;
|
|
||||||
} else if (match->match == SR_TRIGGER_FALLING) {
|
|
||||||
cfg->trig_mask0[0] &= ~channelbit;
|
|
||||||
cfg->trig_mask1[0] &= ~channelbit;
|
|
||||||
cfg->trig_edge0[0] |= channelbit;
|
|
||||||
cfg->trig_edge1[0] |= channelbit;
|
|
||||||
} else if (match->match == SR_TRIGGER_RISING) {
|
|
||||||
cfg->trig_mask0[0] &= ~channelbit;
|
|
||||||
cfg->trig_mask1[0] &= ~channelbit;
|
|
||||||
cfg->trig_value0[0] |= channelbit;
|
|
||||||
cfg->trig_value1[0] |= channelbit;
|
|
||||||
cfg->trig_edge0[0] |= channelbit;
|
|
||||||
cfg->trig_edge1[0] |= channelbit;
|
|
||||||
} else if (match->match == SR_TRIGGER_EDGE) {
|
|
||||||
cfg->trig_edge0[0] |= channelbit;
|
|
||||||
cfg->trig_edge1[0] |= channelbit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
v16 = RL16(&cfg->mode);
|
|
||||||
v16 |= 1 << 0;
|
|
||||||
WL16(&cfg->mode, v16);
|
|
||||||
|
|
||||||
return SR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
SR_PRIV int dslogic_fpga_configure(const struct sr_dev_inst *sdi)
|
|
||||||
{
|
|
||||||
struct dev_context *devc;
|
|
||||||
struct sr_usb_dev_inst *usb;
|
|
||||||
uint8_t c[3];
|
|
||||||
struct dslogic_fpga_config cfg;
|
|
||||||
uint16_t v16;
|
|
||||||
uint32_t v32;
|
|
||||||
int transferred, len, ret;
|
|
||||||
|
|
||||||
sr_dbg("Configuring FPGA.");
|
|
||||||
|
|
||||||
usb = sdi->conn;
|
|
||||||
devc = sdi->priv;
|
|
||||||
|
|
||||||
WL32(&cfg.sync, DS_CFG_START);
|
|
||||||
WL16(&cfg.mode_header, DS_CFG_MODE);
|
|
||||||
WL32(&cfg.divider_header, DS_CFG_DIVIDER);
|
|
||||||
WL32(&cfg.count_header, DS_CFG_COUNT);
|
|
||||||
WL32(&cfg.trig_pos_header, DS_CFG_TRIG_POS);
|
|
||||||
WL16(&cfg.trig_glb_header, DS_CFG_TRIG_GLB);
|
|
||||||
WL32(&cfg.trig_adp_header, DS_CFG_TRIG_ADP);
|
|
||||||
WL32(&cfg.trig_sda_header, DS_CFG_TRIG_SDA);
|
|
||||||
WL32(&cfg.trig_mask0_header, DS_CFG_TRIG_MASK0);
|
|
||||||
WL32(&cfg.trig_mask1_header, DS_CFG_TRIG_MASK1);
|
|
||||||
WL32(&cfg.trig_value0_header, DS_CFG_TRIG_VALUE0);
|
|
||||||
WL32(&cfg.trig_value1_header, DS_CFG_TRIG_VALUE1);
|
|
||||||
WL32(&cfg.trig_edge0_header, DS_CFG_TRIG_EDGE0);
|
|
||||||
WL32(&cfg.trig_edge1_header, DS_CFG_TRIG_EDGE1);
|
|
||||||
WL32(&cfg.trig_count0_header, DS_CFG_TRIG_COUNT0);
|
|
||||||
WL32(&cfg.trig_count1_header, DS_CFG_TRIG_COUNT1);
|
|
||||||
WL32(&cfg.trig_logic0_header, DS_CFG_TRIG_LOGIC0);
|
|
||||||
WL32(&cfg.trig_logic1_header, DS_CFG_TRIG_LOGIC1);
|
|
||||||
WL32(&cfg.end_sync, DS_CFG_END);
|
|
||||||
|
|
||||||
/* Pass in the length of a fixed-size struct. Really. */
|
|
||||||
len = sizeof(struct dslogic_fpga_config) / 2;
|
|
||||||
c[0] = len & 0xff;
|
|
||||||
c[1] = (len >> 8) & 0xff;
|
|
||||||
c[2] = (len >> 16) & 0xff;
|
|
||||||
|
|
||||||
ret = libusb_control_transfer(usb->devhdl, LIBUSB_REQUEST_TYPE_VENDOR |
|
|
||||||
LIBUSB_ENDPOINT_OUT, DS_CMD_CONFIG, 0x0000, 0x0000,
|
|
||||||
c, 3, USB_TIMEOUT);
|
|
||||||
if (ret < 0) {
|
|
||||||
sr_err("Failed to send FPGA configure command: %s.",
|
|
||||||
libusb_error_name(ret));
|
|
||||||
return SR_ERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 15 1 = internal test mode
|
|
||||||
* 14 1 = external test mode
|
|
||||||
* 13 1 = loopback test mode
|
|
||||||
* 12 1 = stream mode
|
|
||||||
* 11 1 = serial trigger
|
|
||||||
* 8-10 unused
|
|
||||||
* 7 1 = analog mode
|
|
||||||
* 6 1 = samplerate 400MHz
|
|
||||||
* 5 1 = samplerate 200MHz or analog mode
|
|
||||||
* 4 0 = logic, 1 = dso or analog
|
|
||||||
* 3 1 = RLE encoding (enable for more than 16 Megasamples)
|
|
||||||
* 1-2 00 = internal clock,
|
|
||||||
* 01 = external clock rising,
|
|
||||||
* 11 = external clock falling
|
|
||||||
* 0 1 = trigger enabled
|
|
||||||
*/
|
|
||||||
v16 = 0x0000;
|
|
||||||
if (devc->dslogic_mode == DS_OP_INTERNAL_TEST)
|
|
||||||
v16 = 1 << 15;
|
|
||||||
else if (devc->dslogic_mode == DS_OP_EXTERNAL_TEST)
|
|
||||||
v16 = 1 << 14;
|
|
||||||
else if (devc->dslogic_mode == DS_OP_LOOPBACK_TEST)
|
|
||||||
v16 = 1 << 13;
|
|
||||||
if (devc->dslogic_continuous_mode)
|
|
||||||
v16 |= 1 << 12;
|
|
||||||
if (devc->dslogic_external_clock) {
|
|
||||||
v16 |= 1 << 1;
|
|
||||||
if (devc->dslogic_clock_edge == DS_EDGE_FALLING)
|
|
||||||
v16 |= 1 << 2;
|
|
||||||
}
|
|
||||||
if (devc->limit_samples > DS_MAX_LOGIC_DEPTH *
|
|
||||||
ceil(devc->cur_samplerate * 1.0 / DS_MAX_LOGIC_SAMPLERATE)
|
|
||||||
&& !devc->dslogic_continuous_mode) {
|
|
||||||
/* Enable RLE for long captures.
|
|
||||||
* Without this, captured data present errors.
|
|
||||||
*/
|
|
||||||
v16 |= 1 << 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
WL16(&cfg.mode, v16);
|
|
||||||
v32 = ceil(DS_MAX_LOGIC_SAMPLERATE * 1.0 / devc->cur_samplerate);
|
|
||||||
WL32(&cfg.divider, v32);
|
|
||||||
WL32(&cfg.count, devc->limit_samples);
|
|
||||||
|
|
||||||
dslogic_set_trigger(sdi, &cfg);
|
|
||||||
|
|
||||||
len = sizeof(struct dslogic_fpga_config);
|
|
||||||
ret = libusb_bulk_transfer(usb->devhdl, 2 | LIBUSB_ENDPOINT_OUT,
|
|
||||||
(unsigned char *)&cfg, len, &transferred, USB_TIMEOUT);
|
|
||||||
if (ret < 0 || transferred != len) {
|
|
||||||
sr_err("Failed to send FPGA configuration: %s.", libusb_error_name(ret));
|
|
||||||
return SR_ERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int to_bytes_per_ms(struct dev_context *devc)
|
|
||||||
{
|
|
||||||
if (devc->cur_samplerate > SR_MHZ(100))
|
|
||||||
return SR_MHZ(100) / 1000 * (devc->sample_wide ? 2 : 1);
|
|
||||||
|
|
||||||
return devc->cur_samplerate / 1000 * (devc->sample_wide ? 2 : 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t get_buffer_size(struct dev_context *devc)
|
|
||||||
{
|
|
||||||
size_t s;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The buffer should be large enough to hold 10ms of data and
|
|
||||||
* a multiple of 512.
|
|
||||||
*/
|
|
||||||
s = 10 * to_bytes_per_ms(devc);
|
|
||||||
// s = to_bytes_per_ms(devc->cur_samplerate);
|
|
||||||
return (s + 511) & ~511;
|
|
||||||
}
|
|
||||||
|
|
||||||
SR_PRIV int dslogic_get_number_of_transfers(struct dev_context *devc)
|
|
||||||
{
|
|
||||||
unsigned int n;
|
|
||||||
|
|
||||||
/* Total buffer size should be able to hold about 100ms of data. */
|
|
||||||
n = (100 * to_bytes_per_ms(devc) / get_buffer_size(devc));
|
|
||||||
sr_info("New calculation: %d", n);
|
|
||||||
|
|
||||||
if (n > NUM_SIMUL_TRANSFERS)
|
|
||||||
return NUM_SIMUL_TRANSFERS;
|
|
||||||
|
|
||||||
return n;
|
|
||||||
}
|
|
|
@ -1,150 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of the libsigrok project.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
|
|
||||||
* Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
|
|
||||||
*
|
|
||||||
* 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_FX2LAFW_DSLOGIC_H
|
|
||||||
#define LIBSIGROK_HARDWARE_FX2LAFW_DSLOGIC_H
|
|
||||||
|
|
||||||
/* Modified protocol commands & flags used by DSLogic */
|
|
||||||
#define DS_CMD_GET_FW_VERSION 0xb0
|
|
||||||
#define DS_CMD_GET_REVID_VERSION 0xb1
|
|
||||||
#define DS_CMD_START 0xb2
|
|
||||||
#define DS_CMD_FPGA_FW 0xb3
|
|
||||||
#define DS_CMD_CONFIG 0xb4
|
|
||||||
#define DS_CMD_VTH 0xb8
|
|
||||||
|
|
||||||
#define DS_NUM_TRIGGER_STAGES 16
|
|
||||||
#define DS_START_FLAGS_STOP (1 << 7)
|
|
||||||
#define DS_START_FLAGS_CLK_48MHZ (1 << 6)
|
|
||||||
#define DS_START_FLAGS_SAMPLE_WIDE (1 << 5)
|
|
||||||
#define DS_START_FLAGS_MODE_LA (1 << 4)
|
|
||||||
|
|
||||||
#define DS_MAX_LOGIC_DEPTH SR_MHZ(16)
|
|
||||||
#define DS_MAX_LOGIC_SAMPLERATE SR_MHZ(100)
|
|
||||||
|
|
||||||
enum dslogic_operation_modes {
|
|
||||||
DS_OP_NORMAL,
|
|
||||||
DS_OP_INTERNAL_TEST,
|
|
||||||
DS_OP_EXTERNAL_TEST,
|
|
||||||
DS_OP_LOOPBACK_TEST,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum {
|
|
||||||
DS_VOLTAGE_RANGE_18_33_V, /* 1.8V and 3.3V logic */
|
|
||||||
DS_VOLTAGE_RANGE_5_V, /* 5V logic */
|
|
||||||
};
|
|
||||||
|
|
||||||
enum {
|
|
||||||
DS_EDGE_RISING,
|
|
||||||
DS_EDGE_FALLING,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct dslogic_version {
|
|
||||||
uint8_t major;
|
|
||||||
uint8_t minor;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct dslogic_mode {
|
|
||||||
uint8_t flags;
|
|
||||||
uint8_t sample_delay_h;
|
|
||||||
uint8_t sample_delay_l;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct dslogic_trigger_pos {
|
|
||||||
uint32_t real_pos;
|
|
||||||
uint32_t ram_saddr;
|
|
||||||
uint32_t remain_cnt;
|
|
||||||
uint8_t first_block[500];
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The FPGA is configured with TLV tuples. Length is specified as the
|
|
||||||
* number of 16-bit words, and the (type, length) header is in some
|
|
||||||
* cases padded with 0xffff.
|
|
||||||
*/
|
|
||||||
#define _DS_CFG(variable, wordcnt) ((variable << 8) | wordcnt)
|
|
||||||
#define _DS_CFG_PAD(variable, wordcnt) ((_DS_CFG(variable, wordcnt) << 16) | 0xffff)
|
|
||||||
#define DS_CFG_START 0xf5a5f5a5
|
|
||||||
#define DS_CFG_MODE _DS_CFG(0, 1)
|
|
||||||
#define DS_CFG_DIVIDER _DS_CFG_PAD(1, 2)
|
|
||||||
#define DS_CFG_COUNT _DS_CFG_PAD(3, 2)
|
|
||||||
#define DS_CFG_TRIG_POS _DS_CFG_PAD(5, 2)
|
|
||||||
#define DS_CFG_TRIG_GLB _DS_CFG(7, 1)
|
|
||||||
#define DS_CFG_TRIG_ADP _DS_CFG_PAD(10, 2)
|
|
||||||
#define DS_CFG_TRIG_SDA _DS_CFG_PAD(12, 2)
|
|
||||||
#define DS_CFG_TRIG_MASK0 _DS_CFG_PAD(16, 16)
|
|
||||||
#define DS_CFG_TRIG_MASK1 _DS_CFG_PAD(17, 16)
|
|
||||||
#define DS_CFG_TRIG_VALUE0 _DS_CFG_PAD(20, 16)
|
|
||||||
#define DS_CFG_TRIG_VALUE1 _DS_CFG_PAD(21, 16)
|
|
||||||
#define DS_CFG_TRIG_EDGE0 _DS_CFG_PAD(24, 16)
|
|
||||||
#define DS_CFG_TRIG_EDGE1 _DS_CFG_PAD(25, 16)
|
|
||||||
#define DS_CFG_TRIG_COUNT0 _DS_CFG_PAD(28, 16)
|
|
||||||
#define DS_CFG_TRIG_COUNT1 _DS_CFG_PAD(29, 16)
|
|
||||||
#define DS_CFG_TRIG_LOGIC0 _DS_CFG_PAD(32, 16)
|
|
||||||
#define DS_CFG_TRIG_LOGIC1 _DS_CFG_PAD(33, 16)
|
|
||||||
#define DS_CFG_END 0xfa5afa5a
|
|
||||||
|
|
||||||
struct dslogic_fpga_config {
|
|
||||||
uint32_t sync;
|
|
||||||
uint16_t mode_header;
|
|
||||||
uint16_t mode;
|
|
||||||
uint32_t divider_header;
|
|
||||||
uint32_t divider;
|
|
||||||
uint32_t count_header;
|
|
||||||
uint32_t count;
|
|
||||||
uint32_t trig_pos_header;
|
|
||||||
uint32_t trig_pos;
|
|
||||||
uint16_t trig_glb_header;
|
|
||||||
uint16_t trig_glb;
|
|
||||||
uint32_t trig_adp_header;
|
|
||||||
uint32_t trig_adp;
|
|
||||||
uint32_t trig_sda_header;
|
|
||||||
uint32_t trig_sda;
|
|
||||||
uint32_t trig_mask0_header;
|
|
||||||
uint16_t trig_mask0[DS_NUM_TRIGGER_STAGES];
|
|
||||||
uint32_t trig_mask1_header;
|
|
||||||
uint16_t trig_mask1[DS_NUM_TRIGGER_STAGES];
|
|
||||||
uint32_t trig_value0_header;
|
|
||||||
uint16_t trig_value0[DS_NUM_TRIGGER_STAGES];
|
|
||||||
uint32_t trig_value1_header;
|
|
||||||
uint16_t trig_value1[DS_NUM_TRIGGER_STAGES];
|
|
||||||
uint32_t trig_edge0_header;
|
|
||||||
uint16_t trig_edge0[DS_NUM_TRIGGER_STAGES];
|
|
||||||
uint32_t trig_edge1_header;
|
|
||||||
uint16_t trig_edge1[DS_NUM_TRIGGER_STAGES];
|
|
||||||
uint32_t trig_count0_header;
|
|
||||||
uint16_t trig_count0[DS_NUM_TRIGGER_STAGES];
|
|
||||||
uint32_t trig_count1_header;
|
|
||||||
uint16_t trig_count1[DS_NUM_TRIGGER_STAGES];
|
|
||||||
uint32_t trig_logic0_header;
|
|
||||||
uint16_t trig_logic0[DS_NUM_TRIGGER_STAGES];
|
|
||||||
uint32_t trig_logic1_header;
|
|
||||||
uint16_t trig_logic1[DS_NUM_TRIGGER_STAGES];
|
|
||||||
uint32_t end_sync;
|
|
||||||
};
|
|
||||||
|
|
||||||
SR_PRIV int dslogic_fpga_firmware_upload(const struct sr_dev_inst *sdi,
|
|
||||||
const char *name);
|
|
||||||
SR_PRIV int dslogic_start_acquisition(const struct sr_dev_inst *sdi);
|
|
||||||
SR_PRIV int dslogic_stop_acquisition(const struct sr_dev_inst *sdi);
|
|
||||||
SR_PRIV int dslogic_fpga_configure(const struct sr_dev_inst *sdi);
|
|
||||||
SR_PRIV int dslogic_set_vth(const struct sr_dev_inst *sdi, double vth);
|
|
||||||
SR_PRIV int dslogic_get_number_of_transfers(struct dev_context *devc);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -22,7 +22,6 @@
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <glib/gstdio.h>
|
#include <glib/gstdio.h>
|
||||||
#include "protocol.h"
|
#include "protocol.h"
|
||||||
#include "dslogic.h"
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
|
@ -61,14 +60,13 @@ static int command_get_fw_version(libusb_device_handle *devhdl,
|
||||||
|
|
||||||
static int command_get_revid_version(struct sr_dev_inst *sdi, uint8_t *revid)
|
static int command_get_revid_version(struct sr_dev_inst *sdi, uint8_t *revid)
|
||||||
{
|
{
|
||||||
struct dev_context *devc = sdi->priv;
|
|
||||||
struct sr_usb_dev_inst *usb = sdi->conn;
|
struct sr_usb_dev_inst *usb = sdi->conn;
|
||||||
libusb_device_handle *devhdl = usb->devhdl;
|
libusb_device_handle *devhdl = usb->devhdl;
|
||||||
int cmd, ret;
|
int ret;
|
||||||
|
|
||||||
cmd = devc->dslogic ? DS_CMD_GET_REVID_VERSION : CMD_GET_REVID_VERSION;
|
|
||||||
ret = libusb_control_transfer(devhdl, LIBUSB_REQUEST_TYPE_VENDOR |
|
ret = libusb_control_transfer(devhdl, LIBUSB_REQUEST_TYPE_VENDOR |
|
||||||
LIBUSB_ENDPOINT_IN, cmd, 0x0000, 0x0000, revid, 1, USB_TIMEOUT);
|
LIBUSB_ENDPOINT_IN, CMD_GET_REVID_VERSION, 0x0000, 0x0000,
|
||||||
|
revid, 1, USB_TIMEOUT);
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
sr_err("Unable to get REVID: %s.", libusb_error_name(ret));
|
sr_err("Unable to get REVID: %s.", libusb_error_name(ret));
|
||||||
|
@ -78,7 +76,7 @@ static int command_get_revid_version(struct sr_dev_inst *sdi, uint8_t *revid)
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
SR_PRIV int fx2lafw_command_start_acquisition(const struct sr_dev_inst *sdi)
|
static int command_start_acquisition(const struct sr_dev_inst *sdi)
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
struct sr_usb_dev_inst *usb;
|
struct sr_usb_dev_inst *usb;
|
||||||
|
@ -141,49 +139,6 @@ SR_PRIV int fx2lafw_command_start_acquisition(const struct sr_dev_inst *sdi)
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Check the USB configuration to determine if this is an fx2lafw device.
|
|
||||||
*
|
|
||||||
* @return TRUE if the device's configuration profile matches fx2lafw
|
|
||||||
* configuration, FALSE otherwise.
|
|
||||||
*/
|
|
||||||
SR_PRIV gboolean match_manuf_prod(libusb_device *dev, const char *manufacturer,
|
|
||||||
const char *product)
|
|
||||||
{
|
|
||||||
struct libusb_device_descriptor des;
|
|
||||||
struct libusb_device_handle *hdl;
|
|
||||||
gboolean ret;
|
|
||||||
unsigned char strdesc[64];
|
|
||||||
|
|
||||||
hdl = NULL;
|
|
||||||
ret = FALSE;
|
|
||||||
while (!ret) {
|
|
||||||
/* Assume the FW has not been loaded, unless proven wrong. */
|
|
||||||
libusb_get_device_descriptor(dev, &des);
|
|
||||||
|
|
||||||
if (libusb_open(dev, &hdl) != 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (libusb_get_string_descriptor_ascii(hdl,
|
|
||||||
des.iManufacturer, strdesc, sizeof(strdesc)) < 0)
|
|
||||||
break;
|
|
||||||
if (strcmp((const char *)strdesc, manufacturer))
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (libusb_get_string_descriptor_ascii(hdl,
|
|
||||||
des.iProduct, strdesc, sizeof(strdesc)) < 0)
|
|
||||||
break;
|
|
||||||
if (strcmp((const char *)strdesc, product))
|
|
||||||
break;
|
|
||||||
|
|
||||||
ret = TRUE;
|
|
||||||
}
|
|
||||||
if (hdl)
|
|
||||||
libusb_close(hdl);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
SR_PRIV int fx2lafw_dev_open(struct sr_dev_inst *sdi, struct sr_dev_driver *di)
|
SR_PRIV int fx2lafw_dev_open(struct sr_dev_inst *sdi, struct sr_dev_driver *di)
|
||||||
{
|
{
|
||||||
libusb_device **devlist;
|
libusb_device **devlist;
|
||||||
|
@ -192,7 +147,7 @@ SR_PRIV int fx2lafw_dev_open(struct sr_dev_inst *sdi, struct sr_dev_driver *di)
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
struct drv_context *drvc;
|
struct drv_context *drvc;
|
||||||
struct version_info vi;
|
struct version_info vi;
|
||||||
int ret, i, device_count;
|
int ret = SR_ERR, i, device_count;
|
||||||
uint8_t revid;
|
uint8_t revid;
|
||||||
char connection_id[64];
|
char connection_id[64];
|
||||||
|
|
||||||
|
@ -200,10 +155,6 @@ SR_PRIV int fx2lafw_dev_open(struct sr_dev_inst *sdi, struct sr_dev_driver *di)
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
usb = sdi->conn;
|
usb = sdi->conn;
|
||||||
|
|
||||||
if (sdi->status == SR_ST_ACTIVE)
|
|
||||||
/* Device is already in use. */
|
|
||||||
return SR_ERR;
|
|
||||||
|
|
||||||
device_count = libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
|
device_count = libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
|
||||||
if (device_count < 0) {
|
if (device_count < 0) {
|
||||||
sr_err("Failed to get device list: %s.",
|
sr_err("Failed to get device list: %s.",
|
||||||
|
@ -223,7 +174,9 @@ SR_PRIV int fx2lafw_dev_open(struct sr_dev_inst *sdi, struct sr_dev_driver *di)
|
||||||
/*
|
/*
|
||||||
* Check device by its physical USB bus/port address.
|
* Check device by its physical USB bus/port address.
|
||||||
*/
|
*/
|
||||||
usb_get_port_path(devlist[i], connection_id, sizeof(connection_id));
|
if (usb_get_port_path(devlist[i], connection_id, sizeof(connection_id)) < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (strcmp(sdi->connection_id, connection_id))
|
if (strcmp(sdi->connection_id, connection_id))
|
||||||
/* This is not the one. */
|
/* This is not the one. */
|
||||||
continue;
|
continue;
|
||||||
|
@ -239,6 +192,7 @@ SR_PRIV int fx2lafw_dev_open(struct sr_dev_inst *sdi, struct sr_dev_driver *di)
|
||||||
} else {
|
} else {
|
||||||
sr_err("Failed to open device: %s.",
|
sr_err("Failed to open device: %s.",
|
||||||
libusb_error_name(ret));
|
libusb_error_name(ret));
|
||||||
|
ret = SR_ERR;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,7 +201,8 @@ SR_PRIV int fx2lafw_dev_open(struct sr_dev_inst *sdi, struct sr_dev_driver *di)
|
||||||
if ((ret = libusb_detach_kernel_driver(usb->devhdl, USB_INTERFACE)) < 0) {
|
if ((ret = libusb_detach_kernel_driver(usb->devhdl, USB_INTERFACE)) < 0) {
|
||||||
sr_err("Failed to detach kernel driver: %s.",
|
sr_err("Failed to detach kernel driver: %s.",
|
||||||
libusb_error_name(ret));
|
libusb_error_name(ret));
|
||||||
return SR_ERR;
|
ret = SR_ERR;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -276,7 +231,6 @@ SR_PRIV int fx2lafw_dev_open(struct sr_dev_inst *sdi, struct sr_dev_driver *di)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
sdi->status = SR_ST_ACTIVE;
|
|
||||||
sr_info("Opened device on %d.%d (logical) / %s (physical), "
|
sr_info("Opened device on %d.%d (logical) / %s (physical), "
|
||||||
"interface %d, firmware %d.%d.",
|
"interface %d, firmware %d.%d.",
|
||||||
usb->bus, usb->address, connection_id,
|
usb->bus, usb->address, connection_id,
|
||||||
|
@ -285,14 +239,14 @@ SR_PRIV int fx2lafw_dev_open(struct sr_dev_inst *sdi, struct sr_dev_driver *di)
|
||||||
sr_info("Detected REVID=%d, it's a Cypress CY7C68013%s.",
|
sr_info("Detected REVID=%d, it's a Cypress CY7C68013%s.",
|
||||||
revid, (revid != 1) ? " (FX2)" : "A (FX2LP)");
|
revid, (revid != 1) ? " (FX2)" : "A (FX2LP)");
|
||||||
|
|
||||||
|
ret = SR_OK;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
libusb_free_device_list(devlist, 1);
|
libusb_free_device_list(devlist, 1);
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
return ret;
|
||||||
return SR_ERR;
|
|
||||||
|
|
||||||
return SR_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SR_PRIV struct dev_context *fx2lafw_dev_new(void)
|
SR_PRIV struct dev_context *fx2lafw_dev_new(void)
|
||||||
|
@ -306,8 +260,6 @@ SR_PRIV struct dev_context *fx2lafw_dev_new(void)
|
||||||
devc->limit_samples = 0;
|
devc->limit_samples = 0;
|
||||||
devc->capture_ratio = 0;
|
devc->capture_ratio = 0;
|
||||||
devc->sample_wide = FALSE;
|
devc->sample_wide = FALSE;
|
||||||
devc->dslogic_continuous_mode = FALSE;
|
|
||||||
devc->dslogic_clock_edge = DS_EDGE_RISING;
|
|
||||||
devc->stl = NULL;
|
devc->stl = NULL;
|
||||||
|
|
||||||
return devc;
|
return devc;
|
||||||
|
@ -387,7 +339,7 @@ static void resubmit_transfer(struct libusb_transfer *transfer)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SR_PRIV void mso_send_data_proc(struct sr_dev_inst *sdi,
|
static void mso_send_data_proc(struct sr_dev_inst *sdi,
|
||||||
uint8_t *data, size_t length, size_t sample_width)
|
uint8_t *data, size_t length, size_t sample_width)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
|
@ -439,7 +391,7 @@ SR_PRIV void mso_send_data_proc(struct sr_dev_inst *sdi,
|
||||||
sr_session_send(sdi, &analog_packet);
|
sr_session_send(sdi, &analog_packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
SR_PRIV void la_send_data_proc(struct sr_dev_inst *sdi,
|
static void la_send_data_proc(struct sr_dev_inst *sdi,
|
||||||
uint8_t *data, size_t length, size_t sample_width)
|
uint8_t *data, size_t length, size_t sample_width)
|
||||||
{
|
{
|
||||||
const struct sr_datafeed_logic logic = {
|
const struct sr_datafeed_logic logic = {
|
||||||
|
@ -456,12 +408,11 @@ SR_PRIV void la_send_data_proc(struct sr_dev_inst *sdi,
|
||||||
sr_session_send(sdi, &packet);
|
sr_session_send(sdi, &packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
SR_PRIV void LIBUSB_CALL fx2lafw_receive_transfer(struct libusb_transfer *transfer)
|
static void LIBUSB_CALL receive_transfer(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct sr_dev_inst *sdi;
|
struct sr_dev_inst *sdi;
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
gboolean packet_has_error = FALSE;
|
gboolean packet_has_error = FALSE;
|
||||||
struct sr_datafeed_packet packet;
|
|
||||||
unsigned int num_samples;
|
unsigned int num_samples;
|
||||||
int trigger_offset, cur_sample_count, unitsize;
|
int trigger_offset, cur_sample_count, unitsize;
|
||||||
int pre_trigger_samples;
|
int pre_trigger_samples;
|
||||||
|
@ -522,30 +473,10 @@ SR_PRIV void LIBUSB_CALL fx2lafw_receive_transfer(struct libusb_transfer *transf
|
||||||
else
|
else
|
||||||
num_samples = cur_sample_count;
|
num_samples = cur_sample_count;
|
||||||
|
|
||||||
if (devc->dslogic && devc->trigger_pos > devc->sent_samples
|
|
||||||
&& devc->trigger_pos <= devc->sent_samples + num_samples) {
|
|
||||||
/* DSLogic trigger in this block. Send trigger position. */
|
|
||||||
trigger_offset = devc->trigger_pos - devc->sent_samples;
|
|
||||||
/* Pre-trigger samples. */
|
|
||||||
devc->send_data_proc(sdi, (uint8_t *)transfer->buffer,
|
|
||||||
trigger_offset * unitsize, unitsize);
|
|
||||||
devc->sent_samples += trigger_offset;
|
|
||||||
/* Trigger position. */
|
|
||||||
devc->trigger_pos = 0;
|
|
||||||
packet.type = SR_DF_TRIGGER;
|
|
||||||
packet.payload = NULL;
|
|
||||||
sr_session_send(sdi, &packet);
|
|
||||||
/* Post trigger samples. */
|
|
||||||
num_samples -= trigger_offset;
|
|
||||||
devc->send_data_proc(sdi, (uint8_t *)transfer->buffer
|
|
||||||
+ trigger_offset * unitsize, num_samples * unitsize, unitsize);
|
|
||||||
devc->sent_samples += num_samples;
|
|
||||||
} else {
|
|
||||||
devc->send_data_proc(sdi, (uint8_t *)transfer->buffer,
|
devc->send_data_proc(sdi, (uint8_t *)transfer->buffer,
|
||||||
num_samples * unitsize, unitsize);
|
num_samples * unitsize, unitsize);
|
||||||
devc->sent_samples += num_samples;
|
devc->sent_samples += num_samples;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
trigger_offset = soft_trigger_logic_check(devc->stl,
|
trigger_offset = soft_trigger_logic_check(devc->stl,
|
||||||
transfer->buffer, transfer->actual_length, &pre_trigger_samples);
|
transfer->buffer, transfer->actual_length, &pre_trigger_samples);
|
||||||
|
@ -572,12 +503,46 @@ SR_PRIV void LIBUSB_CALL fx2lafw_receive_transfer(struct libusb_transfer *transf
|
||||||
resubmit_transfer(transfer);
|
resubmit_transfer(transfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int configure_channels(const struct sr_dev_inst *sdi)
|
||||||
|
{
|
||||||
|
struct dev_context *devc;
|
||||||
|
const GSList *l;
|
||||||
|
int p;
|
||||||
|
struct sr_channel *ch;
|
||||||
|
uint32_t channel_mask = 0, num_analog = 0;
|
||||||
|
|
||||||
|
devc = sdi->priv;
|
||||||
|
|
||||||
|
g_slist_free(devc->enabled_analog_channels);
|
||||||
|
devc->enabled_analog_channels = NULL;
|
||||||
|
|
||||||
|
for (l = sdi->channels, p = 0; l; l = l->next, p++) {
|
||||||
|
ch = l->data;
|
||||||
|
if ((p <= NUM_CHANNELS) && (ch->type == SR_CHANNEL_ANALOG)
|
||||||
|
&& (ch->enabled)) {
|
||||||
|
num_analog++;
|
||||||
|
devc->enabled_analog_channels =
|
||||||
|
g_slist_append(devc->enabled_analog_channels, ch);
|
||||||
|
} else {
|
||||||
|
channel_mask |= ch->enabled << p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use wide sampling if either any of the LA channels 8..15 is enabled,
|
||||||
|
* and/or at least one analog channel is enabled.
|
||||||
|
*/
|
||||||
|
devc->sample_wide = channel_mask > 0xff || num_analog > 0;
|
||||||
|
|
||||||
|
return SR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
static unsigned int to_bytes_per_ms(unsigned int samplerate)
|
static unsigned int to_bytes_per_ms(unsigned int samplerate)
|
||||||
{
|
{
|
||||||
return samplerate / 1000;
|
return samplerate / 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
SR_PRIV size_t fx2lafw_get_buffer_size(struct dev_context *devc)
|
static size_t get_buffer_size(struct dev_context *devc)
|
||||||
{
|
{
|
||||||
size_t s;
|
size_t s;
|
||||||
|
|
||||||
|
@ -589,13 +554,13 @@ SR_PRIV size_t fx2lafw_get_buffer_size(struct dev_context *devc)
|
||||||
return (s + 511) & ~511;
|
return (s + 511) & ~511;
|
||||||
}
|
}
|
||||||
|
|
||||||
SR_PRIV unsigned int fx2lafw_get_number_of_transfers(struct dev_context *devc)
|
static unsigned int get_number_of_transfers(struct dev_context *devc)
|
||||||
{
|
{
|
||||||
unsigned int n;
|
unsigned int n;
|
||||||
|
|
||||||
/* Total buffer size should be able to hold about 500ms of data. */
|
/* Total buffer size should be able to hold about 500ms of data. */
|
||||||
n = (500 * to_bytes_per_ms(devc->cur_samplerate) /
|
n = (500 * to_bytes_per_ms(devc->cur_samplerate) /
|
||||||
fx2lafw_get_buffer_size(devc));
|
get_buffer_size(devc));
|
||||||
|
|
||||||
if (n > NUM_SIMUL_TRANSFERS)
|
if (n > NUM_SIMUL_TRANSFERS)
|
||||||
return NUM_SIMUL_TRANSFERS;
|
return NUM_SIMUL_TRANSFERS;
|
||||||
|
@ -603,13 +568,150 @@ SR_PRIV unsigned int fx2lafw_get_number_of_transfers(struct dev_context *devc)
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
SR_PRIV unsigned int fx2lafw_get_timeout(struct dev_context *devc)
|
static unsigned int get_timeout(struct dev_context *devc)
|
||||||
{
|
{
|
||||||
size_t total_size;
|
size_t total_size;
|
||||||
unsigned int timeout;
|
unsigned int timeout;
|
||||||
|
|
||||||
total_size = fx2lafw_get_buffer_size(devc) *
|
total_size = get_buffer_size(devc) *
|
||||||
fx2lafw_get_number_of_transfers(devc);
|
get_number_of_transfers(devc);
|
||||||
timeout = total_size / to_bytes_per_ms(devc->cur_samplerate);
|
timeout = total_size / to_bytes_per_ms(devc->cur_samplerate);
|
||||||
return timeout + timeout / 4; /* Leave a headroom of 25% percent. */
|
return timeout + timeout / 4; /* Leave a headroom of 25% percent. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int receive_data(int fd, int revents, void *cb_data)
|
||||||
|
{
|
||||||
|
struct timeval tv;
|
||||||
|
struct drv_context *drvc;
|
||||||
|
|
||||||
|
(void)fd;
|
||||||
|
(void)revents;
|
||||||
|
|
||||||
|
drvc = (struct drv_context *)cb_data;
|
||||||
|
|
||||||
|
tv.tv_sec = tv.tv_usec = 0;
|
||||||
|
libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int start_transfers(const struct sr_dev_inst *sdi)
|
||||||
|
{
|
||||||
|
struct dev_context *devc;
|
||||||
|
struct sr_usb_dev_inst *usb;
|
||||||
|
struct sr_trigger *trigger;
|
||||||
|
struct libusb_transfer *transfer;
|
||||||
|
unsigned int i, num_transfers;
|
||||||
|
int timeout, ret;
|
||||||
|
unsigned char *buf;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
devc = sdi->priv;
|
||||||
|
usb = sdi->conn;
|
||||||
|
|
||||||
|
devc->sent_samples = 0;
|
||||||
|
devc->acq_aborted = FALSE;
|
||||||
|
devc->empty_transfer_count = 0;
|
||||||
|
|
||||||
|
if ((trigger = sr_session_trigger_get(sdi->session))) {
|
||||||
|
int pre_trigger_samples = 0;
|
||||||
|
if (devc->limit_samples > 0)
|
||||||
|
pre_trigger_samples = (devc->capture_ratio * devc->limit_samples) / 100;
|
||||||
|
devc->stl = soft_trigger_logic_new(sdi, trigger, pre_trigger_samples);
|
||||||
|
if (!devc->stl)
|
||||||
|
return SR_ERR_MALLOC;
|
||||||
|
devc->trigger_fired = FALSE;
|
||||||
|
} else
|
||||||
|
devc->trigger_fired = TRUE;
|
||||||
|
|
||||||
|
num_transfers = get_number_of_transfers(devc);
|
||||||
|
|
||||||
|
size = get_buffer_size(devc);
|
||||||
|
devc->submitted_transfers = 0;
|
||||||
|
|
||||||
|
devc->transfers = g_try_malloc0(sizeof(*devc->transfers) * num_transfers);
|
||||||
|
if (!devc->transfers) {
|
||||||
|
sr_err("USB transfers malloc failed.");
|
||||||
|
return SR_ERR_MALLOC;
|
||||||
|
}
|
||||||
|
|
||||||
|
timeout = get_timeout(devc);
|
||||||
|
devc->num_transfers = num_transfers;
|
||||||
|
for (i = 0; i < num_transfers; i++) {
|
||||||
|
if (!(buf = g_try_malloc(size))) {
|
||||||
|
sr_err("USB transfer buffer malloc failed.");
|
||||||
|
return SR_ERR_MALLOC;
|
||||||
|
}
|
||||||
|
transfer = libusb_alloc_transfer(0);
|
||||||
|
libusb_fill_bulk_transfer(transfer, usb->devhdl,
|
||||||
|
2 | LIBUSB_ENDPOINT_IN, buf, size,
|
||||||
|
receive_transfer, (void *)sdi, timeout);
|
||||||
|
sr_info("submitting transfer: %d", i);
|
||||||
|
if ((ret = libusb_submit_transfer(transfer)) != 0) {
|
||||||
|
sr_err("Failed to submit transfer: %s.",
|
||||||
|
libusb_error_name(ret));
|
||||||
|
libusb_free_transfer(transfer);
|
||||||
|
g_free(buf);
|
||||||
|
fx2lafw_abort_acquisition(devc);
|
||||||
|
return SR_ERR;
|
||||||
|
}
|
||||||
|
devc->transfers[i] = transfer;
|
||||||
|
devc->submitted_transfers++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If this device has analog channels and at least one of them is
|
||||||
|
* enabled, use mso_send_data_proc() to properly handle the analog
|
||||||
|
* data. Otherwise use la_send_data_proc().
|
||||||
|
*/
|
||||||
|
if (g_slist_length(devc->enabled_analog_channels) > 0)
|
||||||
|
devc->send_data_proc = mso_send_data_proc;
|
||||||
|
else
|
||||||
|
devc->send_data_proc = la_send_data_proc;
|
||||||
|
|
||||||
|
std_session_send_df_header(sdi);
|
||||||
|
|
||||||
|
return SR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
SR_PRIV int fx2lafw_start_acquisition(const struct sr_dev_inst *sdi)
|
||||||
|
{
|
||||||
|
struct sr_dev_driver *di;
|
||||||
|
struct drv_context *drvc;
|
||||||
|
struct dev_context *devc;
|
||||||
|
int timeout, ret;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
di = sdi->driver;
|
||||||
|
drvc = di->context;
|
||||||
|
devc = sdi->priv;
|
||||||
|
|
||||||
|
devc->ctx = drvc->sr_ctx;
|
||||||
|
devc->sent_samples = 0;
|
||||||
|
devc->empty_transfer_count = 0;
|
||||||
|
devc->acq_aborted = FALSE;
|
||||||
|
|
||||||
|
if (configure_channels(sdi) != SR_OK) {
|
||||||
|
sr_err("Failed to configure channels.");
|
||||||
|
return SR_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
timeout = get_timeout(devc);
|
||||||
|
usb_source_add(sdi->session, devc->ctx, timeout, receive_data, drvc);
|
||||||
|
|
||||||
|
size = get_buffer_size(devc);
|
||||||
|
/* Prepare for analog sampling. */
|
||||||
|
if (g_slist_length(devc->enabled_analog_channels) > 0) {
|
||||||
|
/* We need a buffer half the size of a transfer. */
|
||||||
|
devc->logic_buffer = g_try_malloc(size / 2);
|
||||||
|
devc->analog_buffer = g_try_malloc(
|
||||||
|
sizeof(float) * size / 2);
|
||||||
|
}
|
||||||
|
start_transfers(sdi);
|
||||||
|
if ((ret = command_start_acquisition(sdi)) != SR_OK) {
|
||||||
|
fx2lafw_abort_acquisition(devc);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SR_OK;
|
||||||
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue