Compare commits

...

13 Commits

Author SHA1 Message Date
Uwe Hermann a6b07d7e28 Bump package version to 0.5.2. 2019-12-25 21:25:15 +01:00
Uwe Hermann c66fde84f6 configure.ac: Bump libtool/library version from 5:0:1 to 5:1:1.
The libtool current:revision:age numbers change from 5:0:1 to 5:1:1
since no new APIs were added and no existing ones were changed or
removed. Thus, revision is incremented, current and age stay unchanged.

Details:
http://www.gnu.org/software/libtool/manual/libtool.html#Updating-version-info

This changes the library filename (e.g. on Linux) from
libsigrok.so.4.1.0 to libsigrok.so.4.1.1, the SONAME
(+symlink) remains the same, though (libsigrok.so.4).
2019-12-25 21:24:29 +01:00
Uwe Hermann c1a8e19d9a Doxyfile: Set version to 0.5.2. 2019-12-24 16:42:45 +01:00
Uwe Hermann fdb297c6de NEWS: Add list of user-visible changes so far. 2019-12-24 16:42:45 +01:00
Uwe Hermann e4204b1757 Backport recent changes from mainline.
This includes all changes from

  4c660b46c1
  Makefile.am: Add missing src/serial_hid.h.

up to

  39ea7b7d39
  dmm/eev121gw: add missing scale items for sub display in power modes

This is possible since none of the changes above change or
remove public API calls of the library.
2019-12-24 16:40:57 +01:00
Uwe Hermann 8686b747cd configure.ac: Bump package version to 0.5.1. 2018-10-14 22:41:49 +02:00
Uwe Hermann 45106f0ca5 configure.ac: Bump libtool/library version from 4:0:0 to 5:0:1.
The libtool current:revision:age numbers change from 4:0:0 to 5:0:1
since new APIs were added (but no existing ones were changed or
removed). Thus, revision is set to 0, current and age are bumped.

Details:
http://www.gnu.org/software/libtool/manual/libtool.html#Updating-version-info

This changes the library filename (e.g. on Linux) from
libsigrok.so.4.0.0 to libsigrok.so.4.1.0, the SONAME
(+symlink) remains the same, though (libsigrok.so.4).
2018-10-14 22:41:49 +02:00
Uwe Hermann 6cec31aeac Doxygen: Update relevant @since tags to 0.5.1. 2018-10-14 22:41:49 +02:00
Uwe Hermann d0667da66f Doxyfile: Set version to 0.5.1. 2018-10-14 22:41:49 +02:00
Uwe Hermann 2d5ccd2601 NEWS: Add list of user-visible changes so far. 2018-10-14 22:41:49 +02:00
Uwe Hermann d2af13d03f Revert API/ABI change for Context::create_analog_packet().
This is fine in libsigrokcxx mainline, but for the 0.5.x series we need
to remain API/ABI-compatible.
2018-10-14 22:40:09 +02:00
Uwe Hermann 8cd15dd4ce Backport recent changes from mainline.
This includes all changes from

  59cae77e28
  serial_stream_detect(): Make a code comment more generic.

up to

  a7600dc5c7
  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.
2018-10-14 22:39:48 +02:00
Uwe Hermann 1aba657270 Doxyfile: Set version to 0.5.0. 2017-06-12 03:08:36 +02:00
333 changed files with 44690 additions and 13386 deletions

1
.gitignore vendored
View File

@ -12,6 +12,7 @@
# Editor/IDE cruft
*.kate-swp
*~
.*.sw*
/*.kdev4
/Makefile.am.user

View File

@ -38,7 +38,7 @@ PROJECT_NAME = "libsigrok"
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = "unreleased development snapshot"
PROJECT_NUMBER = "0.5.2"
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
@ -743,7 +743,7 @@ WARN_LOGFILE =
# spaces.
# Note: If this tag is empty the current directory is searched.
INPUT = src include $(BUILDDIR)include/libsigrok
INPUT = $(SRCDIR)src $(SRCDIR)include $(BUILDDIR)include/libsigrok
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
@ -763,7 +763,11 @@ INPUT_ENCODING = UTF-8
# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
# *.qsf, *.as and *.js.
FILE_PATTERNS =
# BEWARE! DON'T set the variable to an empty value. Don't set the variable
# at all instead. See https://github.com/doxygen/doxygen/issues/7190 and
# https://sigrok.org/bugzilla/show_bug.cgi?id=1422 (can get reverted when
# the Doxygen version which causes the issue no longer is used in the wild).
## FILE_PATTERNS =
# The RECURSIVE tag can be used to specify whether or not subdirectories should
# be searched for input files as well.

View File

@ -61,8 +61,9 @@ This is a rough overview of what you need to do in order to add a new driver
(using the Tondaj SL-814 device as example). It's basically what the
'new-driver' script (see above) does for you:
- Makefile.am: Add HW_TONDAJ_SL_814 and add to libsigrok_la_SOURCES.
- configure.ac: Add a DRIVER() and DRIVER2() call.
- Makefile.am: Add to src_libdrivers_la_SOURCES under the HW_TONDAJ_SL_814
condition.
- configure.ac: Add an SR_DRIVER() call.
- src/drivers.c: Add a tondaj_sl_814_driver_info entry in two places.
- src/hardware/tondaj-sl-814/ directory: Add api.c, protocol.c, protocol.h.

View File

@ -50,6 +50,7 @@ lib_LTLIBRARIES = libsigrok.la
# Backend files
libsigrok_la_SOURCES = \
src/backend.c \
src/conversion.c \
src/device.c \
src/session.c \
src/session_file.c \
@ -73,10 +74,12 @@ libsigrok_la_SOURCES += \
src/input/binary.c \
src/input/chronovu_la8.c \
src/input/csv.c \
src/input/logicport.c \
src/input/raw_analog.c \
src/input/trace32_ad.c \
src/input/vcd.c \
src/input/wav.c
src/input/wav.c \
src/input/null.c
# Output modules
libsigrok_la_SOURCES += \
@ -91,7 +94,9 @@ libsigrok_la_SOURCES += \
src/output/hex.c \
src/output/ols.c \
src/output/srzip.c \
src/output/vcd.c
src/output/vcd.c \
src/output/wavedrom.c \
src/output/null.c
# Transform modules
libsigrok_la_SOURCES += \
@ -104,7 +109,6 @@ libsigrok_la_SOURCES += \
libsigrok_la_SOURCES += \
src/scpi.h \
src/scpi/scpi.c \
src/scpi/helpers.c \
src/scpi/scpi_tcp.c
if NEED_RPC
libsigrok_la_SOURCES += \
@ -113,9 +117,21 @@ libsigrok_la_SOURCES += \
src/scpi/vxi_xdr.c \
src/scpi/vxi.h
endif
# if HAVE_BLUETOOTH
libsigrok_la_SOURCES += \
src/bt/bt_bluez.c
# endif
if NEED_SERIAL
libsigrok_la_SOURCES += \
src/serial.c \
src/serial_bt.c \
src/serial_hid.c \
src/serial_hid.h \
src/serial_hid_bu86x.c \
src/serial_hid_ch9325.c \
src/serial_hid_cp2110.c \
src/serial_hid_victor.c \
src/serial_libsp.c \
src/scpi/scpi_serial.c
endif
if NEED_USB
@ -143,23 +159,29 @@ endif
# Hardware (DMM chip parsers)
libsigrok_la_SOURCES += \
src/dmm/asycii.c \
src/dmm/bm25x.c \
src/dmm/bm86x.c \
src/dmm/dtm0660.c \
src/dmm/eev121gw.c \
src/dmm/es519xx.c \
src/dmm/fs9721.c \
src/dmm/fs9922.c \
src/dmm/m2110.c \
src/dmm/metex14.c \
src/dmm/asycii.c \
src/dmm/ms2115b.c \
src/dmm/ms8250d.c \
src/dmm/rs9lcd.c \
src/dmm/bm25x.c \
src/dmm/ut71x.c \
src/dmm/ut372.c \
src/dmm/ut71x.c \
src/dmm/vc870.c \
src/dmm/dtm0660.c
src/dmm/vc96.c
# Hardware (LCR chip parsers)
if NEED_SERIAL
libsigrok_la_SOURCES += \
src/lcr/es51919.c
src/lcr/es51919.c \
src/lcr/vc4080.c
endif
# Hardware (Scale protocol parsers)
@ -167,15 +189,22 @@ libsigrok_la_SOURCES += \
src/scale/kern.c
# 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
$(AM_V_CCLD)$(LINK) src/libdrivers.la
src/libdrivers.o: 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
$(AM_V_GEN)echo "# Generated by libtool" > $@
$(AM_V_at)echo "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
if HW_AGILENT_DMM
@ -221,13 +250,9 @@ src_libdrivers_la_SOURCES += \
src/hardware/beaglelogic/beaglelogic.h \
src/hardware/beaglelogic/protocol.h \
src/hardware/beaglelogic/protocol.c \
src/hardware/beaglelogic/api.c
endif
if HW_BRYMEN_BM86X
src_libdrivers_la_SOURCES += \
src/hardware/brymen-bm86x/protocol.h \
src/hardware/brymen-bm86x/protocol.c \
src/hardware/brymen-bm86x/api.c
src/hardware/beaglelogic/api.c \
src/hardware/beaglelogic/beaglelogic_native.c \
src/hardware/beaglelogic/beaglelogic_tcp.c
endif
if HW_BRYMEN_DMM
src_libdrivers_la_SOURCES += \
@ -272,6 +297,18 @@ src_libdrivers_la_SOURCES += \
src/hardware/demo/protocol.c \
src/hardware/demo/api.c
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
src_libdrivers_la_SOURCES += \
src/hardware/fluke-dmm/protocol.h \
@ -288,9 +325,7 @@ if HW_FX2LAFW
src_libdrivers_la_SOURCES += \
src/hardware/fx2lafw/protocol.h \
src/hardware/fx2lafw/protocol.c \
src/hardware/fx2lafw/api.c \
src/hardware/fx2lafw/dslogic.c \
src/hardware/fx2lafw/dslogic.h
src/hardware/fx2lafw/api.c
endif
if HW_GMC_MH_1X_2X
src_libdrivers_la_SOURCES += \
@ -304,12 +339,24 @@ src_libdrivers_la_SOURCES += \
src/hardware/gwinstek-gds-800/protocol.c \
src/hardware/gwinstek-gds-800/api.c
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
src_libdrivers_la_SOURCES += \
src/hardware/hameg-hmo/protocol.h \
src/hardware/hameg-hmo/protocol.c \
src/hardware/hameg-hmo/api.c
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
src_libdrivers_la_SOURCES += \
src/hardware/hantek-6xxx/protocol.h \
@ -328,6 +375,12 @@ src_libdrivers_la_SOURCES += \
src/hardware/hp-3457a/protocol.c \
src/hardware/hp-3457a/api.c
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
src_libdrivers_la_SOURCES += \
src/hardware/hung-chang-dso-2100/protocol.h \
@ -346,6 +399,12 @@ src_libdrivers_la_SOURCES += \
src/hardware/ikalogic-scanaplus/protocol.c \
src/hardware/ikalogic-scanaplus/api.c
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
src_libdrivers_la_SOURCES += \
src/hardware/kecheng-kc-330b/protocol.h \
@ -388,18 +447,36 @@ src_libdrivers_la_SOURCES += \
src/hardware/manson-hcs-3xxx/protocol.c \
src/hardware/manson-hcs-3xxx/api.c
endif
if HW_MASTECH_MS6514
src_libdrivers_la_SOURCES += \
src/hardware/mastech-ms6514/protocol.h \
src/hardware/mastech-ms6514/protocol.c \
src/hardware/mastech-ms6514/api.c
endif
if HW_MAYNUO_M97
src_libdrivers_la_SOURCES += \
src/hardware/maynuo-m97/protocol.h \
src/hardware/maynuo-m97/protocol.c \
src/hardware/maynuo-m97/api.c
endif
if HW_MICROCHIP_PICKIT2
src_libdrivers_la_SOURCES += \
src/hardware/microchip-pickit2/protocol.h \
src/hardware/microchip-pickit2/protocol.c \
src/hardware/microchip-pickit2/api.c
endif
if HW_MIC_985XX
src_libdrivers_la_SOURCES += \
src/hardware/mic-985xx/protocol.h \
src/hardware/mic-985xx/protocol.c \
src/hardware/mic-985xx/api.c
endif
if HW_MOOSHIMETER_DMM
src_libdrivers_la_SOURCES += \
src/hardware/mooshimeter-dmm/protocol.h \
src/hardware/mooshimeter-dmm/protocol.c \
src/hardware/mooshimeter-dmm/api.c
endif
if HW_MOTECH_LPS_30X
src_libdrivers_la_SOURCES += \
src/hardware/motech-lps-30x/protocol.h \
@ -430,6 +507,12 @@ src_libdrivers_la_SOURCES += \
src/hardware/pipistrello-ols/protocol.c \
src/hardware/pipistrello-ols/api.c
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
src_libdrivers_la_SOURCES += \
src/hardware/rigol-ds/protocol.h \
@ -448,6 +531,18 @@ src_libdrivers_la_SOURCES += \
src/hardware/saleae-logic16/protocol.c \
src/hardware/saleae-logic16/api.c
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_DMM
src_libdrivers_la_SOURCES += \
src/hardware/scpi-dmm/protocol.h \
src/hardware/scpi-dmm/protocol.c \
src/hardware/scpi-dmm/api.c
endif
if HW_SCPI_PPS
src_libdrivers_la_SOURCES += \
src/hardware/scpi-pps/protocol.h \
@ -463,8 +558,16 @@ src_libdrivers_la_SOURCES += \
endif
if HW_SERIAL_LCR
src_libdrivers_la_SOURCES += \
src/hardware/serial-lcr/protocol.h \
src/hardware/serial-lcr/protocol.c \
src/hardware/serial-lcr/api.c
endif
if HW_SIGLENT_SDS
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
src_libdrivers_la_SOURCES += \
src/hardware/sysclk-lwla/lwla.h \
@ -475,6 +578,12 @@ src_libdrivers_la_SOURCES += \
src/hardware/sysclk-lwla/protocol.c \
src/hardware/sysclk-lwla/api.c
endif
if HW_SYSCLK_SLA5032
src_libdrivers_la_SOURCES += \
src/hardware/sysclk-sla5032/protocol.h \
src/hardware/sysclk-sla5032/protocol.c \
src/hardware/sysclk-sla5032/api.c
endif
if HW_TELEINFO
src_libdrivers_la_SOURCES += \
src/hardware/teleinfo/protocol.h \
@ -505,12 +614,6 @@ src_libdrivers_la_SOURCES += \
src/hardware/uni-t-ut32x/protocol.c \
src/hardware/uni-t-ut32x/api.c
endif
if HW_VICTOR_DMM
src_libdrivers_la_SOURCES += \
src/hardware/victor-dmm/protocol.h \
src/hardware/victor-dmm/protocol.c \
src/hardware/victor-dmm/api.c
endif
if HW_YOKOGAWA_DLM
src_libdrivers_la_SOURCES += \
src/hardware/yokogawa-dlm/protocol.h \
@ -529,6 +632,12 @@ src_libdrivers_la_SOURCES += \
src/hardware/zeroplus-logic-cube/protocol.c \
src/hardware/zeroplus-logic-cube/api.c
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_LDFLAGS = -version-info $(SR_LIB_VERSION) -no-undefined
@ -544,7 +653,7 @@ noinst_HEADERS = src/libsigrok-internal.h
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libsigrok.pc
mimeappdir = $(datadir)/mime/application
mimeappdir = $(datadir)/mime/packages
mimeapp_DATA = contrib/vnd.sigrok.session.xml
mimeicondir = $(datadir)/icons/hicolor/48x48/mimetypes
@ -581,7 +690,9 @@ EXTRA_DIST = \
contrib/libsigrok.png \
contrib/libsigrok.svg \
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
TESTS = tests/main
@ -636,7 +747,7 @@ nodist_bindings_cxx_libsigrokcxx_la_include_HEADERS = \
pkgconfig_DATA += bindings/cxx/libsigrokcxx.pc
doxy/xml/index.xml: include/libsigrok/libsigrok.h
$(AM_V_GEN)cd $(srcdir) && BUILDDIR=$(abs_builddir)/ doxygen Doxyfile 2>/dev/null
$(AM_V_GEN)cd $(srcdir) && SRCDIR=$(abs_srcdir)/ BUILDDIR=$(abs_builddir)/ doxygen Doxyfile 2>/dev/null
bindings/swig/enums.i: bindings/cxx/enums.timestamp
bindings/cxx/enums.cpp: bindings/cxx/enums.timestamp
@ -671,7 +782,7 @@ CPPXMLDOC = bindings/cxx/doxy/xml/index.xml
$(CPPXMLDOC): bindings/cxx/include/libsigrokcxx/libsigrokcxx.hpp \
bindings/cxx/enums.timestamp
$(AM_V_GEN)cd $(srcdir)/bindings/cxx && BUILDDIR=$(abs_builddir)/bindings/cxx/ doxygen Doxyfile 2>/dev/null
$(AM_V_GEN)cd $(srcdir)/bindings/cxx && SRCDIR=$(abs_srcdir)/bindings/cxx/ BUILDDIR=$(abs_builddir)/bindings/cxx/ doxygen Doxyfile 2>/dev/null
# Macro definitions to be used by the SWIG parser.
swig_defs = -Dnoexcept= -Dprivate=protected -DG_GNUC_BEGIN_IGNORE_DEPRECATIONS= -DG_GNUC_END_IGNORE_DEPRECATIONS=
@ -719,7 +830,7 @@ python-clean:
-$(AM_V_at)$(setup_py) clean --all 2>/dev/null
python-doc:
$(AM_V_at)cd $(srcdir)/$(PDIR) && BUILDDIR="$(abs_builddir)/$(PDIR)/" doxygen Doxyfile 2>/dev/null
$(AM_V_at)cd $(srcdir)/$(PDIR) && SRCDIR="$(abs_srcdir)/$(PDIR)/" BUILDDIR="$(abs_builddir)/$(PDIR)/" doxygen Doxyfile 2>/dev/null
BUILD_EXTRA += python-build
INSTALL_EXTRA += python-install
@ -836,7 +947,7 @@ java-clean:
-$(AM_V_at)rm -fr $(JDIR)/doxy
java-doc:
$(AM_V_at)cd $(srcdir)/$(JDIR) && BUILDDIR="$(abs_builddir)/$(JDIR)/" doxygen Doxyfile
$(AM_V_at)cd $(srcdir)/$(JDIR) && SRCDIR="$(abs_srcdir)/$(JDIR)/" BUILDDIR="$(abs_builddir)/$(JDIR)/" doxygen Doxyfile
BUILD_EXTRA += java-build
INSTALL_EXTRA += java-install

479
NEWS
View File

@ -1,3 +1,480 @@
0.5.2 (2019-12-23)
------------------
Note: This release does NOT change the libsigrok public C API in incompatible
ways. While new config keys have been added (additional enum
entries / numbers), no existing interfaces were changed or removed.
Frontends should continue to work fine without recompiling or relinking.
* New supported hardware:
- Logic analyzers:
- Microchip PICkit2
- Sysclk SLA5032
- Multimeters:
- Agilent 34405A
- Agilent U1271
- Agilent U1272
- Agilent U1273
- HP 34401A
- Keysight 34465A
- MASTECH MS2115B
- Mooshimeter
- Power supplies:
- BK Precision 9130
- HP 6611C
- HP 6612C
- HP 6613C
- HP 6614C
- HP 66312A
- HP 6632A
- HP 6634A
- Korad KA3005P (with 0xBC as extra byte in the model ID).
- Korad KD6005P
- Manson HCS-3300
- Manson HCS-3302
- RND 320-KD3005P
- Stamos S-LS-31
- TENMA 72-2535 V2.1
- Voltcraft DPPS-32-15
- Oscilloscopes:
- Agilent DSO1000B series
- Hameg HMO3522
- Rigol MSO5000 series
- Rohde&Schwarz HMO1000 series (e.g. bug #1286)
- Rohde&Schwarz RTA4000 series
- Rohde&Schwarz RTB2000 series
- Rohde&Schwarz RTC1000 series
- Rohde&Schwarz RTM3000 series
- YiXingDianZi MDSO
- LCR meters:
- MASTECH MS5308
- PeakTech 2165
- UNI-T UT612
- Voltcraft 4080
- Thermometers:
- MASTECH MS6514
* New config keys:
- SR_CONF_OFFSET
- SR_CONF_TRIGGER_PATTERN
- SR_CONF_HIGH_RESOLUTION
- SR_CONF_PEAK_DETECTION
- SR_CONF_LOGIC_THRESHOLD
- SR_CONF_LOGIC_THRESHOLD_CUSTOM
- SR_CONF_RANGE
- SR_CONF_DIGITS
* New output modules:
- wavedrom: WaveDrom JSON-based digital timing diagrams.
* Build dependencies:
- hidapi >= 0.8.0 (optional, used for some HID based "serial cables")
- bluez/libbluetooth >= 4.0 (optional, used for Bluetooth/BLE; Linux-only)
- libgio >= 2.32.0 (optional, used by some drivers)
* C++ bindings:
- Add Output::format().
- Avoid "using namespace" in headers (bug #1354).
* Python bindings:
- Add data array for logic packet payload.
- Add override for Context.create_logic_packet().
- Add new Context::create_end_packet() method.
* Backend:
- Add support for "serial over USB HID" transport, e.g. in DMMs (bug #555).
Supported chips/protocols: WCH CH9325, SiLabs CP2110, Brymen BU-86X IR
adapter, Victor DMM chip.
- Add support for Bluetooth and BLE (currently Linux-only).
- Add support for "serial over Bluetooth/BLE" transport (used e.g. in DMMs).
- serial: Add support for optional "RX chunk" callback.
- Remove sr_dev_close call from std_serial_dev_acquisition_stop (bug #1271).
* input/trace32_ad:
- Add support for new file format (BINHDR2).
* input/csv:
- Unbreak re-import of CSV files.
- Various parsing robustness improvements.
- Introduce generic "column processing" support.
- Various module option changes and renames.
- Add support for analog input data.
- Add support for timestamp columns, auto detect samplerate.
- Add automatic format match support.
- Set default "header" option value to true.
- Fix incorrect/incomplete startline/newline handling (bug #968).
* output/analog:
- Also print meta strings (not just numbers).
* output/vcd:
- Use larger data type to internally store frequency.
- Support smaller timescales with higher resolution.
* output/csv:
- Set default "time" option value to false.
* scpi:
- Add connenction_id() function to all SCPI drivers.
- scpi_libgpib: Add mutex to SPoll.
* dmm/bm86x:
- Unbreak temperature modes for two probes and no probes (bug #1394).
* brymen-bm86x, victor-dmm:
- Removed in favor of serial-dmm based driver support.
* scpi-pps:
- Add support for various config keys for HP 66xxB power supplies.
- Add init_acquisition() and update_status() for HP 66xxB power supplies.
- Set device and channel group feature for HP 66xxB.
- Don't use SCPI_CMD_REMOTE/_LOCAL for HP 66xxB devices when in GPIB mode.
- Add support for various config keys for HP 66xxA power supplies.
- Add configurable sr_mqflags.
- Add missing frequency channel settings for acquisition.
* hantek-4032l:
- Fix broken triggering on low signal (bug #1402).
* hameg-hmo:
- Use g_byte_array_free() instead of g_free() (bug #1324).
- Remove invalid HMO2522, add missing HMO3522 (bug #1322).
- Add support for 16 digital (logic) channels, i.e. two pods.
- Add support for various new config keys.
- Avoid getting stuck upon SCPI timeouts (bug #1323).
- Try to find a valid serialcomm if none is supplied (bug #1321).
- When setting slope, also set trigger type to edge (bug #1328).
- Use 1-based (not 0-based) POD numbers.
- Fix for an incorrect samplerate being returned.
- Fix the upper limit for the vertical scale.
* agilent-dmm:
- Fix support for Agilent/Keysight U1252A.
* asix-sigma:
- Fix a compiler warning (bug #1411).
* beaglelogic:
- Fix mismatched printf specifiers.
* saleae-logic16:
- Warn (instead of erroring out) if FPGA is unsupported.
* demo:
- Set an initial MQ, MQ flag and digits to the analog package.
- Get/set measurement quantity for the analog channels.
- Get/set amplitude while data acquisition is running.
- Get/set new config key SR_CONF_OFFSET.
- Add random analog signal generation.
* korad-kaxxxxp:
- Add SR_MQFLAG_DC flag to the current channel packet.
- Fix bug when setting values while acquisition is running.
- Send META packet when states have changed.
* lecroy-xstream:
- Remove header read, which caused issues on some devices (PR #33).
* uni-t-ut32x:
- Pre-set to default conn= spec.
- Use common code for sample/time limits.
- Improve robustness of packet parser, more diagnostics.
* chronovu-la:
- Fix broken triggering (#1369).
* openbench-logic-sniffer:
- Use 32bit for handling sample counts.
- Extend reponse delay when scanning device (helps on Pepino).
- Add feature to support >256K memory.
- Introduce metadata quirks support, unbreak Logic Shrimp.
* ftdi-la:
- Added FTDI FT232H device ID.
- Do enter the error path upon VID:PID mismatch (bug #1390).
* hp-3478a:
- Check via GPIB serial poll if new data is available.
- Add get/set/list of measurement ranges.
- Add get/set/list of digits.
- Check for measurement value overflow.
* manson-hcs-3xxx:
- Add support for some models with changes ID string (e.g. bug #1441).
* fx2lafw:
- Add support for 48MHz sampling (for very short intervals only).
* ipdbg-la:
- Check if limit samples is valid.
- Improve acquisition speed.
- Fix various issues on Windows.
- Fix an issue when capture rate is 100% (bug #1393).
* scpi-dmm:
- Accept serialcomm= scan options.
- Run OPC queries immediately before essential commands.
* brymen-bm86x:
- Fix incorrect channel indices.
* dmm/eev121gw:
- Add missing scale items for sub display in power modes.
* rigol-ds:
- Fix memory buffer readout on DS4000 series.
* fluke-45:
- Avoid NULL dereference in the probe routine.
- Disable ECHO test, it confuses other SCPI devices (bug #1272).
fluke-dmm:
- Fix use-after-free bugs (bug #1423).
* rdtech-dps:
- Synchronize read and write operations.
- Retry sr_modbus_read_holding_registers() up to 3 times.
- Handle different per-model current/voltage digits (bug #1385).
- Send META package when states have changed.
* udev:
- Add an additional Rohde&Schwarz HMO VID/PID.
- Add Siglent SDS1104X-E VID/PID (bug #1357).
- Add Lecroy WaveRunner VID/PID.
* Build system:
- Fix an issue when building in directories that are symlinks (bug #547).
- Fix C++ bindings compilation with Doxygen >= 1.8.16 (bug #1422).
* Fix various memory leaks in the backend and in drivers.
* README.devices: Update/amend docs, add more examples.
0.5.1 (2018-10-14)
------------------
Note: This release does NOT change the libsigrok public C API in incompatible
ways. While new config keys have been added (additional enum
entries / numbers), no existing interfaces were changed or removed.
Frontends should continue to work fine without recompiling or relinking.
* New supported hardware:
- Logic analyzers:
- DreamSourceLab DSLogic Basic
- DreamSourceLab DSLogic Plus
- Hantek 4032L
- IPDBG (ipdbg.org FPGA IP debugger)
- Meilhaus Logian-16L
- Saleae Logic Pro 16 (experimental)
- ZEROPLUS Logic Cube LAP-16032U
- ZEROPLUS Logic Cube LAP-C (16128+) (bug #1045)
- Oscilloscopes:
- Agilent MSO7034A (experimental, digital channels not yet supported)
- Hantek DSO-2250 (experimental)
- Rigol DS4000 series (bug #1208)
- Siglent SDS1000 series
- Siglent SDS2000 series
- Multimeters:
- EEVblog 121GW (supports serial connection, requires BLE-serial bridge)
- Fluke 45
- HP 3478A
- MASTECH MS8250D
- Metex M-3860M
- PeakTech 4390A
- SparkFun 70C
- Victor DMMs with Mini-USB connector
- Voltcraft VC-96
- Power supplies:
- GW Instek GPD series
- HP 6631B
- HP 66332A
- HP 6633B
- HP 6634B
- Korad KD3005P
- RDTech DPS/DPH series
- Rigol DP711
- Rigol DP712
- RND KA3005P
- Tenma 72-2540
- Electronic loads:
- ZKETECH EBD-USB
* New config keys:
- SR_CONF_POWERMETER
- SR_CONF_UNDER_VOLTAGE_CONDITION_THRESHOLD
- SR_CONF_EXTERNAL_CLOCK_SOURCE
* Build dependencies:
- Drop libftdi 0.x support, require libftdi 1.x (bug #959).
* dreamsourcelab-dslogic:
- Split DSLogic devices into this new driver (were in fx2lafw previously).
- Handle SR_CONF_TRIGGER_MATCH in config_list() (bug #1032).
- Fix incorrect default/initial threshold setting.
- Fix deinterleaving when non-contiguous set of channels is enabled.
- Fix a triggering issue (bug #1188).
* demo:
- Unbreak execution with all analog channels disabled (bug #625).
- Only send average result data when averaging is active (bug #930).
- Don't generate analog output data for disabled channels (bug #923).
- Skip generating data when all channels in a group are disabled (bug #923).
- Mask out logic data for disabled channels in datafeed packets.
- Add multi-frame and frame-count (development) feature.
- Properly handle low samplerates.
- Add graycode generator mode.
- Add triggering support.
* conrad-digi-35-cpu:
- Add SR_CONF_LIST for voltage_target and current_limit.
* arachnid-labs-re-load-pro:
- Stop monitoring when open/close device.
- Add SR_DF_META packets for changed values/states.
- Change serial read in acquisition mode to prevent data loss.
- Fix a rounding issue when setting a current limit.
- Add SR_CONF_UNDER_VOLTAGE_THRESHOLD support.
- Make SR_CONF_REGULATION listable.
- Get a response when in acquision mode.
- Set an encoding "digits" value for analog packets.
* asix-sigma:
- Propagate errors from firmware upload (bug #471).
- Only change number of channels after successful firmware upload (bug #471).
- Only open the USB device once; fails with newer libftdi (bug #471).
- Download sample data upon user initiated stop, too.
* serial-lcr:
- Fix a double-free error (tested with PeakTech 2170).
- Support channel selection (enable/disable P1/P2).
* brymen-bm86x:
- Support channel selection (enable/disable channels).
- Fix a crash upon device closing.
* manson-hcs-3xxx:
- Add new name for the HCS-3304 (adjustment for new Manson firmware).
* chronovu-la:
- Silence overly verbose and confusing log messages.
* beaglelogic:
- Update scan() to return all 14 channels by default.
- Enable seamless continuous capturing.
- Use a flexible sampleunit depending on enabled channels.
- Add TCP protocol support.
- Fix a crash on device connection closing.
- Correctly advertise samplerates via SR_CONF_SAMPLERATE/SR_CONF_LIST.
- Fix a compiler warning (bug #1094).
* lecroy-xstream:
- Fix COMM_HEADER and COMM_FORMAT.
- Use best-effort strategy for models unknown to the driver.
- Fix trigger source/slope handling.
- Implement config_channel_set API callback.
- Fix sample rate handling.
- Keep acquiring infinitely if no frame limit is set.
- Properly handle a stopping acquisition.
- Wait for trigger before acquiring additional frames.
* hantek-6xxx:
- Use lower MAX_PACKET_SIZE on Windows (bug #1048).
- Use FIFO-based sampling, don't buffer all samples before send (bug #1214).
- Hantek 6022BE: Add VID/PID 04b5:6022 support (bug #918).
- Hantek 6022BL: Add VID/PID 04b5:602a support (bug #1295).
* scpi-pps:
- Add channel group device options for HP 663xx.
- Use thread safe SCPI functions, return float not double (bug #779).
- Improve switching of channel groups (PSU channels).
- Add missing functionality for the HP 6632B power supply.
- Add listable OVP/OCP threshold for HP 66xxx and prepared all others.
- Don't block waiting for a value on capture stop.
- Use software sample and time limits.
- Fix broken channel selection code (bug #1279).
* hameg-hmo:
- Forward internal channel state to sigrok channel state (bug #883).
* sysclk-lwla:
- Fix a segfault in dev_close().
- Fix a regression with (at least) the LWLA1034.
* rigol-ds:
- Fix crash when fetching logic channels (bug #1073).
- Fix a memory leak.
- Fix an issue causing only one channel to be acquired (bug #1018).
- Store trigger sources and their number for each model (bug #299).
* hantek-dso:
- Fix segfault when accessing already free()d memory (bug #458).
* korad-kaxxxxp:
- Add two channels "V" and "I", remove channel "CH1".
- Synchronize read and write operations.
* serial-dmm:
- Add support for multiple channels per DMM.
- Count analog DMM channels starting at 1.
- Print data bytes according to specific meter's packet length.
* siglent-sds:
- Fixed timebase problem where "ns" could not be selected (bug #1120).
- Add an averaging function.
- Partial fix for a USB connection problem (bug #1130).
- Fix samplerate and memory depth calculation.
- Better support for *-E series devices (more work might be needed).
- Fix SR_CONF_AVERAGING/SR_CONF_AVG_SAMPLES handling.
* hantek-4032l:
- Various data acquisition fixes (bug #1190).
- Add support for cleanly aborting an acquisition.
* fx2lafw:
- Silence message in query for channel group's device options (bug #1267).
- Add usb-c-grok IDs for upcoming device support.
* input/wav:
- Fix incorrect memset() call.
- Fix module reset issue (bug #1167).
- Don't assume CHUNK_SIZE >= total_samples.
* input/raw_analog:
- Fix module reset issue (bug #1167).
- Set appropriate precision digits for sample format (bug #950).
* input/vcd:
- Fixup VCD timestamp to sigrok samplenum mapping (bug #1075).
- Abort VCD import when timestamp counts backwards (bug #1250).
- Expand the reset() logic (bug #1306).
- Add channel list checks for file re-read (bug #1306).
* input/csv:
- Make the data format option a list.
* input/logicport:
- Add input module for LogicPort File (*.lpf) files.
* input/chronovu_la8:
- Only send data to the session, don't send the header.
- Also claim responsibility for ChronoVu LA16 files (.kdt/.kd1).
* input/null:
- Add this new input module (used for testing and benchmarking purposes).
* Input modules:
- Improve option names and descriptions.
- Increase chunk sizes to 4MB in most cases for improved performance.
- Add confidence (detection strength) to format_match() (bug #1200).
* output/null:
- Add this new output module (used for testing and benchmarking purposes).
* output/analog:
- Display SR_DF_META packets.
- Convert binary to digital digits of precision (bug #950).
* output/vcd:
- Assign adjacent names to enabled channels (bug #519).
- Assume packed input data image, unbreak 2nd+ channel (bug #519).
* output/wav:
- Change default for scale factor from 0.0 to 1.0.
* output/csv:
- Fix out-of-bounds array access in process_analog() (bug #1124).
- Make the label values option a list.
- Disable the dedup option by default.
* Output modules:
- Fixup trigger marker position in ascii/bits/hex output modules.
* Fix various compiler warnings, scan-build issues, and memory leaks.
* soft-trigger:
- Fix a memory allocation issue (bug #1000).
- Fix an issue causing triggers to not work.
* session_driver: Fix an issue causing incorrect analog data reads.
* Logging:
- Flush log lines to cope with non-terminal output (pipes).
- Move log level check so that it affects all handlers (bug #698).
* SCPI:
- Fix an issue caused by trailing whitespace handling (bug #788).
- Synchronize read, write and write+read operations.
* Various DMMs: Set DC flag for diode mode (bug #144).
* All drivers:
- Use serial_write_blocking() everywhere (bug #962).
- Fix locale dependent string to float conversion (bug #1064).
- Show firmware name when loading fails (bug #1262).
* FreeBSD:
- Ensure device is closed before usb_get_port_path() (bug #1109).
* Metex DMMs:
- Add missing modes and set correct digits values.
- Add power factor measurement mode.
- Fix incorrect measurement modes.
* DTM0660 DMMs:
- Do not apply the exponent twice on the value (bug #1236).
* libsigrok API:
- Add sr_a2l_threshold().
- Add sr_a2l_schmitt_trigger().
- Add sr_sprintf_ascii().
- Add sr_snprintf_ascii().
- Add sr_vsprintf_ascii().
- Add sr_vsnprintf_ascii().
- Add sr_resourcepaths_get() (bug #1128).
- Add sr_input_module_get().
- Add sr_log_callback_get().
- Add sr_packet_copy().
- Add sr_packet_free().
- sr_parse_boolstring(): Assume bool is true when no value is specified.
- sr_voltage_string(): Add a space before the unit.
- sr_parse_rational():
- Bugfix for integral parts between -0 and -1.
- Bugfix in an error path (bug #1093).
- Various parsing robustness improvements/fixes.
- Accept leading whitespace.
- Insist on some mantissa.
- sr_analog_si_prefix_friendly(): Fix read past end of array (bug #950).
- sr_parse_sizestring(): Support tera/peta/exa suffixes (bug #763).
* libsigrokcxx API:
- Add Analog::get_logic_via_threshold().
- Add Analog::get_logic_via_schmitt_trigger().
- Add Context::input_format_match().
- Add Option::parse_string().
- Add ConfigKey::parse_string().
* backend: Emit firmware search paths in a log message.
* Fix a driver-independent firmware loading issue (bug #1140).
* modbus: Improve error handling.
* Multiple internal refactorings to massively reduce per-driver boilerplate.
* Also check $SIGROK_FIRMWARE_DIR for firmware files.
* udev rules file:
- Add Brymen BU-86X adapter IDs.
- Add Rigol DP800 series IDs.
- Add usb-c-grok IDs.
- Rename file for correct rule ordering on systemd systems (bug #1059).
- Split device access policy from the device database. New files:
60-libsigrok.rules, 61-libsigrok-{plugdev,uaccess}.rules.
* Build system:
- Emit a warning if the C++ bindings are not being built.
- Install MIME info file in $(datadir)/mime/packages (bug #983).
0.5.0 (2017-06-12)
------------------
@ -205,7 +682,7 @@ Note: This release DOES change the libsigrok API. That means it is NOT
- LeCroy LogicStudio
- mcupro Logic16 clone
- Pipistrello OLS
- SysClk LWLA1016
- Sysclk LWLA1016
- Oscilloscopes:
- Rigol/Agilent DS1000Z series
- Yokogawa DLM2000 series

5
README
View File

@ -41,9 +41,12 @@ Requirements for the C library:
- libserialport >= 0.1.1 (optional, used by some drivers)
- librevisa >= 0.0.20130412 (optional, used by some drivers)
- libusb-1.0 >= 1.0.16 (optional, used by some drivers)
- libftdi >= 0.16 or libftdi1 >= 1.0 (optional, used by some drivers)
- hidapi >= 0.8.0 (optional, used for some HID based "serial cables")
- bluez/libbluetooth >= 4.0 (optional, used for Bluetooth/BLE communication)
- libftdi1 >= 1.0 (optional, used by some drivers)
- libgpib (optional, used by some drivers)
- libieee1284 (optional, used by some drivers)
- libgio >= 2.32.0 (optional, used by some drivers)
- check >= 0.9.4 (optional, only needed to run unit tests)
- doxygen (optional, only needed for the C API docs)
- graphviz (optional, only needed for the C API docs)

View File

@ -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:
$SIGROK_FIRMWARE_DIR (environment variable)
$HOME/.local/share/sigrok-firmware
$prefix/share/sigrok-firmware
/usr/local/share/sigrok-firmware
@ -36,6 +37,11 @@ The following drivers/devices require a firmware upload upon connection:
'sigrok-firmware' repository/project under a license which allows us
to redistribute them.
- dreamsourcelab-dslogic: The DreamSourceLab DSLogic/DSCope device series
requires various firmware files and FPGA bitstream files.
These can be extracted/downloaded from the vendor's GitHub repo using a
tool from our 'sigrok-util' repository/project.
- fx2lafw: Logic analyzers based on the Cypress FX2(LP) chip need the
firmware files from the 'sigrok-firmware-fx2lafw' repository/project.
The firmware is written from scratch and licensed under the GNU GPLv2+.
@ -63,6 +69,11 @@ The following drivers/devices require a firmware upload upon connection:
These can be extracted from the vendor's Linux application using a tool
from our 'sigrok-util' repository/project.
- saleae-logic-pro: The Saleae Logic Pro 16 needs a firmware file for the
Cypress FX3 chip in the device, as well as an FPGA bitstream file.
These can be extracted from the vendor's Linux application using a tool
from our 'sigrok-util' repository/project.
- sysclk-lwla:
- The Sysclk LWLA1034 requires various bitstream files.
@ -73,6 +84,12 @@ The following drivers/devices require a firmware upload upon connection:
These can be extracted from the vendor's Windows drivers using a tool
from our 'sigrok-util' repository/project.
- sysclk-sla5032: The Sysclk SLA5032 needs an FPGA bitstream file.
This file can be copied (and renamed) from the Windows vendor software
installation directory. Details:
https://sigrok.org/wiki/Sysclk_SLA5032#Firmware
The following drivers/devices do not need any firmware upload:
- agilent-dmm
@ -81,7 +98,6 @@ The following drivers/devices do not need any firmware upload:
- atten-pps3xxx
- baylibre-acme
- beaglelogic
- brymen-bm86x
- brymen-dmm
- cem-dt-885x
- center-3xx (including all subdrivers)
@ -89,46 +105,66 @@ The following drivers/devices do not need any firmware upload:
- colead-slm
- conrad-digi-35-cpu
- demo
- fluke-45
- fluke-dmm
- ftdi-la
- gmc-mh-1x-2x (including all subdrivers)
- gwinstek-gds-800
- gwinstek-gpd
- hameg-hmo
- hantek-4032l
- hp-3457a
- hp-3478a
- hung-chang-dso-2100
- ikalogic-scanalogic2
- ikalogic-scanaplus
- ipdbg-la
- kecheng-kc-330b
- kern-scale
- korad-kaxxxxp
- lascar-el-usb
- lecroy-xstream
- link-mso19
- manson-hcs-3xxx
- maynuo-m97
- mic-985xx (including all subdrivers)
- microchip-pickit2
- mooshimeter-dmm
- motech-lps-30x
- norma-dmm
- openbench-logic-sniffer
- pce-322a
- pipistrello-ols
- rdtech-dps
- rigol-ds
- rohde-schwarz-sme-0x
- scpi-dmm
- scpi-pps
- serial-dmm (including all subdrivers)
- serial-lcr (including all subdrivers)
- siglent-sds
- teleinfo
- testo
- tondaj-sl-814
- uni-t-dmm (including all subdrivers)
- uni-t-ut32x
- victor-dmm
- yokogawa-dlm
- zeroplus-logic-cube
- zketech-ebd-usb
Specifying serial ports
-----------------------
Many devices supported by libsigrok use serial port based cables (real RS232
or USB-to-serial ones) to connect to a PC.
or USB-to-serial ones, CDC class) to connect to a PC. These serial cables are
supported by the libserialport library. Some vendors prefer to use HID chips
instead of CDC chips in their serial cables. These cables can get supported
by means of the hidapi library. Note that each chip type requires specific
support in the libsigrok library. Bluetooth connected devices may be supported
as well when they communicate by means of RFCOMM channels, or one of the
implemented BLE notification/indication approaches, and one of the Bluetooth
supporting platforms is used.
For all these devices, you need to specify the serial port they are connected
to (e.g. using the 'conn' option in sigrok-cli). It is not possible to scan
@ -137,51 +173,42 @@ for such devices without specifying a serial port.
Example:
$ sigrok-cli --driver <somedriver>:conn=/dev/ttyUSB0 ...
$ sigrok-cli --driver <somedriver>:conn=hid/cp2110 ...
$ sigrok-cli --driver <somedriver>:conn=bt/rfcomm/01-23-45-67-89-ab ...
The following drivers/devices require a serial port specification:
Formal syntax for serial communication:
- agilent-dmm
- appa-55ii
- atten-pps3xxx
- brymen-dmm
- cem-dt-885x
- center-3xx (including all subdrivers)
- colead-slm
- conrad-digi-35-cpu
- fluke-dmm
- gmc-mh-1x-2x (including all subdrivers)
- hameg-hmo
- link-mso19
- mic-985xx (including all subdrivers)
- norma-dmm
- openbench-logic-sniffer
- rigol-ds (for RS232; not required for USBTMC or TCP)
- serial-dmm (including all subdrivers)
- serial-lcr (including all subdrivers)
- teleinfo
- tondaj-sl-814
- COM ports (RS232, USB CDC):
conn=<com-port>
- USB HID cables:
conn=hid[/<chip>]
conn=hid[/<chip>]/usb=<bus>.<dev>[.<if>]
conn=hid[/<chip>]/raw=<path>
conn=hid[/<chip>]/sn=<serno>
chip can be: bu86x, ch9325, cp2110, victor
path may contain slashes
path and serno are "greedy" (span to the end of the spec)
- Bluetooth Classic and Bluetooth Low Energy (BLE):
conn=bt/<conn>/<addr>
conn can be: rfcomm, ble122, nrf51, cc254x
addr can be "dense" or separated, bt/cc254x/0123456789ab or
bt/rfcomm/11-22-33-44-55-66 or bt/ble122/88:6b:12:34:56:78
(note that colons may not be available when the conn= spec is taken
from a string that separates fields by colon, e.g. in the "--driver
<name>:conn=<spec>" example, that is why the dense form and the use
of dashes for separation are supported)
The following drivers/devices do not require a serial port specification:
Some of the drivers implement a default for the connection. Some of the
drivers can auto-detect USB connected devices.
- asix-sigma
- brymen-bm86x
- chronovu-la
- demo
- fx2lafw
- hantek-dso
- ikalogic-scanalogic2
- ikalogic-scanaplus
- kecheng-kc-330b
- lascar-el-usb
- pipistrello-ols
- rigol-ds (USBTMC or TCP)
- saleae-logic16
- sysclk-lwla
- uni-t-dmm (including all subdrivers)
- uni-t-ut32x
- victor-dmm
- yokogawa-dlm (USBTMC or TCP)
- zeroplus-logic-cube
Beyond strict serial communication over COM ports (discussed above), the
conn= property can also address specific USB devices, as well as specify TCP
or VXI communication parameters. See these examples:
$ sigrok-cli --driver <somedriver>:conn=<vid>.<pid> ...
$ sigrok-cli --driver <somedriver>:conn=tcp-raw/<ipaddr>/<port> ...
$ sigrok-cli --driver <somedriver>:conn=vxi/<ipaddr> ...
$ sigrok-cli --driver <somedriver>:conn=usbtmc/<bus>.<addr> ...
Specifying serial port parameters
@ -212,33 +239,39 @@ For USB-to-serial based devices, we recommended using our udev rules file
(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
libsigrok frontend (e.g. sigrok-cli) has to have (read/write) permissions
for the respective USB device.
On Linux, this is accomplished using either 'chmod' (not recommended) or
using the udev rules file shipped with libsigrok (recommended).
On Linux, this is accomplished using udev rules. libsigrok ships a rules
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
for all libsigrok-supported (USB-based) devices and changes their group
to 'plugdev' and the permissions to '664'.
The file is available in contrib/60-libsigrok.rules. This file just contains
the list of devices and flags these devices with ID_SIGROK="1". Access is
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
packager will have already taken care of properly installing the udev file
in the correct (distro-specific) place, and you don't have to do anything.
The packager might also have adapted 'plugdev' and '664' as needed.
files should already be installed in /usr/lib/udev/rules.d/, i.e.
60-libsigrok.rules and one of the access granting rules files. Use of
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
where your distro expects such files. This is beyond the scope of this README,
but generally the location could be e.g. /etc/udev/rules.d, or maybe
/lib/udev/rules.d, or something else. Afterwards you might have to restart
udev, e.g. via '/etc/init.d/udev restart' or similar, and you'll have to
re-attach your device via USB.
where udev will read these rules. Local rules should go to /etc/udev/rules.d.
Keep the file naming, otherwise interaction between the libsigrok rules and
rules shipped by the system will be broken.
Please consult the udev docs of your distro for details.
Please consult the udev docs for details.
Cypress FX2 based devices
@ -260,9 +293,11 @@ UNI-T DMM (and rebranded models) cables
UNI-T multimeters (and rebranded devices, e.g. some Voltcraft models) can
ship with different PC connectivity cables:
- UT-D02 (RS232 cable)
- UT-D04 (USB/HID cable with Hoitek HE2325U chip, USB VID/PID 04fa:2490)
- UT-D04 (USB/HID cable with WCH CH9325 chip, USB VID/PID 1a86:e008)
- UT-D02 (RS232 cable)
- UT-D07 (Bluetooth adapter, ISSC BL79 BLETR chip)
- UT-D09 (USB/HID cable with SiL CP2110 chip, USB VID/PID 10c4:ea80)
The above cables are all physically compatible (same IR connector shape)
with all/most currently known UNI-T multimeters. For example, you can
@ -337,7 +372,12 @@ a short list for convenience:
- BBC Goertz Metrawatt M2110: Briefly press the "Start/Reset" button on the
interface panel on top.
- Brymen BM257s: Press HOLD during power-on.
- Digitek DT4000ZC: Briefly press the "RS232" button.
- EEVBlog 121GW: Hold "1ms PEAK" until the "BT" indicator is shown.
- ES51919 based LCR meters (DER EE DE-5000, PeakTech 2170, UNI-T UT612):
Press the button with the "RS232" or "USB" or "PC link" label (usually
the "up" cursor button).
- Gossen Metrawatt Metrahit 1x/2x devices, driver gmc-mh-1x-2x-rs232:
- Power on the device with the "DATA" button pressed.
- Metrahit 2x devices must be configured for the respective interface type.
@ -349,6 +389,10 @@ a short list for convenience:
'SI232 online' (28-29S) or 'SI232 store' (22-26x). The interface must
be configured to the same baud rate as the host (default 9600).
Multimeter and interface must be configured to the same address.
- MASTECH MS6514: Press the "Setup/PC-Link" button for roughly 3 seconds.
- Metrix MX56C: Press the PRINT button to have the meter send acquisition
data via IR. Hold the PRINT button to adjust the meter's transmission
interval.
- 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).
- PCE PCE-DM32: Briefly press the "RS232" button.
@ -407,3 +451,74 @@ Example:
$ sigrok-cli --driver ols:conn=/dev/ttyACM0 ...
Mooshimeter
-----------
The Mooshim Engineering Mooshimeter is controlled via Bluetooth Low Energy
(sometimes called Bluetooth 4.0), as such it requires a supported Bluetooth
interface available. The 'conn' option is required and must contain the
Bluetooth MAC address of the meter.
Example:
$ sigrok-cli --driver mooshimeter-dmm:conn=12-34-56-78-9A-BC ...
Since the Mooshimeter has no physical interface on the meter itself, the
channel configuration is set with the 'channel_config' option. The format
of this option is 'CH1,CH2' where each channel configuration has the form
'MODE:RANGE:ANALYSIS', with later parts being optional. In addition for
CLI compatibility, the ',' in the channels can also be a '/' and the ':' in
the individual configuration can be a ';'.
Available channel 1 modes:
- Current, A: Current in amps
- Temperature, T, K: Internal meter temperature in Kelvin
- Resistance, Ohm, W: Resistance in ohms
- Diode, D: Diode voltage
- Aux, LV: Auxiliary (W input) low voltage sensor (1.2V max)
Available channel 2 modes:
- Voltage, V: Voltage
- Temperature, T, K: Internal meter temperature in Kelvin
- Resistance, Ohm, W: Resistance in ohms
- Diode, D: Diode voltage
- Aux, LV: Auxiliary (W input) low voltage sensor (1.2V max)
Only one channel can use the shared inputs at a time (e.g. if CH1 is measuring
resistance, CH2 cannot measure low voltage). Temperature is excepted from
this, so the meter can measure internal temperature and low voltage at the
same time.
Additionally, the meter can calculate the real power of both channels. This
generally only makes sense when CH1 is set to current and CH2 is set to a
voltage and so it is disabled by default. It must be enabled by enabling the
'P' channel (the third channel).
The range of the channel specification sets the maximum input for that channel
and is rounded up to the next value the meter itself supports. For example,
specifying 50 for the voltage will result in the actual maximum of 60.
Specifying 61 would result in 600. If omitted, sigrok will perform
auto-ranging of the channel by selecting the next greater value than the
latest maximum.
The analysis option sets how the meter reports its internal sampling buffer
to sigrok:
- Mean, DC: The default is a simple arithmetic mean of the sample buffer
- RMS, AC: The root mean square of the sample buffer
- Buf, Buffer, Samples: Report the entire sample buffer to sigrok. This
results in packets that contain all the samples in the buffer instead
of a single output value.
The size of the sample buffer is set with the 'avg_samples' option, while
the sampling rate is set with the 'samplerate' option. So the update rate
is avg_samples/samplerate. Both are rounded up to the next supported value
by the meter.
Example:
$ sigrok-cli -c channel_config="Aux;0.1/T" --driver mooshimeter-dmm...
$ sigrok-cli -c channel_config="A;;AC/V;;AC" --driver mooshimeter-dmm...

View File

@ -1,3 +1,5 @@
#include <config.h>
const DataType *ConfigKey::data_type() const
{
const struct sr_key_info *info = sr_key_info_get(SR_KEY_CONFIG, id());
@ -6,7 +8,7 @@ const DataType *ConfigKey::data_type() const
return DataType::get(info->datatype);
}
string ConfigKey::identifier() const
std::string ConfigKey::identifier() const
{
const struct sr_key_info *info = sr_key_info_get(SR_KEY_CONFIG, id());
if (!info)
@ -14,7 +16,7 @@ string ConfigKey::identifier() const
return valid_string(info->id);
}
string ConfigKey::description() const
std::string ConfigKey::description() const
{
const struct sr_key_info *info = sr_key_info_get(SR_KEY_CONFIG, id());
if (!info)
@ -22,7 +24,7 @@ string ConfigKey::description() const
return valid_string(info->name);
}
const ConfigKey *ConfigKey::get_by_identifier(string identifier)
const ConfigKey *ConfigKey::get_by_identifier(std::string identifier)
{
const struct sr_key_info *info = sr_key_info_name_get(SR_KEY_CONFIG, identifier.c_str());
if (!info)
@ -30,8 +32,6 @@ const ConfigKey *ConfigKey::get_by_identifier(string identifier)
return get(info->key);
}
#include <config.h>
#ifndef HAVE_STOI_STOD
/* Fallback implementation of stoi and stod */
@ -70,12 +70,12 @@ static inline double stod( const std::string& str )
}
#endif
Glib::VariantBase ConfigKey::parse_string(string value) const
Glib::VariantBase ConfigKey::parse_string(std::string value, enum sr_datatype dt)
{
GVariant *variant;
uint64_t p, q;
switch (data_type()->id())
switch (dt)
{
case SR_T_UINT64:
check(sr_parse_sizestring(value.c_str(), &p));
@ -90,7 +90,7 @@ Glib::VariantBase ConfigKey::parse_string(string value) const
case SR_T_FLOAT:
try {
variant = g_variant_new_double(stod(value));
} catch (invalid_argument) {
} catch (invalid_argument&) {
throw Error(SR_ERR_ARG);
}
break;
@ -105,7 +105,7 @@ Glib::VariantBase ConfigKey::parse_string(string value) const
case SR_T_INT32:
try {
variant = g_variant_new_int32(stoi(value));
} catch (invalid_argument) {
} catch (invalid_argument&) {
throw Error(SR_ERR_ARG);
}
break;
@ -116,3 +116,8 @@ Glib::VariantBase ConfigKey::parse_string(string value) const
return Glib::VariantBase(variant, false);
}
Glib::VariantBase ConfigKey::parse_string(std::string value) const
{
enum sr_datatype dt = (enum sr_datatype)(data_type()->id());
return parse_string(value, dt);
}

View File

@ -1,10 +1,11 @@
/** Data type used for this configuration key. */
const DataType *data_type() const;
/** String identifier for this configuration key, suitable for CLI use. */
string identifier() const;
std::string identifier() const;
/** Description of this configuration key. */
string description() const;
std::string description() const;
/** Get configuration key by string identifier. */
static const ConfigKey *get_by_identifier(string identifier);
static const ConfigKey *get_by_identifier(std::string identifier);
/** Parse a string argument into the appropriate type for this key. */
Glib::VariantBase parse_string(string value) const;
static Glib::VariantBase parse_string(std::string value, enum sr_datatype dt);
Glib::VariantBase parse_string(std::string value) const;

View File

@ -743,7 +743,7 @@ WARN_LOGFILE =
# spaces.
# Note: If this tag is empty the current directory is searched.
INPUT = include/libsigrokcxx/libsigrokcxx.hpp \
INPUT = $(SRCDIR)include/libsigrokcxx/libsigrokcxx.hpp \
$(BUILDDIR)include/libsigrokcxx/enums.hpp
# This tag can be used to specify the character encoding of the source files

View File

@ -1,7 +1,7 @@
vector<const QuantityFlag *>
std::vector<const QuantityFlag *>
QuantityFlag::flags_from_mask(unsigned int mask)
{
auto result = vector<const QuantityFlag *>();
auto result = std::vector<const QuantityFlag *>();
while (mask)
{
unsigned int new_mask = mask & (mask - 1);
@ -12,7 +12,7 @@ vector<const QuantityFlag *>
return result;
}
unsigned int QuantityFlag::mask_from_flags(vector<const QuantityFlag *> flags)
unsigned int QuantityFlag::mask_from_flags(std::vector<const QuantityFlag *> flags)
{
unsigned int result = 0;
for (auto flag : flags)

View File

@ -1,7 +1,7 @@
/** Get flags corresponding to a bitmask. */
static vector<const QuantityFlag *>
static std::vector<const QuantityFlag *>
flags_from_mask(unsigned int mask);
/** Get bitmask corresponding to a set of flags. */
static unsigned int mask_from_flags(
vector<const QuantityFlag *> flags);
std::vector<const QuantityFlag *> flags);

View File

@ -18,8 +18,9 @@
*/
/* Needed for isascii(), as used in the GNU libstdc++ headers */
/* Needed in strutil.c for POSIX.1-2008 locale functions */
#ifndef _XOPEN_SOURCE
#define _XOPEN_SOURCE 600
#define _XOPEN_SOURCE 700
#endif
#include <config.h>
@ -31,6 +32,8 @@
namespace sigrok
{
using namespace std;
/** Helper function to translate C errors to C++ exceptions. */
static void check(int result)
{
@ -128,19 +131,19 @@ Context::Context() :
if (struct sr_dev_driver **driver_list = sr_driver_list(_structure))
for (int i = 0; driver_list[i]; 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())
for (int i = 0; input_list[i]; 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())
for (int i = 0; output_list[i]; 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 +160,10 @@ string Context::lib_version()
map<string, shared_ptr<Driver>> Context::drivers()
{
map<string, shared_ptr<Driver>> result;
for (const auto &entry: _drivers)
{
for (const auto &entry: _drivers) {
const auto &name = entry.first;
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;
}
@ -169,23 +171,47 @@ map<string, shared_ptr<Driver>> Context::drivers()
map<string, shared_ptr<InputFormat>> Context::input_formats()
{
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 &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;
}
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>> result;
for (const auto &entry: _output_formats)
{
for (const auto &entry: _output_formats) {
const auto &name = entry.first;
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;
}
@ -213,12 +239,9 @@ static int call_log_callback(void *cb_data, int loglevel,
auto *const callback = static_cast<LogCallbackFunction *>(cb_data);
try
{
try {
(*callback)(LogLevel::get(loglevel), message.get());
}
catch (Error e)
{
} catch (Error &e) {
return e.result;
}
@ -281,8 +304,7 @@ shared_ptr<Packet> Context::create_meta_packet(
map<const ConfigKey *, Glib::VariantBase> config)
{
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 &value = input.second;
auto *const output = g_new(struct sr_config, 1);
@ -357,6 +379,14 @@ shared_ptr<Packet> Context::create_analog_packet(
return shared_ptr<Packet>{new Packet{nullptr, packet}, default_delete<Packet>{}};
}
shared_ptr<Packet> Context::create_end_packet()
{
auto packet = g_new(struct sr_datafeed_packet, 1);
packet->type = SR_DF_END;
return shared_ptr<Packet>{new Packet{nullptr, packet},
default_delete<Packet>{}};
}
shared_ptr<Session> Context::load_session(string filename)
{
return shared_ptr<Session>{
@ -446,16 +476,14 @@ vector<shared_ptr<HardwareDevice>> Driver::scan(
map<const ConfigKey *, Glib::VariantBase> options)
{
/* Initialise the driver if not yet done. */
if (!_initialized)
{
if (!_initialized) {
check(sr_driver_init(_parent->_structure, _structure));
_initialized = true;
}
/* Translate scan options to GSList of struct sr_config pointers. */
GSList *option_list = nullptr;
for (const auto &entry : options)
{
for (const auto &entry : options) {
const auto &key = entry.first;
const auto &value = entry.second;
auto *const config = g_new(struct sr_config, 1);
@ -473,8 +501,7 @@ vector<shared_ptr<HardwareDevice>> Driver::scan(
/* Create device objects. */
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);
shared_ptr<HardwareDevice> hwdev {
new HardwareDevice{shared_from_this(), sdi},
@ -570,23 +597,22 @@ Device::Device(struct sr_dev_inst *structure) :
Configurable(sr_dev_inst_driver_get(structure), structure, nullptr),
_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);
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);
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()
{}
{
}
string Device::vendor() const
{
@ -632,11 +658,10 @@ map<string, shared_ptr<ChannelGroup>>
Device::channel_groups()
{
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 &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;
}
@ -695,7 +720,7 @@ shared_ptr<Channel> UserDevice::add_channel(unsigned int index,
GSList *const last = g_slist_last(sr_dev_inst_channels_get(Device::_structure));
auto *const ch = static_cast<struct sr_channel *>(last->data);
unique_ptr<Channel> channel {new Channel{ch}};
_channels.insert(make_pair(ch, move(channel)));
_channels.emplace(ch, move(channel));
return get_channel(ch);
}
@ -918,9 +943,10 @@ Session::Session(shared_ptr<Context> context, string filename) :
for (GSList *dev = dev_list; dev; dev = dev->next) {
auto *const sdi = static_cast<struct sr_dev_inst *>(dev->data);
unique_ptr<SessionDevice> device {new SessionDevice{sdi}};
_owned_devices.insert(make_pair(sdi, move(device)));
_owned_devices.emplace(sdi, move(device));
}
_context->_session = this;
g_slist_free(dev_list);
}
Session::~Session()
@ -955,6 +981,7 @@ vector<shared_ptr<Device>> Session::devices()
auto *const sdi = static_cast<struct sr_dev_inst *>(dev->data);
result.push_back(get_device(sdi));
}
g_slist_free(dev_list);
return result;
}
@ -1299,6 +1326,48 @@ vector<const QuantityFlag *> Analog::mq_flags() const
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) :
_structure(structure)
{
@ -1361,15 +1430,14 @@ map<string, shared_ptr<Option>> InputFormat::options()
{
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
{options, &sr_input_options_free};
for (int i = 0; options[i]; i++) {
shared_ptr<Option> opt {
new Option{options[i], option_array},
default_delete<Option>{}};
result.insert({opt->id(), move(opt)});
result.emplace(opt->id(), move(opt));
}
}
return result;
@ -1392,8 +1460,7 @@ Input::Input(shared_ptr<Context> context, const struct sr_input *structure) :
shared_ptr<InputDevice> Input::device()
{
if (!_device)
{
if (!_device) {
auto sdi = sr_input_dev_inst_get(_structure);
if (!sdi)
throw Error(SR_ERR_NA);
@ -1483,6 +1550,28 @@ vector<Glib::VariantBase> Option::values() const
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) :
_structure(structure)
{
@ -1515,15 +1604,14 @@ map<string, shared_ptr<Option>> OutputFormat::options()
{
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
{options, &sr_output_options_free};
for (int i = 0; options[i]; i++) {
shared_ptr<Option> opt {
new Option{options[i], option_array},
default_delete<Option>{}};
result.insert({opt->id(), move(opt)});
result.emplace(opt->id(), move(opt));
}
}
return result;
@ -1575,18 +1663,20 @@ Output::~Output()
check(sr_output_free(_structure));
}
shared_ptr<OutputFormat> Output::format()
{
return _format;
}
string Output::receive(shared_ptr<Packet> packet)
{
GString *out;
check(sr_output_send(_structure, packet->_structure, &out));
if (out)
{
if (out) {
auto result = string(out->str, out->str + out->len);
g_string_free(out, true);
return result;
}
else
{
} else {
return string();
}
}

View File

@ -87,8 +87,6 @@ G_GNUC_END_IGNORE_DEPRECATIONS
namespace sigrok
{
using namespace std;
/* Forward declarations */
class SR_API Error;
class SR_API Context;
@ -124,7 +122,7 @@ class SR_API Option;
class SR_API UserDevice;
/** Exception thrown when an error code is returned by any libsigrok call. */
class SR_API Error: public exception
class SR_API Error: public std::exception
{
public:
explicit Error(int result);
@ -139,7 +137,7 @@ class SR_API ParentOwned
{
private:
/* Weak pointer for shared_from_this() implementation. */
weak_ptr<Class> _weak_this;
std::weak_ptr<Class> _weak_this;
static void reset_parent(Class *object)
{
@ -162,14 +160,14 @@ protected:
This strategy ensures that the destructors for both the child and
the parent are called at the correct time, i.e. only when all
references to both the parent and all its children are gone. */
shared_ptr<Parent> _parent;
std::shared_ptr<Parent> _parent;
ParentOwned() {}
/* Note, this implementation will create a new smart_ptr if none exists. */
shared_ptr<Class> shared_from_this()
std::shared_ptr<Class> shared_from_this()
{
shared_ptr<Class> shared = _weak_this.lock();
std::shared_ptr<Class> shared = _weak_this.lock();
if (!shared)
{
@ -180,7 +178,7 @@ protected:
return shared;
}
shared_ptr<Class> share_owned_by(shared_ptr<Parent> parent)
std::shared_ptr<Class> share_owned_by(std::shared_ptr<Parent> parent)
{
if (!parent)
throw Error(SR_ERR_BUG);
@ -190,7 +188,7 @@ protected:
public:
/* Get parent object that owns this object. */
shared_ptr<Parent> parent()
std::shared_ptr<Parent> parent()
{
return _parent;
}
@ -198,14 +196,14 @@ public:
/* Base template for classes whose resources are owned by the user. */
template <class Class>
class SR_API UserOwned : public enable_shared_from_this<Class>
class SR_API UserOwned : public std::enable_shared_from_this<Class>
{
protected:
UserOwned() {}
shared_ptr<Class> shared_from_this()
std::shared_ptr<Class> shared_from_this()
{
auto shared = enable_shared_from_this<Class>::shared_from_this();
auto shared = std::enable_shared_from_this<Class>::shared_from_this();
if (!shared)
throw Error(SR_ERR_BUG);
return shared;
@ -213,7 +211,7 @@ protected:
};
/** Type of log callback */
typedef function<void(const LogLevel *, string message)> LogCallbackFunction;
typedef std::function<void(const LogLevel *, std::string message)> LogCallbackFunction;
/** Resource reader delegate. */
class SR_API ResourceReader
@ -223,7 +221,7 @@ public:
virtual ~ResourceReader();
private:
/** Resource open hook. */
virtual void open(struct sr_resource *res, string name) = 0;
virtual void open(struct sr_resource *res, std::string name) = 0;
/** Resource close hook. */
virtual void close(struct sr_resource *res) = 0;
/** Resource read hook. */
@ -243,17 +241,19 @@ class SR_API Context : public UserOwned<Context>
{
public:
/** Create new context */
static shared_ptr<Context> create();
static std::shared_ptr<Context> create();
/** libsigrok package version. */
static string package_version();
static std::string package_version();
/** libsigrok library version. */
static string lib_version();
static std::string lib_version();
/** Available hardware drivers, indexed by name. */
map<string, shared_ptr<Driver> > drivers();
std::map<std::string, std::shared_ptr<Driver> > drivers();
/** Available input formats, indexed by name. */
map<string, shared_ptr<InputFormat> > input_formats();
std::map<std::string, std::shared_ptr<InputFormat> > input_formats();
/** Lookup the responsible input module for an input file. */
std::shared_ptr<InputFormat> input_format_match(std::string filename);
/** Available output formats, indexed by name. */
map<string, shared_ptr<OutputFormat> > output_formats();
std::map<std::string, std::shared_ptr<OutputFormat> > output_formats();
/** Current log level. */
const LogLevel *log_level() const;
/** Set the log level.
@ -268,41 +268,43 @@ public:
* @param reader The resource reader delegate, or nullptr to unset. */
void set_resource_reader(ResourceReader *reader);
/** Create a new session. */
shared_ptr<Session> create_session();
std::shared_ptr<Session> create_session();
/** Create a new user device. */
shared_ptr<UserDevice> create_user_device(
string vendor, string model, string version);
std::shared_ptr<UserDevice> create_user_device(
std::string vendor, std::string model, std::string version);
/** Create a header packet. */
shared_ptr<Packet> create_header_packet(Glib::TimeVal start_time);
std::shared_ptr<Packet> create_header_packet(Glib::TimeVal start_time);
/** Create a meta packet. */
shared_ptr<Packet> create_meta_packet(
map<const ConfigKey *, Glib::VariantBase> config);
std::shared_ptr<Packet> create_meta_packet(
std::map<const ConfigKey *, Glib::VariantBase> config);
/** Create a logic packet. */
shared_ptr<Packet> create_logic_packet(
std::shared_ptr<Packet> create_logic_packet(
void *data_pointer, size_t data_length, unsigned int unit_size);
/** Create an analog packet. */
shared_ptr<Packet> create_analog_packet(
vector<shared_ptr<Channel> > channels,
std::shared_ptr<Packet> create_analog_packet(
std::vector<std::shared_ptr<Channel> > channels,
float *data_pointer, unsigned int num_samples, const Quantity *mq,
const Unit *unit, vector<const QuantityFlag *> mqflags);
const Unit *unit, std::vector<const QuantityFlag *> mqflags);
/** Create an end packet. */
std::shared_ptr<Packet> create_end_packet();
/** Load a saved session.
* @param filename File name string. */
shared_ptr<Session> load_session(string filename);
std::shared_ptr<Session> load_session(std::string filename);
/** Create a new trigger.
* @param name Name string for new trigger. */
shared_ptr<Trigger> create_trigger(string name);
std::shared_ptr<Trigger> create_trigger(std::string name);
/** Open an input file.
* @param filename File name string. */
shared_ptr<Input> open_file(string filename);
std::shared_ptr<Input> open_file(std::string filename);
/** Open an input stream based on header data.
* @param header Initial data from stream. */
shared_ptr<Input> open_stream(string header);
map<string, string> serials(shared_ptr<Driver> driver) const;
std::shared_ptr<Input> open_stream(std::string header);
std::map<std::string, std::string> serials(std::shared_ptr<Driver> driver) const;
private:
struct sr_context *_structure;
map<string, unique_ptr<Driver> > _drivers;
map<string, unique_ptr<InputFormat> > _input_formats;
map<string, unique_ptr<OutputFormat> > _output_formats;
std::map<std::string, std::unique_ptr<Driver> > _drivers;
std::map<std::string, std::unique_ptr<InputFormat> > _input_formats;
std::map<std::string, std::unique_ptr<OutputFormat> > _output_formats;
Session *_session;
LogCallbackFunction _log_callback;
Context();
@ -317,7 +319,7 @@ class SR_API Configurable
{
public:
/** Supported configuration keys. */
set<const ConfigKey *> config_keys() const;
std::set<const ConfigKey *> config_keys() const;
/** Read configuration for the given key.
* @param key ConfigKey to read. */
Glib::VariantBase config_get(const ConfigKey *key) const;
@ -330,10 +332,10 @@ public:
Glib::VariantContainerBase config_list(const ConfigKey *key) const;
/** Enumerate configuration capabilities for the given configuration key.
* @param key ConfigKey to enumerate capabilities for. */
set<const Capability *> config_capabilities(const ConfigKey *key) const;
std::set<const Capability *> config_capabilities(const ConfigKey *key) const;
/** Check whether a configuration capability is supported for a given key.
* @param key ConfigKey to check.
* @param capability Capability to check for. */
* @param capability Capability to check for. */
bool config_check(const ConfigKey *key, const Capability *capability) const;
protected:
Configurable(
@ -351,19 +353,19 @@ class SR_API Driver : public ParentOwned<Driver, Context>, public Configurable
{
public:
/** Name of this driver. */
string name() const;
std::string name() const;
/** Long name for this driver. */
string long_name() const;
std::string long_name() const;
/** Scan options supported by this driver. */
set<const ConfigKey *> scan_options() const;
std::set<const ConfigKey *> scan_options() const;
/** Scan for devices and return a list of devices found.
* @param options Mapping of (ConfigKey, value) pairs. */
vector<shared_ptr<HardwareDevice> > scan(map<const ConfigKey *, Glib::VariantBase>
options = map<const ConfigKey *, Glib::VariantBase>());
std::vector<std::shared_ptr<HardwareDevice> > scan(std::map<const ConfigKey *, Glib::VariantBase>
options = std::map<const ConfigKey *, Glib::VariantBase>());
private:
struct sr_dev_driver *_structure;
bool _initialized;
vector<HardwareDevice *> _devices;
std::vector<HardwareDevice *> _devices;
explicit Driver(struct sr_dev_driver *structure);
~Driver();
friend class Context;
@ -377,19 +379,19 @@ class SR_API Device : public Configurable
{
public:
/** Vendor name for this device. */
string vendor() const;
std::string vendor() const;
/** Model name for this device. */
string model() const;
std::string model() const;
/** Version string for this device. */
string version() const;
std::string version() const;
/** Serial number for this device. */
string serial_number() const;
std::string serial_number() const;
/** Connection ID for this device. */
string connection_id() const;
std::string connection_id() const;
/** List of the channels available on this device. */
vector<shared_ptr<Channel> > channels();
std::vector<std::shared_ptr<Channel> > channels();
/** Channel groups available on this device, indexed by name. */
map<string, shared_ptr<ChannelGroup> > channel_groups();
std::map<std::string, std::shared_ptr<ChannelGroup> > channel_groups();
/** Open device. */
void open();
/** Close device. */
@ -397,13 +399,13 @@ public:
protected:
explicit Device(struct sr_dev_inst *structure);
~Device();
virtual shared_ptr<Device> get_shared_from_this() = 0;
shared_ptr<Channel> get_channel(struct sr_channel *ptr);
virtual std::shared_ptr<Device> get_shared_from_this() = 0;
std::shared_ptr<Channel> get_channel(struct sr_channel *ptr);
struct sr_dev_inst *_structure;
map<struct sr_channel *, unique_ptr<Channel> > _channels;
std::map<struct sr_channel *, std::unique_ptr<Channel> > _channels;
private:
map<string, unique_ptr<ChannelGroup> > _channel_groups;
std::map<std::string, std::unique_ptr<ChannelGroup> > _channel_groups;
friend class Session;
friend class Channel;
@ -420,12 +422,12 @@ class SR_API HardwareDevice :
{
public:
/** Driver providing this device. */
shared_ptr<Driver> driver();
std::shared_ptr<Driver> driver();
private:
HardwareDevice(shared_ptr<Driver> driver, struct sr_dev_inst *structure);
HardwareDevice(std::shared_ptr<Driver> driver, struct sr_dev_inst *structure);
~HardwareDevice();
shared_ptr<Device> get_shared_from_this();
shared_ptr<Driver> _driver;
std::shared_ptr<Device> get_shared_from_this();
std::shared_ptr<Driver> _driver;
friend class Driver;
friend class ChannelGroup;
@ -439,11 +441,11 @@ class SR_API UserDevice :
{
public:
/** Add a new channel to this device. */
shared_ptr<Channel> add_channel(unsigned int index, const ChannelType *type, string name);
std::shared_ptr<Channel> add_channel(unsigned int index, const ChannelType *type, std::string name);
private:
UserDevice(string vendor, string model, string version);
UserDevice(std::string vendor, std::string model, std::string version);
~UserDevice();
shared_ptr<Device> get_shared_from_this();
std::shared_ptr<Device> get_shared_from_this();
friend class Context;
friend struct std::default_delete<UserDevice>;
@ -455,10 +457,10 @@ class SR_API Channel :
{
public:
/** Current name of this channel. */
string name() const;
std::string name() const;
/** Set the name of this channel. *
* @param name Name string to set. */
void set_name(string name);
void set_name(std::string name);
/** Type of this channel. */
const ChannelType *type() const;
/** Enabled status of this channel. */
@ -489,13 +491,13 @@ class SR_API ChannelGroup :
{
public:
/** Name of this channel group. */
string name() const;
std::string name() const;
/** List of the channels in this group. */
vector<shared_ptr<Channel> > channels();
std::vector<std::shared_ptr<Channel> > channels();
private:
ChannelGroup(const Device *device, struct sr_channel_group *structure);
~ChannelGroup();
vector<Channel *> _channels;
std::vector<Channel *> _channels;
friend class Device;
friend struct std::default_delete<ChannelGroup>;
};
@ -505,17 +507,17 @@ class SR_API Trigger : public UserOwned<Trigger>
{
public:
/** Name of this trigger configuration. */
string name() const;
std::string name() const;
/** List of the stages in this trigger. */
vector<shared_ptr<TriggerStage> > stages();
std::vector<std::shared_ptr<TriggerStage> > stages();
/** Add a new stage to this trigger. */
shared_ptr<TriggerStage> add_stage();
std::shared_ptr<TriggerStage> add_stage();
private:
Trigger(shared_ptr<Context> context, string name);
Trigger(std::shared_ptr<Context> context, std::string name);
~Trigger();
struct sr_trigger *_structure;
shared_ptr<Context> _context;
vector<unique_ptr<TriggerStage> > _stages;
std::shared_ptr<Context> _context;
std::vector<std::unique_ptr<TriggerStage> > _stages;
friend class Context;
friend class Session;
friend struct std::default_delete<Trigger>;
@ -529,19 +531,19 @@ public:
/** Index number of this stage. */
int number() const;
/** List of match conditions on this stage. */
vector<shared_ptr<TriggerMatch> > matches();
std::vector<std::shared_ptr<TriggerMatch> > matches();
/** Add a new match condition to this stage.
* @param channel Channel to match on.
* @param type TriggerMatchType to apply. */
void add_match(shared_ptr<Channel> channel, const TriggerMatchType *type);
void add_match(std::shared_ptr<Channel> channel, const TriggerMatchType *type);
/** Add a new match condition to this stage.
* @param channel Channel to match on.
* @param type TriggerMatchType to apply.
* @param value Threshold value. */
void add_match(shared_ptr<Channel> channel, const TriggerMatchType *type, float value);
void add_match(std::shared_ptr<Channel> channel, const TriggerMatchType *type, float value);
private:
struct sr_trigger_stage *_structure;
vector<unique_ptr<TriggerMatch> > _matches;
std::vector<std::unique_ptr<TriggerMatch> > _matches;
explicit TriggerStage(struct sr_trigger_stage *structure);
~TriggerStage();
friend class Trigger;
@ -554,25 +556,25 @@ class SR_API TriggerMatch :
{
public:
/** Channel this condition matches on. */
shared_ptr<Channel> channel();
std::shared_ptr<Channel> channel();
/** Type of match. */
const TriggerMatchType *type() const;
/** Threshold value. */
float value() const;
private:
TriggerMatch(struct sr_trigger_match *structure, shared_ptr<Channel> channel);
TriggerMatch(struct sr_trigger_match *structure, std::shared_ptr<Channel> channel);
~TriggerMatch();
struct sr_trigger_match *_structure;
shared_ptr<Channel> _channel;
std::shared_ptr<Channel> _channel;
friend class TriggerStage;
friend struct std::default_delete<TriggerMatch>;
};
/** Type of session stopped callback */
typedef function<void()> SessionStoppedCallback;
typedef std::function<void()> SessionStoppedCallback;
/** Type of datafeed callback */
typedef function<void(shared_ptr<Device>, shared_ptr<Packet>)>
typedef std::function<void(std::shared_ptr<Device>, std::shared_ptr<Packet>)>
DatafeedCallbackFunction;
/* Data required for C callback function to call a C++ datafeed callback */
@ -597,7 +599,7 @@ class SR_API SessionDevice :
private:
explicit SessionDevice(struct sr_dev_inst *sdi);
~SessionDevice();
shared_ptr<Device> get_shared_from_this();
std::shared_ptr<Device> get_shared_from_this();
friend class Session;
friend struct std::default_delete<SessionDevice>;
@ -609,9 +611,9 @@ class SR_API Session : public UserOwned<Session>
public:
/** Add a device to this session.
* @param device Device to add. */
void add_device(shared_ptr<Device> device);
void add_device(std::shared_ptr<Device> device);
/** List devices attached to this session. */
vector<shared_ptr<Device> > devices();
std::vector<std::shared_ptr<Device> > devices();
/** Remove all devices from this session. */
void remove_devices();
/** Add a datafeed callback to this session.
@ -630,27 +632,27 @@ public:
/** Set callback to be invoked on session stop. */
void set_stopped_callback(SessionStoppedCallback callback);
/** Get current trigger setting. */
shared_ptr<Trigger> trigger();
std::shared_ptr<Trigger> trigger();
/** Get the context. */
shared_ptr<Context> context();
std::shared_ptr<Context> context();
/** Set trigger setting.
* @param trigger Trigger object to use. */
void set_trigger(shared_ptr<Trigger> trigger);
void set_trigger(std::shared_ptr<Trigger> trigger);
/** Get filename this session was loaded from. */
string filename() const;
std::string filename() const;
private:
explicit Session(shared_ptr<Context> context);
Session(shared_ptr<Context> context, string filename);
explicit Session(std::shared_ptr<Context> context);
Session(std::shared_ptr<Context> context, std::string filename);
~Session();
shared_ptr<Device> get_device(const struct sr_dev_inst *sdi);
std::shared_ptr<Device> get_device(const struct sr_dev_inst *sdi);
struct sr_session *_structure;
const shared_ptr<Context> _context;
map<const struct sr_dev_inst *, unique_ptr<SessionDevice> > _owned_devices;
map<const struct sr_dev_inst *, shared_ptr<Device> > _other_devices;
vector<unique_ptr<DatafeedCallbackData> > _datafeed_callbacks;
const std::shared_ptr<Context> _context;
std::map<const struct sr_dev_inst *, std::unique_ptr<SessionDevice> > _owned_devices;
std::map<const struct sr_dev_inst *, std::shared_ptr<Device> > _other_devices;
std::vector<std::unique_ptr<DatafeedCallbackData> > _datafeed_callbacks;
SessionStoppedCallback _stopped_callback;
string _filename;
shared_ptr<Trigger> _trigger;
std::string _filename;
std::shared_ptr<Trigger> _trigger;
friend class Context;
friend class DatafeedCallbackData;
@ -665,14 +667,14 @@ public:
/** Type of this packet. */
const PacketType *type() const;
/** Payload of this packet. */
shared_ptr<PacketPayload> payload();
std::shared_ptr<PacketPayload> payload();
private:
Packet(shared_ptr<Device> device,
Packet(std::shared_ptr<Device> device,
const struct sr_datafeed_packet *structure);
~Packet();
const struct sr_datafeed_packet *_structure;
shared_ptr<Device> _device;
unique_ptr<PacketPayload> _payload;
std::shared_ptr<Device> _device;
std::unique_ptr<PacketPayload> _payload;
friend class Session;
friend class Output;
@ -692,7 +694,7 @@ protected:
PacketPayload();
virtual ~PacketPayload() = 0;
private:
virtual shared_ptr<PacketPayload> share_owned_by(shared_ptr<Packet> parent) = 0;
virtual std::shared_ptr<PacketPayload> share_owned_by(std::shared_ptr<Packet> parent) = 0;
friend class Packet;
friend class Output;
@ -712,7 +714,7 @@ public:
private:
explicit Header(const struct sr_datafeed_header *structure);
~Header();
shared_ptr<PacketPayload> share_owned_by(shared_ptr<Packet> parent);
std::shared_ptr<PacketPayload> share_owned_by(std::shared_ptr<Packet> parent);
const struct sr_datafeed_header *_structure;
@ -726,14 +728,14 @@ class SR_API Meta :
{
public:
/* Mapping of (ConfigKey, value) pairs. */
map<const ConfigKey *, Glib::VariantBase> config() const;
std::map<const ConfigKey *, Glib::VariantBase> config() const;
private:
explicit Meta(const struct sr_datafeed_meta *structure);
~Meta();
shared_ptr<PacketPayload> share_owned_by(shared_ptr<Packet> parent);
std::shared_ptr<PacketPayload> share_owned_by(std::shared_ptr<Packet> parent);
const struct sr_datafeed_meta *_structure;
map<const ConfigKey *, Glib::VariantBase> _config;
std::map<const ConfigKey *, Glib::VariantBase> _config;
friend class Packet;
};
@ -753,11 +755,13 @@ public:
private:
explicit Logic(const struct sr_datafeed_logic *structure);
~Logic();
shared_ptr<PacketPayload> share_owned_by(shared_ptr<Packet> parent);
std::shared_ptr<PacketPayload> share_owned_by(std::shared_ptr<Packet> parent);
const struct sr_datafeed_logic *_structure;
friend class Packet;
friend class Analog;
friend struct std::default_delete<Logic>;
};
/** Payload of a datafeed packet with analog data */
@ -776,7 +780,7 @@ public:
/** Number of samples in this packet. */
unsigned int num_samples() const;
/** Channels for which this packet contains data. */
vector<shared_ptr<Channel> > channels();
std::vector<std::shared_ptr<Channel> > channels();
/** Size of a single sample in bytes. */
unsigned int unitsize() const;
/** Samples use a signed data type. */
@ -794,19 +798,47 @@ public:
/** TBD */
bool is_digits_decimal() const;
/** TBD */
shared_ptr<Rational> scale();
std::shared_ptr<Rational> scale();
/** TBD */
shared_ptr<Rational> offset();
std::shared_ptr<Rational> offset();
/** Measured quantity of the samples in this packet. */
const Quantity *mq() const;
/** Unit of the samples in this packet. */
const Unit *unit() const;
/** Measurement flags associated with the samples in this packet. */
vector<const QuantityFlag *> mq_flags() const;
std::vector<const QuantityFlag *> mq_flags() const;
/**
* Provides a Logic packet that contains a conversion of the analog
* data using a simple threshold.
*
* @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.
*/
std::shared_ptr<Logic> get_logic_via_threshold(float threshold,
uint8_t *data_ptr=nullptr) const;
/**
* Provides a Logic packet that contains a conversion of the analog
* 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.
*/
std::shared_ptr<Logic> get_logic_via_schmitt_trigger(float lo_thr,
float hi_thr, uint8_t *state, uint8_t *data_ptr=nullptr) const;
private:
explicit Analog(const struct sr_datafeed_analog *structure);
~Analog();
shared_ptr<PacketPayload> share_owned_by(shared_ptr<Packet> parent);
std::shared_ptr<PacketPayload> share_owned_by(std::shared_ptr<Packet> parent);
const struct sr_datafeed_analog *_structure;
@ -827,7 +859,7 @@ public:
private:
explicit Rational(const struct sr_rational *structure);
~Rational();
shared_ptr<Rational> share_owned_by(shared_ptr<Analog> parent);
std::shared_ptr<Rational> share_owned_by(std::shared_ptr<Analog> parent);
const struct sr_rational *_structure;
@ -841,18 +873,18 @@ class SR_API InputFormat :
{
public:
/** Name of this input format. */
string name() const;
std::string name() const;
/** Description of this input format. */
string description() const;
std::string description() const;
/** A list of preferred file name extensions for this file format.
* @note This list is a recommendation only. */
vector<string> extensions() const;
* @note This list is a recommendation only. */
std::vector<std::string> extensions() const;
/** Options supported by this input format. */
map<string, shared_ptr<Option> > options();
std::map<std::string, std::shared_ptr<Option> > options();
/** Create an input using this input format.
* @param options Mapping of (option name, value) pairs. */
shared_ptr<Input> create_input(map<string, Glib::VariantBase>
options = map<string, Glib::VariantBase>());
std::shared_ptr<Input> create_input(std::map<std::string, Glib::VariantBase>
options = std::map<std::string, Glib::VariantBase>());
private:
explicit InputFormat(const struct sr_input_module *structure);
~InputFormat();
@ -869,7 +901,7 @@ class SR_API Input : public UserOwned<Input>
{
public:
/** Virtual device associated with this input. */
shared_ptr<InputDevice> device();
std::shared_ptr<InputDevice> device();
/** Send next stream data.
* @param data Next stream data.
* @param length Length of data. */
@ -878,11 +910,11 @@ public:
void end();
void reset();
private:
Input(shared_ptr<Context> context, const struct sr_input *structure);
Input(std::shared_ptr<Context> context, const struct sr_input *structure);
~Input();
const struct sr_input *_structure;
shared_ptr<Context> _context;
unique_ptr<InputDevice> _device;
std::shared_ptr<Context> _context;
std::unique_ptr<InputDevice> _device;
friend class Context;
friend class InputFormat;
@ -895,10 +927,10 @@ class SR_API InputDevice :
public Device
{
private:
InputDevice(shared_ptr<Input> input, struct sr_dev_inst *sdi);
InputDevice(std::shared_ptr<Input> input, struct sr_dev_inst *sdi);
~InputDevice();
shared_ptr<Device> get_shared_from_this();
shared_ptr<Input> _input;
std::shared_ptr<Device> get_shared_from_this();
std::shared_ptr<Input> _input;
friend class Input;
friend struct std::default_delete<InputDevice>;
};
@ -908,21 +940,23 @@ class SR_API Option : public UserOwned<Option>
{
public:
/** Short name of this option suitable for command line usage. */
string id() const;
std::string id() const;
/** Short name of this option suitable for GUI usage. */
string name() const;
std::string name() const;
/** Description of this option in a sentence. */
string description() const;
std::string description() const;
/** Default value for this option. */
Glib::VariantBase default_value() const;
/** Possible values for this option, if a limited set. */
vector<Glib::VariantBase> values() const;
std::vector<Glib::VariantBase> values() const;
/** Parse a string argument into the appropriate type for this option. */
Glib::VariantBase parse_string(std::string value);
private:
Option(const struct sr_option *structure,
shared_ptr<const struct sr_option *> structure_array);
std::shared_ptr<const struct sr_option *> structure_array);
~Option();
const struct sr_option *_structure;
shared_ptr<const struct sr_option *> _structure_array;
std::shared_ptr<const struct sr_option *> _structure_array;
friend class InputFormat;
friend class OutputFormat;
@ -935,26 +969,26 @@ class SR_API OutputFormat :
{
public:
/** Name of this output format. */
string name() const;
std::string name() const;
/** Description of this output format. */
string description() const;
std::string description() const;
/** A list of preferred file name extensions for this file format.
* @note This list is a recommendation only. */
vector<string> extensions() const;
* @note This list is a recommendation only. */
std::vector<std::string> extensions() const;
/** Options supported by this output format. */
map<string, shared_ptr<Option> > options();
std::map<std::string, std::shared_ptr<Option> > options();
/** Create an output using this format.
* @param device Device to output for.
* @param options Mapping of (option name, value) pairs. */
shared_ptr<Output> create_output(shared_ptr<Device> device,
map<string, Glib::VariantBase> options = map<string, Glib::VariantBase>());
std::shared_ptr<Output> create_output(std::shared_ptr<Device> device,
std::map<std::string, Glib::VariantBase> options = std::map<std::string, Glib::VariantBase>());
/** Create an output using this format.
* @param filename Name of destination file.
* @param device Device to output for.
* @param options Mapping of (option name, value) pairs. */
shared_ptr<Output> create_output(string filename,
shared_ptr<Device> device,
map<string, Glib::VariantBase> options = map<string, Glib::VariantBase>());
std::shared_ptr<Output> create_output(std::string filename,
std::shared_ptr<Device> device,
std::map<std::string, Glib::VariantBase> options = std::map<std::string, Glib::VariantBase>());
/**
* Checks whether a given flag is set.
* @param flag Flag to check
@ -979,19 +1013,21 @@ class SR_API Output : public UserOwned<Output>
public:
/** Update output with data from the given packet.
* @param packet Packet to handle. */
string receive(shared_ptr<Packet> packet);
std::string receive(std::shared_ptr<Packet> packet);
/** Output format in use for this output */
std::shared_ptr<OutputFormat> format();
private:
Output(shared_ptr<OutputFormat> format, shared_ptr<Device> device);
Output(shared_ptr<OutputFormat> format,
shared_ptr<Device> device, map<string, Glib::VariantBase> options);
Output(string filename, shared_ptr<OutputFormat> format,
shared_ptr<Device> device, map<string, Glib::VariantBase> options);
Output(std::shared_ptr<OutputFormat> format, std::shared_ptr<Device> device);
Output(std::shared_ptr<OutputFormat> format,
std::shared_ptr<Device> device, std::map<std::string, Glib::VariantBase> options);
Output(std::string filename, std::shared_ptr<OutputFormat> format,
std::shared_ptr<Device> device, std::map<std::string, Glib::VariantBase> options);
~Output();
const struct sr_output *_structure;
const shared_ptr<OutputFormat> _format;
const shared_ptr<Device> _device;
const map<string, Glib::VariantBase> _options;
const std::shared_ptr<OutputFormat> _format;
const std::shared_ptr<Device> _device;
const std::map<std::string, Glib::VariantBase> _options;
friend class OutputFormat;
friend struct std::default_delete<Output>;
@ -1007,7 +1043,7 @@ public:
return static_cast<int>(_id);
}
/** The name associated with this value. */
string name() const
std::string name() const
{
return _name;
}
@ -1037,7 +1073,7 @@ protected:
private:
static const std::map<const Enum, const Class * const> _values;
const Enum _id;
const string _name;
const std::string _name;
};
}

View File

@ -743,7 +743,7 @@ WARN_LOGFILE =
# spaces.
# Note: If this tag is empty the current directory is searched.
INPUT = org/sigrok/core $(BUILDDIR)org/sigrok/core
INPUT = $(SRCDIR)org/sigrok/core $(BUILDDIR)org/sigrok/core
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses

View File

@ -45,6 +45,8 @@ which provides access to the error code and description."
%module(docstring=DOCSTRING) classes
%{
#include "config.h"
#include <stdio.h>
#include <pygobject.h>
#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 *GLib;
#include "config.h"
#if PYGOBJECT_FLAGS_SIGNED
typedef gint pyg_flags_type;
#else
@ -390,6 +390,7 @@ std::map<std::string, Glib::VariantBase> dict_to_map_options(PyObject *dict,
/* Ignore these methods, we will override them below. */
%ignore sigrok::Analog::data;
%ignore sigrok::Logic::data;
%ignore sigrok::Driver::scan;
%ignore sigrok::InputFormat::create_input;
%ignore sigrok::OutputFormat::create_output;
@ -548,4 +549,42 @@ std::map<std::string, Glib::VariantBase> dict_to_map_options(PyObject *dict,
}
}
/* Return NumPy array from Logic::data(). */
%extend sigrok::Logic
{
PyObject * _data()
{
npy_intp dims[2];
dims[0] = $self->data_length() / $self->unit_size();
dims[1] = $self->unit_size();
int typenum = NPY_UINT8;
void *data = $self->data_pointer();
return PyArray_SimpleNewFromData(2, dims, typenum, data);
}
%pythoncode
{
data = property(_data)
}
}
/* Create logic packet from Python buffer. */
%extend sigrok::Context
{
std::shared_ptr<Packet> _create_logic_packet_buf(PyObject *buf, unsigned int unit_size)
{
Py_buffer view;
PyObject_GetBuffer(buf, &view, PyBUF_SIMPLE);
return $self->create_logic_packet(view.buf, view.len, unit_size);
}
}
%pythoncode
{
def _Context_create_logic_packet(self, buf, unit_size):
return self._create_logic_packet_buf(buf, unit_size)
Context.create_logic_packet = _Context_create_logic_packet
}
%include "doc_end.i"

View File

@ -41,10 +41,10 @@ which provides access to the error code and description."
%module(docstring=DOCSTRING) sigrok
%{
#include "config.h"
#include <stdio.h>
#include <glibmm.h>
#include "config.h"
%}
%include "../swig/templates.i"

View File

@ -21,7 +21,7 @@
# We require at least autoconf 2.63 (AC_INIT format changed there).
AC_PREREQ([2.63])
AC_INIT([libsigrok], [0.5.0],
AC_INIT([libsigrok], [0.5.2],
[sigrok-devel@lists.sourceforge.net],
[libsigrok], [http://www.sigrok.org])
AC_CONFIG_MACRO_DIR([m4])
@ -68,7 +68,7 @@ SR_PKG_VERSION_SET([SR_PACKAGE_VERSION], [AC_PACKAGE_VERSION])
# The algorithm for determining which number to change (and how) is nontrivial!
# http://www.gnu.org/software/libtool/manual/libtool.html#Updating-version-info
# Format: current:revision:age.
SR_LIB_VERSION_SET([SR_LIB_VERSION], [4:0:0])
SR_LIB_VERSION_SET([SR_LIB_VERSION], [5:1:1])
AM_CONDITIONAL([WIN32], [test -z "${host_os##mingw*}" || test -z "${host_os##cygwin*}"])
@ -96,11 +96,16 @@ SR_PKGLIBS_RUBY=
SR_EXTRA_LIBS=
SR_EXTRA_CXX_LIBS=
SR_ARG_OPT_PKG([libserialport], [LIBSERIALPORT], [NEED_SERIAL],
SR_ARG_OPT_PKG([libserialport], [LIBSERIALPORT], ,
[libserialport >= 0.1.1])
SR_ARG_OPT_PKG([libftdi], [LIBFTDI],,
[libftdi1 >= 1.0], [libftdi >= 0.16])
SR_ARG_OPT_PKG([libftdi], [LIBFTDI], , [libftdi1 >= 1.0])
# pkg-config file names: MinGW/MacOSX: hidapi; Linux: hidapi-hidraw/-libusb
SR_ARG_OPT_PKG([libhidapi], [LIBHIDAPI], ,
[hidapi >= 0.8.0], [hidapi-hidraw >= 0.8.0], [hidapi-libusb >= 0.8.0])
SR_ARG_OPT_PKG([libbluez], [LIBBLUEZ], , [bluez >= 4.0])
# FreeBSD comes with an "integrated" libusb-1.0-style USB API.
# This means libusb-1.0 is always available; no need to check for it.
@ -131,6 +136,25 @@ SR_ARG_OPT_CHECK([libieee1284], [LIBIEEE1284],, [
AS_IF([test "x$sr_have_libieee1284" = xyes],
[SR_PREPEND([SR_EXTRA_LIBS], [-lieee1284])])
SR_ARG_OPT_PKG([libgio], [LIBGIO], , [gio-2.0 >= 2.24.0])
# See if any of the (potentially platform specific) libs are available
# which provide some means of Bluetooth communication.
AS_IF([test "x$sr_have_libbluez" = xyes],
sr_have_bluetooth=yes, sr_have_bluetooth=no)
AS_IF([test "x$sr_have_bluetooth" = xyes],
[AC_DEFINE([HAVE_BLUETOOTH], [1], [Specifies whether Bluetooth communication is supported.])])
AS_IF([test "x$sr_have_bluetooth" = xyes],
[SR_APPEND([sr_deps_avail], [bluetooth_comm])])
AS_IF([test "x$sr_have_libserialport" = xyes -o "x$sr_have_libhidapi" = xyes -o "x$sr_have_bluetooth" = xyes],
sr_have_serial_comm=yes, sr_have_serial_comm=no)
AS_IF([test "x$sr_have_serial_comm" = xyes],
[AC_DEFINE([HAVE_SERIAL_COMM], [1], [Specifies whether serial communication is supported.])])
AS_IF([test "x$sr_have_serial_comm" = xyes],
[SR_APPEND([sr_deps_avail], [serial_comm])])
AM_CONDITIONAL([NEED_SERIAL], [test "x$sr_have_serial_comm" = xyes])
######################
## Feature checks ##
######################
@ -175,6 +199,15 @@ AM_CONDITIONAL([NEED_RPC], [test "x$sr_cv_have_rpc" = xyes])
# Check for compiler support of 128 bit integers
AC_CHECK_TYPES([__int128_t, __uint128_t], [], [], [])
# Availability of bt_put_le16() depends on the bluez library version.
AC_CACHE_CHECK([for bt_put_le16], [sr_cv_have_btputle16],
[AC_LINK_IFELSE([AC_LANG_PROGRAM(
[[#include <bluetooth/bluetooth.h>]],
[[bt_put_le16(0, (void *)0);]])],
[sr_cv_have_btputle16=yes], [sr_cv_have_btputle16=no])])
AS_IF([test "x$sr_cv_have_btputle16" = xyes],
[AC_DEFINE([HAVE_BT_PUT_LE16], [1], [Specifies whether we have bt_put_le16().])])
########################
## Hardware drivers ##
########################
@ -219,62 +252,75 @@ m4_define([_SR_DRIVER], [
m4_define([SR_DRIVER],
[_SR_DRIVER([$1], [$2], m4_expand([AS_TR_CPP([HW_$2])]), [$3])])
SR_DRIVER([Agilent DMM], [agilent-dmm], [libserialport])
SR_DRIVER([Appa 55II], [appa-55ii], [libserialport])
SR_DRIVER([Arachnid Labs Re:load Pro], [arachnid-labs-re-load-pro], [libserialport])
SR_DRIVER([Agilent DMM], [agilent-dmm], [serial_comm])
SR_DRIVER([Appa 55II], [appa-55ii], [serial_comm])
SR_DRIVER([Arachnid Labs Re:load Pro], [arachnid-labs-re-load-pro], [serial_comm])
SR_DRIVER([ASIX SIGMA/SIGMA2], [asix-sigma], [libftdi])
SR_DRIVER([Atten PPS3xxx], [atten-pps3xxx], [libserialport])
SR_DRIVER([Atten PPS3xxx], [atten-pps3xxx], [serial_comm])
SR_DRIVER([BayLibre ACME], [baylibre-acme], [sys_timerfd_h])
SR_DRIVER([BeagleLogic], [beaglelogic], [sys_mman_h sys_ioctl_h])
SR_DRIVER([Brymen BM86x], [brymen-bm86x], [libusb])
SR_DRIVER([Brymen DMM], [brymen-dmm], [libserialport])
SR_DRIVER([CEM DT-885x], [cem-dt-885x], [libserialport])
SR_DRIVER([Center 3xx], [center-3xx], [libserialport])
SR_DRIVER([Brymen DMM], [brymen-dmm], [serial_comm])
SR_DRIVER([CEM DT-885x], [cem-dt-885x], [serial_comm])
SR_DRIVER([Center 3xx], [center-3xx], [serial_comm])
SR_DRIVER([ChronoVu LA], [chronovu-la], [libusb libftdi])
SR_DRIVER([Colead SLM], [colead-slm], [libserialport])
SR_DRIVER([Conrad DIGI 35 CPU], [conrad-digi-35-cpu], [libserialport])
SR_DRIVER([Colead SLM], [colead-slm], [serial_comm])
SR_DRIVER([Conrad DIGI 35 CPU], [conrad-digi-35-cpu], [serial_comm])
SR_DRIVER([demo], [demo])
SR_DRIVER([Fluke DMM], [fluke-dmm], [libserialport])
SR_DRIVER([DreamSourceLab DSLogic], [dreamsourcelab-dslogic], [libusb])
SR_DRIVER([Fluke 45], [fluke-45])
SR_DRIVER([Fluke DMM], [fluke-dmm], [serial_comm])
SR_DRIVER([FTDI LA], [ftdi-la], [libusb libftdi])
SR_DRIVER([fx2lafw], [fx2lafw], [libusb])
SR_DRIVER([GMC MH 1x/2x], [gmc-mh-1x-2x], [libserialport])
SR_DRIVER([GW Instek GDS-800], [gwinstek-gds-800], [libserialport])
SR_DRIVER([Hameg HMO], [hameg-hmo], [libserialport])
SR_DRIVER([GMC MH 1x/2x], [gmc-mh-1x-2x], [serial_comm])
SR_DRIVER([GW Instek GDS-800], [gwinstek-gds-800], [serial_comm])
SR_DRIVER([GW Instek GPD], [gwinstek-gpd], [serial_comm])
SR_DRIVER([Hameg HMO], [hameg-hmo], [serial_comm])
SR_DRIVER([Hantek 4032L], [hantek-4032l], [libusb])
SR_DRIVER([Hantek 6xxx], [hantek-6xxx], [libusb])
SR_DRIVER([Hantek DSO], [hantek-dso], [libusb])
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([Ikalogic Scanalogic-2], [ikalogic-scanalogic2], [libusb])
SR_DRIVER([Ikalogic Scanaplus], [ikalogic-scanaplus], [libftdi])
SR_DRIVER([IPDBG LA], [ipdbg-la])
SR_DRIVER([Kecheng KC-330B], [kecheng-kc-330b], [libusb])
SR_DRIVER([KERN scale], [kern-scale], [libserialport])
SR_DRIVER([Korad KAxxxxP], [korad-kaxxxxp], [libserialport])
SR_DRIVER([KERN scale], [kern-scale], [serial_comm])
SR_DRIVER([Korad KAxxxxP], [korad-kaxxxxp], [serial_comm])
SR_DRIVER([Lascar EL-USB], [lascar-el-usb], [libusb])
SR_DRIVER([LeCroy LogicStudio], [lecroy-logicstudio], [libusb])
SR_DRIVER([LeCroy X-Stream], [lecroy-xstream])
SR_DRIVER([Manson HCS-3xxx], [manson-hcs-3xxx], [libserialport])
SR_DRIVER([Manson HCS-3xxx], [manson-hcs-3xxx], [serial_comm])
SR_DRIVER([Mastech MS6514], [mastech-ms6514], [serial_comm])
SR_DRIVER([maynuo-m97], [maynuo-m97])
SR_DRIVER([MIC 985xx], [mic-985xx], [libserialport])
SR_DRIVER([Motech LPS 30x], [motech-lps-30x], [libserialport])
SR_DRIVER([Norma DMM], [norma-dmm], [libserialport])
SR_DRIVER([OpenBench Logic Sniffer], [openbench-logic-sniffer], [libserialport])
SR_DRIVER([PCE PCE-322A], [pce-322a], [libserialport])
SR_DRIVER([MIC 985xx], [mic-985xx], [serial_comm])
SR_DRIVER([Microchip PICkit2], [microchip-pickit2], [libusb])
SR_DRIVER([Mooshimeter DMM], [mooshimeter-dmm], [bluetooth_comm libgio])
SR_DRIVER([Motech LPS 30x], [motech-lps-30x], [serial_comm])
SR_DRIVER([Norma DMM], [norma-dmm], [serial_comm])
SR_DRIVER([OpenBench Logic Sniffer], [openbench-logic-sniffer], [serial_comm])
SR_DRIVER([PCE PCE-322A], [pce-322a], [serial_comm])
SR_DRIVER([Pipistrello-OLS], [pipistrello-ols], [libftdi])
SR_DRIVER([RDTech DPSxxxx/DPHxxxx], [rdtech-dps], [serial_comm])
SR_DRIVER([Rigol DS], [rigol-ds])
SR_DRIVER([Rohde&Schwarz SME-0x], [rohde-schwarz-sme-0x], [libserialport])
SR_DRIVER([Rohde&Schwarz SME-0x], [rohde-schwarz-sme-0x], [serial_comm])
SR_DRIVER([Saleae Logic16], [saleae-logic16], [libusb])
SR_DRIVER([Saleae Logic Pro], [saleae-logic-pro], [libusb])
SR_DRIVER([SCPI DMM], [scpi-dmm])
SR_DRIVER([SCPI PPS], [scpi-pps])
SR_DRIVER([serial DMM], [serial-dmm], [libserialport])
SR_DRIVER([serial LCR], [serial-lcr], [libserialport])
SR_DRIVER([serial DMM], [serial-dmm], [serial_comm])
SR_DRIVER([serial LCR], [serial-lcr], [serial_comm])
SR_DRIVER([Siglent SDS], [siglent-sds])
SR_DRIVER([Sysclk LWLA], [sysclk-lwla], [libusb])
SR_DRIVER([Teleinfo], [teleinfo], [libserialport])
SR_DRIVER([Sysclk SLA5032], [sysclk-sla5032], [libusb])
SR_DRIVER([Teleinfo], [teleinfo], [serial_comm])
SR_DRIVER([Testo], [testo], [libusb])
SR_DRIVER([Tondaj SL-814], [tondaj-sl-814], [libserialport])
SR_DRIVER([Tondaj SL-814], [tondaj-sl-814], [serial_comm])
SR_DRIVER([UNI-T DMM], [uni-t-dmm], [libusb])
SR_DRIVER([UNI-T UT32x], [uni-t-ut32x], [libusb])
SR_DRIVER([Victor DMM], [victor-dmm], [libusb])
SR_DRIVER([UNI-T UT32x], [uni-t-ut32x], [serial_comm])
SR_DRIVER([Yokogawa DL/DLM], [yokogawa-dlm])
SR_DRIVER([ZEROPLUS Logic Cube], [zeroplus-logic-cube], [libusb])
SR_DRIVER([ZKETECH EBD-USB], [zketech-ebd-usb], [serial_comm])
###############################
## Language bindings setup ##
@ -589,10 +635,17 @@ Detected libraries (optional):
$sr_pkglibs_summary
Enabled hardware drivers:
$sr_driver_summary
Enabled serial communication transports:
- serial comm ................... $sr_have_serial_comm
- libserialport ................. $sr_have_libserialport
- hidapi ........................ $sr_have_libhidapi
- bluetooth ..................... $sr_have_bluetooth
- bluez ......................... $sr_have_libbluez
Enabled SCPI backends:
- TCP............................. yes
- RPC............................. $sr_cv_have_rpc
- serial.......................... $sr_have_libserialport
- serial.......................... $sr_have_serial_comm
- VISA............................ $sr_have_librevisa
- GPIB............................ $sr_have_libgpib
- USBTMC.......................... $sr_have_libusb
@ -604,3 +657,24 @@ Enabled language bindings:
- Java............................ $BINDINGS_JAVA$sr_report_java
_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
])

324
contrib/60-libsigrok.rules Normal file
View File

@ -0,0 +1,324 @@
##
## 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|hidraw", 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"
# 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
# ftdi-la
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"
# LeCroy WaveRunner
# 05ff:1023: 625Zi
ATTRS{idVendor}=="05ff", ATTRS{idProduct}=="1023", ENV{ID_SIGROK}="1"
# Link Instruments MSO-19
ATTRS{idVendor}=="3195", ATTRS{idProduct}=="f190", ENV{ID_SIGROK}="1"
# 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"
# Rigol MSO5000 series
ATTRS{idVendor}=="1ab1", ATTRS{idProduct}=="0515", ENV{ID_SIGROK}="1"
# Rohde&Schwarz HMO series mixed-signal oscilloscope (previously branded Hameg) VCP/USBTMC mode
ATTRS{idVendor}=="0aad", ATTRS{idProduct}=="0117", ENV{ID_SIGROK}="1"
ATTRS{idVendor}=="0aad", ATTRS{idProduct}=="0118", ENV{ID_SIGROK}="1"
ATTRS{idVendor}=="0aad", ATTRS{idProduct}=="0119", ENV{ID_SIGROK}="1"
# 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
# f4ec:ee38: E.g. SDS1104X-E scope
# f4ed:ee3a: E.g. SDS1202X-E scope or SDG1010 waveform generator
ATTRS{idVendor}=="f4ec", ATTRS{idProduct}=="ee3a", ENV{ID_SIGROK}="1"
ATTRS{idVendor}=="f4ed", ATTRS{idProduct}=="ee3a", ENV{ID_SIGROK}="1"
# 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"
# SiLabs CP210x (USB CDC) UART bridge, used (among others) in:
# CEM DT-8852
# Manson HCS-3202
# MASTECH MS2115B
# MASTECH MS5308
# MASTECH MS8250D
# PeakTech 3330
# Voltcraft PPS-11815
ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", ENV{ID_SIGROK}="1"
# SiLabs CP2110 (USB HID) UART bridge, used (among others) in:
# UNI-T UT612
# UNI-T UT-D09 multimeter cable (for various UNI-T and rebranded DMMs)
ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea80", ENV{ID_SIGROK}="1"
# Sysclk LWLA1016
ATTRS{idVendor}=="2961", ATTRS{idProduct}=="6688", ENV{ID_SIGROK}="1"
# Sysclk LWLA1034
ATTRS{idVendor}=="2961", ATTRS{idProduct}=="6689", ENV{ID_SIGROK}="1"
# Sysclk SLA5032 ("32CH 500M" mode)
ATTRS{idVendor}=="2961", ATTRS{idProduct}=="66b0", ENV{ID_SIGROK}="1"
# Testo 435
ATTRS{idVendor}=="128d", ATTRS{idProduct}=="0003", ENV{ID_SIGROK}="1"
# UNI-T UT-D04 multimeter cable (for various UNI-T and rebranded DMMs)
# UNI-T UT325
ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="e008", ENV{ID_SIGROK}="1"
# V&A VA4000 multimeter cable (for various V&A DMMs)
ATTRS{idVendor}=="04fc", ATTRS{idProduct}=="0201", ENV{ID_SIGROK}="1"
# Victor 70C
# Victor 86C
ATTRS{idVendor}=="1244", ATTRS{idProduct}=="d237", ENV{ID_SIGROK}="1"
# YiXingDianZi MDSO
ATTRS{idVendor}=="d4a2", ATTRS{idProduct}=="5660", ENV{ID_SIGROK}="1"
# ZEROPLUS Logic Cube LAP-C series
# There are various devices in the ZEROPLUS Logic Cube series:
# 0c12:7002: LAP-16128U
# 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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -84,11 +84,11 @@ enum sr_error_code {
/* Handy little macros */
#define SR_HZ(n) (n)
#define SR_KHZ(n) ((n) * (uint64_t)(1000ULL))
#define SR_MHZ(n) ((n) * (uint64_t)(1000000ULL))
#define SR_GHZ(n) ((n) * (uint64_t)(1000000000ULL))
#define SR_KHZ(n) ((n) * UINT64_C(1000))
#define SR_MHZ(n) ((n) * UINT64_C(1000000))
#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. */
enum sr_loglevel {
@ -650,11 +650,11 @@ struct sr_key_info {
/** Configuration capabilities. */
enum sr_configcap {
/** Value can be read. */
SR_CONF_GET = (1 << 31),
SR_CONF_GET = (1UL << 31),
/** Value can be written. */
SR_CONF_SET = (1 << 30),
SR_CONF_SET = (1UL << 30),
/** Possible values can be enumerated. */
SR_CONF_LIST = (1 << 29),
SR_CONF_LIST = (1UL << 29),
};
/** Configuration keys */
@ -703,6 +703,9 @@ enum sr_configkey {
/** The device can act as a function generator. */
SR_CONF_SIGNAL_GENERATOR,
/** The device can measure power. */
SR_CONF_POWERMETER,
/* Update sr_key_info_config[] (hwdriver.c) upon changes! */
/*--- Driver scan options -------------------------------------------*/
@ -953,6 +956,8 @@ enum sr_configkey {
* Channel regulation
* get: "CV", "CC" or "UR", denoting constant voltage, constant current
* or unregulated.
* "CC-" denotes a power supply in current sink mode (e.g. HP 66xxB).
* "" is used when there is no regulation, e.g. the output is disabled.
*/
SR_CONF_REGULATION,
@ -983,6 +988,39 @@ enum sr_configkey {
/** 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,
/** Offset of a source without strictly-defined MQ. */
SR_CONF_OFFSET,
/** The device supports setting a pattern for the logic trigger. */
SR_CONF_TRIGGER_PATTERN,
/** High resolution mode. */
SR_CONF_HIGH_RESOLUTION,
/** Peak detection. */
SR_CONF_PEAK_DETECTION,
/** Logic threshold: predefined levels (TTL, ECL, CMOS, etc). */
SR_CONF_LOGIC_THRESHOLD,
/** Logic threshold: custom numerical value. */
SR_CONF_LOGIC_THRESHOLD_CUSTOM,
/** The measurement range of a DMM or the output range of a power supply. */
SR_CONF_RANGE,
/** The number of digits (e.g. for a DMM). */
SR_CONF_DIGITS,
/* Update sr_key_info_config[] (hwdriver.c) upon changes! */
/*--- Special stuff -------------------------------------------------*/

View File

@ -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_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 -----------------------------------------------------------------*/
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_callback_set(sr_log_callback cb, void *cb_data);
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 --------------------------------------------------------------*/
@ -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_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 ---------------------------------------------------------*/
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);
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 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 struct sr_input *sr_input_new(const struct sr_input_module *imod,
GHashTable *options);
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 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 int sr_input_send(const struct sr_input *in, GString *buf);
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,
GHashTable *params, const struct sr_dev_inst *sdi,
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,
const struct sr_datafeed_packet *packet, GString **out);
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,
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_resource_open_callback open_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 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_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);
/*--- version.c -------------------------------------------------------------*/

View File

@ -4,7 +4,7 @@ libdir=@libdir@
includedir=@includedir@
Name: libsigrok
Description: Backend library of the sigrok logic analyzer software
Description: Backend library for the sigrok signal analysis software suite
URL: http://www.sigrok.org
Requires: glib-2.0
Requires.private: @SR_PKGLIBS@

View File

@ -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,
float *outbuf)
{
float offset;
unsigned int b, i, count;
unsigned int b, count;
gboolean bigendian;
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. */
memcpy(outbuf, analog->data, count * sizeof(float));
} 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++) {
if (analog->encoding->is_bigendian == bigendian)
((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
|| analog->encoding->scale.q != 1)
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;
}
}
@ -308,7 +307,7 @@ SR_API int sr_analog_to_float(const struct sr_datafeed_analog *analog,
SR_API const char *sr_analog_si_prefix(float *value, int *digits)
{
/** @cond PRIVATE */
#define NEG_PREFIX_COUNT 5 /* number of prefixes below unity */
#define NEG_PREFIX_COUNT 5 /* number of prefixes below unity */
#define POS_PREFIX_COUNT (int)(ARRAY_SIZE(prefixes) - NEG_PREFIX_COUNT - 1)
/** @endcond */
static const char *prefixes[] = { "f", "p", "n", "µ", "m", "", "k", "M", "G", "T" };
@ -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++)
if (unit == prefix_friendly_units[i])
break;
return TRUE;
if (unit != prefix_friendly_units[i])
return FALSE;
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;
}
res->p = (int64_t)(p);
res->q = (uint64_t)(q);
res->p = (int64_t)p;
res->q = (uint64_t)q;
return SR_OK;

View File

@ -153,9 +153,25 @@ SR_API GSList *sr_buildinfo_libs_get(void)
m = g_slist_append(m, g_strdup_printf("%s", CONF_LIBUSB_1_0_VERSION));
#else
lv = libusb_get_version();
m = g_slist_append(m, g_strdup_printf("%d.%d.%d.%d%s",
lv->major, lv->minor, lv->micro, lv->nano, lv->rc));
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,
#if defined(LIBUSB_API_VERSION)
LIBUSB_API_VERSION
#elif defined(LIBUSBX_API_VERSION)
LIBUSBX_API_VERSION
#endif
));
#endif
l = g_slist_append(l, m);
#endif
#ifdef HAVE_LIBHIDAPI
m = g_slist_append(NULL, g_strdup("hidapi"));
m = g_slist_append(m, g_strdup_printf("%s", CONF_LIBHIDAPI_VERSION));
l = g_slist_append(l, m);
#endif
#ifdef HAVE_LIBBLUEZ
m = g_slist_append(NULL, g_strdup("bluez"));
m = g_slist_append(m, g_strdup_printf("%s", CONF_LIBBLUEZ_VERSION));
l = g_slist_append(l, m);
#endif
#ifdef HAVE_LIBFTDI
@ -199,7 +215,7 @@ SR_API char *sr_buildinfo_scpi_backends_get(void)
#if HAVE_RPC
g_string_append_printf(s, "RPC, ");
#endif
#ifdef HAVE_LIBSERIALPORT
#ifdef HAVE_SERIAL_COMM
g_string_append_printf(s, "serial, ");
#endif
#ifdef HAVE_LIBREVISA
@ -226,8 +242,7 @@ static void print_versions(void)
char *str;
const char *lib, *version;
sr_dbg("libsigrok %s/%s (rt: %s/%s).",
SR_PACKAGE_VERSION_STRING, SR_LIB_VERSION_STRING,
sr_dbg("libsigrok %s/%s.",
sr_package_version_string_get(), sr_lib_version_string_get());
s = g_string_sized_new(200);
@ -255,6 +270,17 @@ static void print_versions(void)
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.
*
@ -309,7 +335,10 @@ static int sanity_check_all_drivers(const struct sr_context *ctx)
sr_err("No dev_list in driver %d ('%s').", i, d);
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. */
if (!drivers[i]->config_set) {
sr_err("No config_set in driver %d ('%s').", i, d);
@ -526,6 +555,8 @@ SR_API int sr_init(struct sr_context **ctx)
print_versions();
print_resourcepaths();
if (!ctx) {
sr_err("%s(): libsigrok context was NULL.", __func__);
return SR_ERR;
@ -537,22 +568,22 @@ SR_API int sr_init(struct sr_context **ctx)
if (sanity_check_all_drivers(context) < 0) {
sr_err("Internal driver error(s), aborting.");
return ret;
goto done;
}
if (sanity_check_all_input_modules() < 0) {
sr_err("Internal input module error(s), aborting.");
return ret;
goto done;
}
if (sanity_check_all_output_modules() < 0) {
sr_err("Internal output module error(s), aborting.");
return ret;
goto done;
}
if (sanity_check_all_transform_modules() < 0) {
sr_err("Internal transform module error(s), aborting.");
return ret;
goto done;
}
#ifdef _WIN32
@ -570,6 +601,20 @@ SR_API int sr_init(struct sr_context **ctx)
ret = SR_ERR;
goto done;
}
#endif
#ifdef HAVE_LIBHIDAPI
/*
* According to <hidapi.h>, the hid_init() routine just returns
* zero or non-zero, and hid_error() appears to relate to calls
* for a specific device after hid_open(). Which means that there
* is no more detailled information available beyond success/fail
* at this point in time.
*/
if (hid_init() != 0) {
sr_err("HIDAPI hid_init() failed.");
ret = SR_ERR;
goto done;
}
#endif
sr_resource_set_hooks(context, NULL, NULL, NULL, NULL);
@ -577,9 +622,7 @@ SR_API int sr_init(struct sr_context **ctx)
context = NULL;
ret = SR_OK;
#if defined(HAVE_LIBUSB_1_0) || defined(_WIN32)
done:
#endif
g_free(context);
return ret;
}
@ -607,6 +650,9 @@ SR_API int sr_exit(struct sr_context *ctx)
WSACleanup();
#endif
#ifdef HAVE_LIBHIDAPI
hid_exit();
#endif
#ifdef HAVE_LIBUSB_1_0
libusb_exit(ctx->libusb_ctx);
#endif

1091
src/bt/bt_bluez.c Normal file

File diff suppressed because it is too large Load Diff

107
src/conversion.c Normal file
View File

@ -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;
}

View File

@ -18,10 +18,12 @@
*/
#include <config.h>
#include <stdio.h>
#include <glib.h>
#include <stdio.h>
#include <string.h>
#include <libsigrok/libsigrok.h>
#include "libsigrok-internal.h"
#include "scpi.h"
/** @cond PRIVATE */
#define LOG_PREFIX "device"
@ -60,7 +62,7 @@ SR_PRIV struct sr_channel *sr_channel_new(struct sr_dev_inst *sdi,
{
struct sr_channel *ch;
ch = g_malloc0(sizeof(struct sr_channel));
ch = g_malloc0(sizeof(*ch));
ch->sdi = sdi;
ch->index = index;
ch->type = type;
@ -73,6 +75,30 @@ SR_PRIV struct sr_channel *sr_channel_new(struct sr_dev_inst *sdi,
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.
*
@ -135,10 +161,18 @@ SR_API int sr_dev_channel_enable(struct sr_channel *channel, gboolean state)
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,
struct sr_channel *cur_channel)
{
struct sr_channel *next_channel;
@ -156,6 +190,69 @@ SR_PRIV struct sr_channel *sr_next_enabled_channel(const struct sr_dev_inst *sdi
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
* capability.
@ -308,7 +405,7 @@ SR_API struct sr_dev_inst *sr_dev_inst_user_new(const char *vendor,
{
struct sr_dev_inst *sdi;
sdi = g_malloc0(sizeof(struct sr_dev_inst));
sdi = g_malloc0(sizeof(*sdi));
sdi->vendor = g_strdup(vendor);
sdi->model = g_strdup(model);
@ -356,9 +453,7 @@ SR_PRIV void sr_dev_inst_free(struct sr_dev_inst *sdi)
for (l = sdi->channels; l; l = l->next) {
ch = l->data;
g_free(ch->name);
g_free(ch->priv);
g_free(ch);
sr_channel_free(ch);
}
g_slist_free(sdi->channels);
@ -400,7 +495,7 @@ SR_PRIV struct sr_usb_dev_inst *sr_usb_dev_inst_new(uint8_t bus,
{
struct sr_usb_dev_inst *udi;
udi = g_malloc0(sizeof(struct sr_usb_dev_inst));
udi = g_malloc0(sizeof(*udi));
udi->bus = bus;
udi->address = address;
udi->devhdl = hdl;
@ -423,7 +518,7 @@ SR_PRIV void sr_usb_dev_inst_free(struct sr_usb_dev_inst *usb)
#endif
#ifdef HAVE_LIBSERIALPORT
#ifdef HAVE_SERIAL_COMM
/**
* Allocate and init a struct for a serial device instance.
@ -449,7 +544,7 @@ SR_PRIV struct sr_serial_dev_inst *sr_serial_dev_inst_new(const char *port,
{
struct sr_serial_dev_inst *serial;
serial = g_malloc0(sizeof(struct sr_serial_dev_inst));
serial = g_malloc0(sizeof(*serial));
serial->port = g_strdup(port);
if (serialcomm)
serial->serialcomm = g_strdup(serialcomm);
@ -481,7 +576,7 @@ SR_PRIV struct sr_usbtmc_dev_inst *sr_usbtmc_dev_inst_new(const char *device)
{
struct sr_usbtmc_dev_inst *usbtmc;
usbtmc = g_malloc0(sizeof(struct sr_usbtmc_dev_inst));
usbtmc = g_malloc0(sizeof(*usbtmc));
usbtmc->device = g_strdup(device);
usbtmc->fd = -1;
@ -529,27 +624,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)
{
int ret;
if (!driver) {
sr_err("Invalid driver.");
return SR_ERR_ARG;
}
if (driver->dev_clear)
ret = driver->dev_clear(driver);
else
ret = std_dev_clear(driver, NULL);
if (!driver->context) {
/*
* Driver was never initialized, nothing to do.
*
* 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.
*
* @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
*/
@ -558,32 +666,59 @@ SR_API int sr_dev_open(struct sr_dev_inst *sdi)
int ret;
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;
}
sr_dbg("%s: Opening device instance.", sdi->driver->name);
ret = sdi->driver->dev_open(sdi);
if (ret == SR_OK)
sdi->status = SR_ST_ACTIVE;
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.
*
* @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
*/
SR_API int sr_dev_close(struct sr_dev_inst *sdi)
{
int ret;
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);
}
/**
@ -674,19 +809,24 @@ SR_API const char *sr_dev_inst_connid_get(const struct sr_dev_inst *sdi)
#ifdef HAVE_LIBUSB_1_0
struct drv_context *drvc;
int cnt, i, a, b;
char connection_id[64];
char conn_id_usb[64];
struct sr_usb_dev_inst *usb;
struct libusb_device **devlist;
#endif
#ifdef HAVE_SERIAL_COMM
struct sr_serial_dev_inst *serial;
#endif
struct sr_scpi_dev_inst *scpi;
char *conn_id_scpi;
if (!sdi)
return NULL;
#ifdef HAVE_LIBSERIALPORT
struct sr_serial_dev_inst *serial;
#ifdef HAVE_SERIAL_COMM
if ((!sdi->connection_id) && (sdi->inst_type == SR_INST_SERIAL)) {
/* connection_id isn't populated, let's do that here. */
/* connection_id isn't populated, let's do that for serial devices. */
serial = sdi->conn;
((struct sr_dev_inst *)sdi)->connection_id = g_strdup(serial->port);
@ -695,7 +835,7 @@ SR_API const char *sr_dev_inst_connid_get(const struct sr_dev_inst *sdi)
#ifdef HAVE_LIBUSB_1_0
if ((!sdi->connection_id) && (sdi->inst_type == SR_INST_USB)) {
/* connection_id isn't populated, let's do that here. */
/* connection_id isn't populated, let's do that for USB devices. */
drvc = sdi->driver->context;
usb = sdi->conn;
@ -713,8 +853,10 @@ SR_API const char *sr_dev_inst_connid_get(const struct sr_dev_inst *sdi)
if (b != usb->bus || a != usb->address)
continue;
usb_get_port_path(devlist[i], connection_id, sizeof(connection_id));
((struct sr_dev_inst *)sdi)->connection_id = g_strdup(connection_id);
if (usb_get_port_path(devlist[i], conn_id_usb, sizeof(conn_id_usb)) < 0)
continue;
((struct sr_dev_inst *)sdi)->connection_id = g_strdup(conn_id_usb);
break;
}
@ -722,6 +864,15 @@ SR_API const char *sr_dev_inst_connid_get(const struct sr_dev_inst *sdi)
}
#endif
if ((!sdi->connection_id) && (sdi->inst_type == SR_INST_SCPI)) {
/* connection_id isn't populated, let's do that for SCPI devices. */
scpi = sdi->conn;
sr_scpi_connection_id(scpi, &conn_id_scpi);
((struct sr_dev_inst *)sdi)->connection_id = g_strdup(conn_id_scpi);
g_free(conn_id_scpi);
}
return sdi->connection_id;
}

View File

@ -379,7 +379,7 @@ static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
if (info->is_dc)
analog->meaning->mqflags |= SR_MQFLAG_DC;
if (info->is_diode)
analog->meaning->mqflags |= SR_MQFLAG_DIODE;
analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
if (info->is_peak_max)
analog->meaning->mqflags |= SR_MQFLAG_MAX;
if (info->is_peak_min)
@ -446,7 +446,7 @@ static gboolean flags_valid(const struct asycii_info *info)
return TRUE;
}
#ifdef HAVE_LIBSERIALPORT
#ifdef HAVE_SERIAL_COMM
/**
* Arrange for the reception of another measurement from the DMM.
*
@ -519,7 +519,7 @@ SR_PRIV int sr_asycii_parse(const uint8_t *buf, float *floatval,
int ret, exponent;
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. */
sr_dbg("DMM packet: \"%.15s\"", buf);

View File

@ -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->unit = SR_UNIT_VOLT;
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) {
analog->meaning->mq = SR_MQ_CURRENT;

356
src/dmm/bm86x.c Normal file
View File

@ -0,0 +1,356 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
* Copyright (C) 2019 Gerhard Sittig <gerhard.sittig@gmx.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file
*
* Brymen BM86x serial protocol parser. The USB protocol (for the cable)
* and the packet description (for the meter) were retrieved from:
* http://brymen.com/product-html/Download2.html
* http://brymen.com/product-html/PD02BM860s_protocolDL.html
* http://brymen.com/product-html/images/DownloadList/ProtocolList/BM860-BM860s_List/BM860-BM860s-500000-count-dual-display-DMMs-protocol.pdf
*/
#include <config.h>
#include <math.h>
#include <libsigrok/libsigrok.h>
#include "libsigrok-internal.h"
#include <string.h>
#define LOG_PREFIX "brymen-bm86x"
#ifdef HAVE_SERIAL_COMM
SR_PRIV int sr_brymen_bm86x_packet_request(struct sr_serial_dev_inst *serial)
{
static const uint8_t request[] = { 0x00, 0x00, 0x86, 0x66, };
serial_write_nonblocking(serial, request, sizeof(request));
return SR_OK;
}
#endif
SR_PRIV gboolean sr_brymen_bm86x_packet_valid(const uint8_t *buf)
{
/*
* "Model ID3" (3rd HID report, byte 3) is the only documented
* fixed value, and must be 0x86. All other positions either depend
* on the meter's function, or the measurement's value, or are not
* documented by the vendor (are marked as "don't care", no fixed
* values are listed). There is nothing else we can check reliably.
*/
if (buf[19] != 0x86)
return FALSE;
return TRUE;
}
/*
* Data bytes in the DMM packet encode LCD segments in an unusual order
* (bgcdafe) and in an unusual position (bits 7:1 within the byte). The
* decimal point (bit 0) for one digit resides in the _next_ digit's byte.
*
* These routines convert LCD segments to characters, and a section of the
* DMM packet (which corresponds to the primary or secondary display) to
* the text representation of the measurement's value, before regular text
* to number conversion is applied. The first byte of the passed in block
* contains indicators, the value's digits start at the second byte.
*/
static char brymen_bm86x_parse_digit(uint8_t b)
{
switch (b >> 1) {
/* Sign. */
case 0x20: return '-';
/* Decimal digits. */
case 0x5f: return '0';
case 0x50: return '1';
case 0x6d: return '2';
case 0x7c: return '3';
case 0x72: return '4';
case 0x3e: return '5';
case 0x3f: return '6';
case 0x54: return '7';
case 0x7f: return '8';
case 0x7e: return '9';
/* Temperature units. */
case 0x0f: return 'C';
case 0x27: return 'F';
/* OL condition, and diode mode. */
case 0x0b: return 'L';
case 0x79: return 'd';
case 0x10: return 'i';
case 0x39: return 'o';
/* Blank digit. */
case 0x00: return '\0';
/* Invalid or unknown segment combination. */
default:
sr_warn("Unknown encoding for digit: 0x%02x.", b);
return '\0';
}
}
static int brymen_bm86x_parse_digits(const uint8_t *pkt, size_t pktlen,
char *txtbuf, float *value, char *temp_unit, int *digits, int signflag)
{
uint8_t byte;
char *txtptr, txtchar;
size_t pos;
int ret;
txtptr = txtbuf;
if (digits)
*digits = INT_MIN;
if (pkt[0] & signflag)
*txtptr++ = '-';
for (pos = 0; pos < pktlen; pos++) {
byte = pkt[1 + pos];
if (pos && pos < 5 && (byte & 0x01)) {
*txtptr++ = '.';
if (digits)
*digits = 0;
}
txtchar = brymen_bm86x_parse_digit(byte);
if (pos == 5 && (txtchar == 'C' || txtchar == 'F')) {
if (temp_unit)
*temp_unit = txtchar;
} else if (txtchar) {
*txtptr++ = txtchar;
if (digits)
(*digits)++;
}
}
*txtptr = '\0';
if (digits && *digits < 0)
*digits = 0;
ret = value ? sr_atof_ascii(txtbuf, value) : SR_OK;
if (ret != SR_OK) {
sr_dbg("invalid float string: '%s'", txtbuf);
return ret;
}
return SR_OK;
}
/*
* Extract the measurement value and its properties for one of the
* meter's displays from the DMM packet.
*/
static void brymen_bm86x_parse(const uint8_t *buf, float *floatval,
struct sr_datafeed_analog *analog, size_t ch_idx)
{
char txtbuf[16], temp_unit;
int ret, digits, is_diode, over_limit, scale;
uint8_t ind1, ind15;
temp_unit = '\0';
if (ch_idx == 0) {
/*
* Main display. Note that _some_ of the second display's
* indicators are involved in the inspection of the _first_
* display's measurement value. So we have to get the
* second display's text buffer here, too.
*/
(void)brymen_bm86x_parse_digits(&buf[9], 4, txtbuf,
NULL, NULL, NULL, 0);
is_diode = strcmp(txtbuf, "diod") == 0;
ret = brymen_bm86x_parse_digits(&buf[2], 6, txtbuf,
floatval, &temp_unit, &digits, 0x80);
over_limit = strstr(txtbuf, "0L") || strstr(txtbuf, "0.L");
if (ret != SR_OK && !over_limit)
return;
/* SI unit. */
if (buf[8] & 0x01) {
analog->meaning->mq = SR_MQ_VOLTAGE;
analog->meaning->unit = SR_UNIT_VOLT;
if (is_diode) {
analog->meaning->mqflags |= SR_MQFLAG_DIODE;
analog->meaning->mqflags |= SR_MQFLAG_DC;
}
} else if (buf[14] & 0x80) {
analog->meaning->mq = SR_MQ_CURRENT;
analog->meaning->unit = SR_UNIT_AMPERE;
} else if (buf[14] & 0x20) {
analog->meaning->mq = SR_MQ_CAPACITANCE;
analog->meaning->unit = SR_UNIT_FARAD;
} else if (buf[14] & 0x10) {
analog->meaning->mq = SR_MQ_CONDUCTANCE;
analog->meaning->unit = SR_UNIT_SIEMENS;
} else if (buf[15] & 0x01) {
analog->meaning->mq = SR_MQ_FREQUENCY;
analog->meaning->unit = SR_UNIT_HERTZ;
} else if (buf[10] & 0x01) {
analog->meaning->mq = SR_MQ_CONTINUITY;
analog->meaning->unit = SR_UNIT_OHM;
} else if (buf[15] & 0x10) {
analog->meaning->mq = SR_MQ_RESISTANCE;
analog->meaning->unit = SR_UNIT_OHM;
} else if (buf[15] & 0x02) {
analog->meaning->mq = SR_MQ_POWER;
analog->meaning->unit = SR_UNIT_DECIBEL_MW;
} else if (buf[15] & 0x80) {
analog->meaning->mq = SR_MQ_DUTY_CYCLE;
analog->meaning->unit = SR_UNIT_PERCENTAGE;
} else if ((buf[2] & 0x0a) && temp_unit) {
analog->meaning->mq = SR_MQ_TEMPERATURE;
if (temp_unit == 'F')
analog->meaning->unit = SR_UNIT_FAHRENHEIT;
else
analog->meaning->unit = SR_UNIT_CELSIUS;
}
/*
* Remove the MIN/MAX/AVG indicators when all of them
* are shown at the same time.
*/
ind1 = buf[1];
if ((ind1 & 0xe0) == 0xe0)
ind1 &= ~0xe0;
/* AC/DC/Auto flags. */
if (buf[1] & 0x10)
analog->meaning->mqflags |= SR_MQFLAG_DC;
if (buf[2] & 0x01)
analog->meaning->mqflags |= SR_MQFLAG_AC;
if (buf[1] & 0x01)
analog->meaning->mqflags |= SR_MQFLAG_AUTORANGE;
if (buf[1] & 0x08)
analog->meaning->mqflags |= SR_MQFLAG_HOLD;
if (ind1 & 0x20)
analog->meaning->mqflags |= SR_MQFLAG_MAX;
if (ind1 & 0x40)
analog->meaning->mqflags |= SR_MQFLAG_MIN;
if (ind1 & 0x80)
analog->meaning->mqflags |= SR_MQFLAG_AVG;
if (buf[3] & 0x01)
analog->meaning->mqflags |= SR_MQFLAG_RELATIVE;
/*
* Remove the "dBm" indication's "m" indicator before the
* SI unit's prefixes get inspected. To avoid an interaction
* with the "milli" prefix.
*/
ind15 = buf[15];
if (ind15 & 0x02)
ind15 &= ~0x04;
/* SI prefix. */
scale = 0;
if (buf[14] & 0x40) /* n */
scale = -9;
if (buf[15] & 0x08) /* u */
scale = -6;
if (ind15 & 0x04) /* m */
scale = -3;
if (buf[15] & 0x40) /* k */
scale = +3;
if (buf[15] & 0x20) /* M */
scale = +6;
if (scale) {
*floatval *= pow(10, scale);
digits += -scale;
}
if (over_limit)
*floatval = INFINITY;
analog->encoding->digits = digits;
analog->spec->spec_digits = digits;
} else if (ch_idx == 1) {
/*
* Secondary display. Also inspect _some_ primary display
* data, to determine the secondary display's validity.
*/
(void)brymen_bm86x_parse_digits(&buf[2], 6, txtbuf,
NULL, &temp_unit, NULL, 0x80);
ret = brymen_bm86x_parse_digits(&buf[9], 4, txtbuf,
floatval, NULL, &digits, 0x10);
/* SI unit. */
if (buf[14] & 0x08) {
analog->meaning->mq = SR_MQ_VOLTAGE;
analog->meaning->unit = SR_UNIT_VOLT;
} else if (buf[9] & 0x04) {
analog->meaning->mq = SR_MQ_CURRENT;
analog->meaning->unit = SR_UNIT_AMPERE;
} else if (buf[9] & 0x08) {
analog->meaning->mq = SR_MQ_CURRENT;
analog->meaning->unit = SR_UNIT_PERCENTAGE;
} else if (buf[14] & 0x04) {
analog->meaning->mq = SR_MQ_FREQUENCY;
analog->meaning->unit = SR_UNIT_HERTZ;
} else if ((buf[9] & 0x40) && temp_unit) {
analog->meaning->mq = SR_MQ_TEMPERATURE;
if (temp_unit == 'F')
analog->meaning->unit = SR_UNIT_FAHRENHEIT;
else
analog->meaning->unit = SR_UNIT_CELSIUS;
}
/* AC flag. */
if (buf[9] & 0x20)
analog->meaning->mqflags |= SR_MQFLAG_AC;
/* SI prefix. */
scale = 0;
if (buf[ 9] & 0x01) /* u */
scale = -6;
if (buf[ 9] & 0x02) /* m */
scale = -3;
if (buf[14] & 0x02) /* k */
scale = +3;
if (buf[14] & 0x01) /* M */
scale = +6;
if (scale) {
*floatval *= pow(10, scale);
digits += -scale;
}
analog->encoding->digits = digits;
analog->spec->spec_digits = digits;
}
if (buf[9] & 0x80)
sr_warn("Battery is low.");
}
SR_PRIV int sr_brymen_bm86x_parse(const uint8_t *buf, float *val,
struct sr_datafeed_analog *analog, void *info)
{
struct brymen_bm86x_info *info_local;
size_t ch_idx;
/*
* Scan a portion of the received DMM packet which corresponds
* to the caller's specified display. Then prepare to scan a
* different portion of the packet for another display. This
* routine gets called multiple times for one received packet.
*/
info_local = info;
ch_idx = info_local->ch_idx;
brymen_bm86x_parse(buf, val, analog, ch_idx);
info_local->ch_idx = ch_idx + 1;
return SR_OK;
}

View File

@ -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,
int *exponent, const struct dtm0660_info *info)
{
int initial_exponent = *exponent;
/* Factors */
if (info->is_nano)
*exponent -= 9;
@ -265,7 +267,7 @@ static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
*exponent += 3;
if (info->is_mega)
*exponent += 6;
*floatval *= powf(10, *exponent);
*floatval *= powf(10, (*exponent - initial_exponent));
/* Measurement modes */
if (info->is_volt) {
@ -318,7 +320,7 @@ static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
if (info->is_auto)
analog->meaning->mqflags |= SR_MQFLAG_AUTORANGE;
if (info->is_diode)
analog->meaning->mqflags |= SR_MQFLAG_DIODE;
analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
if (info->is_hold)
analog->meaning->mqflags |= SR_MQFLAG_HOLD;
if (info->is_rel)
@ -373,7 +375,7 @@ SR_PRIV int sr_dtm0660_parse(const uint8_t *buf, float *floatval,
int ret, exponent = 0;
struct dtm0660_info *info_local;
info_local = (struct dtm0660_info *)info;
info_local = info;
if ((ret = parse_value(buf, floatval, &exponent)) != SR_OK) {
sr_dbg("Error parsing value: %d.", ret);

1355
src/dmm/eev121gw.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -502,7 +502,7 @@ static void handle_flags(struct sr_datafeed_analog *analog,
if (info->is_auto)
analog->meaning->mqflags |= SR_MQFLAG_AUTORANGE;
if (info->is_diode)
analog->meaning->mqflags |= SR_MQFLAG_DIODE;
analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
if (info->is_hold)
/*
* Note: HOLD only affects the number displayed on the LCD,

View File

@ -302,7 +302,7 @@ static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
if (info->is_auto)
analog->meaning->mqflags |= SR_MQFLAG_AUTORANGE;
if (info->is_diode)
analog->meaning->mqflags |= SR_MQFLAG_DIODE;
analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
if (info->is_hold)
analog->meaning->mqflags |= SR_MQFLAG_HOLD;
if (info->is_rel)
@ -353,7 +353,7 @@ SR_PRIV int sr_fs9721_parse(const uint8_t *buf, float *floatval,
int ret, exponent = 0;
struct fs9721_info *info_local;
info_local = (struct fs9721_info *)info;
info_local = info;
if ((ret = parse_value(buf, floatval, &exponent)) != SR_OK) {
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;
info_local = (struct fs9721_info *)info;
info_local = info;
/* User-defined FS9721_LP3 flag 'c2c1_00' means temperature (C). */
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;
info_local = (struct fs9721_info *)info;
info_local = info;
/* User-defined FS9721_LP3 flag 'c2c1_01' means temperature (C). */
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;
info_local = (struct fs9721_info *)info;
info_local = info;
/* User-defined FS9721_LP3 flag 'c2c1_10' means temperature (C). */
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;
info_local = (struct fs9721_info *)info;
info_local = info;
/* User-defined FS9721_LP3 flag 'c2c1_01' means temperature (F). */
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;
info_local = (struct fs9721_info *)info;
info_local = info;
/* User-defined FS9721_LP3 flag 'c2c1_00' means MAX. */
if (info_local->is_c2c1_00)

View File

@ -290,7 +290,7 @@ static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
if (info->is_auto)
analog->meaning->mqflags |= SR_MQFLAG_AUTORANGE;
if (info->is_diode)
analog->meaning->mqflags |= SR_MQFLAG_DIODE;
analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
if (info->is_hold)
analog->meaning->mqflags |= SR_MQFLAG_HOLD;
if (info->is_max)
@ -359,7 +359,7 @@ SR_PRIV int sr_fs9922_parse(const uint8_t *buf, float *floatval,
int ret, exponent = 0;
struct fs9922_info *info_local;
info_local = (struct fs9922_info *)info;
info_local = info;
if ((ret = parse_value(buf, floatval, &exponent)) != SR_OK) {
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;
info_local = (struct fs9922_info *)info;
info_local = info;
/* User-defined z1 flag means "diode mode". */
if (info_local->is_z1) {
analog->meaning->mq = SR_MQ_VOLTAGE;
analog->meaning->unit = SR_UNIT_VOLT;
analog->meaning->mqflags |= SR_MQFLAG_DIODE;
analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
}
}

View File

@ -44,7 +44,7 @@ SR_PRIV gboolean sr_m2110_packet_valid(const uint8_t *buf)
if (!strncmp((const char *)buf, "OVERRNG", 7))
return TRUE;
if (sscanf((const char *)buf, "%f", &val) == 1)
if (sr_atof_ascii((const char *)buf, &val) == SR_OK)
return TRUE;
else
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))
*floatval = INFINITY;
else if (sscanf((const char *)buf, "%f", &val) == 1) {
else if (sr_atof_ascii((const char *)buf, &val) == SR_OK) {
*floatval = val;
dot_pos = strcspn((const char *)buf, ".");
if (dot_pos < 7)

View File

@ -86,7 +86,7 @@ static int parse_value(const uint8_t *buf, struct metex14_info *info,
return SR_OK;
/* 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, ".");
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;
else if (!g_ascii_strcasecmp(u, "C"))
info->is_celsius = TRUE;
else if (!g_ascii_strcasecmp(u, "F"))
info->is_fahrenheit = TRUE;
else if (!g_ascii_strcasecmp(u, "DB"))
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, ""))
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);
info->is_capacity = !strncmp(buf, "CA", 2) ||
(!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) ||
(!strncmp(buf, " ", 2) && info->is_volt && info->is_milli);
info->is_frequency = !strncmp(buf, "FR", 2) ||
(!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) ||
(!strncmp(buf, " ", 2) && !info->is_volt && !info->is_ohm &&
!info->is_logic && !info->is_farad && !info->is_hertz);
(!strncmp(buf, " ", 2) && !info->is_ampere &&!info->is_volt &&
!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:
* - 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,
int *exponent, const struct metex14_info *info)
{
int factor = 0;
int factor;
(void)exponent;
/* Factors */
factor = 0;
if (info->is_pico)
factor -= 12;
if (info->is_nano)
@ -193,7 +213,6 @@ static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
if (info->is_mega)
factor += 6;
*floatval *= powf(10, factor);
*exponent += factor;
/* Measurement modes */
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->unit = SR_UNIT_FARAD;
}
if (info->is_celsius) {
if (info->is_temperature) {
analog->meaning->mq = SR_MQ_TEMPERATURE;
analog->meaning->unit = SR_UNIT_CELSIUS;
if (info->is_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) {
analog->meaning->mq = SR_MQ_VOLTAGE;
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) {
analog->meaning->mq = SR_MQ_GAIN;
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)
analog->meaning->mqflags |= SR_MQFLAG_DC;
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)
@ -286,14 +329,14 @@ static gboolean flags_valid(const struct metex14_info *info)
return TRUE;
}
#ifdef HAVE_LIBSERIALPORT
#ifdef HAVE_SERIAL_COMM
SR_PRIV int sr_metex14_packet_request(struct sr_serial_dev_inst *serial)
{
const uint8_t wbuf = 'D';
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
@ -313,6 +356,25 @@ SR_PRIV gboolean sr_metex14_packet_valid(const uint8_t *buf)
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.
*
@ -334,7 +396,7 @@ SR_PRIV int sr_metex14_parse(const uint8_t *buf, float *floatval,
int ret, exponent = 0;
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. */
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;
}
/**
* 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;
}

374
src/dmm/ms2115b.c Normal file
View File

@ -0,0 +1,374 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2019 Vitaliy Vorobyov
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
/*
* MASTECH MS2115B protocol parser.
*
* Sends 9 bytes.
* D0 D1 D2 D3 D4 D5 D6 D7 D8 D9
*
* D0 = 0x55 - sync byte
*
* D1 - mode:
* bits:
* B7..B4 ??
* B3 - func
* B2..B0:
* 0 - A 600/1000 (func=0 AC, func=1 DC), signed
* 1 - A 60 (func=0 AC, func=1 DC), signed
* 2 - V (func=0 AC, func=1 DC), signed
* 3 - diode/beep (func=0 buz, func=1 diode)
* 4 - resistance
* 5 - capacitance
* 6 - hz
*
* D2 - range
*
* D3 - frq range
*
* D4 main value LSB
* D5 main value MSB
*
* (secondary value, hz, min/max, rel)
* D6 secondary value LSB
* D7 secondary value MSB
*
* D8 - flags
* bits:
* B7..B1:??
* B0 - 0 - auto, 1 - manual
*
* resistance:
* 55 04 00 00 9B 18 00 00 01 (0.L, manual) 600.0 Ohm (x 0.1)
* 55 04 01 00 9B 18 00 00 01 (0.L, manual) 6.000 kOhm (x 0.001)
* 55 04 02 00 9B 18 00 00 01 (0.L, manual) 60.00 kOhm (x 0.01)
* 55 04 03 00 9B 18 00 00 01 (0.L, manual) 600.0 kOhm (x 0.1)
* 55 04 04 00 9B 18 00 00 01 (0.L, manual) 6.000 MOhm (x 0.001)
* 55 04 05 00 9B 18 00 00 00 (0.L, auto) 60.00 MOhm (x 0.01)
*
* capacitance:
* 55 05 00 00 04 00 00 00 00 (4nF, auto)
* 55 05 00 00 05 00 00 00 01 (5nF, manual) 6.000 nF (x 0.001)
* 55 05 01 00 03 19 00 00 01 (0.L nF, manual) 60.00 nF (x 0.01)
* 55 05 02 00 D4 03 00 00 01 (980.0 nF, manual) 600.0 nF (x 0.1)
* 55 05 03 00 63 00 00 00 01 (0.099 uF, manual) 6.000 uF (x 0.001)
* 55 05 04 00 40 18 00 00 01 (0.L uF, manual)
* 55 05 04 00 F0 00 00 00 01 (2.40 uF, manual) 60.00 uF (x 0.01)
* 55 05 05 00 17 00 00 00 01 (2.3 uF, manual) 600.0 uF (x 0.1)
* 55 05 06 00 02 00 00 00 01 (0.002 mF, manual) 6.000 mF (x 0.001)
* 55 05 07 00 2F 00 00 00 01 (0.47 mF, manual) 60.00 mF (x 0.01)
*
* voltage:
* 55 02 00 00 00 00 00 00 01 (0.0mV, manual) 600.0 mV (x 0.1)
* 55 02 01 00 00 00 00 00 00 (0.000V, auto)
* 55 02 01 00 00 00 00 00 01 (0.000V, manual) 6.000 V (x 0.001)
* 55 02 02 00 00 00 00 00 01 (0.00V, manual) 60.00 V (x 0.01)
* 55 02 03 00 00 00 00 00 01 (0.0V, manual) 600.0 V (x 0.1)
* 55 02 04 00 00 00 00 00 01 (0V, manual) 1000 V (x 1)
*
* - Communication parameters: Unidirectional, 1200/8n1
* - CP2102 USB to UART bridge controller
*/
#include <config.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <glib.h>
#include <libsigrok/libsigrok.h>
#include "libsigrok-internal.h"
#define LOG_PREFIX "ms2115b"
static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
const struct ms2115b_info *info)
{
/* Measurement modes */
if (info->is_volt) {
analog->meaning->mq = SR_MQ_VOLTAGE;
analog->meaning->unit = SR_UNIT_VOLT;
}
if (info->is_ampere) {
analog->meaning->mq = SR_MQ_CURRENT;
analog->meaning->unit = SR_UNIT_AMPERE;
}
if (info->is_ohm) {
analog->meaning->mq = SR_MQ_RESISTANCE;
analog->meaning->unit = SR_UNIT_OHM;
}
if (info->is_hz) {
analog->meaning->mq = SR_MQ_FREQUENCY;
analog->meaning->unit = SR_UNIT_HERTZ;
}
if (info->is_farad) {
analog->meaning->mq = SR_MQ_CAPACITANCE;
analog->meaning->unit = SR_UNIT_FARAD;
}
if (info->is_beep) {
analog->meaning->mq = SR_MQ_CONTINUITY;
analog->meaning->unit = SR_UNIT_BOOLEAN;
*floatval = (*floatval == INFINITY) ? 0.0 : 1.0;
}
if (info->is_diode) {
analog->meaning->mq = SR_MQ_VOLTAGE;
analog->meaning->unit = SR_UNIT_VOLT;
}
if (info->is_duty_cycle)
analog->meaning->mq = SR_MQ_DUTY_CYCLE;
if (info->is_percent)
analog->meaning->unit = SR_UNIT_PERCENTAGE;
/* Measurement related flags */
if (info->is_ac)
analog->meaning->mqflags |= SR_MQFLAG_AC;
if (info->is_dc)
analog->meaning->mqflags |= SR_MQFLAG_DC;
if (info->is_auto)
analog->meaning->mqflags |= SR_MQFLAG_AUTORANGE;
if (info->is_diode)
analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
}
SR_PRIV gboolean sr_ms2115b_packet_valid(const uint8_t *buf)
{
sr_dbg("DMM packet: %02x %02x %02x %02x %02x %02x %02x %02x %02x",
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6],
buf[7], buf[8]);
if (buf[0] == 0x55)
return TRUE;
return FALSE;
}
/* Mode values equal to received data */
enum {
MODE_A600_1000 = 0,
MODE_A60 = 1,
MODE_V = 2,
MODE_DIODE_BEEP = 3,
MODE_OHM = 4,
MODE_CAP = 5,
MODE_HZ = 6,
};
static const int res_exp[] = {
-1, /* 600.0 Ohm (x 0.1) */
-3 + 3, /* 6.000 kOhm (x 0.001) */
-2 + 3, /* 60.00 kOhm (x 0.01) */
-1 + 3, /* 600.0 kOhm (x 0.1) */
-3 + 6, /* 6.000 MOhm (x 0.001) */
-2 + 6, /* 60.00 MOhm (x 0.01) */
};
static const int cap_exp[] = {
-3 - 9, /* 6.000 nF (x 0.001) */
-2 - 9, /* 60.00 nF (x 0.01) */
-1 - 9, /* 600.0 nF (x 0.1) */
-3 - 6, /* 6.000 uF (x 0.001) */
-2 - 6, /* 60.00 uF (x 0.01) */
-1 - 6, /* 600.0 uF (x 0.1) */
-3 - 3, /* 6.000 mF (x 0.001) */
-2 - 3, /* 60.00 mF (x 0.01) */
};
static const int hz_exp[] = {
-2, /* 60.00 Hz (x 0.01) */
-1, /* 600.0 Hz (x 0.1) */
-3 + 3, /* 6.000 kHz (x 0.001) */
-2 + 3, /* 60.00 kHz (x 0.01) */
-1 + 3, /* 600.0 kHz (x 0.1) */
-3 + 6, /* 6.000 MHz (x 0.001) */
-2 + 6, /* 60.00 MHz (x 0.01) */
};
static const int v_exp[] = {
-1 - 3, /* 600.0 mV (x 0.1) */
-3, /* 6.000 V (x 0.001) */
-2, /* 60.00 V (x 0.01) */
-1, /* 600.0 V (x 0.1) */
0, /* 1000 V (x 1) */
};
SR_PRIV const char *ms2115b_channel_formats[MS2115B_DISPLAY_COUNT] = {
"main", "sub",
};
static int ms2115b_parse(const uint8_t *buf, float *floatval,
struct sr_datafeed_analog *analog, void *info)
{
int exponent = 0;
float up_limit = 6000.0;
gboolean sign = FALSE;
uint32_t mode = (buf[1] & 7);
gboolean func = (buf[1] & 8) ? TRUE : FALSE;
uint32_t range = (buf[2] & 7);
struct ms2115b_info *info_local = info;
enum eev121gw_display display = info_local->ch_idx;
memset(info_local, 0, sizeof(*info_local));
info_local->ch_idx = display;
switch (display) {
case MS2115B_DISPLAY_MAIN:
switch (mode) {
case MODE_A600_1000:
exponent = -1;
sign = TRUE;
info_local->is_ampere = TRUE;
if (func)
info_local->is_dc = TRUE;
else
info_local->is_ac = TRUE;
break;
case MODE_A60:
exponent = -2;
sign = TRUE;
info_local->is_ampere = TRUE;
if (func)
info_local->is_dc = TRUE;
else
info_local->is_ac = TRUE;
break;
case MODE_V:
if (range >= ARRAY_SIZE(v_exp))
return SR_ERR;
exponent = v_exp[range];
sign = TRUE;
info_local->is_volt = TRUE;
if (func)
info_local->is_dc = TRUE;
else
info_local->is_ac = TRUE;
break;
case MODE_DIODE_BEEP:
if (func) {
exponent = -3;
up_limit = 2500.0;
info_local->is_diode = TRUE;
} else {
info_local->is_beep = TRUE;
}
break;
case MODE_OHM:
if (range >= ARRAY_SIZE(res_exp))
return SR_ERR;
exponent = res_exp[range];
info_local->is_ohm = TRUE;
break;
case MODE_CAP:
if (range >= ARRAY_SIZE(cap_exp))
return SR_ERR;
exponent = cap_exp[range];
info_local->is_farad = TRUE;
break;
case MODE_HZ:
range = (buf[3] & 7);
if (range >= ARRAY_SIZE(hz_exp))
return SR_ERR;
exponent = hz_exp[range];
info_local->is_hz = TRUE;
break;
default:
return SR_ERR;
}
if (sign) {
*floatval = RL16S(buf + 4); /* signed 16bit value */
} else {
*floatval = RL16(buf + 4); /* unsigned 16bit value */
}
info_local->is_auto = (buf[8] & 1) ? FALSE : TRUE;
break;
case MS2115B_DISPLAY_SUB:
switch (mode) {
case MODE_A600_1000:
case MODE_A60:
case MODE_V:
if (func) /* DC */
return SR_ERR_NA;
/* AC */
info_local->is_hz = TRUE;
exponent = -2;
break;
case MODE_HZ:
info_local->is_duty_cycle = TRUE;
info_local->is_percent = TRUE;
exponent = -1;
break;
default:
return SR_ERR_NA;
}
*floatval = RL16(buf + 6); /* unsigned 16bit value */
break;
default:
return SR_ERR;
}
if (fabsf(*floatval) > up_limit) {
sr_spew("Over limit.");
*floatval = INFINITY;
return SR_OK;
}
*floatval *= powf(10, exponent);
handle_flags(analog, floatval, info_local);
analog->encoding->digits = -exponent;
analog->spec->spec_digits = -exponent;
return SR_OK;
}
/**
* Parse a protocol packet.
*
* @param buf Buffer containing the 9-byte protocol packet. Must not be NULL.
* @param floatval Pointer to a float variable. That variable will contain the
* result value upon parsing success. Must not be NULL.
* @param analog Pointer to a struct sr_datafeed_analog. The struct will be
* filled with data according to the protocol packet.
* Must not be NULL.
* @param info Pointer to a struct ms2115b_info. The struct will be filled
* with data according to the protocol packet. Must not be NULL.
*
* @return SR_OK upon success, SR_ERR upon failure. Upon errors, the
* 'analog' variable contents are undefined and should not be used.
*/
SR_PRIV int sr_ms2115b_parse(const uint8_t *buf, float *floatval,
struct sr_datafeed_analog *analog, void *info)
{
int ret;
int ch_idx;
struct ms2115b_info *info_local = info;
ch_idx = info_local->ch_idx;
ret = ms2115b_parse(buf, floatval, analog, info);
info_local->ch_idx = ch_idx + 1;
return ret;
}

389
src/dmm/ms8250d.c Normal file
View File

@ -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;
}

View File

@ -132,7 +132,7 @@ SR_PRIV int sr_ut372_parse(const uint8_t *buf, float *floatval,
*floatval = (float) value * powf(10, exponent);
analog->encoding->digits = -exponent;
analog->encoding->digits = -exponent;
analog->spec->spec_digits = -exponent;
return SR_OK;

View File

@ -284,7 +284,7 @@ static void handle_flags(struct sr_datafeed_analog *analog,
if (info->is_auto)
analog->meaning->mqflags |= SR_MQFLAG_AUTORANGE;
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)
@ -336,7 +336,7 @@ SR_PRIV int sr_ut71x_parse(const uint8_t *buf, float *floatval,
int ret, exponent = 0;
struct ut71x_info *info_local;
info_local = (struct ut71x_info *)info;
info_local = info;
memset(info_local, 0, sizeof(struct ut71x_info));
if (!sr_ut71x_packet_valid(buf))

View File

@ -360,7 +360,7 @@ static void handle_flags(struct sr_datafeed_analog *analog,
if (info->is_auto)
analog->meaning->mqflags |= SR_MQFLAG_AUTORANGE;
if (info->is_diode)
analog->meaning->mqflags |= SR_MQFLAG_DIODE;
analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
if (info->is_hold)
/*
* 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;
struct vc870_info *info_local;
info_local = (struct vc870_info *)info;
info_local = info;
memset(info_local, 0, sizeof(struct vc870_info));
if (!sr_vc870_packet_valid(buf))

288
src/dmm/vc96.c Normal file
View File

@ -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;
}

View File

@ -1,7 +1,7 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2014 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
* it under the terms of the GNU General Public License as published by
@ -17,28 +17,17 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBSIGROK_HARDWARE_BRYMEN_BM86X_PROTOCOL_H
#define LIBSIGROK_HARDWARE_BRYMEN_BM86X_PROTOCOL_H
#include <stdint.h>
#include <config.h>
#include <glib.h>
#include <libsigrok/libsigrok.h>
#include "libsigrok-internal.h"
#define LOG_PREFIX "brymen-bm86x"
/*
* This marks the start of the driver list. This file must be linked
* before any actual drivers.
*/
/** Private, per-device-instance driver context. */
struct dev_context {
/* Acquisition settings */
struct sr_sw_limits sw_limits;
/* Operational state */
int detached_kernel_driver;/**< Whether kernel driver was detached or not */
/* Temporary state across callbacks */
int interrupt_pending;
};
SR_PRIV int brymen_bm86x_receive_data(int fd, int revents, void *cb_data);
#endif
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 */ };

View File

@ -1,7 +1,7 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2012 Bert Vermeulen <bert@biot.com>
* 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
@ -17,22 +17,17 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBSIGROK_HARDWARE_VICTOR_DMM_PROTOCOL_H
#define LIBSIGROK_HARDWARE_VICTOR_DMM_PROTOCOL_H
#include <stdint.h>
#include <config.h>
#include <glib.h>
#include <libsigrok/libsigrok.h>
#include "libsigrok-internal.h"
#define LOG_PREFIX "victor-dmm"
/*
* This marks the end of the driver list. This file must be linked
* after any actual drivers.
*/
#define DMM_DATA_SIZE 14
/** Private, per-device-instance driver context. */
struct dev_context {
struct sr_sw_limits limits;
};
SR_PRIV int victor_dmm_receive_data(struct sr_dev_inst *sdi, unsigned char *buf);
#endif
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 */ };

View File

@ -3,6 +3,7 @@
*
* Copyright (C) 2016 Lars-Peter Clausen <lars@metafoo.de>
* 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
* 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
* 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
* and end of the section. They are used to iterate over the list of all
* drivers.
* created from driver_list_start.c and driver_list_stop.c, and point to the
* start and end of the section. They are used to iterate over the list of
* all drivers.
*/
#ifdef __APPLE__
extern struct sr_dev_driver *__start_sr_driver_list __asm("section$start$__DATA$__sr_driver_list");
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
SR_PRIV extern const struct sr_dev_driver *sr_driver_list__start[];
SR_PRIV extern const struct sr_dev_driver *sr_driver_list__stop[];
/** @private
* 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 *));
#ifdef HAVE_DRIVERS
for (struct sr_dev_driver **drivers = &__start_sr_driver_list;
drivers < &__stop_sr_driver_list; drivers++)
for (const struct sr_dev_driver **drivers = sr_driver_list__start + 1;
drivers < sr_driver_list__stop; drivers++)
g_array_append_val(array, *drivers);
#endif
ctx->driver_list = (struct sr_dev_driver **)array->data;

View File

@ -20,8 +20,9 @@
#include <config.h>
#include <glib.h>
#include <libsigrok/libsigrok.h>
#include "libsigrok-internal.h"
#ifndef HAVE_LIBSERIALPORT
#ifndef HAVE_SERIAL_COMM
SR_API GSList *sr_serial_list(const struct sr_dev_driver *driver)
{

View File

@ -51,11 +51,7 @@ static const uint64_t samplerates[] = {
};
static const char *data_sources[] = {
"Live",
"Log-Hand",
"Log-Trig",
"Log-Auto",
"Log-Export",
"Live", "Log-Hand", "Log-Trig", "Log-Auto", "Log-Export",
};
extern const struct agdmm_job agdmm_jobs_live[];
@ -64,6 +60,7 @@ extern const struct agdmm_recv agdmm_recvs_u123x[];
extern const struct agdmm_recv agdmm_recvs_u124x[];
extern const struct agdmm_recv agdmm_recvs_u124xc[];
extern const struct agdmm_recv agdmm_recvs_u125x[];
extern const struct agdmm_recv agdmm_recvs_u127x[];
extern const struct agdmm_recv agdmm_recvs_u128x[];
/* This works on all the Agilent U12xxA series, although the
@ -90,6 +87,10 @@ static const struct agdmm_profile supported_agdmm[] = {
{ AGILENT_U1252, "U1252B", 3, agdmm_jobs_live, NULL, agdmm_recvs_u125x },
{ AGILENT_U1253, "U1253B", 3, agdmm_jobs_live, NULL, agdmm_recvs_u125x },
{ AGILENT_U1271, "U1271A", 3, agdmm_jobs_live, NULL, agdmm_recvs_u127x },
{ AGILENT_U1272, "U1272A", 3, agdmm_jobs_live, NULL, agdmm_recvs_u127x },
{ AGILENT_U1273, "U1273A", 3, agdmm_jobs_live, NULL, agdmm_recvs_u127x },
{ KEYSIGHT_U1281, "U1281A", 3, agdmm_jobs_live, agdmm_jobs_log, agdmm_recvs_u128x },
{ KEYSIGHT_U1282, "U1282A", 3, agdmm_jobs_live, agdmm_jobs_log, agdmm_recvs_u128x },
ALL_ZERO
@ -187,25 +188,22 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
return std_scan_complete(di, devices);
}
static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
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;
int ret;
(void)cg;
devc = sdi->priv;
ret = SR_OK;
switch (key) {
case SR_CONF_SAMPLERATE:
*data = g_variant_new_uint64(devc->cur_samplerate);
break;
case SR_CONF_LIMIT_SAMPLES:
case SR_CONF_LIMIT_MSEC:
ret = sr_sw_limits_config_get(&devc->limits, key, data);
break;
return sr_sw_limits_config_get(&devc->limits, key, data);
case SR_CONF_DATA_SOURCE:
*data = g_variant_new_string(data_sources[devc->data_source]);
break;
@ -213,91 +211,54 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s
return SR_ERR_NA;
}
return ret;
return SR_OK;
}
static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
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;
uint64_t samplerate;
const char *tmp_str;
unsigned int i;
int ret;
int idx;
(void)cg;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv;
ret = SR_OK;
switch (key) {
case SR_CONF_SAMPLERATE:
samplerate = g_variant_get_uint64(data);
if (samplerate < samplerates[0] || samplerate > samplerates[1])
ret = SR_ERR_ARG;
else
devc->cur_samplerate = g_variant_get_uint64(data);
return SR_ERR_ARG;
devc->cur_samplerate = g_variant_get_uint64(data);
break;
case SR_CONF_LIMIT_SAMPLES:
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;
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:
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,
const struct sr_channel_group *cg)
static int config_list(uint32_t key, GVariant **data,
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) {
case SR_CONF_SCAN_OPTIONS:
case SR_CONF_DEVICE_OPTIONS:
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
break;
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
case SR_CONF_SAMPLERATE:
g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
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);
*data = std_gvar_samplerates_steps(ARRAY_AND_SIZE(samplerates));
break;
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;
default:
return SR_ERR_NA;
@ -311,9 +272,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
struct dev_context *devc = sdi->priv;
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_conf = sr_next_enabled_channel(sdi, NULL);
devc->cur_sample = 1;
@ -338,7 +296,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
sr_sw_limits_acquisition_start(&devc->limits);
std_session_send_df_header(sdi);
/* Poll every 10ms, or whenever some data comes in. */
serial = sdi->conn;
serial_source_add(sdi->session, serial, G_IO_IN, 10,
agdmm_receive_data, (void *)sdi);
@ -354,7 +311,7 @@ static struct sr_dev_driver agdmm_driver_info = {
.cleanup = std_cleanup,
.scan = scan,
.dev_list = std_dev_list,
.dev_clear = NULL,
.dev_clear = std_dev_clear,
.config_get = config_get,
.config_set = config_set,
.config_list = config_list,

View File

@ -77,7 +77,7 @@ static const struct agdmm_job *job_next(struct dev_context *devc)
devc->current_job++;
if (!job_current(devc)->send)
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);
}
@ -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)
sdi->driver->dev_acquisition_stop(sdi);
sr_dev_acquisition_stop(sdi);
else
dispatch(sdi);
@ -574,6 +574,12 @@ static int recv_conf_u123x(const struct sr_dev_inst *sdi, GMatchInfo *match)
devc->cur_mqflags[i] = 0;
devc->cur_exponent[i] = 0;
devc->cur_digits[i] = 3 - resolution;
} else if (!strcmp(mstr, "MA")) {
devc->cur_mq[i] = SR_MQ_CURRENT;
devc->cur_unit[i] = SR_UNIT_AMPERE;
devc->cur_mqflags[i] = 0;
devc->cur_exponent[i] = -3;
devc->cur_digits[i] = 8 - resolution;
} else if (!strcmp(mstr, "UA")) {
devc->cur_mq[i] = SR_MQ_CURRENT;
devc->cur_unit[i] = SR_UNIT_AMPERE;
@ -600,9 +606,15 @@ static int recv_conf_u123x(const struct sr_dev_inst *sdi, GMatchInfo *match)
} else if (!strcmp(mstr, "DIOD")) {
devc->cur_mq[i] = SR_MQ_VOLTAGE;
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_digits[i] = 3;
} else if (!strcmp(mstr, "TEMP")) {
devc->cur_mq[i] = SR_MQ_TEMPERATURE;
devc->cur_unit[i] = SR_UNIT_CELSIUS;
devc->cur_mqflags[i] = 0;
devc->cur_exponent[i] = 0;
devc->cur_digits[i] = 1;
} else if (!strcmp(mstr, "CAP")) {
devc->cur_mq[i] = SR_MQ_CAPACITANCE;
devc->cur_unit[i] = SR_UNIT_FARAD;
@ -625,14 +637,23 @@ static int recv_conf_u123x(const struct sr_dev_inst *sdi, GMatchInfo *match)
devc->cur_mqflags[i] |= SR_MQFLAG_RMS;
} else if (!strcmp(mstr, "DC")) {
devc->cur_mqflags[i] |= SR_MQFLAG_DC;
} else if (!strcmp(mstr, "ACDC")) {
devc->cur_mqflags[i] |= SR_MQFLAG_AC | SR_MQFLAG_DC | SR_MQFLAG_RMS;
} else {
sr_dbg("Unknown first argument '%s'.", mstr);
sr_dbg("Unknown first argument '%s'.", mstr);
}
g_free(mstr);
} else
devc->cur_mqflags[i] &= ~(SR_MQFLAG_AC | SR_MQFLAG_DC);
return JOB_CONF;
struct sr_channel *prev_conf = devc->cur_conf;
devc->cur_conf = sr_next_enabled_channel(sdi, devc->cur_conf);
if (devc->cur_conf->index >= MIN(devc->profile->nb_channels, 2))
devc->cur_conf = sr_next_enabled_channel(sdi, devc->cur_conf);
if (devc->cur_conf->index > prev_conf->index)
return JOB_AGAIN;
else
return JOB_CONF;
}
static int recv_conf_u124x_5x(const struct sr_dev_inst *sdi, GMatchInfo *match)
@ -738,7 +759,7 @@ static int recv_conf_u124x_5x(const struct sr_dev_inst *sdi, GMatchInfo *match)
} else if (!strcmp(mstr, "DIOD")) {
devc->cur_mq[i] = SR_MQ_VOLTAGE;
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;
if (devc->profile->model == KEYSIGHT_U1281 ||
devc->profile->model == KEYSIGHT_U1282) {
@ -871,7 +892,7 @@ static int recv_log(const struct sr_dev_inst *sdi, GMatchInfo *match,
if (mstr[12] & 1) mqflags |= SR_MQFLAG_AVG;
if (mstr[12] & 2) mqflags |= SR_MQFLAG_MIN;
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);
mq = mqs[function];
@ -1017,12 +1038,24 @@ SR_PRIV const struct agdmm_recv agdmm_recvs_u125x[] = {
{ "^\"(\\d\\d.{18}\\d)\"$", recv_stat_u125x },
{ "^\\*([0-9])$", recv_switch },
{ "^([-+][0-9]\\.[0-9]{8}E[-+][0-9]{2})$", recv_fetc },
{ "^\"(VOLT|CURR|RES|CAP|FREQ) ([-+][0-9\\.E\\-+]+),([-+][0-9]\\.[0-9]{8}E([-+][0-9]{2}))\"$", recv_conf_u124x_5x },
{ "^\"(VOLT:[ACD]+) ([-+][0-9\\.E\\-+]+),([-+][0-9]\\.[0-9]{8}E([-+][0-9]{2}))\"$", recv_conf_u124x_5x },
{ "^\"(CURR:[ACD]+) ([-+][0-9\\.E\\-+]+),([-+][0-9]\\.[0-9]{8}E([-+][0-9]{2}))\"$", recv_conf_u124x_5x },
{ "^\"(CPER:[40]-20mA) ([-+][0-9\\.E\\-+]+),([-+][0-9]\\.[0-9]{8}E([-+][0-9]{2}))\"$", recv_conf_u124x_5x },
{ "^\"(VOLT|CURR|RES|CONT|COND|CAP|FREQ) ([-+][0-9\\.E\\-+]+),([-+][0-9]\\.[0-9]{6}E([-+][0-9]{2}))\"$", recv_conf_u124x_5x },
{ "^\"(VOLT:[ACD]+) ([-+][0-9\\.E\\-+]+),([-+][0-9]\\.[0-9]{6}E([-+][0-9]{2}))\"$", recv_conf_u124x_5x },
{ "^\"(CURR:[ACD]+) ([-+][0-9\\.E\\-+]+),([-+][0-9]\\.[0-9]{6}E([-+][0-9]{2}))\"$", recv_conf_u124x_5x },
{ "^\"(CPER:[40]-20mA) ([-+][0-9\\.E\\-+]+),([-+][0-9]\\.[0-9]{6}E([-+][0-9]{2}))\"$", recv_conf_u124x_5x },
{ "^\"(PULS:PWID|PULS:PWID:[ACD]+) ([-+][0-9\\.E\\-+]+),([-+][0-9]\\.[0-9]{6}E([-+][0-9]{2}))\"$", recv_conf_u124x_5x },
{ "^\"(TEMP:[A-Z]+) ([A-Z]+)\"$", recv_conf_u124x_5x },
{ "^\"(T[0-9]:[A-Z]+) ([A-Z]+)\"$", recv_conf_u124x_5x },
{ "^\"(DIOD)\"$", recv_conf_u124x_5x },
{ "^\"(DIOD|PULS:[PN]DUT)\"$", recv_conf_u124x_5x },
ALL_ZERO
};
SR_PRIV const struct agdmm_recv agdmm_recvs_u127x[] = {
{ "^\"(\\d\\d.{18}\\d)\"$", recv_stat_u123x },
{ "^\\*([0-9])$", recv_switch },
{ "^([-+][0-9]\\.[0-9]{8}E[-+][0-9]{2})$", recv_fetc },
{ "^\"(V|MV|A|MA|UA|FREQ),(\\d),(AC|DC|ACDC)\"$", recv_conf_u123x },
{ "^\"(RES|CAP),(\\d)\"$", recv_conf_u123x},
{ "^\"(DIOD|TEMP)\"$", recv_conf_u123x },
ALL_ZERO
};

View File

@ -54,6 +54,10 @@ enum {
AGILENT_U1252,
AGILENT_U1253,
AGILENT_U1271,
AGILENT_U1272,
AGILENT_U1273,
KEYSIGHT_U1281,
KEYSIGHT_U1282,
};
@ -68,13 +72,11 @@ struct agdmm_profile {
const struct agdmm_recv *recvs;
};
/* Private, per-device-instance driver context. */
struct dev_context {
const struct agdmm_profile *profile;
struct sr_sw_limits limits;
int data_source;
/* Runtime. */
const struct agdmm_job *jobs;
int current_job;
gboolean job_running;

View File

@ -83,7 +83,7 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
/* Let's get a bit of data and see if we can find a packet. */
if (serial_stream_detect(serial, buf, &len, 25,
appa_55ii_packet_valid, 500, 9600) != SR_OK)
appa_55ii_packet_valid, 500) != SR_OK)
goto scan_cleanup;
sr_info("Found device on port %s.", conn);
@ -109,8 +109,8 @@ scan_cleanup:
return std_scan_complete(di, devices);
}
static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
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;
@ -130,35 +130,25 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s
return SR_OK;
}
static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
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;
const char *tmp_str;
unsigned int i;
int idx;
(void)cg;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv;
switch (key) {
case SR_CONF_LIMIT_SAMPLES:
case SR_CONF_LIMIT_MSEC:
return sr_sw_limits_config_set(&devc->limits, key, data);
case SR_CONF_DATA_SOURCE: {
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;
case SR_CONF_DATA_SOURCE:
if ((idx = std_str_idx(data, ARRAY_AND_SIZE(data_sources))) < 0)
return SR_ERR_ARG;
devc->data_source = idx;
break;
}
default:
return SR_ERR_NA;
}
@ -166,26 +156,15 @@ static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sd
return SR_OK;
}
static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
static int config_list(uint32_t key, GVariant **data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
(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:
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;
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
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;
default:
return SR_ERR_NA;
@ -200,16 +179,12 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
struct dev_context *devc;
serial = sdi->conn;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv;
sr_sw_limits_acquisition_start(&devc->limits);
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,
appa_55ii_receive_data, (void *)sdi);
@ -224,7 +199,7 @@ static struct sr_dev_driver appa_55ii_driver_info = {
.cleanup = std_cleanup,
.scan = scan,
.dev_list = std_dev_list,
.dev_clear = NULL,
.dev_clear = std_dev_clear,
.config_get = config_get,
.config_set = config_set,
.config_list = config_list,

View File

@ -224,7 +224,7 @@ static void appa_55ii_log_end(struct sr_dev_inst *sdi)
if (devc->data_source != DATA_SOURCE_MEMORY)
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,
@ -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)) {
sdi->driver->dev_acquisition_stop(sdi);
sr_dev_acquisition_stop(sdi);
return TRUE;
}

View File

@ -36,13 +36,10 @@ enum {
DATA_SOURCE_MEMORY,
};
/** Private, per-device-instance driver context. */
struct dev_context {
/* Acquisition settings */
struct sr_sw_limits limits;
gboolean data_source; /**< Whether to read live samples or memory */
/* Temporary state across callbacks */
uint8_t buf[APPA_55II_BUF_SIZE];
unsigned int buf_len;
uint8_t log_buf[64];

View File

@ -25,6 +25,7 @@
#define CMD_VERSION "version\r\n"
#define CMD_MONITOR "monitor 200\r\n"
#define CMD_MONITOR_STOP "monitor 0\r\n"
static const uint32_t scanopts[] = {
SR_CONF_CONN,
@ -43,7 +44,7 @@ static const uint32_t devopts[] = {
static const uint32_t devopts_cg[] = {
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_CURRENT | SR_CONF_GET,
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_UNDER_VOLTAGE_CONDITION | 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)
@ -94,6 +101,19 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
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,
strlen(CMD_VERSION), serial_timeout(serial,
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");
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);
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,
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) {
/* No channel group: global options. */
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;
}
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
} else {
switch (key) {
case SR_CONF_DEVICE_OPTIONS:
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
devopts_cg, ARRAY_SIZE(devopts_cg), sizeof(uint32_t));
*data = std_gvar_array_u32(ARRAY_AND_SIZE(devopts_cg));
break;
case SR_CONF_REGULATION:
*data = std_gvar_array_str(ARRAY_AND_SIZE(regulation));
break;
case SR_CONF_CURRENT_LIMIT:
g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
/* Min, max, step. */
g_variant_builder_add_value(&gvb, g_variant_new_double(0.0));
g_variant_builder_add_value(&gvb, g_variant_new_double(6.0));
g_variant_builder_add_value(&gvb, g_variant_new_double(0.001)); /* 1mA steps */
*data = g_variant_builder_end(&gvb);
*data = std_gvar_min_max_step(0.0, 6.0, 0.001);
break;
case SR_CONF_UNDER_VOLTAGE_CONDITION_THRESHOLD:
*data = std_gvar_min_max_step(0.0, 60.0, 0.001);
break;
default:
return SR_ERR_NA;
}
}
return ret;
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;
int ret;
float fvalue;
(void)cg;
@ -223,7 +213,6 @@ static int config_get(uint32_t key, GVariant **data,
* - SR_CONF_ENABLED (state cannot be queried, only set)
*/
ret = SR_OK;
switch (key) {
case SR_CONF_LIMIT_SAMPLES:
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);
break;
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;
case SR_CONF_UNDER_VOLTAGE_CONDITION_ACTIVE:
*data = g_variant_new_boolean(devc->uvc_active);
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:
return SR_ERR_NA;
}
return ret;
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 ret;
(void)cg;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv;
ret = SR_OK;
switch (key) {
case SR_CONF_LIMIT_SAMPLES:
case SR_CONF_LIMIT_MSEC:
return sr_sw_limits_config_set(&devc->limits, key, data);
case SR_CONF_ENABLED:
ret = reloadpro_set_on_off(sdi, g_variant_get_boolean(data));
break;
return reloadpro_set_on_off(sdi, g_variant_get_boolean(data));
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));
break;
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)
@ -308,10 +308,9 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
struct dev_context *devc;
struct sr_serial_dev_inst *serial;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv;
devc->acquisition_running = TRUE;
serial = sdi->conn;
/* 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;
}
/* 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);
std_session_send_df_header(sdi);
memset(devc->buf, 0, RELOADPRO_BUFSIZE);
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;
}
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 = {
.name = "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,
.scan = scan,
.dev_list = std_dev_list,
.dev_clear = std_dev_clear,
.config_get = config_get,
.config_set = config_set,
.config_list = config_list,
.dev_open = std_serial_dev_open,
.dev_close = std_serial_dev_close,
.dev_close = dev_close,
.dev_acquisition_start = dev_acquisition_start,
.dev_acquisition_stop = std_serial_dev_acquisition_stop,
.dev_acquisition_stop = dev_acquisition_stop,
.context = NULL,
};
SR_REGISTER_DEV_DRIVER(arachnid_labs_re_load_pro_driver_info);

View File

@ -18,18 +18,21 @@
*/
#include <config.h>
#include <math.h>
#include <string.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,
char *replybuf, int replybufsize)
{
char *bufptr;
int len, ret;
struct dev_context *devc;
struct sr_serial_dev_inst *serial;
devc = sdi->priv;
serial = sdi->conn;
/* Send the command (blocking, with timeout). */
@ -40,82 +43,182 @@ static int send_cmd(const struct sr_dev_inst *sdi, const char *cmd,
return SR_ERR;
}
/* Read the reply (blocking, with timeout). */
memset(replybuf, 0, replybufsize);
bufptr = replybuf;
len = replybufsize;
ret = serial_readline(serial, &bufptr, &len, READ_TIMEOUT_MS);
/* If we got 0 characters (possibly one \r or \n), retry once. */
if (len == 0) {
if (!devc->acquisition_running) {
/* Read the reply (blocking, with timeout). */
memset(replybuf, 0, replybufsize);
bufptr = replybuf;
len = replybufsize;
ret = serial_readline(serial, &bufptr, &len, READ_TIMEOUT_MS);
}
if (g_str_has_prefix((const char *)&bufptr, "err ")) {
sr_err("Device replied with an error: '%s'.", bufptr);
return SR_ERR;
/* If we got 0 characters (possibly one \r or \n), retry once. */
if (len == 0) {
len = replybufsize;
ret = serial_readline(serial, &bufptr, &len, READ_TIMEOUT_MS);
}
if (g_str_has_prefix((const char *)&bufptr, "err ")) {
sr_err("Device replied with an error: '%s'.", bufptr);
return SR_ERR;
}
}
return ret;
}
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;
char buf[100];
char *cmd;
if (current < 0 || current > 6) {
sr_err("The current limit must be 0-6 A (was %f A).", current);
devc = sdi->priv;
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;
}
/* Hardware expects current in mA, integer (0..6000). */
ma = (int)(current * 1000);
sr_err("Setting current limit to %f A (%d mA).", current, ma);
/* Hardware expects current limit in mA, integer (0..6000). */
ma = (int)round(current_limit * 1000);
cmd = g_strdup_printf("set %d\n", ma);
if ((ret = send_cmd(sdi, cmd, (char *)&buf, sizeof(buf))) < 0) {
sr_err("Error sending current limit command: %d.", ret);
g_free(cmd);
return SR_ERR;
}
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 current limit command: %d.", ret);
return SR_ERR;
}
return SR_OK;
}
SR_PRIV int reloadpro_set_on_off(const struct sr_dev_inst *sdi, gboolean on)
{
struct dev_context *devc;
int ret;
char buf[100];
const char *cmd;
devc = sdi->priv;
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);
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;
}
SR_PRIV int reloadpro_get_current_limit(const struct sr_dev_inst *sdi,
float *current)
float *current_limit)
{
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, "set\n", (char *)&buf, sizeof(buf))) < 0) {
sr_err("Error sending current limit query: %d.", ret);
return SR_ERR;
}
/* Hardware sends current in mA, integer (0..6000). */
*current = g_ascii_strtod(buf + 4, NULL) / 1000;
if (devc->acquisition_running) {
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;
}
@ -123,29 +226,47 @@ 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,
float *voltage, float *current)
{
struct dev_context *devc;
int ret;
char buf[100];
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) {
sr_err("Error sending voltage/current query: %d.", ret);
return SR_ERR;
}
/* Reply: "read <current> <voltage>". */
tokens = g_strsplit((const char *)&buf, " ", 3);
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>". */
tokens = g_strsplit((const char *)&buf, " ", 3);
devc->voltage = g_ascii_strtod(tokens[2], NULL) / 1000;
devc->current = g_ascii_strtod(tokens[1], NULL) / 1000;
g_strfreev(tokens);
}
g_mutex_unlock(&devc->acquisition_mutex);
if (voltage)
*voltage = g_ascii_strtod(tokens[2], NULL) / 1000;
*voltage = devc->voltage;
if (current)
*current = g_ascii_strtod(tokens[1], NULL) / 1000;
g_strfreev(tokens);
*current = devc->current;
return SR_OK;
}
static void handle_packet(const struct sr_dev_inst *sdi)
{
float voltage, current;
struct sr_datafeed_packet packet;
struct sr_datafeed_analog analog;
struct sr_analog_encoding encoding;
@ -160,12 +281,49 @@ static void handle_packet(const struct sr_dev_inst *sdi)
if (g_str_has_prefix((const char *)devc->buf, "overtemp")) {
sr_warn("Overtemperature condition!");
devc->otp_active = TRUE;
sr_session_send_meta(sdi, SR_CONF_OVER_TEMPERATURE_PROTECTION_ACTIVE,
g_variant_new_boolean(TRUE));
return;
}
if (g_str_has_prefix((const char *)devc->buf, "undervolt")) {
sr_warn("Undervoltage condition!");
devc->uvc_active = TRUE;
sr_session_send_meta(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);
sr_session_send_meta(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) {
sr_session_send_meta(sdi, SR_CONF_UNDER_VOLTAGE_CONDITION,
g_variant_new_boolean(FALSE));
} else {
sr_session_send_meta(sdi, SR_CONF_UNDER_VOLTAGE_CONDITION,
g_variant_new_boolean(TRUE));
sr_session_send_meta(sdi,
SR_CONF_UNDER_VOLTAGE_CONDITION_THRESHOLD,
g_variant_new_double(devc->uvc_threshold));
}
return;
}
@ -175,8 +333,8 @@ static void handle_packet(const struct sr_dev_inst *sdi)
}
tokens = g_strsplit((const char *)devc->buf, " ", 3);
voltage = g_ascii_strtod(tokens[2], NULL) / 1000;
current = g_ascii_strtod(tokens[1], NULL) / 1000;
devc->voltage = g_ascii_strtod(tokens[2], NULL) / 1000;
devc->current = g_ascii_strtod(tokens[1], NULL) / 1000;
g_strfreev(tokens);
/* Begin frame. */
@ -197,7 +355,8 @@ static void handle_packet(const struct sr_dev_inst *sdi)
meaning.mq = SR_MQ_VOLTAGE;
meaning.mqflags = SR_MQFLAG_DC;
meaning.unit = SR_UNIT_VOLT;
analog.data = &voltage;
encoding.digits = 3;
analog.data = &devc->voltage;
sr_session_send(sdi, &packet);
g_slist_free(l);
@ -208,7 +367,8 @@ static void handle_packet(const struct sr_dev_inst *sdi)
meaning.mq = SR_MQ_CURRENT;
meaning.mqflags = SR_MQFLAG_DC;
meaning.unit = SR_UNIT_AMPERE;
analog.data = &current;
encoding.digits = 3;
analog.data = &devc->current;
sr_session_send(sdi, &packet);
g_slist_free(l);
@ -225,26 +385,34 @@ static void handle_new_data(const struct sr_dev_inst *sdi)
int len;
struct dev_context *devc;
struct sr_serial_dev_inst *serial;
char *buf;
devc = sdi->priv;
serial = sdi->conn;
/* Try to get as much data as the buffer can hold. */
len = RELOADPRO_BUFSIZE - devc->buflen;
len = serial_read_nonblocking(serial, devc->buf + devc->buflen, len);
if (len == 0)
buf = devc->buf;
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. */
}
if (len < 0) {
sr_err("Serial port read error: %d.", len);
g_mutex_unlock(&devc->acquisition_mutex);
return;
}
devc->buflen += len;
if (g_str_has_suffix((const char *)devc->buf, "\n")) {
handle_packet(sdi);
memset(devc->buf, 0, RELOADPRO_BUFSIZE);
devc->buflen = 0;
}
handle_packet(sdi);
g_mutex_unlock(&devc->acquisition_mutex);
memset(devc->buf, 0, RELOADPRO_BUFSIZE);
devc->buflen = 0;
}
SR_PRIV int reloadpro_receive_data(int fd, int revents, void *cb_data)
@ -263,7 +431,7 @@ SR_PRIV int reloadpro_receive_data(int fd, int revents, void *cb_data)
handle_new_data(sdi);
if (sr_sw_limits_check(&devc->limits))
sdi->driver->dev_acquisition_stop(sdi);
sr_dev_acquisition_stop(sdi);
return TRUE;
}

View File

@ -25,24 +25,40 @@
#include <libsigrok/libsigrok.h>
#include "libsigrok-internal.h"
#define LOG_PREFIX "re-load-pro"
#define LOG_PREFIX "arachnid-labs-re-load-pro"
#define RELOADPRO_BUFSIZE 100
/** Private, per-device-instance driver context. */
struct dev_context {
struct sr_sw_limits limits;
uint8_t buf[RELOADPRO_BUFSIZE];
char buf[RELOADPRO_BUFSIZE];
int buflen;
float current_limit;
float voltage;
float current;
gboolean otp_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,
float current);
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,
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,
float *voltage, float *current);
SR_PRIV int reloadpro_receive_data(int fd, int revents, void *cb_data);

View File

@ -19,10 +19,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* ASIX SIGMA/SIGMA2 logic analyzer driver
*/
#include <config.h>
#include "protocol.h"
@ -59,9 +55,14 @@ static const int32_t trigger_matches[] = {
};
#endif
static void clear_helper(struct dev_context *devc)
{
ftdi_deinit(&devc->ftdic);
}
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)
@ -80,8 +81,6 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
ftdi_init(&devc->ftdic);
/* Look for SIGMAs. */
if ((ret = ftdi_usb_find_all(&devc->ftdic, &devlist,
USB_VENDOR, USB_PRODUCT)) <= 0) {
if (ret < 0)
@ -111,18 +110,16 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
devc->capture_ratio = 50;
devc->use_triggers = 0;
/* Register SIGMA device. */
sdi = g_malloc0(sizeof(struct sr_dev_inst));
sdi->status = SR_ST_INITIALIZING;
sdi->vendor = g_strdup(USB_VENDOR_NAME);
sdi->model = g_strdup(USB_MODEL_NAME);
sdi->vendor = g_strdup("ASIX");
sdi->model = g_strdup("SIGMA");
for (i = 0; i < ARRAY_SIZE(channel_names); i++)
sr_channel_new(sdi, i, SR_CHANNEL_LOGIC, TRUE, channel_names[i]);
sdi->priv = devc;
/* We will open the device again when we need it. */
ftdi_list_free(&devlist);
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;
/* Make sure it's an ASIX SIGMA. */
if ((ret = ftdi_usb_open_desc(&devc->ftdic,
USB_VENDOR, USB_PRODUCT, USB_DESCRIPTION, NULL)) < 0) {
sr_err("ftdi_usb_open failed: %s",
ftdi_get_error_string(&devc->ftdic));
return 0;
USB_VENDOR, USB_PRODUCT, USB_DESCRIPTION, NULL)) < 0) {
sr_err("Failed to open device (%d): %s.",
ret, ftdi_get_error_string(&devc->ftdic));
return SR_ERR;
}
sdi->status = SR_ST_ACTIVE;
return SR_OK;
}
@ -161,17 +153,11 @@ static int dev_close(struct sr_dev_inst *sdi)
devc = sdi->priv;
/* TODO */
if (sdi->status == SR_ST_ACTIVE)
ftdi_usb_close(&devc->ftdic);
sdi->status = SR_ST_INACTIVE;
return SR_OK;
return (ftdi_usb_close(&devc->ftdic) == 0) ? SR_OK : SR_ERR;
}
static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
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;
@ -203,81 +189,50 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s
return SR_OK;
}
static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
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;
uint64_t tmp;
int ret;
(void)cg;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv;
ret = SR_OK;
switch (key) {
case SR_CONF_SAMPLERATE:
ret = sigma_set_samplerate(sdi, g_variant_get_uint64(data));
break;
return sigma_set_samplerate(sdi, g_variant_get_uint64(data));
case SR_CONF_LIMIT_MSEC:
tmp = g_variant_get_uint64(data);
if (tmp > 0)
devc->limit_msec = g_variant_get_uint64(data);
else
ret = SR_ERR;
devc->limit_msec = g_variant_get_uint64(data);
break;
case SR_CONF_LIMIT_SAMPLES:
tmp = g_variant_get_uint64(data);
devc->limit_samples = tmp;
devc->limit_msec = sigma_limit_samples_to_msec(devc, tmp);
devc->limit_samples = g_variant_get_uint64(data);
devc->limit_msec = sigma_limit_samples_to_msec(devc,
devc->limit_samples);
break;
#if ASIX_SIGMA_WITH_TRIGGER
case SR_CONF_CAPTURE_RATIO:
tmp = g_variant_get_uint64(data);
if (tmp > 100)
return SR_ERR;
devc->capture_ratio = tmp;
devc->capture_ratio = g_variant_get_uint64(data);
break;
#endif
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,
const struct sr_channel_group *cg)
static int config_list(uint32_t key, GVariant **data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
GVariant *gvar;
GVariantBuilder gvb;
(void)cg;
switch (key) {
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;
return STD_CONFIG_LIST(key, data, sdi, cg, NO_OPTS, drvopts, devopts);
case SR_CONF_SAMPLERATE:
g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
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);
*data = std_gvar_samplerates(samplerates, samplerates_count);
break;
#if ASIX_SIGMA_WITH_TRIGGER
case SR_CONF_TRIGGER_MATCH:
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
trigger_matches, ARRAY_SIZE(trigger_matches),
sizeof(int32_t));
*data = std_gvar_array_i32(ARRAY_AND_SIZE(trigger_matches));
break;
#endif
default:
@ -299,9 +254,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
uint8_t clock_bytes[sizeof(clockselect)];
size_t clock_idx;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv;
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;
devc = sdi->priv;
devc->state.state = SIGMA_IDLE;
sr_session_source_remove(sdi->session, -1);
/*
* 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);
}
return SR_OK;
}

View File

@ -47,7 +47,7 @@ SR_PRIV const uint64_t 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 */
"asix-sigma-50.fw",
/* 100 MHz */
@ -78,12 +78,11 @@ static int sigma_write(void *buf, size_t size, struct dev_context *devc)
int ret;
ret = ftdi_write_data(&devc->ftdic, (unsigned char *)buf, size);
if (ret < 0) {
if (ret < 0)
sr_err("ftdi_write_data failed: %s",
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.");
}
return ret;
}
@ -169,11 +168,17 @@ static int sigma_read_pos(uint32_t *stoppos, uint32_t *triggerpos,
*triggerpos = result[0] | (result[1] << 8) | (result[2] << 16);
*stoppos = result[3] | (result[4] << 8) | (result[5] << 16);
/* Not really sure why this must be done, but according to spec. */
/*
* These "position" values point to after the event (end of
* capture data, trigger condition matched). This is why they
* get decremented here. Sample memory consists of 512-byte
* chunks with meta data in the upper 64 bytes. Thus when the
* decrements takes us into this upper part of the chunk, then
* further move backwards to the end of the chunk's data part.
*/
if ((--*stoppos & 0x1ff) == 0x1ff)
*stoppos -= 64;
if ((*--triggerpos & 0x1ff) == 0x1ff)
if ((--*triggerpos & 0x1ff) == 0x1ff)
*triggerpos -= 64;
return 1;
@ -272,15 +277,6 @@ SR_PRIV int sigma_write_trigger_lut(struct triggerlut *lut, struct dev_context *
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.
* This sequence is documented in section 2. of the ASIX Sigma programming
@ -446,38 +442,27 @@ static int upload_firmware(struct sr_context *ctx,
unsigned char pins;
size_t buf_size;
const char *firmware;
struct ftdi_context *ftdic;
/* Avoid downloading the same firmware multiple times. */
firmware = sigma_firmware_files[firmware_idx];
firmware = firmware_files[firmware_idx];
if (devc->cur_firmware == firmware_idx) {
sr_info("Not uploading firmware file '%s' again.", firmware);
return SR_OK;
}
/* Make sure it's an ASIX SIGMA. */
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);
ret = ftdi_set_bitmode(&devc->ftdic, 0xdf, BITMODE_BITBANG);
if (ret < 0) {
sr_err("ftdi_set_bitmode failed: %s",
ftdi_get_error_string(ftdic));
return 0;
ftdi_get_error_string(&devc->ftdic));
return SR_ERR;
}
/* 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) {
sr_err("ftdi_set_baudrate failed: %s",
ftdi_get_error_string(ftdic));
return 0;
ftdi_get_error_string(&devc->ftdic));
return SR_ERR;
}
/* Initialize the FPGA for firmware upload. */
@ -499,14 +484,14 @@ static int upload_firmware(struct sr_context *ctx,
g_free(buf);
ret = ftdi_set_bitmode(ftdic, 0x00, BITMODE_RESET);
ret = ftdi_set_bitmode(&devc->ftdic, 0x00, BITMODE_RESET);
if (ret < 0) {
sr_err("ftdi_set_bitmode failed: %s",
ftdi_get_error_string(ftdic));
ftdi_get_error_string(&devc->ftdic));
return SR_ERR;
}
ftdi_usb_purge_buffers(ftdic);
ftdi_usb_purge_buffers(&devc->ftdic);
/* Discard garbage. */
while (sigma_read(&pins, 1, devc) == 1)
@ -554,6 +539,7 @@ SR_PRIV int sigma_set_samplerate(const struct sr_dev_inst *sdi, uint64_t sampler
struct drv_context *drvc;
size_t i;
int ret;
int num_channels;
devc = sdi->priv;
drvc = sdi->driver->context;
@ -572,15 +558,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
* of available channels.
*/
num_channels = devc->num_channels;
if (samplerate <= SR_MHZ(50)) {
ret = upload_firmware(drvc->sr_ctx, 0, devc);
devc->num_channels = 16;
num_channels = 16;
} else if (samplerate == SR_MHZ(100)) {
ret = upload_firmware(drvc->sr_ctx, 1, devc);
devc->num_channels = 8;
num_channels = 8;
} else if (samplerate == SR_MHZ(200)) {
ret = upload_firmware(drvc->sr_ctx, 2, devc);
devc->num_channels = 4;
num_channels = 4;
}
/*
@ -589,6 +576,7 @@ SR_PRIV int sigma_set_samplerate(const struct sr_dev_inst *sdi, uint64_t sampler
* an "event" (memory organization internal to the device).
*/
if (ret == SR_OK) {
devc->num_channels = num_channels;
devc->cur_samplerate = samplerate;
devc->samples_per_event = 16 / devc->num_channels;
devc->state.state = SIGMA_IDLE;
@ -663,16 +651,13 @@ SR_PRIV int sigma_convert_trigger(const struct sr_dev_inst *sdi)
if (match->match == SR_TRIGGER_ONE) {
devc->trigger.simplevalue |= 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.simplemask |= channelbit;
}
else if (match->match == SR_TRIGGER_FALLING) {
} else if (match->match == SR_TRIGGER_FALLING) {
devc->trigger.fallingmask |= channelbit;
trigger_set++;
}
else if (match->match == SR_TRIGGER_RISING) {
} else if (match->match == SR_TRIGGER_RISING) {
devc->trigger.risingmask |= channelbit;
trigger_set++;
}
@ -694,7 +679,6 @@ SR_PRIV int sigma_convert_trigger(const struct sr_dev_inst *sdi)
return SR_OK;
}
/* Software trigger to determine exact trigger position. */
static int get_trigger_offset(uint8_t *samples, uint16_t last_sample,
struct sigma_trigger *t)
@ -1031,14 +1015,13 @@ static int download_capture(struct sr_dev_inst *sdi)
devc = sdi->priv;
dl_events_in_line = 64 * 7;
trg_line = ~0;
trg_event = ~0;
dram_line = g_try_malloc0(chunks_per_read * sizeof(*dram_line));
if (!dram_line)
return FALSE;
sr_info("Downloading sample data.");
devc->state.state = SIGMA_DOWNLOAD;
/*
* Ask the hardware to stop data acquisition. Reception of the
@ -1059,6 +1042,8 @@ static int download_capture(struct sr_dev_inst *sdi)
/* Check if trigger has fired. */
modestatus = sigma_get_register(READ_MODE, devc);
trg_line = ~0;
trg_event = ~0;
if (modestatus & RMR_TRIGGERED) {
trg_line = triggerpos >> 9;
trg_event = triggerpos & 0x1ff;
@ -1119,12 +1104,12 @@ static int download_capture(struct sr_dev_inst *sdi)
dl_lines_done += dl_lines_curr;
}
g_free(dram_line);
std_session_send_df_end(sdi);
sdi->driver->dev_acquisition_stop(sdi);
g_free(dram_line);
devc->state.state = SIGMA_IDLE;
sr_dev_acquisition_stop(sdi);
return TRUE;
}
@ -1168,6 +1153,14 @@ SR_PRIV int sigma_receive_data(int fd, int revents, void *cb_data)
if (devc->state.state == SIGMA_IDLE)
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)
return sigma_capture_mode(sdi);

View File

@ -30,6 +30,8 @@
#include <libsigrok/libsigrok.h>
#include "libsigrok-internal.h"
#define LOG_PREFIX "asix-sigma"
/*
* Triggers are not working in this implementation. Stop claiming
* support for the feature which effectively is not available, until
@ -38,13 +40,9 @@
*/
#define ASIX_SIGMA_WITH_TRIGGER 0
#define LOG_PREFIX "asix-sigma"
#define USB_VENDOR 0xa600
#define USB_PRODUCT 0xa000
#define USB_DESCRIPTION "ASIX SIGMA"
#define USB_VENDOR_NAME "ASIX"
#define USB_MODEL_NAME "SIGMA"
enum sigma_write_register {
WRITE_CLOCK_SELECT = 0,
@ -248,14 +246,13 @@ struct sigma_state {
SIGMA_UNINITIALIZED = 0,
SIGMA_IDLE,
SIGMA_CAPTURE,
SIGMA_STOPPING,
SIGMA_DOWNLOAD,
} state;
uint16_t lastts;
uint16_t lastsample;
};
/* Private, per-device-instance driver context. */
struct dev_context {
struct ftdi_context ftdic;
uint64_t cur_samplerate;
@ -267,7 +264,7 @@ struct dev_context {
int num_channels;
int cur_channels;
int samples_per_event;
int capture_ratio;
uint64_t capture_ratio;
struct sigma_trigger trigger;
int use_triggers;
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);
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 void sigma_clear_helper(void *priv);
SR_PRIV uint64_t sigma_limit_samples_to_msec(const struct dev_context *devc,
uint64_t limit_samples);
SR_PRIV int sigma_set_samplerate(const struct sr_dev_inst *sdi, uint64_t samplerate);

View File

@ -182,21 +182,19 @@ static GSList *scan_3203(struct sr_dev_driver *di, GSList *options)
return scan(di, options, PPS_3203T_3S);
}
static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
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_channel *ch;
int channel, ret;
int channel;
if (!sdi)
return SR_ERR_ARG;
devc = sdi->priv;
ret = SR_OK;
if (!cg) {
/* No channel group: global options. */
switch (key) {
case SR_CONF_CHANNEL_CONFIG:
*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)
{
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)
static int config_set(uint32_t key, GVariant *data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
struct dev_context *devc;
struct sr_channel *ch;
gdouble dval;
int channel, ret, ival;
const char *sval;
int channel, ival;
gboolean bval;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
ret = SR_OK;
devc = sdi->priv;
if (!cg) {
/* No channel group: global options. */
switch (key) {
case SR_CONF_CHANNEL_CONFIG:
sval = g_variant_get_string(data, NULL);
if ((ival = find_str(sval, channel_modes,
ARRAY_SIZE(channel_modes))) == -1) {
ret = SR_ERR_ARG;
break;
}
if (devc->model->channel_modes && (1 << ival) == 0) {
/* Not supported on this model. */
ret = SR_ERR_ARG;
}
if ((ival = std_str_idx(data, ARRAY_AND_SIZE(channel_modes))) < 0)
return SR_ERR_ARG;
if (devc->model->channel_modes && (1 << ival) == 0)
return SR_ERR_ARG; /* Not supported on this model. */
if (ival == devc->channel_mode_set)
/* Nothing to do. */
break;
break; /* Nothing to do. */
devc->channel_mode_set = ival;
devc->config_dirty = TRUE;
break;
case SR_CONF_OVER_CURRENT_PROTECTION_ENABLED:
bval = g_variant_get_boolean(data);
if (bval == devc->over_current_protection_set)
/* Nothing to do. */
break;
break; /* Nothing to do. */
devc->over_current_protection_set = bval;
devc->config_dirty = TRUE;
break;
@ -298,7 +268,6 @@ static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sd
return SR_ERR_NA;
}
} else {
/* Channel group specified: per-channel options. */
/* We only ever have one channel per channel group in this driver. */
ch = cg->channels->data;
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:
dval = g_variant_get_double(data);
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_dirty = TRUE;
break;
case SR_CONF_CURRENT_LIMIT:
dval = g_variant_get_double(data);
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_dirty = TRUE;
break;
case SR_CONF_ENABLED:
bval = g_variant_get_boolean(data);
if (bval == devc->config[channel].output_enabled_set)
/* Nothing to do. */
break;
break; /* Nothing to do. */
devc->config[channel].output_enabled_set = bval;
devc->config_dirty = TRUE;
break;
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,
const struct sr_channel_group *cg)
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;
struct sr_channel *ch;
GVariant *gvar;
GVariantBuilder gvb;
int channel, ret, i;
int channel;
/* 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;
}
devc = (sdi) ? sdi->priv : NULL;
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) {
/* No channel group: global options. */
switch (key) {
case SR_CONF_SCAN_OPTIONS:
case SR_CONF_DEVICE_OPTIONS:
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
break;
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
case SR_CONF_CHANNEL_CONFIG:
if (!devc || !devc->model)
return SR_ERR_ARG;
if (devc->model->channel_modes == CHANMODE_INDEPENDENT) {
/* The 1-channel models. */
*data = g_variant_new_strv(channel_modes, 1);
} else {
/* 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;
default:
return SR_ERR_NA;
}
} 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. */
ch = cg->channels->data;
channel = ch->index;
switch (key) {
case SR_CONF_DEVICE_OPTIONS:
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
devopts_cg, ARRAY_SIZE(devopts_cg), sizeof(uint32_t));
*data = std_gvar_array_u32(ARRAY_AND_SIZE(devopts_cg));
break;
case SR_CONF_VOLTAGE_TARGET:
g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
/* Min, max, step. */
for (i = 0; i < 3; i++) {
gvar = g_variant_new_double(devc->model->channels[channel].voltage[i]);
g_variant_builder_add_value(&gvb, gvar);
}
*data = g_variant_builder_end(&gvb);
if (!devc || !devc->model)
return SR_ERR_ARG;
*data = std_gvar_min_max_step_array(devc->model->channels[channel].voltage);
break;
case SR_CONF_CURRENT_LIMIT:
g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
/* Min, max, step. */
for (i = 0; i < 3; i++) {
gvar = g_variant_new_double(devc->model->channels[channel].current[i]);
g_variant_builder_add_value(&gvb, gvar);
}
*data = g_variant_builder_end(&gvb);
if (!devc || !devc->model)
return SR_ERR_ARG;
*data = std_gvar_min_max_step_array(devc->model->channels[channel].current);
break;
default:
return SR_ERR_NA;
}
}
return ret;
return SR_OK;
}
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;
devc = sdi->priv;
if (devc->config_dirty)
/* Some configuration changes were queued up but didn't
* 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;
uint8_t packet[PACKET_SIZE];
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv;
memset(devc->packet, 0x44, PACKET_SIZE);
devc->packet_size = 0;
@ -466,9 +402,6 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi)
{
struct dev_context *devc;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv;
devc->acquisition_running = FALSE;
@ -483,7 +416,7 @@ static struct sr_dev_driver atten_pps3203_driver_info = {
.cleanup = std_cleanup,
.scan = scan_3203,
.dev_list = std_dev_list,
.dev_clear = NULL,
.dev_clear = std_dev_clear,
.config_get = config_get,
.config_set = config_set,
.config_list = config_list,

View File

@ -71,15 +71,11 @@ struct per_channel_config {
gboolean output_enabled_set;
};
/** Private, per-device-instance driver context. */
struct dev_context {
/* Model-specific information */
const struct pps_model *model;
/* Acquisition state */
gboolean acquisition_running;
/* Operational state */
gboolean config_dirty;
struct per_channel_config *config;
/* Blocking write timeout for packet. */
@ -91,7 +87,6 @@ struct dev_context {
int channel_mode_set;
gboolean over_current_protection_set;
/* Temporary state across callbacks */
uint8_t packet[PACKET_SIZE];
int packet_size;

View File

@ -22,6 +22,11 @@
#include <time.h>
#include <sys/timerfd.h>
static const uint32_t drvopts[] = {
SR_CONF_THERMOMETER,
SR_CONF_POWERMETER,
};
static const uint32_t devopts[] = {
SR_CONF_CONTINUOUS,
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
@ -126,27 +131,8 @@ err_out:
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,
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;
int ret;
@ -156,11 +142,11 @@ static int config_get(uint32_t key, GVariant **data,
devc = sdi->priv;
ret = SR_OK;
switch (key) {
case SR_CONF_LIMIT_SAMPLES:
case SR_CONF_LIMIT_MSEC:
ret = sr_sw_limits_config_get(&devc->limits, key, data);
break;
return sr_sw_limits_config_get(&devc->limits, key, data);
case SR_CONF_SAMPLERATE:
*data = g_variant_new_uint64(devc->samplerate);
break;
@ -186,30 +172,22 @@ static int config_get(uint32_t key, GVariant **data,
}
static int config_set(uint32_t key, GVariant *data,
const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
struct dev_context *devc;
uint64_t samplerate;
int ret;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv;
ret = SR_OK;
switch (key) {
case SR_CONF_LIMIT_SAMPLES:
case SR_CONF_LIMIT_MSEC:
ret = sr_sw_limits_config_set(&devc->limits, key, data);
break;
return sr_sw_limits_config_set(&devc->limits, key, data);
case SR_CONF_SAMPLERATE:
samplerate = g_variant_get_uint64(data);
if (samplerate > MAX_SAMPLE_RATE) {
sr_err("Maximum sample rate is %d", MAX_SAMPLE_RATE);
ret = SR_ERR_SAMPLERATE;
break;
return SR_ERR_SAMPLERATE;
}
devc->samplerate = 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:
if (!cg)
return SR_ERR_CHANNEL_GROUP;
ret = bl_acme_set_shunt(cg, g_variant_get_uint64(data));
break;
return bl_acme_set_shunt(cg, g_variant_get_uint64(data));
case SR_CONF_POWER_OFF:
if (!cg)
return SR_ERR_CHANNEL_GROUP;
ret = bl_acme_set_power_off(cg, g_variant_get_boolean(data));
break;
return bl_acme_set_power_off(cg, g_variant_get_boolean(data));
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,
const struct sr_channel_group *cg)
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
uint32_t devopts_cg[MAX_DEVOPTS_CG];
GVariant *gvar;
GVariantBuilder gvb;
int ret, num_devopts_cg = 0;
int num_devopts_cg = 0;
(void)sdi;
(void)cg;
ret = SR_OK;
if (!cg) {
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;
return STD_CONFIG_LIST(key, data, sdi, cg, NO_OPTS, drvopts, devopts);
case SR_CONF_SAMPLERATE:
g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
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);
*data = std_gvar_samplerates_steps(ARRAY_AND_SIZE(samplerates));
break;
default:
return SR_ERR_NA;
@ -269,15 +231,14 @@ static int config_list(uint32_t key, GVariant **data,
if (bl_acme_probe_has_pws(cg))
devopts_cg[num_devopts_cg++] = HAS_POWER_OFF;
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
devopts_cg, num_devopts_cg, sizeof(uint32_t));
*data = std_gvar_array_u32(devopts_cg, num_devopts_cg);
break;
default:
return SR_ERR_NA;
}
}
return ret;
return SR_OK;
}
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 }
};
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
if (dev_acquisition_open(sdi))
return SR_ERR;
@ -360,9 +318,6 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi)
devc = sdi->priv;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
dev_acquisition_close(sdi);
sr_session_source_remove_channel(sdi->session, devc->channel);
g_io_channel_shutdown(devc->channel, FALSE, NULL);
@ -385,11 +340,12 @@ static struct sr_dev_driver baylibre_acme_driver_info = {
.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_open = std_dummy_dev_open,
.dev_close = std_dummy_dev_close,
.dev_acquisition_start = dev_acquisition_start,
.dev_acquisition_stop = dev_acquisition_stop,
.context = NULL,

View File

@ -166,8 +166,10 @@ SR_PRIV gboolean bl_acme_detect_probe(unsigned int addr,
probe_name_path(addr, path);
status = g_file_get_contents(path->str, &buf, &size, &err);
if (!status) {
sr_dbg("Name for probe %d can't be read: %s",
prb_num, err->message);
/* Don't log "No such file or directory" messages. */
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_error_free(err);
return ret;
@ -308,11 +310,11 @@ static int read_probe_eeprom(unsigned int addr, struct probe_eeprom *eeprom)
static int revB_addr_to_num(unsigned int addr)
{
switch (addr) {
case 0x44: return 5;
case 0x45: return 6;
case 0x42: return 3;
case 0x43: return 4;
default: return addr - 0x3f;
case 0x44: return 5;
case 0x45: return 6;
case 0x42: return 3;
case 0x43: return 4;
default: return addr - 0x3f;
}
}
@ -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);
if (sr_sw_limits_check(&devc->limits)) {
sdi->driver->dev_acquisition_stop(sdi);
sr_dev_acquisition_stop(sdi);
return TRUE;
}

View File

@ -49,7 +49,6 @@ enum probe_type {
PROBE_TEMP,
};
/** Private, per-device-instance driver context. */
struct dev_context {
uint64_t samplerate;
struct sr_sw_limits limits;

View File

@ -1,7 +1,7 @@
/*
* 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
* it under the terms of the GNU General Public License as published by
@ -21,24 +21,25 @@
#include "protocol.h"
#include "beaglelogic.h"
/* Scan options */
static const uint32_t scanopts[] = {
SR_CONF_CONN,
SR_CONF_NUM_LOGIC_CHANNELS,
};
/* Hardware capabilities */
static const uint32_t devopts[] = {
static const uint32_t drvopts[] = {
SR_CONF_LOGIC_ANALYZER,
};
static const uint32_t devopts[] = {
SR_CONF_CONTINUOUS,
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_CAPTURE_RATIO | SR_CONF_GET | SR_CONF_SET,
SR_CONF_NUM_LOGIC_CHANNELS | SR_CONF_GET,
};
/* Trigger matching capabilities */
static const int32_t soft_trigger_matches[] = {
static const int32_t trigger_matches[] = {
SR_TRIGGER_ZERO,
SR_TRIGGER_ONE,
SR_TRIGGER_RISING,
@ -58,67 +59,78 @@ static const uint64_t samplerates[] = {
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)
{
GSList *l;
struct sr_config *src;
struct sr_dev_inst *sdi;
struct dev_context *devc;
const char *conn;
gchar **params;
int i, maxch;
/* Probe for /dev/beaglelogic */
if (!g_file_test(BEAGLELOGIC_DEV_NODE, G_FILE_TEST_EXISTS))
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;
maxch = NUM_CHANNELS;
conn = NULL;
for (l = options; l; l = l->next) {
src = l->data;
if (src->key == SR_CONF_NUM_LOGIC_CHANNELS)
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 */
devc = beaglelogic_devc_alloc();
if (beaglelogic_open_nonblock(devc) != SR_OK) {
g_free(devc);
sr_dev_inst_free(sdi);
return NULL;
}
if (maxch > 8) {
maxch = NUM_CHANNELS;
devc->sampleunit = BL_SAMPLEUNIT_16_BITS;
/* Probe for /dev/beaglelogic if not connecting via TCP */
if (!conn) {
params = NULL;
if (!g_file_test(BEAGLELOGIC_DEV_NODE, G_FILE_TEST_EXISTS))
return NULL;
} else {
maxch = 8;
devc->sampleunit = BL_SAMPLEUNIT_8_BITS;
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;
}
}
beaglelogic_set_sampleunit(devc);
beaglelogic_close(devc);
maxch = (maxch > 8) ? NUM_CHANNELS : 8;
/* Signal */
sr_info("BeagleLogic device found at "BEAGLELOGIC_DEV_NODE);
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);
} 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 */
for (i = 0; i < maxch; i++)
@ -128,6 +140,16 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
sdi->priv = devc;
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)
@ -135,30 +157,39 @@ static int dev_open(struct sr_dev_inst *sdi)
struct dev_context *devc = sdi->priv;
/* Open BeagleLogic */
if (beaglelogic_open_nonblock(devc))
if (devc->beaglelogic->open(devc))
return SR_ERR;
/* Set fd and local attributes */
devc->pollfd.fd = devc->fd;
if (devc->beaglelogic == &beaglelogic_tcp_ops)
devc->pollfd.fd = devc->socket;
else
devc->pollfd.fd = devc->fd;
devc->pollfd.events = G_IO_IN;
devc->pollfd.revents = 0;
/* Get the default attributes */
beaglelogic_get_samplerate(devc);
beaglelogic_get_sampleunit(devc);
beaglelogic_get_triggerflags(devc);
beaglelogic_get_buffersize(devc);
beaglelogic_get_bufunitsize(devc);
devc->beaglelogic->get_samplerate(devc);
devc->beaglelogic->get_sampleunit(devc);
devc->beaglelogic->get_buffersize(devc);
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 */
if (beaglelogic_mmap(devc) != SR_OK) {
sr_err("Unable to map capture buffer");
beaglelogic_close(devc);
return SR_ERR;
if (devc->beaglelogic == &beaglelogic_native_ops) {
if (devc->beaglelogic->mmap(devc) != SR_OK) {
sr_err("Unable to map capture buffer");
devc->beaglelogic->close(devc);
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;
}
@ -166,17 +197,28 @@ static int dev_close(struct sr_dev_inst *sdi)
{
struct dev_context *devc = sdi->priv;
if (sdi->status == SR_ST_ACTIVE) {
/* Close the memory mapping and the file */
beaglelogic_munmap(devc);
beaglelogic_close(devc);
}
sdi->status = SR_ST_INACTIVE;
/* Close the memory mapping and the file */
if (devc->beaglelogic == &beaglelogic_native_ops)
devc->beaglelogic->munmap(devc);
devc->beaglelogic->close(devc);
return SR_OK;
}
static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
static void clear_helper(struct dev_context *devc)
{
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;
@ -202,21 +244,18 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s
return SR_OK;
}
static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
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 = sdi->priv;
uint64_t tmp_u64;
(void)cg;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
switch (key) {
case SR_CONF_SAMPLERATE:
devc->cur_samplerate = g_variant_get_uint64(data);
return beaglelogic_set_samplerate(devc);
return devc->beaglelogic->set_samplerate(devc);
case SR_CONF_LIMIT_SAMPLES:
tmp_u64 = g_variant_get_uint64(data);
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("Please use \'echo <size in bytes> > "\
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",
devc->buffersize /
(SAMPLEUNIT_TO_BYTES(devc->sampleunit) * 1000000));
}
return beaglelogic_set_triggerflags(devc);
return devc->beaglelogic->set_triggerflags(devc);
case SR_CONF_CAPTURE_RATIO:
devc->capture_ratio = g_variant_get_uint64(data);
if (devc->capture_ratio > 100)
return SR_ERR;
return SR_OK;
break;
default:
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;
}
static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
static int config_list(uint32_t key, GVariant **data,
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) {
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;
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
case SR_CONF_SAMPLERATE:
g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
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);
*data = std_gvar_samplerates_steps(ARRAY_AND_SIZE(samplerates));
break;
case SR_CONF_TRIGGER_MATCH:
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
soft_trigger_matches, ARRAY_SIZE(soft_trigger_matches),
sizeof(int32_t));
*data = std_gvar_array_i32(ARRAY_AND_SIZE(trigger_matches));
break;
default:
return SR_ERR_NA;
}
return ret;
return SR_OK;
}
/* 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)
{
struct dev_context *devc = sdi->priv;
GSList *l;
struct sr_trigger *trigger;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
struct sr_channel *channel;
/* Clear capture state */
devc->bytes_read = 0;
devc->offset = 0;
/* Configure channels */
devc->sampleunit = g_slist_length(sdi->channels) > 8 ?
BL_SAMPLEUNIT_16_BITS : BL_SAMPLEUNIT_8_BITS;
beaglelogic_set_sampleunit(devc);
devc->sampleunit = BL_SAMPLEUNIT_8_BITS;
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 */
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;
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;
@ -320,9 +346,14 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
std_session_send_df_header(sdi);
/* Trigger and add poll on file */
beaglelogic_start(devc);
sr_session_source_add_pollfd(sdi->session, &devc->pollfd,
BUFUNIT_TIMEOUT_MS(devc), beaglelogic_receive_data,
devc->beaglelogic->start(devc);
if (devc->beaglelogic == &beaglelogic_native_ops)
sr_session_source_add_pollfd(sdi->session, &devc->pollfd,
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);
return SR_OK;
@ -332,14 +363,14 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi)
{
struct dev_context *devc = sdi->priv;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
/* Execute a stop on BeagleLogic */
beaglelogic_stop(devc);
devc->beaglelogic->stop(devc);
/* lseek to offset 0, flushes the cache */
lseek(devc->fd, 0, SEEK_SET);
/* Flush the cache */
if (devc->beaglelogic == &beaglelogic_native_ops)
lseek(devc->fd, 0, SEEK_SET);
else
beaglelogic_tcp_drain(devc);
/* Remove session source and send EOT packet */
sr_session_source_remove_pollfd(sdi->session, &devc->pollfd);
@ -356,6 +387,7 @@ static struct sr_dev_driver beaglelogic_driver_info = {
.cleanup = std_cleanup,
.scan = scan,
.dev_list = std_dev_list,
.dev_clear = dev_clear,
.config_get = config_get,
.config_set = config_set,
.config_list = config_list,

View File

@ -1,7 +1,7 @@
/*
* 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
* 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_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_GET_BUFFER_SIZE _IOR('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_SET_BUFUNIT_SIZE _IOW('k', 0x27, uint32_t)
#define IOCTL_BL_FILL_TEST_PATTERN _IO('k', 0x28)
@ -90,120 +92,41 @@ enum beaglelogic_sampleunit {
* SR_OK or SR_ERR
*/
SR_PRIV int beaglelogic_open_nonblock(struct dev_context *devc);
SR_PRIV int beaglelogic_close(struct dev_context *devc);
struct beaglelogic_ops {
int (*open)(struct dev_context *devc);
int (*close)(struct dev_context *devc);
SR_PRIV int beaglelogic_get_buffersize(struct dev_context *devc);
SR_PRIV int beaglelogic_set_buffersize(struct dev_context *devc);
int (*get_buffersize)(struct dev_context *devc);
int (*set_buffersize)(struct dev_context *devc);
SR_PRIV int beaglelogic_get_samplerate(struct dev_context *devc);
SR_PRIV int beaglelogic_set_samplerate(struct dev_context *devc);
int (*get_samplerate)(struct dev_context *devc);
int (*set_samplerate)(struct dev_context *devc);
SR_PRIV int beaglelogic_get_sampleunit(struct dev_context *devc);
SR_PRIV int beaglelogic_set_sampleunit(struct dev_context *devc);
int (*get_sampleunit)(struct dev_context *devc);
int (*set_sampleunit)(struct dev_context *devc);
SR_PRIV int beaglelogic_get_triggerflags(struct dev_context *devc);
SR_PRIV int beaglelogic_set_triggerflags(struct dev_context *devc);
int (*get_triggerflags)(struct dev_context *devc);
int (*set_triggerflags)(struct dev_context *devc);
/* Start and stop the capture operation */
SR_PRIV int beaglelogic_start(struct dev_context *devc);
SR_PRIV int beaglelogic_stop(struct dev_context *devc);
/* Start and stop the capture operation */
int (*start)(struct dev_context *devc);
int (*stop)(struct dev_context *devc);
/* Get the last error size */
SR_PRIV int beaglelogic_getlasterror(struct dev_context *devc);
/* Get the last error size */
int (*get_lasterror)(struct dev_context *devc);
/* Gets the unit size of the capture buffer (usually 4 or 8 MB) */
SR_PRIV int beaglelogic_get_bufunitsize(struct dev_context *devc);
/* Gets the unit size of the capture buffer (usually 4 or 8 MB) */
int (*get_bufunitsize)(struct dev_context *devc);
int (*set_bufunitsize)(struct dev_context *devc);
SR_PRIV int beaglelogic_mmap(struct dev_context *devc);
SR_PRIV int beaglelogic_munmap(struct dev_context *devc);
int (*mmap)(struct dev_context *devc);
int (*munmap)(struct dev_context *devc);
};
/* Sources */
SR_PRIV inline 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);
}
SR_PRIV extern const struct beaglelogic_ops beaglelogic_native_ops;
SR_PRIV extern const struct beaglelogic_ops beaglelogic_tcp_ops;
SR_PRIV inline int beaglelogic_close(struct dev_context *devc) {
return close(devc->fd);
}
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);
}
SR_PRIV int beaglelogic_tcp_detect(struct dev_context *devc);
SR_PRIV int beaglelogic_tcp_drain(struct dev_context *devc);
#endif

View File

@ -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,
};

View File

@ -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 %" PRIu32, 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 %" PRIu32,
(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 %" PRIu32, 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 %" PRIu32, 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 %" PRIu32, 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,
};

View File

@ -1,7 +1,7 @@
/*
* 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
* it under the terms of the GNU General Public License as published by
@ -21,7 +21,16 @@
#include <stdlib.h>
#include <string.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 "beaglelogic.h"
/* Define data packet size independent of packet (bufunitsize bytes) size
* from the BeagleLogic kernel module */
@ -32,7 +41,7 @@
* kernel buffers appropriately. It is up to the application which is
* 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;
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) {
/* One shot capture, we abort and settle with less than
* the required number of samples */
if (devc->triggerflags)
if (devc->triggerflags == BL_TRIGGERFLAGS_CONTINUOUS)
devc->offset = 0;
else
packetsize = 0;
@ -107,3 +116,90 @@ SR_PRIV int beaglelogic_receive_data(int fd, int revents, void *cb_data)
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;
}

View File

@ -1,7 +1,7 @@
/*
* 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
* 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 TCP_BUFFER_SIZE (128 * 1024)
/** Private, per-device-instance driver context. */
struct dev_context {
/* Model-specific information */
int max_channels;
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 */
uint64_t cur_samplerate;
uint64_t limit_samples;
@ -49,7 +60,6 @@ struct dev_context {
uint32_t bufunitsize;
uint32_t buffersize;
/* Operational state */
int fd;
GPollFD pollfd;
int last_error;
@ -64,6 +74,7 @@ struct dev_context {
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

View File

@ -1,258 +0,0 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include "protocol.h"
#define BRYMEN_BC86X "0820.0001"
static const uint32_t scanopts[] = {
SR_CONF_CONN,
};
static const uint32_t devopts[] = {
SR_CONF_MULTIMETER,
SR_CONF_CONTINUOUS,
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET,
};
static GSList *scan(struct sr_dev_driver *di, GSList *options)
{
GSList *usb_devices, *devices, *l;
struct drv_context *drvc;
struct dev_context *devc;
struct sr_dev_inst *sdi;
struct sr_usb_dev_inst *usb;
struct sr_config *src;
const char *conn;
drvc = di->context;
conn = BRYMEN_BC86X;
for (l = options; l; l = l->next) {
src = l->data;
switch (src->key) {
case SR_CONF_CONN:
conn = g_variant_get_string(src->data, NULL);
break;
}
}
devices = NULL;
if (!(usb_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn))) {
g_slist_free_full(usb_devices, g_free);
return NULL;
}
for (l = usb_devices; l; l = l->next) {
usb = l->data;
sdi = g_malloc0(sizeof(struct sr_dev_inst));
sdi->status = SR_ST_INACTIVE;
sdi->vendor = g_strdup("Brymen");
sdi->model = g_strdup("BM869");
devc = g_malloc0(sizeof(struct dev_context));
sdi->priv = devc;
sr_channel_new(sdi, 0, SR_CHANNEL_ANALOG, TRUE, "P1");
sr_channel_new(sdi, 0, SR_CHANNEL_ANALOG, TRUE, "P2");
sdi->inst_type = SR_INST_USB;
sdi->conn = usb;
sr_sw_limits_init(&devc->sw_limits);
devices = g_slist_append(devices, sdi);
}
return std_scan_complete(di, devices);
}
static int dev_open(struct sr_dev_inst *sdi)
{
struct sr_dev_driver *di = sdi->driver;
struct drv_context *drvc = di->context;
struct sr_usb_dev_inst *usb;
struct dev_context *devc;
int ret;
usb = sdi->conn;
devc = sdi->priv;
if ((ret = sr_usb_open(drvc->sr_ctx->libusb_ctx, usb)) == SR_OK)
sdi->status = SR_ST_ACTIVE;
else
return SR_ERR;
/* Detach kernel drivers which grabbed this device (if any). */
if (libusb_kernel_driver_active(usb->devhdl, 0) == 1) {
ret = libusb_detach_kernel_driver(usb->devhdl, 0);
if (ret < 0) {
sr_err("Failed to detach kernel driver: %s.",
libusb_error_name(ret));
return SR_ERR;
}
devc->detached_kernel_driver = 1;
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) {
sr_err("Failed to claim interface 0: %s.",
libusb_error_name(ret));
return SR_ERR;
}
sr_dbg("Successfully claimed interface 0.");
return ret;
}
static int dev_close(struct sr_dev_inst *sdi)
{
struct sr_usb_dev_inst *usb;
struct dev_context *devc;
int ret;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
usb = sdi->conn;
devc = sdi->priv;
if ((ret = libusb_release_interface(usb->devhdl, 0)))
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 = libusb_attach_kernel_driver(usb->devhdl, 0))) {
sr_err("Failed to attach kernel driver: %s.\n",
libusb_error_name(ret));
} else {
devc->detached_kernel_driver = 0;
sr_dbg("Successfully attached kernel driver.\n");
}
}
libusb_close(usb->devhdl);
sdi->status = SR_ST_INACTIVE;
return ret;
}
static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
{
struct dev_context *devc = sdi->priv;
(void)cg;
return sr_sw_limits_config_get(&devc->sw_limits, key, data);
}
static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
{
struct dev_context *devc;
(void)cg;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv;
return sr_sw_limits_config_set(&devc->sw_limits, key, data);
}
static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
{
(void)sdi;
(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)
{
struct dev_context *devc;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv;
sr_sw_limits_acquisition_start(&devc->sw_limits);
std_session_send_df_header(sdi);
sr_session_source_add(sdi->session, -1, 0, 10,
brymen_bm86x_receive_data, (void *)sdi);
return SR_OK;
}
static int dev_acquisition_stop(struct sr_dev_inst *sdi)
{
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
std_session_send_df_end(sdi);
sr_session_source_remove(sdi->session, -1);
return SR_OK;
}
static struct sr_dev_driver brymen_bm86x_driver_info = {
.name = "brymen-bm86x",
.longname = "Brymen BM86X",
.api_version = 1,
.init = std_init,
.cleanup = std_cleanup,
.scan = scan,
.dev_list = std_dev_list,
.dev_clear = NULL,
.config_get = config_get,
.config_set = config_set,
.config_list = config_list,
.dev_open = dev_open,
.dev_close = dev_close,
.dev_acquisition_start = dev_acquisition_start,
.dev_acquisition_stop = dev_acquisition_stop,
.context = NULL,
};
SR_REGISTER_DEV_DRIVER(brymen_bm86x_driver_info);

View File

@ -1,350 +0,0 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <string.h>
#include <math.h>
#include "protocol.h"
#define USB_TIMEOUT 500
static const char char_map[128] = {
[0x20] = '-',
[0x5F] = '0',
[0x50] = '1',
[0x6D] = '2',
[0x7C] = '3',
[0x72] = '4',
[0x3E] = '5',
[0x3F] = '6',
[0x54] = '7',
[0x7F] = '8',
[0x7E] = '9',
[0x0F] = 'C',
[0x27] = 'F',
[0x0B] = 'L',
[0x79] = 'd',
[0x10] = 'i',
[0x39] = 'o',
};
static int brymen_bm86x_parse_digits(const unsigned char *buf, int length,
char *str, float *floatval,
char *temp_unit, int *digits, int flag)
{
char c, *p = str;
int i, ret;
*digits = INT_MIN;
if (buf[0] & flag)
*p++ = '-';
for (i = 0; i < length; i++) {
if (i && i < 5 && buf[i+1] & 0x01) {
*p++ = '.';
*digits = 0;
}
c = char_map[buf[i+1] >> 1];
if (i == 5 && (c == 'C' || c == 'F'))
*temp_unit = c;
else if (c) {
*p++ = c;
(*digits)++;
}
}
*p = 0;
if (*digits < 0)
*digits = 0;
if ((ret = sr_atof_ascii(str, floatval))) {
sr_dbg("invalid float string: '%s'", str);
return ret;
}
return SR_OK;
}
static void brymen_bm86x_parse(unsigned char *buf, float *floatval,
struct sr_datafeed_analog *analog)
{
char str[16], temp_unit;
int ret1, ret2, digits[2], over_limit;
ret1 = brymen_bm86x_parse_digits(buf+2, 6, str, &floatval[0],
&temp_unit, &digits[0], 0x80);
over_limit = strstr(str, "0L") || strstr(str, "0.L");
ret2 = brymen_bm86x_parse_digits(buf+9, 4, str, &floatval[1],
&temp_unit, &digits[1], 0x10);
/* main display */
if (ret1 == SR_OK || over_limit) {
/* SI unit */
if (buf[8] & 0x01) {
analog[0].meaning->mq = SR_MQ_VOLTAGE;
analog[0].meaning->unit = SR_UNIT_VOLT;
if (!strcmp(str, "diod"))
analog[0].meaning->mqflags |= SR_MQFLAG_DIODE;
} else if (buf[14] & 0x80) {
analog[0].meaning->mq = SR_MQ_CURRENT;
analog[0].meaning->unit = SR_UNIT_AMPERE;
} else if (buf[14] & 0x20) {
analog[0].meaning->mq = SR_MQ_CAPACITANCE;
analog[0].meaning->unit = SR_UNIT_FARAD;
} else if (buf[14] & 0x10) {
analog[0].meaning->mq = SR_MQ_CONDUCTANCE;
analog[0].meaning->unit = SR_UNIT_SIEMENS;
} else if (buf[15] & 0x01) {
analog[0].meaning->mq = SR_MQ_FREQUENCY;
analog[0].meaning->unit = SR_UNIT_HERTZ;
} else if (buf[10] & 0x01) {
analog[0].meaning->mq = SR_MQ_CONTINUITY;
analog[0].meaning->unit = SR_UNIT_OHM;
} else if (buf[15] & 0x10) {
analog[0].meaning->mq = SR_MQ_RESISTANCE;
analog[0].meaning->unit = SR_UNIT_OHM;
} else if (buf[15] & 0x02) {
analog[0].meaning->mq = SR_MQ_POWER;
analog[0].meaning->unit = SR_UNIT_DECIBEL_MW;
} else if (buf[15] & 0x80) {
analog[0].meaning->mq = SR_MQ_DUTY_CYCLE;
analog[0].meaning->unit = SR_UNIT_PERCENTAGE;
} else if (buf[ 2] & 0x0A) {
analog[0].meaning->mq = SR_MQ_TEMPERATURE;
if (temp_unit == 'F')
analog[0].meaning->unit = SR_UNIT_FAHRENHEIT;
else
analog[0].meaning->unit = SR_UNIT_CELSIUS;
}
/* when MIN MAX and AVG are displayed at the same time, remove them */
if ((buf[1] & 0xE0) == 0xE0)
buf[1] &= ~0xE0;
/* AC/DC/Auto flags */
if (buf[1] & 0x10) analog[0].meaning->mqflags |= SR_MQFLAG_DC;
if (buf[2] & 0x01) analog[0].meaning->mqflags |= SR_MQFLAG_AC;
if (buf[1] & 0x01) analog[0].meaning->mqflags |= SR_MQFLAG_AUTORANGE;
if (buf[1] & 0x08) analog[0].meaning->mqflags |= SR_MQFLAG_HOLD;
if (buf[1] & 0x20) analog[0].meaning->mqflags |= SR_MQFLAG_MAX;
if (buf[1] & 0x40) analog[0].meaning->mqflags |= SR_MQFLAG_MIN;
if (buf[1] & 0x80) analog[0].meaning->mqflags |= SR_MQFLAG_AVG;
if (buf[3] & 0x01) analog[0].meaning->mqflags |= SR_MQFLAG_RELATIVE;
/* when dBm is displayed, remove the m suffix so that it is
not considered as the 10e-3 SI prefix */
if (buf[15] & 0x02)
buf[15] &= ~0x04;
/* SI prefix */
if (buf[14] & 0x40) { floatval[0] *= 1e-9; digits[0] += 9; } /* n */
if (buf[15] & 0x08) { floatval[0] *= 1e-6; digits[0] += 6; } /* µ */
if (buf[15] & 0x04) { floatval[0] *= 1e-3; digits[0] += 3; } /* m */
if (buf[15] & 0x40) { floatval[0] *= 1e3; digits[0] -= 3; } /* k */
if (buf[15] & 0x20) { floatval[0] *= 1e6; digits[0] -= 6; } /* M */
if (over_limit) floatval[0] = INFINITY;
analog[0].encoding->digits = digits[0];
analog[0].spec->spec_digits = digits[0];
}
/* secondary display */
if (ret2 == SR_OK) {
/* SI unit */
if (buf[14] & 0x08) {
analog[1].meaning->mq = SR_MQ_VOLTAGE;
analog[1].meaning->unit = SR_UNIT_VOLT;
} else if (buf[9] & 0x04) {
analog[1].meaning->mq = SR_MQ_CURRENT;
analog[1].meaning->unit = SR_UNIT_AMPERE;
} else if (buf[9] & 0x08) {
analog[1].meaning->mq = SR_MQ_CURRENT;
analog[1].meaning->unit = SR_UNIT_PERCENTAGE;
} else if (buf[14] & 0x04) {
analog[1].meaning->mq = SR_MQ_FREQUENCY;
analog[1].meaning->unit = SR_UNIT_HERTZ;
} else if (buf[9] & 0x40) {
analog[1].meaning->mq = SR_MQ_TEMPERATURE;
if (temp_unit == 'F')
analog[1].meaning->unit = SR_UNIT_FAHRENHEIT;
else
analog[1].meaning->unit = SR_UNIT_CELSIUS;
}
/* AC flag */
if (buf[9] & 0x20) analog[1].meaning->mqflags |= SR_MQFLAG_AC;
/* SI prefix */
if (buf[ 9] & 0x01) { floatval[1] *= 1e-6; digits[1] += 6; } /* µ */
if (buf[ 9] & 0x02) { floatval[1] *= 1e-3; digits[1] += 3; } /* m */
if (buf[14] & 0x02) { floatval[1] *= 1e3; digits[1] -= 3; } /* k */
if (buf[14] & 0x01) { floatval[1] *= 1e6; digits[1] -= 6; } /* M */
analog[1].encoding->digits = digits[1];
analog[1].spec->spec_digits = digits[1];
}
if (buf[9] & 0x80)
sr_spew("Battery is low.");
}
static void brymen_bm86x_handle_packet(const struct sr_dev_inst *sdi,
unsigned char *buf)
{
struct dev_context *devc;
struct sr_datafeed_packet packet;
struct sr_datafeed_analog analog[2];
struct sr_analog_encoding encoding[2];
struct sr_analog_meaning meaning[2];
struct sr_analog_spec spec[2];
float floatval[2];
devc = sdi->priv;
/* Note: digits/spec_digits will be overridden later. */
sr_analog_init(&analog[0], &encoding[0], &meaning[0], &spec[0], 0);
sr_analog_init(&analog[1], &encoding[1], &meaning[1], &spec[1], 0);
brymen_bm86x_parse(buf, floatval, analog);
if (analog[0].meaning->mq != 0) {
/* Got a measurement. */
analog[0].num_samples = 1;
analog[0].data = &floatval[0];
analog[0].meaning->channels = g_slist_append(NULL, sdi->channels->data);
packet.type = SR_DF_ANALOG;
packet.payload = &analog[0];
sr_session_send(sdi, &packet);
g_slist_free(analog[0].meaning->channels);
}
if (analog[1].meaning->mq != 0) {
/* Got a measurement. */
analog[1].num_samples = 1;
analog[1].data = &floatval[1];
analog[1].meaning->channels = g_slist_append(NULL, sdi->channels->next->data);
packet.type = SR_DF_ANALOG;
packet.payload = &analog[1];
sr_session_send(sdi, &packet);
g_slist_free(analog[1].meaning->channels);
}
if (analog[0].meaning->mq != 0 || analog[1].meaning->mq != 0)
sr_sw_limits_update_samples_read(&devc->sw_limits, 1);
}
static int brymen_bm86x_send_command(const struct sr_dev_inst *sdi)
{
struct sr_usb_dev_inst *usb;
unsigned char buf[] = { 0x00, 0x86, 0x66 };
int ret;
usb = sdi->conn;
sr_dbg("Sending HID set report.");
ret = libusb_control_transfer(usb->devhdl,
LIBUSB_REQUEST_TYPE_CLASS |
LIBUSB_RECIPIENT_INTERFACE |
LIBUSB_ENDPOINT_OUT,
9, /* bRequest: HID set_report */
0x300, /* wValue: HID feature, report num 0 */
0, /* wIndex: interface 0 */
buf, sizeof(buf), USB_TIMEOUT);
if (ret < 0) {
sr_err("HID feature report error: %s.", libusb_error_name(ret));
return SR_ERR;
}
if (ret != sizeof(buf)) {
sr_err("Short packet: sent %d/%zu bytes.", ret, sizeof(buf));
return SR_ERR;
}
return SR_OK;
}
static int brymen_bm86x_read_interrupt(const struct sr_dev_inst *sdi)
{
struct dev_context *devc;
struct sr_usb_dev_inst *usb;
unsigned char buf[24];
int ret, transferred;
devc = sdi->priv;
usb = sdi->conn;
sr_dbg("Reading HID interrupt report.");
/* Get data from EP1 using an interrupt transfer. */
ret = libusb_interrupt_transfer(usb->devhdl,
LIBUSB_ENDPOINT_IN | 1, /* EP1, IN */
buf, sizeof(buf),
&transferred, USB_TIMEOUT);
if (ret == LIBUSB_ERROR_TIMEOUT) {
if (++devc->interrupt_pending > 3)
devc->interrupt_pending = 0;
return SR_OK;
}
if (ret < 0) {
sr_err("USB receive error: %s.", libusb_error_name(ret));
return SR_ERR;
}
if (transferred != sizeof(buf)) {
sr_err("Short packet: received %d/%zu bytes.", transferred, sizeof(buf));
return SR_ERR;
}
devc->interrupt_pending = 0;
brymen_bm86x_handle_packet(sdi, buf);
return SR_OK;
}
SR_PRIV int brymen_bm86x_receive_data(int fd, int revents, void *cb_data)
{
struct sr_dev_inst *sdi;
struct dev_context *devc;
(void)fd;
(void)revents;
if (!(sdi = cb_data))
return TRUE;
if (!(devc = sdi->priv))
return TRUE;
if (!devc->interrupt_pending) {
if (brymen_bm86x_send_command(sdi))
return FALSE;
devc->interrupt_pending = 1;
}
if (brymen_bm86x_read_interrupt(sdi))
return FALSE;
if (sr_sw_limits_check(&devc->sw_limits))
sdi->driver->dev_acquisition_stop(sdi);
return TRUE;
}

View File

@ -25,8 +25,11 @@ static const uint32_t scanopts[] = {
SR_CONF_SERIALCOMM,
};
static const uint32_t devopts[] = {
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,
@ -58,7 +61,7 @@ static GSList *brymen_scan(struct sr_dev_driver *di, const char *conn,
goto scan_cleanup;
}
len = 128;
len = sizeof(buf);
ret = brymen_stream_detect(serial, buf, &len, brymen_packet_length,
brymen_packet_is_valid, 1000, 9600);
if (ret != SR_OK)
@ -107,52 +110,30 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
if (!conn)
return NULL;
if (serialcomm) {
/* Use the provided comm specs. */
if (serialcomm)
devices = brymen_scan(di, conn, serialcomm);
} else {
/* But 9600/8n1 should work all of the time. */
else
devices = brymen_scan(di, conn, "9600/8n1/dtr=1/rts=1");
}
return devices;
}
static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
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;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv;
return sr_sw_limits_config_set(&devc->sw_limits, key, data);
}
static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
static int config_list(uint32_t key, GVariant **data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
(void)sdi;
(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;
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
}
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 sr_serial_dev_inst *serial;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv;
sr_sw_limits_acquisition_start(&devc->sw_limits);
std_session_send_df_header(sdi);
/* Poll every 50ms, or whenever some data comes in. */
serial = sdi->conn;
serial_source_add(sdi->session, serial, G_IO_IN, 50,
brymen_dmm_receive_data, (void *)sdi);
@ -184,7 +161,7 @@ static struct sr_dev_driver brymen_bm857_driver_info = {
.cleanup = std_cleanup,
.scan = scan,
.dev_list = std_dev_list,
.dev_clear = NULL,
.dev_clear = std_dev_clear,
.config_get = NULL,
.config_set = config_set,
.config_list = config_list,

View File

@ -276,7 +276,7 @@ SR_PRIV int brymen_parse(const uint8_t *buf, float *floatval,
}
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. */
if (flags.is_ac)
analog->meaning->mqflags |= SR_MQFLAG_AC;

View File

@ -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))
sdi->driver->dev_acquisition_stop(sdi);
sr_dev_acquisition_stop(sdi);
return TRUE;
}

View File

@ -38,7 +38,6 @@ enum packet_len_status {
PACKET_INVALID_HEADER,
};
/** Private, per-device-instance driver context. */
struct dev_context {
struct sr_sw_limits sw_limits;

View File

@ -125,11 +125,10 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
return std_scan_complete(di, devices);
}
static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
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;
GVariant *range[2];
uint64_t low, high;
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;
devc = sdi->priv;
ret = SR_OK;
switch (key) {
case SR_CONF_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);
break;
case SR_CONF_SPL_MEASUREMENT_RANGE:
if ((ret = cem_dt_885x_meas_range_get(sdi, &low, &high)) == SR_OK) {
range[0] = g_variant_new_uint64(low);
range[1] = g_variant_new_uint64(high);
*data = g_variant_new_tuple(range, 2);
}
if ((ret = cem_dt_885x_meas_range_get(sdi, &low, &high)) == SR_OK)
*data = std_gvar_tuple_u64(low, high);
break;
case SR_CONF_POWER_OFF:
*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;
}
static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
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;
uint64_t tmp_u64, low, high;
unsigned int i;
int tmp, ret;
const char *tmp_str;
int tmp, idx;
(void)cg;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv;
ret = SR_OK;
switch (key) {
case SR_CONF_LIMIT_SAMPLES:
tmp_u64 = g_variant_get_uint64(data);
devc->limit_samples = tmp_u64;
ret = SR_OK;
devc->limit_samples = g_variant_get_uint64(data);
break;
case SR_CONF_DATALOG:
ret = cem_dt_885x_recording_set(sdi, g_variant_get_boolean(data));
break;
return cem_dt_885x_recording_set(sdi, g_variant_get_boolean(data));
case SR_CONF_SPL_WEIGHT_FREQ:
tmp_str = g_variant_get_string(data, NULL);
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
if ((idx = std_str_idx(data, ARRAY_AND_SIZE(weight_freq))) < 0)
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:
tmp_str = g_variant_get_string(data, NULL);
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
if ((idx = std_str_idx(data, ARRAY_AND_SIZE(weight_time))) < 0)
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:
tmp = g_variant_get_boolean(data) ? SR_MQFLAG_MAX : 0;
ret = cem_dt_885x_holdmode_set(sdi, tmp);
break;
return cem_dt_885x_holdmode_set(sdi, tmp);
case SR_CONF_HOLD_MIN:
tmp = g_variant_get_boolean(data) ? SR_MQFLAG_MIN : 0;
ret = cem_dt_885x_holdmode_set(sdi, tmp);
break;
return cem_dt_885x_holdmode_set(sdi, tmp);
case SR_CONF_SPL_MEASUREMENT_RANGE:
g_variant_get(data, "(tt)", &low, &high);
ret = SR_ERR_ARG;
for (i = 0; i < ARRAY_SIZE(meas_ranges); i++) {
if (meas_ranges[i][0] == low && meas_ranges[i][1] == high) {
ret = cem_dt_885x_meas_range_set(sdi, low, high);
break;
}
}
break;
if ((idx = std_u64_tuple_idx(data, ARRAY_AND_SIZE(meas_ranges))) < 0)
return SR_ERR_ARG;
return cem_dt_885x_meas_range_set(sdi, meas_ranges[idx][0], meas_ranges[idx][1]);
case SR_CONF_POWER_OFF:
if (g_variant_get_boolean(data))
ret = cem_dt_885x_power_off(sdi);
return cem_dt_885x_power_off(sdi);
break;
case SR_CONF_DATA_SOURCE:
tmp_str = g_variant_get_string(data, NULL);
if (!strcmp(tmp_str, "Live"))
devc->cur_data_source = DATA_SOURCE_LIVE;
else if (!strcmp(tmp_str, "Memory"))
devc->cur_data_source = DATA_SOURCE_MEMORY;
else
return SR_ERR;
devc->enable_data_source_memory = devc->cur_data_source == DATA_SOURCE_MEMORY;
if ((idx = std_str_idx(data, ARRAY_AND_SIZE(data_sources))) < 0)
return SR_ERR_ARG;
devc->cur_data_source = idx;
devc->enable_data_source_memory = (idx == DATA_SOURCE_MEMORY);
break;
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,
const struct sr_channel_group *cg)
static int config_list(uint32_t key, GVariant **data,
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) {
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,
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:
*data = g_variant_new_strv(weight_freq, ARRAY_SIZE(weight_freq));
break;
case SR_CONF_SPL_WEIGHT_TIME:
*data = g_variant_new_strv(weight_time, ARRAY_SIZE(weight_time));
break;
case SR_CONF_SPL_MEASUREMENT_RANGE:
g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
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;
case SR_CONF_DATA_SOURCE:
*data = g_variant_new_strv(data_sources, ARRAY_SIZE(data_sources));
break;
default:
return SR_ERR_NA;
}
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_SPL_WEIGHT_FREQ:
*data = g_variant_new_strv(ARRAY_AND_SIZE(weight_freq));
break;
case SR_CONF_SPL_WEIGHT_TIME:
*data = g_variant_new_strv(ARRAY_AND_SIZE(weight_time));
break;
case SR_CONF_SPL_MEASUREMENT_RANGE:
*data = std_gvar_tuple_array(ARRAY_AND_SIZE(meas_ranges));
break;
case SR_CONF_DATA_SOURCE:
*data = g_variant_new_strv(ARRAY_AND_SIZE(data_sources));
break;
default:
return SR_ERR_NA;
}
return ret;
return SR_OK;
}
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 sr_serial_dev_inst *serial;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv;
devc->state = ST_INIT;
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);
/* Poll every 100ms, or whenever some data comes in. */
serial = sdi->conn;
serial_source_add(sdi->session, serial, G_IO_IN, 150,
cem_dt_885x_receive_data, (void *)sdi);
@ -372,7 +301,7 @@ static struct sr_dev_driver cem_dt_885x_driver_info = {
.cleanup = std_cleanup,
.scan = scan,
.dev_list = std_dev_list,
.dev_clear = NULL,
.dev_clear = std_dev_clear,
.config_get = config_get,
.config_set = config_set,
.config_list = config_list,

View File

@ -147,7 +147,7 @@ static void process_mset(const struct sr_dev_inst *sdi)
devc->num_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;
case TOKEN_RECORDING_ON:
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;
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;
}
@ -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
* way to tell where stored data ends and live
* 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) {
devc->buf_len = 0;
devc->state = ST_GET_LOG_RECORD_DATA;
@ -346,7 +346,8 @@ static void process_byte(const struct sr_dev_inst *sdi, const unsigned char c,
g_variant_new_uint64(devc->buf[7] * 1000));
meta.config = g_slist_append(NULL, src);
sr_session_send(sdi, &packet);
g_free(src);
g_slist_free(meta.config);
sr_config_free(src);
devc->buf_len = 0;
}
} else if (devc->state == ST_GET_LOG_RECORD_DATA) {
@ -400,7 +401,7 @@ SR_PRIV int cem_dt_885x_receive_data(int fd, int revents, void *cb_data)
} else {
/* Tell device to start transferring from memory. */
cmd = CMD_TRANSFER_MEMORY;
serial_write_nonblocking(serial, &cmd, 1);
serial_write_blocking(serial, &cmd, 1, 0);
}
}
}
@ -456,7 +457,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
* whether the command worked or not, and resend if needed. */
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;
if (wait_for_token(sdi, tokens, timeout) == SR_ERR)
return SR_ERR;
@ -817,7 +818,7 @@ SR_PRIV int cem_dt_885x_power_off(const struct sr_dev_inst *sdi)
cmd = CMD_TOGGLE_POWER_OFF;
while (TRUE) {
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;
/* It never takes more than 23ms for the next token to arrive. */
g_usleep(25 * 1000);

View File

@ -87,23 +87,18 @@ enum {
DATA_SOURCE_MEMORY,
};
/** Private, per-device-instance driver context. */
struct dev_context {
/* Device state */
enum sr_mqflag cur_mqflags;
int recording;
int cur_meas_range;
int cur_data_source;
/* Acquisition settings */
uint64_t limit_samples;
/* Operational state */
int state;
uint64_t num_samples;
gboolean enable_data_source_memory;
/* Temporary state across callbacks */
unsigned char cmd;
unsigned char token;
int buf_len;

View File

@ -109,55 +109,30 @@ static GSList *scan(GSList *options, int idx)
if (!conn)
return NULL;
if (serialcomm) {
/* Use the provided comm specs. */
if (serialcomm)
devices = center_scan(conn, serialcomm, idx);
} else {
/* Try the default. */
else
devices = center_scan(conn, center_devs[idx].conn, idx);
}
return std_scan_complete(center_devs[idx].di, devices);
}
static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
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;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv;
return sr_sw_limits_config_set(&devc->sw_limits, key, data);
}
static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
static int config_list(uint32_t key, GVariant **data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
(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:
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;
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
}
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 sr_serial_dev_inst *serial;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv;
sr_sw_limits_acquisition_start(&devc->sw_limits);
std_session_send_df_header(sdi);
/* Poll every 500ms, or whenever some data comes in. */
serial = sdi->conn;
serial_source_add(sdi->session, serial, G_IO_IN, 500,
center_devs[idx].receive_data, (void *)sdi);
@ -202,6 +173,7 @@ static struct sr_dev_driver ID##_driver_info = { \
.cleanup = std_cleanup, \
.scan = scan_##ID_UPPER, \
.dev_list = std_dev_list, \
.dev_clear = std_dev_clear, \
.config_get = NULL, \
.config_set = config_set, \
.config_list = config_list, \

View File

@ -177,7 +177,7 @@ static gboolean handle_new_data(struct sr_dev_inst *sdi, int idx)
{
struct dev_context *devc;
struct sr_serial_dev_inst *serial;
int len, i, offset = 0, ret = FALSE;
int len, offset, ret = FALSE;
devc = sdi->priv;
serial = sdi->conn;
@ -193,6 +193,7 @@ static gboolean handle_new_data(struct sr_dev_inst *sdi, int idx)
devc->buflen += len;
/* Now look for packets in that data. */
offset = 0;
while ((devc->buflen - offset) >= center_devs[idx].packet_size) {
if (center_devs[idx].packet_valid(devc->buf + offset)) {
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. */
for (i = 0; i < devc->buflen - offset; i++)
devc->buf[i] = devc->buf[offset + i];
if (offset < devc->buflen)
memmove(devc->buf, devc->buf + offset, devc->buflen - offset);
devc->buflen -= offset;
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))
sdi->driver->dev_acquisition_stop(sdi);
sr_dev_acquisition_stop(sdi);
return TRUE;
}

View File

@ -51,7 +51,6 @@ extern SR_PRIV const struct center_dev_info center_devs[];
#define SERIAL_BUFSIZE 256
/** Private, per-device-instance driver context. */
struct dev_context {
struct sr_sw_limits sw_limits;

View File

@ -20,14 +20,14 @@
#include <config.h>
#include "protocol.h"
static const uint32_t drvopts[] = {
SR_CONF_LOGIC_ANALYZER,
};
static const uint32_t scanopts[] = {
SR_CONF_CONN,
};
static const uint32_t drvopts[] = {
SR_CONF_LOGIC_ANALYZER,
};
static const uint32_t devopts[] = {
SR_CONF_LIMIT_MSEC | SR_CONF_SET,
SR_CONF_LIMIT_SAMPLES | SR_CONF_SET | SR_CONF_LIST,
@ -43,21 +43,15 @@ static const int32_t trigger_matches[] = {
SR_TRIGGER_FALLING,
};
static int dev_acquisition_stop(struct sr_dev_inst *sdi);
static void clear_helper(void *priv)
static void clear_helper(struct dev_context *devc)
{
struct dev_context *devc;
devc = priv;
ftdi_free(devc->ftdic);
g_free(devc->final_buf);
}
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,
@ -71,7 +65,6 @@ static int add_device(int model, struct libusb_device_descriptor *des,
ret = SR_OK;
/* Allocate memory for our private device context. */
devc = g_malloc0(sizeof(struct dev_context));
/* 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. */
devc->cur_samplerate = devc->prof->max_samplerate;
/* Register the device with libsigrok. */
sdi = g_malloc0(sizeof(struct sr_dev_inst));
sdi->status = SR_ST_INACTIVE;
sdi->vendor = g_strdup("ChronoVu");
@ -200,18 +192,17 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
continue;
}
usb_get_port_path(devlist[i], connection_id, sizeof(connection_id));
libusb_close(hdl);
if (!strcmp(product, "ChronoVu LA8")) {
model = 0;
} else if (!strcmp(product, "ChronoVu LA16")) {
model = 1;
} else {
sr_spew("Unknown iProduct string '%s'.", product);
if (usb_get_port_path(devlist[i], connection_id, sizeof(connection_id)) < 0)
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).",
product, des.idVendor, des.idProduct,
@ -237,7 +228,6 @@ static int dev_open(struct sr_dev_inst *sdi)
devc = sdi->priv;
/* Allocate memory for the FTDI context and initialize it. */
if (!(devc->ftdic = ftdi_new())) {
sr_err("Failed to initialize libftdi.");
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,
devc->usb_vid, devc->usb_pid);
/* Open the device. */
if ((ret = ftdi_usb_open_desc(devc->ftdic, devc->usb_vid,
devc->usb_pid, devc->prof->iproduct, NULL)) < 0) {
sr_err("Failed to open FTDI device (%d): %s.",
ret, ftdi_get_error_string(devc->ftdic));
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) {
sr_err("Failed to purge FTDI buffers (%d): %s.",
ret, ftdi_get_error_string(devc->ftdic));
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) {
sr_err("Failed to enable FTDI flow control (%d): %s.",
ret, ftdi_get_error_string(devc->ftdic));
goto err_ftdi_free;
}
sr_dbg("FTDI flow control enabled successfully.");
/* Wait 100ms. */
g_usleep(100 * 1000);
sdi->status = SR_ST_ACTIVE;
if (ret == SR_OK)
return SR_OK;
return SR_OK;
err_ftdi_free:
ftdi_free(devc->ftdic); /* Close device (if open), free FTDI context. */
devc->ftdic = NULL;
return ret;
return SR_ERR;
}
static int dev_close(struct sr_dev_inst *sdi)
@ -290,25 +270,23 @@ static int dev_close(struct sr_dev_inst *sdi)
int ret;
struct dev_context *devc;
if (sdi->status != SR_ST_ACTIVE)
return SR_OK;
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.",
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,
const struct sr_channel_group *cg)
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;
char str[128];
(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:
if (!sdi || !(usb = sdi->conn))
return SR_ERR_ARG;
snprintf(str, 128, "%d.%d", usb->bus, usb->address);
*data = g_variant_new_string(str);
*data = g_variant_new_printf("%d.%d", usb->bus, usb->address);
break;
case SR_CONF_SAMPLERATE:
if (!sdi)
@ -332,16 +309,13 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s
return SR_OK;
}
static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
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;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv;
switch (key) {
@ -350,13 +324,9 @@ static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sd
return SR_ERR;
break;
case SR_CONF_LIMIT_MSEC:
if (g_variant_get_uint64(data) == 0)
return SR_ERR_ARG;
devc->limit_msec = g_variant_get_uint64(data);
break;
case SR_CONF_LIMIT_SAMPLES:
if (g_variant_get_uint64(data) == 0)
return SR_ERR_ARG;
devc->limit_samples = g_variant_get_uint64(data);
break;
default:
@ -366,57 +336,30 @@ static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sd
return SR_OK;
}
static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
static int config_list(uint32_t key, GVariant **data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
GVariant *gvar, *grange[2];
GVariantBuilder gvb;
struct dev_context *devc;
(void)cg;
devc = (sdi) ? sdi->priv : NULL;
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;
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
case SR_CONF_SAMPLERATE:
if (!sdi)
return SR_ERR_BUG;
devc = sdi->priv;
cv_fill_samplerates_if_needed(sdi);
g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
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);
*data = std_gvar_samplerates(ARRAY_AND_SIZE(devc->samplerates));
break;
case SR_CONF_LIMIT_SAMPLES:
if (!sdi || !sdi->priv || !(devc = sdi->priv) || !devc->prof)
if (!devc || !devc->prof)
return SR_ERR_BUG;
grange[0] = g_variant_new_uint64(0);
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);
*data = std_gvar_tuple_u64(0, (devc->prof->model == CHRONOVU_LA8) ? MAX_NUM_SAMPLES : MAX_NUM_SAMPLES / 2);
break;
case SR_CONF_TRIGGER_MATCH:
if (!sdi || !sdi->priv || !(devc = sdi->priv) || !devc->prof)
if (!devc || !devc->prof)
return SR_ERR_BUG;
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
trigger_matches, devc->prof->num_trigger_matches,
sizeof(int32_t));
*data = std_gvar_array_i32(trigger_matches, devc->prof->num_trigger_matches);
break;
default:
return SR_ERR_NA;
@ -452,7 +395,7 @@ static int receive_data(int fd, int revents, void *cb_data)
/* Get one block of data. */
if ((ret = cv_read_block(devc)) < 0) {
sr_err("Failed to read data block: %d.", ret);
dev_acquisition_stop(sdi);
sr_dev_acquisition_stop(sdi);
return FALSE;
}
@ -475,7 +418,7 @@ static int receive_data(int fd, int revents, void *cb_data)
for (i = 0; i < NUM_BLOCKS; i++)
cv_send_block_to_session_bus(sdi, i);
dev_acquisition_stop(sdi);
sr_dev_acquisition_stop(sdi);
return TRUE;
}
@ -486,9 +429,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
uint8_t buf[8];
int bytes_to_write, bytes_written;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv;
if (!devc->ftdic) {
@ -534,8 +474,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
return SR_ERR;
}
sr_dbg("Hardware acquisition started successfully.");
std_session_send_df_header(sdi);
/* 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)
{
sr_dbg("Stopping acquisition.");
sr_session_source_remove(sdi->session, -1);
std_session_send_df_end(sdi);

View File

@ -300,6 +300,11 @@ SR_PRIV int cv_convert_trigger(const struct sr_dev_inst *sdi)
|| match->match == SR_TRIGGER_RISING)
devc->trigger_pattern |= channel_bit;
/* LA8 and LA16 support state triggering. */
if (match->match == SR_TRIGGER_ONE
|| match->match == SR_TRIGGER_ZERO)
devc->trigger_mask |= channel_bit;
/* LA16 (but not LA8) supports edge triggering. */
if ((devc->prof->model == CHRONOVU_LA16)) {
if (match->match == SR_TRIGGER_RISING

View File

@ -28,7 +28,7 @@
#include <libsigrok/libsigrok.h>
#include "libsigrok-internal.h"
#define LOG_PREFIX "la8/la16"
#define LOG_PREFIX "chronovu-la"
#define SDRAM_SIZE (8 * 1024 * 1024)
#define MAX_NUM_SAMPLES SDRAM_SIZE
@ -44,28 +44,18 @@ enum {
struct cv_profile {
int model;
const char *modelname;
const char *iproduct; /* USB iProduct string */
const char *iproduct;
unsigned int num_channels;
uint64_t max_samplerate;
const int num_trigger_matches;
float trigger_constant;
};
/* Private, per-device-instance driver context. */
struct dev_context {
/** Device profile struct for this device. */
const struct cv_profile *prof;
/** FTDI device context (used by libftdi). */
struct ftdi_context *ftdic;
/** The currently configured samplerate of the device. */
uint64_t cur_samplerate;
/** The current sampling limit (in ms). */
uint64_t limit_msec;
/** The current sampling limit (in number of samples). */
uint64_t limit_samples;
/**
@ -124,7 +114,6 @@ struct dev_context {
uint64_t samplerates[255];
};
/* protocol.c */
extern SR_PRIV const char *cv_channel_names[];
extern const struct cv_profile cv_profiles[];
SR_PRIV void cv_fill_samplerates_if_needed(const struct sr_dev_inst *sdi);

View File

@ -35,8 +35,11 @@ static const uint32_t scanopts[] = {
SR_CONF_SERIALCOMM,
};
static const uint32_t devopts[] = {
static const uint32_t drvopts[] = {
SR_CONF_SOUNDLEVELMETER,
};
static const uint32_t devopts[] = {
SR_CONF_CONTINUOUS,
SR_CONF_LIMIT_SAMPLES | 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));
}
static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
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;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
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)
static int config_list(uint32_t key, GVariant **data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
(void)sdi;
(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;
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
}
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 sr_serial_dev_inst *serial;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
sr_sw_limits_acquisition_start(&devc->limits);
std_session_send_df_header(sdi);
/* Poll every 150ms, or whenever some data comes in. */
serial = sdi->conn;
serial_source_add(sdi->session, serial, G_IO_IN, 150,
colead_slm_receive_data, (void *)sdi);
@ -145,7 +125,7 @@ static struct sr_dev_driver colead_slm_driver_info = {
.cleanup = std_cleanup,
.scan = scan,
.dev_list = std_dev_list,
.dev_clear = NULL,
.dev_clear = std_dev_clear,
.config_get = NULL,
.config_set = config_set,
.config_list = config_list,

View File

@ -177,7 +177,7 @@ static void process_packet(const struct sr_dev_inst *sdi)
sr_sw_limits_update_samples_read(&devc->limits, 1);
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)
@ -202,7 +202,7 @@ SR_PRIV int colead_slm_receive_data(int fd, int revents, void *cb_data)
serial = sdi->conn;
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,
* or some garbage. Unless it's a single "data ready" byte,
* we don't want it. */

View File

@ -31,7 +31,6 @@ enum {
COMMAND_SENT,
};
/** Private, per-device-instance driver context. */
struct dev_context {
struct sr_sw_limits limits;

View File

@ -17,14 +17,6 @@
* 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 "protocol.h"
@ -35,15 +27,19 @@ static const uint32_t scanopts[] = {
SR_CONF_SERIALCOMM,
};
static const uint32_t devopts[] = {
static const uint32_t drvopts[] = {
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,
};
static GSList *scan(struct sr_dev_driver *di, GSList *options)
{
struct dev_context *devc;
struct sr_dev_inst *sdi;
struct sr_config *src;
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->vendor = g_strdup("Conrad");
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->priv = NULL;
sdi->priv = devc;
sr_channel_new(sdi, 0, SR_CHANNEL_ANALOG, TRUE, "CH1");
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,
const struct sr_channel_group *cg)
static int config_set(uint32_t key, GVariant *data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
int ret;
double dblval;
(void)cg;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
switch (key) {
case SR_CONF_VOLTAGE:
case SR_CONF_VOLTAGE_TARGET:
dblval = g_variant_get_double(data);
if ((dblval < 0.0) || (dblval > 35.0)) {
sr_err("Voltage out of range (0 - 35.0)!");
return SR_ERR_ARG;
}
ret = send_msg1(sdi, 'V', (int) (dblval * 10 + 0.5));
break;
case SR_CONF_CURRENT:
return send_msg1(sdi, 'V', (int) (dblval * 10 + 0.5));
case SR_CONF_CURRENT_LIMIT:
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)!");
return SR_ERR_ARG;
}
ret = send_msg1(sdi, 'C', (int) (dblval * 100 + 0.5));
break;
return send_msg1(sdi, 'C', (int) (dblval * 100 + 0.5));
case SR_CONF_OVER_CURRENT_PROTECTION_ENABLED:
if (g_variant_get_boolean(data))
ret = send_msg1(sdi, 'V', 900);
return send_msg1(sdi, 'V', 900);
else /* Constant current mode */
ret = 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;
return send_msg1(sdi, 'V', 901);
default:
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;
}
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)
return SR_ERR_DEV_CLOSED;
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_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;
}
@ -185,14 +156,14 @@ static struct sr_dev_driver conrad_digi_35_cpu_driver_info = {
.cleanup = std_cleanup,
.scan = scan,
.dev_list = std_dev_list,
.dev_clear = NULL,
.dev_clear = std_dev_clear,
.config_get = NULL,
.config_set = config_set,
.config_list = config_list,
.dev_open = std_serial_dev_open,
.dev_close = std_serial_dev_close,
.dev_acquisition_start = dev_acquisition_start,
.dev_acquisition_stop = dev_acquisition_stop,
.dev_acquisition_start = std_dummy_dev_acquisition_start,
.dev_acquisition_stop = std_dummy_dev_acquisition_stop,
.context = NULL,
};
SR_REGISTER_DEV_DRIVER(conrad_digi_35_cpu_driver_info);

View File

@ -17,12 +17,6 @@
* 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 "protocol.h"

View File

@ -17,14 +17,6 @@
* 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
#define LIBSIGROK_HARDWARE_CONRAD_DIGI_35_CPU_PROTOCOL_H
@ -36,6 +28,10 @@
#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);
#endif

View File

@ -5,6 +5,7 @@
* Copyright (C) 2011 Olivier Fauchon <olivier@aixmarseille.com>
* Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@gmail.com>
* Copyright (C) 2015 Bartosz Golaszewski <bgolaszewski@baylibre.com>
* Copyright (C) 2019 Frank Stettner <frank-stettner@gmx.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -28,13 +29,10 @@
#include "libsigrok-internal.h"
#include "protocol.h"
#define DEFAULT_NUM_LOGIC_CHANNELS 8
#define DEFAULT_ENABLED_LOGIC_CHANNELS 8
#define DEFAULT_LOGIC_PATTERN PATTERN_SIGROK
#define DEFAULT_NUM_LOGIC_CHANNELS 8
#define DEFAULT_LOGIC_PATTERN PATTERN_SIGROK
#define DEFAULT_NUM_ANALOG_CHANNELS 4
#define DEFAULT_ENABLED_ANALOG_CHANNELS 4
#define DEFAULT_ANALOG_AMPLITUDE 10
#define DEFAULT_NUM_ANALOG_CHANNELS 5
/* Note: No spaces allowed because of sigrok-cli. */
static const char *logic_pattern_str[] = {
@ -46,6 +44,13 @@ static const char *logic_pattern_str[] = {
"all-low",
"all-high",
"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[] = {
@ -54,18 +59,16 @@ static const uint32_t drvopts[] = {
SR_CONF_OSCILLOSCOPE,
};
static const uint32_t scanopts[] = {
SR_CONF_NUM_LOGIC_CHANNELS,
SR_CONF_NUM_ANALOG_CHANNELS,
};
static const uint32_t devopts[] = {
SR_CONF_CONTINUOUS,
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET,
SR_CONF_LIMIT_FRAMES | SR_CONF_GET | SR_CONF_SET,
SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
SR_CONF_AVERAGING | 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[] = {
@ -74,11 +77,22 @@ static const uint32_t devopts_cg_logic[] = {
static const uint32_t devopts_cg_analog_group[] = {
SR_CONF_AMPLITUDE | SR_CONF_GET | SR_CONF_SET,
SR_CONF_OFFSET | SR_CONF_GET | SR_CONF_SET,
};
static const uint32_t devopts_cg_analog_channel[] = {
SR_CONF_MEASURED_QUANTITY | SR_CONF_GET | SR_CONF_SET,
SR_CONF_PATTERN_MODE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
SR_CONF_AMPLITUDE | SR_CONF_GET | SR_CONF_SET,
SR_CONF_OFFSET | SR_CONF_GET | SR_CONF_SET,
};
static const int32_t trigger_matches[] = {
SR_TRIGGER_ZERO,
SR_TRIGGER_ONE,
SR_TRIGGER_RISING,
SR_TRIGGER_FALLING,
SR_TRIGGER_EDGE,
};
static const uint64_t samplerates[] = {
@ -97,11 +111,12 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
struct analog_gen *ag;
GSList *l;
int num_logic_channels, num_analog_channels, pattern, i;
uint64_t limit_frames;
char channel_name[16];
gboolean enabled;
num_logic_channels = DEFAULT_NUM_LOGIC_CHANNELS;
num_analog_channels = DEFAULT_NUM_ANALOG_CHANNELS;
limit_frames = DEFAULT_LIMIT_FRAMES;
for (l = options; l; l = l->next) {
src = l->data;
switch (src->key) {
@ -111,6 +126,9 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
case SR_CONF_NUM_ANALOG_CHANNELS:
num_analog_channels = g_variant_get_int32(src->data);
break;
case SR_CONF_LIMIT_FRAMES:
limit_frames = g_variant_get_uint64(src->data);
break;
}
}
@ -122,8 +140,14 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
devc->cur_samplerate = SR_KHZ(200);
devc->num_logic_channels = num_logic_channels;
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->num_analog_channels = num_analog_channels;
devc->limit_frames = limit_frames;
devc->capture_ratio = 20;
devc->stl = NULL;
if (num_logic_channels > 0) {
/* Logic channels, all in one channel group. */
@ -131,27 +155,32 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
cg->name = g_strdup("Logic");
for (i = 0; i < num_logic_channels; i++) {
sprintf(channel_name, "D%d", i);
enabled = (i < DEFAULT_ENABLED_LOGIC_CHANNELS) ? TRUE : FALSE;
ch = sr_channel_new(sdi, i, SR_CHANNEL_LOGIC, enabled, channel_name);
ch = sr_channel_new(sdi, i, SR_CHANNEL_LOGIC, TRUE, channel_name);
cg->channels = g_slist_append(cg->channels, ch);
}
sdi->channel_groups = g_slist_append(NULL, cg);
}
/* Analog channels, channel groups and pattern generators. */
devc->ch_ag = g_hash_table_new(g_direct_hash, g_direct_equal);
if (num_analog_channels > 0) {
/*
* Have the waveform for analog patterns pre-generated. It's
* supposed to be periodic, so the generator just needs to
* access the prepared sample data (DDS style).
*/
demo_generate_analog_pattern(devc);
pattern = 0;
/* An "Analog" channel group with all analog channels in it. */
acg = g_malloc0(sizeof(struct sr_channel_group));
acg->name = g_strdup("Analog");
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++) {
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,
enabled, channel_name);
TRUE, channel_name);
acg->channels = g_slist_append(acg->channels, ch);
/* Every analog channel gets its own channel group as well. */
@ -162,13 +191,20 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
/* Every channel gets a generator struct. */
ag = g_malloc(sizeof(struct analog_gen));
ag->ch = ch;
ag->mq = SR_MQ_VOLTAGE;
ag->mq_flags = SR_MQFLAG_DC;
ag->unit = SR_UNIT_VOLT;
ag->amplitude = DEFAULT_ANALOG_AMPLITUDE;
ag->offset = DEFAULT_ANALOG_OFFSET;
sr_analog_init(&ag->packet, &ag->encoding, &ag->meaning, &ag->spec, 2);
ag->packet.meaning->channels = cg->channels;
ag->packet.meaning->mq = 0;
ag->packet.meaning->mqflags = 0;
ag->packet.meaning->unit = SR_UNIT_VOLT;
ag->packet.data = ag->pattern_data;
ag->packet.meaning->mq = ag->mq;
ag->packet.meaning->mqflags = ag->mq_flags;
ag->packet.meaning->unit = ag->unit;
ag->packet.encoding->digits = DEFAULT_ANALOG_ENCODING_DIGITS;
ag->packet.spec->spec_digits = DEFAULT_ANALOG_SPEC_DIGITS;
ag->packet.data = devc->analog_patterns[pattern];
ag->pattern = pattern;
ag->avg_val = 0.0f;
ag->num_avgs = 0;
@ -184,47 +220,32 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
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;
void *value;
devc = priv;
demo_free_analog_pattern(devc);
/* Analog generators. */
g_hash_table_iter_init(&iter, devc->ch_ag);
while (g_hash_table_iter_next(&iter, NULL, &value))
g_free(value);
g_hash_table_unref(devc->ch_ag);
g_free(devc);
}
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,
const struct sr_channel_group *cg)
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_channel *ch;
struct analog_gen *ag;
GVariant *mq_arr[2];
int pattern;
if (!sdi)
@ -241,12 +262,27 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s
case SR_CONF_LIMIT_MSEC:
*data = g_variant_new_uint64(devc->limit_msec);
break;
case SR_CONF_LIMIT_FRAMES:
*data = g_variant_new_uint64(devc->limit_frames);
break;
case SR_CONF_AVERAGING:
*data = g_variant_new_boolean(devc->avg);
break;
case SR_CONF_AVG_SAMPLES:
*data = g_variant_new_uint64(devc->avg_samples);
break;
case SR_CONF_MEASURED_QUANTITY:
if (!cg)
return SR_ERR_CHANNEL_GROUP;
/* Any channel in the group will do. */
ch = cg->channels->data;
if (ch->type != SR_CHANNEL_ANALOG)
return SR_ERR_ARG;
ag = g_hash_table_lookup(devc->ch_ag, ch);
mq_arr[0] = g_variant_new_uint32(ag->mq);
mq_arr[1] = g_variant_new_uint64(ag->mq_flags);
*data = g_variant_new_tuple(mq_arr, 2);
break;
case SR_CONF_PATTERN_MODE:
if (!cg)
return SR_ERR_CHANNEL_GROUP;
@ -272,6 +308,19 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s
ag = g_hash_table_lookup(devc->ch_ag, ch);
*data = g_variant_new_double(ag->amplitude);
break;
case SR_CONF_OFFSET:
if (!cg)
return SR_ERR_CHANNEL_GROUP;
/* Any channel in the group will do. */
ch = cg->channels->data;
if (ch->type != SR_CHANNEL_ANALOG)
return SR_ERR_ARG;
ag = g_hash_table_lookup(devc->ch_ag, ch);
*data = g_variant_new_double(ag->offset);
break;
case SR_CONF_CAPTURE_RATIO:
*data = g_variant_new_uint64(devc->capture_ratio);
break;
default:
return SR_ERR_NA;
}
@ -279,23 +328,18 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s
return SR_OK;
}
static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
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 analog_gen *ag;
struct sr_channel *ch;
GVariant *mq_tuple_child;
GSList *l;
int logic_pattern, analog_pattern, ret;
unsigned int i;
const char *stropt;
int logic_pattern, analog_pattern;
devc = sdi->priv;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
ret = SR_OK;
switch (key) {
case SR_CONF_SAMPLERATE:
devc->cur_samplerate = g_variant_get_uint64(data);
@ -308,6 +352,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_samples = 0;
break;
case SR_CONF_LIMIT_FRAMES:
devc->limit_frames = g_variant_get_uint64(data);
break;
case SR_CONF_AVERAGING:
devc->avg = g_variant_get_boolean(data);
sr_dbg("%s averaging", devc->avg ? "Enabling" : "Disabling");
@ -316,24 +363,27 @@ static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sd
devc->avg_samples = g_variant_get_uint64(data);
sr_dbg("Setting averaging rate to %" PRIu64, devc->avg_samples);
break;
case SR_CONF_MEASURED_QUANTITY:
if (!cg)
return SR_ERR_CHANNEL_GROUP;
for (l = cg->channels; l; l = l->next) {
ch = l->data;
if (ch->type != SR_CHANNEL_ANALOG)
return SR_ERR_ARG;
ag = g_hash_table_lookup(devc->ch_ag, ch);
mq_tuple_child = g_variant_get_child_value(data, 0);
ag->mq = g_variant_get_uint32(mq_tuple_child);
mq_tuple_child = g_variant_get_child_value(data, 1);
ag->mq_flags = g_variant_get_uint64(mq_tuple_child);
g_variant_unref(mq_tuple_child);
}
break;
case SR_CONF_PATTERN_MODE:
if (!cg)
return SR_ERR_CHANNEL_GROUP;
stropt = g_variant_get_string(data, NULL);
logic_pattern = analog_pattern = -1;
for (i = 0; i < ARRAY_SIZE(logic_pattern_str); i++) {
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)
logic_pattern = std_str_idx(data, ARRAY_AND_SIZE(logic_pattern_str));
analog_pattern = std_str_idx(data, ARRAY_AND_SIZE(analog_pattern_str));
if (logic_pattern < 0 && analog_pattern < 0)
return SR_ERR_ARG;
for (l = cg->channels; l; l = l->next) {
ch = l->data;
@ -370,47 +420,42 @@ static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sd
ag->amplitude = g_variant_get_double(data);
}
break;
case SR_CONF_OFFSET:
if (!cg)
return SR_ERR_CHANNEL_GROUP;
for (l = cg->channels; l; l = l->next) {
ch = l->data;
if (ch->type != SR_CHANNEL_ANALOG)
return SR_ERR_ARG;
ag = g_hash_table_lookup(devc->ch_ag, ch);
ag->offset = g_variant_get_double(data);
}
break;
case SR_CONF_CAPTURE_RATIO:
devc->capture_ratio = g_variant_get_uint64(data);
break;
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,
const struct sr_channel_group *cg)
static int config_list(uint32_t key, GVariant **data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
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) {
switch (key) {
case SR_CONF_SCAN_OPTIONS:
case SR_CONF_DEVICE_OPTIONS:
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
break;
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
case SR_CONF_SAMPLERATE:
g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
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);
*data = std_gvar_samplerates_steps(ARRAY_AND_SIZE(samplerates));
break;
case SR_CONF_TRIGGER_MATCH:
*data = std_gvar_array_i32(ARRAY_AND_SIZE(trigger_matches));
break;
default:
return SR_ERR_NA;
@ -420,18 +465,12 @@ static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *
switch (key) {
case SR_CONF_DEVICE_OPTIONS:
if (ch->type == SR_CHANNEL_LOGIC)
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
devopts_cg_logic, ARRAY_SIZE(devopts_cg_logic),
sizeof(uint32_t));
*data = std_gvar_array_u32(ARRAY_AND_SIZE(devopts_cg_logic));
else if (ch->type == SR_CHANNEL_ANALOG) {
if (strcmp(cg->name, "Analog") == 0)
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
devopts_cg_analog_group, ARRAY_SIZE(devopts_cg_analog_group),
sizeof(uint32_t));
*data = std_gvar_array_u32(ARRAY_AND_SIZE(devopts_cg_analog_group));
else
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
devopts_cg_analog_channel, ARRAY_SIZE(devopts_cg_analog_channel),
sizeof(uint32_t));
*data = std_gvar_array_u32(ARRAY_AND_SIZE(devopts_cg_analog_channel));
}
else
return SR_ERR_BUG;
@ -442,11 +481,9 @@ static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *
return SR_ERR_NA;
if (ch->type == SR_CHANNEL_LOGIC)
*data = g_variant_new_strv(logic_pattern_str,
ARRAY_SIZE(logic_pattern_str));
*data = g_variant_new_strv(ARRAY_AND_SIZE(logic_pattern_str));
else if (ch->type == SR_CHANNEL_ANALOG)
*data = g_variant_new_strv(analog_pattern_str,
ARRAY_SIZE(analog_pattern_str));
*data = g_variant_new_strv(ARRAY_AND_SIZE(analog_pattern_str));
else
return SR_ERR_BUG;
break;
@ -461,24 +498,83 @@ 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)
{
struct dev_context *devc;
GHashTableIter iter;
void *value;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
GSList *l;
struct sr_channel *ch;
int bitpos;
uint8_t mask;
struct sr_trigger *trigger;
devc = sdi->priv;
devc->sent_samples = 0;
devc->sent_frame_samples = 0;
g_hash_table_iter_init(&iter, devc->ch_ag);
while (g_hash_table_iter_next(&iter, NULL, &value))
demo_generate_analog_pattern(value, devc->cur_samplerate);
/* 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);
sr_session_source_add(sdi->session, -1, 0, 100,
demo_prepare_data, (struct sr_dev_inst *)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. */
devc->start_us = g_get_monotonic_time();
devc->spent_us = 0;
@ -489,10 +585,21 @@ static int dev_acquisition_start(const 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);
devc = sdi->priv;
if (devc->limit_frames > 0)
std_session_send_frame_end(sdi);
std_session_send_df_end(sdi);
if (devc->stl) {
soft_trigger_logic_free(devc->stl);
devc->stl = NULL;
}
return SR_OK;
}
@ -508,8 +615,8 @@ static struct sr_dev_driver demo_driver_info = {
.config_get = config_get,
.config_set = config_set,
.config_list = config_list,
.dev_open = dev_open,
.dev_close = dev_close,
.dev_open = std_dummy_dev_open,
.dev_close = std_dummy_dev_close,
.dev_acquisition_start = dev_acquisition_start,
.dev_acquisition_stop = dev_acquisition_stop,
.context = NULL,

View File

@ -5,6 +5,7 @@
* Copyright (C) 2011 Olivier Fauchon <olivier@aixmarseille.com>
* Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@gmail.com>
* Copyright (C) 2015 Bartosz Golaszewski <bgolaszewski@baylibre.com>
* Copyright (C) 2019 Frank Stettner <frank-stettner@gmx.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -172,76 +173,104 @@ static const uint8_t pattern_squid[128][128 / 8] = {
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
};
SR_PRIV void demo_generate_analog_pattern(struct analog_gen *ag, uint64_t sample_rate)
SR_PRIV void demo_generate_analog_pattern(struct dev_context *devc)
{
double t, frequency;
float value;
float amplitude, offset;
struct analog_pattern *pattern;
unsigned int num_samples, i;
float value;
int last_end;
sr_dbg("Generating %s pattern.", analog_pattern_str[ag->pattern]);
num_samples = ANALOG_BUFSIZE / sizeof(float);
frequency = (double) devc->cur_samplerate / ANALOG_SAMPLES_PER_PERIOD;
amplitude = DEFAULT_ANALOG_AMPLITUDE;
offset = DEFAULT_ANALOG_OFFSET;
switch (ag->pattern) {
case PATTERN_SQUARE:
value = ag->amplitude;
last_end = 0;
for (i = 0; i < num_samples; i++) {
if (i % 5 == 0)
value = -value;
if (i % 10 == 0)
last_end = i;
ag->pattern_data[i] = value;
}
ag->num_samples = last_end;
break;
case PATTERN_SINE:
frequency = (double) sample_rate / ANALOG_SAMPLES_PER_PERIOD;
/*
* FIXME: We actually need only one period. A ringbuffer would be
* useful here.
* Make sure the number of samples we put out is an integer
* multiple of our period size.
*/
/* Make sure the number of samples we put out is an integer
* multiple of our period size */
/* FIXME we actually need only one period. A ringbuffer would be
* useful here. */
while (num_samples % ANALOG_SAMPLES_PER_PERIOD != 0)
num_samples--;
/* PATTERN_SQUARE: */
sr_dbg("Generating %s pattern.", analog_pattern_str[PATTERN_SQUARE]);
pattern = g_malloc(sizeof(struct analog_pattern));
value = amplitude;
last_end = 0;
for (i = 0; i < num_samples; i++) {
if (i % 5 == 0)
value = -value;
if (i % 10 == 0)
last_end = i;
pattern->data[i] = value + offset;
}
pattern->num_samples = last_end;
devc->analog_patterns[PATTERN_SQUARE] = pattern;
for (i = 0; i < num_samples; i++) {
t = (double) i / (double) sample_rate;
ag->pattern_data[i] = ag->amplitude *
sin(2 * G_PI * frequency * t);
}
/* Readjusting num_samples for all other patterns. */
while (num_samples % ANALOG_SAMPLES_PER_PERIOD != 0)
num_samples--;
ag->num_samples = num_samples;
break;
case PATTERN_TRIANGLE:
frequency = (double) sample_rate / ANALOG_SAMPLES_PER_PERIOD;
/* PATTERN_SINE: */
sr_dbg("Generating %s pattern.", analog_pattern_str[PATTERN_SINE]);
pattern = g_malloc(sizeof(struct analog_pattern));
for (i = 0; i < num_samples; i++) {
t = (double) i / (double) devc->cur_samplerate;
pattern->data[i] = sin(2 * G_PI * frequency * t) * amplitude + offset;
}
pattern->num_samples = last_end;
devc->analog_patterns[PATTERN_SINE] = pattern;
while (num_samples % ANALOG_SAMPLES_PER_PERIOD != 0)
num_samples--;
/* PATTERN_TRIANGLE: */
sr_dbg("Generating %s pattern.", analog_pattern_str[PATTERN_TRIANGLE]);
pattern = g_malloc(sizeof(struct analog_pattern));
for (i = 0; i < num_samples; i++) {
t = (double) i / (double) devc->cur_samplerate;
pattern->data[i] = (2 / G_PI) * asin(sin(2 * G_PI * frequency * t)) *
amplitude + offset;
}
pattern->num_samples = last_end;
devc->analog_patterns[PATTERN_TRIANGLE] = pattern;
for (i = 0; i < num_samples; i++) {
t = (double) i / (double) sample_rate;
ag->pattern_data[i] = (2 * ag->amplitude / G_PI) *
asin(sin(2 * G_PI * frequency * t));
}
/* PATTERN_SAWTOOTH: */
sr_dbg("Generating %s pattern.", analog_pattern_str[PATTERN_SAWTOOTH]);
pattern = g_malloc(sizeof(struct analog_pattern));
for (i = 0; i < num_samples; i++) {
t = (double) i / (double) devc->cur_samplerate;
pattern->data[i] = 2 * ((t * frequency) - floor(0.5f + t * frequency)) *
amplitude + offset;
}
pattern->num_samples = last_end;
devc->analog_patterns[PATTERN_SAWTOOTH] = pattern;
ag->num_samples = num_samples;
break;
case PATTERN_SAWTOOTH:
frequency = (double) sample_rate / ANALOG_SAMPLES_PER_PERIOD;
/* PATTERN_ANALOG_RANDOM */
/* Data not filled here, will be generated in send_analog_packet(). */
pattern = g_malloc(sizeof(struct analog_pattern));
pattern->num_samples = last_end;
devc->analog_patterns[PATTERN_ANALOG_RANDOM] = pattern;
}
while (num_samples % ANALOG_SAMPLES_PER_PERIOD != 0)
num_samples--;
SR_PRIV void demo_free_analog_pattern(struct dev_context *devc)
{
g_free(devc->analog_patterns[PATTERN_SQUARE]);
g_free(devc->analog_patterns[PATTERN_SINE]);
g_free(devc->analog_patterns[PATTERN_TRIANGLE]);
g_free(devc->analog_patterns[PATTERN_SAWTOOTH]);
g_free(devc->analog_patterns[PATTERN_ANALOG_RANDOM]);
}
for (i = 0; i < num_samples; i++) {
t = (double) i / (double) sample_rate;
ag->pattern_data[i] = 2 * ag->amplitude *
((t * frequency) - floor(0.5f + t * frequency));
}
static uint64_t encode_number_to_gray(uint64_t nr)
{
return nr ^ (nr >> 1);
}
ag->num_samples = num_samples;
break;
static void set_logic_data(uint64_t bits, uint8_t *data, size_t len)
{
while (len--) {
*data++ = bits & 0xff;
bits >>= 8;
}
}
@ -253,6 +282,7 @@ static void logic_generator(struct sr_dev_inst *sdi, uint64_t size)
uint8_t *sample;
const uint8_t *image_col;
size_t col_count, col_height;
uint64_t gray;
devc = sdi->priv;
@ -273,15 +303,14 @@ static void logic_generator(struct sr_dev_inst *sdi, uint64_t size)
break;
case PATTERN_INC:
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->step++;
}
break;
case PATTERN_WALKING_ONE:
/* j contains the value of the highest bit */
j = 1 << (devc->num_logic_channels - 1);
j = 1 << (devc->num_logic_channels - 1);
for (i = 0; i < size; i++) {
devc->logic_data[i] = devc->step;
if (devc->step == 0)
@ -296,7 +325,7 @@ static void logic_generator(struct sr_dev_inst *sdi, uint64_t size)
case PATTERN_WALKING_ZERO:
/* Same as walking one, only with inverted output */
/* j contains the value of the highest bit */
j = 1 << (devc->num_logic_channels - 1);
j = 1 << (devc->num_logic_channels - 1);
for (i = 0; i < size; i++) {
devc->logic_data[i] = ~devc->step;
if (devc->step == 0)
@ -327,52 +356,204 @@ static void logic_generator(struct sr_dev_inst *sdi, uint64_t size)
devc->step %= col_count;
}
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:
sr_err("Unknown pattern: %d.", devc->logic_pattern);
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,
struct sr_dev_inst *sdi, uint64_t *analog_sent,
uint64_t analog_pos, uint64_t analog_todo)
{
struct sr_datafeed_packet packet;
struct dev_context *devc;
struct analog_pattern *pattern;
uint64_t sending_now, to_avg;
int ag_pattern_pos;
unsigned int i;
float amplitude, offset, value;
float *data;
if (!ag->ch || !ag->ch->enabled)
return;
devc = sdi->priv;
packet.type = SR_DF_ANALOG;
packet.payload = &ag->packet;
pattern = devc->analog_patterns[ag->pattern];
ag->packet.meaning->channels = g_slist_append(NULL, ag->ch);
ag->packet.meaning->mq = ag->mq;
ag->packet.meaning->mqflags = ag->mq_flags;
/* Set a unit for the given quantity. */
if (ag->mq == SR_MQ_VOLTAGE)
ag->packet.meaning->unit = SR_UNIT_VOLT;
else if (ag->mq == SR_MQ_CURRENT)
ag->packet.meaning->unit = SR_UNIT_AMPERE;
else if (ag->mq == SR_MQ_RESISTANCE)
ag->packet.meaning->unit = SR_UNIT_OHM;
else if (ag->mq == SR_MQ_CAPACITANCE)
ag->packet.meaning->unit = SR_UNIT_FARAD;
else if (ag->mq == SR_MQ_TEMPERATURE)
ag->packet.meaning->unit = SR_UNIT_CELSIUS;
else if (ag->mq == SR_MQ_FREQUENCY)
ag->packet.meaning->unit = SR_UNIT_HERTZ;
else if (ag->mq == SR_MQ_DUTY_CYCLE)
ag->packet.meaning->unit = SR_UNIT_PERCENTAGE;
else if (ag->mq == SR_MQ_CONTINUITY)
ag->packet.meaning->unit = SR_UNIT_OHM;
else if (ag->mq == SR_MQ_PULSE_WIDTH)
ag->packet.meaning->unit = SR_UNIT_PERCENTAGE;
else if (ag->mq == SR_MQ_CONDUCTANCE)
ag->packet.meaning->unit = SR_UNIT_SIEMENS;
else if (ag->mq == SR_MQ_POWER)
ag->packet.meaning->unit = SR_UNIT_WATT;
else if (ag->mq == SR_MQ_GAIN)
ag->packet.meaning->unit = SR_UNIT_UNITLESS;
else if (ag->mq == SR_MQ_SOUND_PRESSURE_LEVEL)
ag->packet.meaning->unit = SR_UNIT_DECIBEL_SPL;
else if (ag->mq == SR_MQ_CARBON_MONOXIDE)
ag->packet.meaning->unit = SR_UNIT_CONCENTRATION;
else if (ag->mq == SR_MQ_RELATIVE_HUMIDITY)
ag->packet.meaning->unit = SR_UNIT_HUMIDITY_293K;
else if (ag->mq == SR_MQ_TIME)
ag->packet.meaning->unit = SR_UNIT_SECOND;
else if (ag->mq == SR_MQ_WIND_SPEED)
ag->packet.meaning->unit = SR_UNIT_METER_SECOND;
else if (ag->mq == SR_MQ_PRESSURE)
ag->packet.meaning->unit = SR_UNIT_HECTOPASCAL;
else if (ag->mq == SR_MQ_PARALLEL_INDUCTANCE)
ag->packet.meaning->unit = SR_UNIT_HENRY;
else if (ag->mq == SR_MQ_PARALLEL_CAPACITANCE)
ag->packet.meaning->unit = SR_UNIT_FARAD;
else if (ag->mq == SR_MQ_PARALLEL_RESISTANCE)
ag->packet.meaning->unit = SR_UNIT_OHM;
else if (ag->mq == SR_MQ_SERIES_INDUCTANCE)
ag->packet.meaning->unit = SR_UNIT_HENRY;
else if (ag->mq == SR_MQ_SERIES_CAPACITANCE)
ag->packet.meaning->unit = SR_UNIT_FARAD;
else if (ag->mq == SR_MQ_SERIES_RESISTANCE)
ag->packet.meaning->unit = SR_UNIT_OHM;
else if (ag->mq == SR_MQ_DISSIPATION_FACTOR)
ag->packet.meaning->unit = SR_UNIT_UNITLESS;
else if (ag->mq == SR_MQ_QUALITY_FACTOR)
ag->packet.meaning->unit = SR_UNIT_UNITLESS;
else if (ag->mq == SR_MQ_PHASE_ANGLE)
ag->packet.meaning->unit = SR_UNIT_DEGREE;
else if (ag->mq == SR_MQ_DIFFERENCE)
ag->packet.meaning->unit = SR_UNIT_UNITLESS;
else if (ag->mq == SR_MQ_COUNT)
ag->packet.meaning->unit = SR_UNIT_PIECE;
else if (ag->mq == SR_MQ_POWER_FACTOR)
ag->packet.meaning->unit = SR_UNIT_UNITLESS;
else if (ag->mq == SR_MQ_APPARENT_POWER)
ag->packet.meaning->unit = SR_UNIT_VOLT_AMPERE;
else if (ag->mq == SR_MQ_MASS)
ag->packet.meaning->unit = SR_UNIT_GRAM;
else if (ag->mq == SR_MQ_HARMONIC_RATIO)
ag->packet.meaning->unit = SR_UNIT_UNITLESS;
else
ag->packet.meaning->unit = SR_UNIT_UNITLESS;
if (!devc->avg) {
ag_pattern_pos = analog_pos % ag->num_samples;
sending_now = MIN(analog_todo, ag->num_samples-ag_pattern_pos);
ag->packet.data = ag->pattern_data + ag_pattern_pos;
ag_pattern_pos = analog_pos % pattern->num_samples;
sending_now = MIN(analog_todo, pattern->num_samples - ag_pattern_pos);
if (ag->amplitude != DEFAULT_ANALOG_AMPLITUDE ||
ag->offset != DEFAULT_ANALOG_OFFSET ||
ag->pattern == PATTERN_ANALOG_RANDOM) {
/*
* Amplitude or offset changed (or we are generating
* random data), modify each sample.
*/
if (ag->pattern == PATTERN_ANALOG_RANDOM) {
amplitude = ag->amplitude / 500.0;
offset = ag->offset - DEFAULT_ANALOG_OFFSET - ag->amplitude;
} else {
amplitude = ag->amplitude / DEFAULT_ANALOG_AMPLITUDE;
offset = ag->offset - DEFAULT_ANALOG_OFFSET;
}
data = ag->packet.data;
for (i = 0; i < sending_now; i++) {
if (ag->pattern == PATTERN_ANALOG_RANDOM)
data[i] = (rand() % 1000) * amplitude + offset;
else
data[i] = pattern->data[ag_pattern_pos + i] * amplitude + offset;
}
} else {
/* Amplitude and offset unchanged, use the fast way. */
ag->packet.data = pattern->data + ag_pattern_pos;
}
ag->packet.num_samples = sending_now;
sr_session_send(sdi, &packet);
/* Whichever channel group gets there first. */
*analog_sent = MAX(*analog_sent, sending_now);
} else {
ag_pattern_pos = analog_pos % ag->num_samples;
to_avg = MIN(analog_todo, ag->num_samples-ag_pattern_pos);
ag_pattern_pos = analog_pos % pattern->num_samples;
to_avg = MIN(analog_todo, pattern->num_samples - ag_pattern_pos);
if (ag->pattern == PATTERN_ANALOG_RANDOM) {
amplitude = ag->amplitude / 500.0;
offset = ag->offset - DEFAULT_ANALOG_OFFSET - ag->amplitude;
} else {
amplitude = ag->amplitude / DEFAULT_ANALOG_AMPLITUDE;
offset = ag->offset - DEFAULT_ANALOG_OFFSET;
}
for (i = 0; i < to_avg; i++) {
ag->avg_val = (ag->avg_val +
*(ag->pattern_data +
ag_pattern_pos + i)) / 2;
if (ag->pattern == PATTERN_ANALOG_RANDOM)
value = (rand() % 1000) * amplitude + offset;
else
value = *(pattern->data + ag_pattern_pos + i) * amplitude + offset;
ag->avg_val = (ag->avg_val + value) / 2;
ag->num_avgs++;
/* Time to send averaged data? */
if (devc->avg_samples > 0 &&
ag->num_avgs >= devc->avg_samples)
if ((devc->avg_samples > 0) && (ag->num_avgs >= devc->avg_samples))
goto do_send;
}
if (devc->avg_samples == 0) {
/* We're averaging all the samples, so wait with
/*
* We're averaging all the samples, so wait with
* sending until the very end.
*/
*analog_sent = ag->num_avgs;
@ -403,6 +584,8 @@ SR_PRIV int demo_prepare_data(int fd, int revents, void *cb_data)
void *value;
uint64_t samples_todo, logic_done, analog_done, analog_sent, sending_now;
int64_t elapsed_us, limit_us, todo_us;
int64_t trigger_offset;
int pre_trigger_samples;
(void)fd;
(void)revents;
@ -414,7 +597,7 @@ SR_PRIV int demo_prepare_data(int fd, int revents, void *cb_data)
if (devc->cur_samplerate <= 0
|| (devc->num_logic_channels <= 0
&& devc->num_analog_channels <= 0)) {
sdi->driver->dev_acquisition_stop(sdi);
sr_dev_acquisition_stop(sdi);
return G_SOURCE_CONTINUE;
}
@ -429,20 +612,38 @@ SR_PRIV int demo_prepare_data(int fd, int revents, void *cb_data)
/* How many samples are outstanding since the last round? */
samples_todo = (todo_us * devc->cur_samplerate + G_USEC_PER_SEC - 1)
/ G_USEC_PER_SEC;
if (devc->limit_samples > 0) {
if (devc->limit_samples < devc->sent_samples)
samples_todo = 0;
else if (devc->limit_samples - devc->sent_samples < samples_todo)
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
* count, rounded towards zero. This avoids getting stuck on a too-low
* time delta with no samples being sent due to round-off.
*/
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;
if (!devc->enabled_analog_channels)
analog_done = samples_todo;
while (logic_done < samples_todo || analog_done < samples_todo) {
/* Logic */
@ -450,13 +651,47 @@ SR_PRIV int demo_prepare_data(int fd, int revents, void *cb_data)
sending_now = MIN(samples_todo - logic_done,
LOGIC_BUFSIZE / 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.payload = &logic;
logic.length = sending_now * devc->logic_unitsize;
logic.unitsize = devc->logic_unitsize;
logic.data = devc->logic_data;
sr_session_send(sdi, &packet);
logic_done += sending_now;
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_fixup_feed(devc, &logic);
sr_session_send(sdi, &packet);
logic_done += sending_now;
}
}
/* Analog, one channel at a time */
@ -472,21 +707,27 @@ SR_PRIV int demo_prepare_data(int fd, int revents, void *cb_data)
analog_done += analog_sent;
}
}
/* At this point, both logic_done and analog_done should be
* exactly equal to samples_todo, or else.
*/
if (logic_done != samples_todo || analog_done != samples_todo) {
sr_err("BUG: Sample count mismatch.");
return G_SOURCE_REMOVE;
}
devc->sent_samples += samples_todo;
uint64_t min = MIN(logic_done, analog_done);
devc->sent_samples += min;
devc->sent_frame_samples += min;
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)
|| (limit_us > 0 && devc->spent_us >= limit_us)) {
/* 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);
while (g_hash_table_iter_next(&iter, NULL, &value)) {
ag = value;
@ -498,7 +739,10 @@ SR_PRIV int demo_prepare_data(int fd, int revents, void *cb_data)
}
}
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;

View File

@ -5,6 +5,7 @@
* Copyright (C) 2011 Olivier Fauchon <olivier@aixmarseille.com>
* Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@gmail.com>
* Copyright (C) 2015 Bartosz Golaszewski <bgolaszewski@baylibre.com>
* Copyright (C) 2019 Frank Stettner <frank-stettner@gmx.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -33,31 +34,17 @@
#define LOGIC_BUFSIZE 4096
/* Size of the analog pattern space per channel. */
#define ANALOG_BUFSIZE 4096
/* This is a development feature: it starts a new frame every n samples. */
#define SAMPLES_PER_FRAME 1000UL
#define DEFAULT_LIMIT_FRAMES 0
/* Private, per-device-instance driver context. */
struct dev_context {
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;
};
#define DEFAULT_ANALOG_ENCODING_DIGITS 4
#define DEFAULT_ANALOG_SPEC_DIGITS 4
#define DEFAULT_ANALOG_AMPLITUDE 10
#define DEFAULT_ANALOG_OFFSET 0.
/* Logic patterns we can generate. */
enum {
enum logic_pattern_type {
/**
* Spells "sigrok" across 8 channels using '0's (with '1's as
* "background") when displayed using the 'bits' output format.
@ -97,17 +84,18 @@ enum {
* something that can get recognized.
*/
PATTERN_SQUID,
/** Gray encoded data, like rotary encoder signals. */
PATTERN_GRAYCODE,
};
/* Analog patterns we can generate. */
enum {
/**
* Square wave.
*/
enum analog_pattern_type {
PATTERN_SQUARE,
PATTERN_SINE,
PATTERN_TRIANGLE,
PATTERN_SAWTOOTH,
PATTERN_ANALOG_RANDOM,
};
static const char *analog_pattern_str[] = {
@ -115,22 +103,65 @@ static const char *analog_pattern_str[] = {
"sine",
"triangle",
"sawtooth",
"random",
};
struct analog_pattern {
float data[ANALOG_BUFSIZE];
unsigned int num_samples;
};
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 */
struct analog_pattern *analog_patterns[ARRAY_SIZE(analog_pattern_str)];
int32_t num_analog_channels;
GHashTable *ch_ag;
gboolean avg; /* True if averaging is enabled */
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;
};
struct analog_gen {
int pattern;
struct sr_channel *ch;
enum sr_mq mq;
enum sr_mqflag mq_flags;
enum sr_unit unit;
enum analog_pattern_type pattern;
float amplitude;
float pattern_data[ANALOG_BUFSIZE];
unsigned int num_samples;
float offset;
struct sr_datafeed_analog packet;
struct sr_analog_encoding encoding;
struct sr_analog_meaning meaning;
struct sr_analog_spec spec;
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 dev_context *devc);
SR_PRIV void demo_free_analog_pattern(struct dev_context *devc);
SR_PRIV int demo_prepare_data(int fd, int revents, void *cb_data);
#endif

View File

@ -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

View File

@ -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

Some files were not shown because too many files have changed in this diff Show More