Compare commits

..

No commits in common. "hw/sq50" and "libsigrok-unreleased" have entirely different histories.

378 changed files with 17951 additions and 73287 deletions

3
.gitignore vendored
View File

@ -8,13 +8,10 @@
/configure.lineno /configure.lineno
/m4/libtool.m4 /m4/libtool.m4
/m4/lt*.m4 /m4/lt*.m4
/build
/inst
# Editor/IDE cruft # Editor/IDE cruft
*.kate-swp *.kate-swp
*~ *~
.*.sw*
/*.kdev4 /*.kdev4
/Makefile.am.user /Makefile.am.user

690
Doxyfile

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -61,9 +61,8 @@ 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 (using the Tondaj SL-814 device as example). It's basically what the
'new-driver' script (see above) does for you: 'new-driver' script (see above) does for you:
- Makefile.am: Add to src_libdrivers_la_SOURCES under the HW_TONDAJ_SL_814 - Makefile.am: Add HW_TONDAJ_SL_814 and add to libsigrok_la_SOURCES.
condition. - configure.ac: Add a DRIVER() and DRIVER2() call.
- configure.ac: Add an SR_DRIVER() call.
- src/drivers.c: Add a tondaj_sl_814_driver_info entry in two places. - 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. - src/hardware/tondaj-sl-814/ directory: Add api.c, protocol.c, protocol.h.
@ -164,9 +163,7 @@ Doxygen
- Mark private functions (SR_PRIV) with /** @private */, so that Doxygen - Mark private functions (SR_PRIV) with /** @private */, so that Doxygen
doesn't include them in the output. Functions that are "static" anyway doesn't include them in the output. Functions that are "static" anyway
don't need to be marked like this. Functions in non-public files that don't need to be marked like this.
are explicitly excluded in Doxyfile don't need to be marked either.
Don't use @internal, always use @private instead.
- Mark private variables/#defines with /** @cond PRIVATE */ and - Mark private variables/#defines with /** @cond PRIVATE */ and
/** @endcond */, so that Doxygen doesn't include them in the output. /** @endcond */, so that Doxygen doesn't include them in the output.

View File

@ -27,7 +27,7 @@ DISTCHECK_CONFIGURE_FLAGS = --disable-python
FIRMWARE_DIR = $(datadir)/sigrok-firmware FIRMWARE_DIR = $(datadir)/sigrok-firmware
local_includes = -Iinclude -I$(srcdir)/include -I$(srcdir)/src -I. @RPC_CFLAGS@ local_includes = -Iinclude -I$(srcdir)/include -I$(srcdir)/src -I.
if BINDINGS_CXX if BINDINGS_CXX
local_includes += -Ibindings/cxx/include -I$(srcdir)/bindings/cxx/include -Ibindings/cxx local_includes += -Ibindings/cxx/include -I$(srcdir)/bindings/cxx/include -Ibindings/cxx
endif endif
@ -50,9 +50,6 @@ lib_LTLIBRARIES = libsigrok.la
# Backend files # Backend files
libsigrok_la_SOURCES = \ libsigrok_la_SOURCES = \
src/backend.c \ src/backend.c \
src/binary_helpers.c \
src/conversion.c \
src/crc.c \
src/device.c \ src/device.c \
src/session.c \ src/session.c \
src/session_file.c \ src/session_file.c \
@ -73,17 +70,13 @@ libsigrok_la_SOURCES = \
# Input modules # Input modules
libsigrok_la_SOURCES += \ libsigrok_la_SOURCES += \
src/input/input.c \ src/input/input.c \
src/input/feed_queue.c \
src/input/binary.c \ src/input/binary.c \
src/input/chronovu_la8.c \ src/input/chronovu_la8.c \
src/input/csv.c \ src/input/csv.c \
src/input/logicport.c \
src/input/raw_analog.c \ src/input/raw_analog.c \
src/input/saleae.c \
src/input/trace32_ad.c \ src/input/trace32_ad.c \
src/input/vcd.c \ src/input/vcd.c \
src/input/wav.c \ src/input/wav.c
src/input/null.c
# Output modules # Output modules
libsigrok_la_SOURCES += \ libsigrok_la_SOURCES += \
@ -98,9 +91,7 @@ libsigrok_la_SOURCES += \
src/output/hex.c \ src/output/hex.c \
src/output/ols.c \ src/output/ols.c \
src/output/srzip.c \ src/output/srzip.c \
src/output/vcd.c \ src/output/vcd.c
src/output/wavedrom.c \
src/output/null.c
# Transform modules # Transform modules
libsigrok_la_SOURCES += \ libsigrok_la_SOURCES += \
@ -113,6 +104,7 @@ libsigrok_la_SOURCES += \
libsigrok_la_SOURCES += \ libsigrok_la_SOURCES += \
src/scpi.h \ src/scpi.h \
src/scpi/scpi.c \ src/scpi/scpi.c \
src/scpi/helpers.c \
src/scpi/scpi_tcp.c src/scpi/scpi_tcp.c
if NEED_RPC if NEED_RPC
libsigrok_la_SOURCES += \ libsigrok_la_SOURCES += \
@ -121,21 +113,9 @@ libsigrok_la_SOURCES += \
src/scpi/vxi_xdr.c \ src/scpi/vxi_xdr.c \
src/scpi/vxi.h src/scpi/vxi.h
endif endif
# if HAVE_BLUETOOTH
libsigrok_la_SOURCES += \
src/bt/bt_bluez.c
# endif
if NEED_SERIAL if NEED_SERIAL
libsigrok_la_SOURCES += \ libsigrok_la_SOURCES += \
src/serial.c \ 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 src/scpi/scpi_serial.c
endif endif
if NEED_USB if NEED_USB
@ -163,32 +143,23 @@ endif
# Hardware (DMM chip parsers) # Hardware (DMM chip parsers)
libsigrok_la_SOURCES += \ libsigrok_la_SOURCES += \
src/dmm/asycii.c \
src/dmm/bm25x.c \
src/dmm/bm52x.c \
src/dmm/bm85x.c \
src/dmm/bm86x.c \
src/dmm/dtm0660.c \
src/dmm/eev121gw.c \
src/dmm/es519xx.c \ src/dmm/es519xx.c \
src/dmm/fs9721.c \ src/dmm/fs9721.c \
src/dmm/fs9922.c \ src/dmm/fs9922.c \
src/dmm/m2110.c \ src/dmm/m2110.c \
src/dmm/metex14.c \ src/dmm/metex14.c \
src/dmm/mm38xr.c \ src/dmm/asycii.c \
src/dmm/ms2115b.c \
src/dmm/ms8250d.c \
src/dmm/rs9lcd.c \ src/dmm/rs9lcd.c \
src/dmm/ut372.c \ src/dmm/bm25x.c \
src/dmm/ut71x.c \ src/dmm/ut71x.c \
src/dmm/ut372.c \
src/dmm/vc870.c \ src/dmm/vc870.c \
src/dmm/vc96.c src/dmm/dtm0660.c
# Hardware (LCR chip parsers) # Hardware (LCR chip parsers)
if NEED_SERIAL if NEED_SERIAL
libsigrok_la_SOURCES += \ libsigrok_la_SOURCES += \
src/lcr/es51919.c \ src/lcr/es51919.c
src/lcr/vc4080.c
endif endif
# Hardware (Scale protocol parsers) # Hardware (Scale protocol parsers)
@ -196,22 +167,15 @@ libsigrok_la_SOURCES += \
src/scale/kern.c src/scale/kern.c
# Hardware drivers # Hardware drivers
noinst_LTLIBRARIES = src/libdrivers.la \ noinst_LTLIBRARIES = src/libdrivers.la
src/libdrivers_head.la src/libdrivers_tail.la
src/libdrivers.o: src/libdrivers.la \ src/libdrivers.o: src/libdrivers.la
src/libdrivers_head.la src/libdrivers_tail.la $(AM_V_CCLD)$(LINK) src/libdrivers.la
$(AM_V_CCLD)$(LINK) src/libdrivers_head.la src/libdrivers.la \
src/libdrivers_tail.la
src/libdrivers.lo: src/libdrivers.o src/libdrivers.lo: src/libdrivers.o
$(AM_V_GEN)echo "# Generated by libtool" > $@ $(AM_V_GEN)echo "# Generated by libtool" > $@
$(AM_V_at)echo "pic_object='libdrivers.o'" >> $@ $(AM_V_at)echo "pic_object='libdrivers.o'" >> $@
$(AM_V_at)echo "non_pic_object='libdrivers.o'" >> $@ $(AM_V_at)echo "non_pic_object='libdrivers.o'" >> $@
src_libdrivers_head_la_SOURCES = src/driver_list_start.c
src_libdrivers_tail_la_SOURCES = src/driver_list_stop.c
src_libdrivers_la_SOURCES = src/drivers.c src_libdrivers_la_SOURCES = src/drivers.c
if HW_AGILENT_DMM if HW_AGILENT_DMM
@ -257,9 +221,20 @@ src_libdrivers_la_SOURCES += \
src/hardware/beaglelogic/beaglelogic.h \ src/hardware/beaglelogic/beaglelogic.h \
src/hardware/beaglelogic/protocol.h \ src/hardware/beaglelogic/protocol.h \
src/hardware/beaglelogic/protocol.c \ src/hardware/beaglelogic/protocol.c \
src/hardware/beaglelogic/api.c \ src/hardware/beaglelogic/api.c
src/hardware/beaglelogic/beaglelogic_native.c \ endif
src/hardware/beaglelogic/beaglelogic_tcp.c if HW_BRYMEN_BM86X
src_libdrivers_la_SOURCES += \
src/hardware/brymen-bm86x/protocol.h \
src/hardware/brymen-bm86x/protocol.c \
src/hardware/brymen-bm86x/api.c
endif
if HW_BRYMEN_DMM
src_libdrivers_la_SOURCES += \
src/hardware/brymen-dmm/parser.c \
src/hardware/brymen-dmm/protocol.h \
src/hardware/brymen-dmm/protocol.c \
src/hardware/brymen-dmm/api.c
endif endif
if HW_CEM_DT_885X if HW_CEM_DT_885X
src_libdrivers_la_SOURCES += \ src_libdrivers_la_SOURCES += \
@ -291,30 +266,12 @@ src_libdrivers_la_SOURCES += \
src/hardware/conrad-digi-35-cpu/protocol.c \ src/hardware/conrad-digi-35-cpu/protocol.c \
src/hardware/conrad-digi-35-cpu/api.c src/hardware/conrad-digi-35-cpu/api.c
endif endif
if HW_DCTTECH_USBRELAY
src_libdrivers_la_SOURCES += \
src/hardware/dcttech-usbrelay/protocol.h \
src/hardware/dcttech-usbrelay/protocol.c \
src/hardware/dcttech-usbrelay/api.c
endif
if HW_DEMO if HW_DEMO
src_libdrivers_la_SOURCES += \ src_libdrivers_la_SOURCES += \
src/hardware/demo/protocol.h \ src/hardware/demo/protocol.h \
src/hardware/demo/protocol.c \ src/hardware/demo/protocol.c \
src/hardware/demo/api.c src/hardware/demo/api.c
endif endif
if HW_DREAMSOURCELAB_DSLOGIC
src_libdrivers_la_SOURCES += \
src/hardware/dreamsourcelab-dslogic/protocol.h \
src/hardware/dreamsourcelab-dslogic/protocol.c \
src/hardware/dreamsourcelab-dslogic/api.c
endif
if HW_FLUKE_45
src_libdrivers_la_SOURCES += \
src/hardware/fluke-45/protocol.h \
src/hardware/fluke-45/protocol.c \
src/hardware/fluke-45/api.c
endif
if HW_FLUKE_DMM if HW_FLUKE_DMM
src_libdrivers_la_SOURCES += \ src_libdrivers_la_SOURCES += \
src/hardware/fluke-dmm/protocol.h \ src/hardware/fluke-dmm/protocol.h \
@ -331,7 +288,9 @@ if HW_FX2LAFW
src_libdrivers_la_SOURCES += \ src_libdrivers_la_SOURCES += \
src/hardware/fx2lafw/protocol.h \ src/hardware/fx2lafw/protocol.h \
src/hardware/fx2lafw/protocol.c \ src/hardware/fx2lafw/protocol.c \
src/hardware/fx2lafw/api.c src/hardware/fx2lafw/api.c \
src/hardware/fx2lafw/dslogic.c \
src/hardware/fx2lafw/dslogic.h
endif endif
if HW_GMC_MH_1X_2X if HW_GMC_MH_1X_2X
src_libdrivers_la_SOURCES += \ src_libdrivers_la_SOURCES += \
@ -345,24 +304,12 @@ src_libdrivers_la_SOURCES += \
src/hardware/gwinstek-gds-800/protocol.c \ src/hardware/gwinstek-gds-800/protocol.c \
src/hardware/gwinstek-gds-800/api.c src/hardware/gwinstek-gds-800/api.c
endif endif
if HW_GWINSTEK_GPD
src_libdrivers_la_SOURCES += \
src/hardware/gwinstek-gpd/protocol.h \
src/hardware/gwinstek-gpd/protocol.c \
src/hardware/gwinstek-gpd/api.c
endif
if HW_HAMEG_HMO if HW_HAMEG_HMO
src_libdrivers_la_SOURCES += \ src_libdrivers_la_SOURCES += \
src/hardware/hameg-hmo/protocol.h \ src/hardware/hameg-hmo/protocol.h \
src/hardware/hameg-hmo/protocol.c \ src/hardware/hameg-hmo/protocol.c \
src/hardware/hameg-hmo/api.c src/hardware/hameg-hmo/api.c
endif endif
if HW_HANTEK_4032L
src_libdrivers_la_SOURCES += \
src/hardware/hantek-4032l/protocol.h \
src/hardware/hantek-4032l/protocol.c \
src/hardware/hantek-4032l/api.c
endif
if HW_HANTEK_6XXX if HW_HANTEK_6XXX
src_libdrivers_la_SOURCES += \ src_libdrivers_la_SOURCES += \
src/hardware/hantek-6xxx/protocol.h \ src/hardware/hantek-6xxx/protocol.h \
@ -381,18 +328,6 @@ src_libdrivers_la_SOURCES += \
src/hardware/hp-3457a/protocol.c \ src/hardware/hp-3457a/protocol.c \
src/hardware/hp-3457a/api.c src/hardware/hp-3457a/api.c
endif endif
if HW_HP_3478A
src_libdrivers_la_SOURCES += \
src/hardware/hp-3478a/protocol.h \
src/hardware/hp-3478a/protocol.c \
src/hardware/hp-3478a/api.c
endif
if HW_HP_59306A
src_libdrivers_la_SOURCES += \
src/hardware/hp-59306a/protocol.h \
src/hardware/hp-59306a/protocol.c \
src/hardware/hp-59306a/api.c
endif
if HW_HUNG_CHANG_DSO_2100 if HW_HUNG_CHANG_DSO_2100
src_libdrivers_la_SOURCES += \ src_libdrivers_la_SOURCES += \
src/hardware/hung-chang-dso-2100/protocol.h \ src/hardware/hung-chang-dso-2100/protocol.h \
@ -411,24 +346,6 @@ src_libdrivers_la_SOURCES += \
src/hardware/ikalogic-scanaplus/protocol.c \ src/hardware/ikalogic-scanaplus/protocol.c \
src/hardware/ikalogic-scanaplus/api.c src/hardware/ikalogic-scanaplus/api.c
endif endif
if HW_IKALOGIC_SCANAQUAD
src_libdrivers_la_SOURCES += \
src/hardware/ikalogic-scanaquad/protocol.h \
src/hardware/ikalogic-scanaquad/protocol.c \
src/hardware/ikalogic-scanaquad/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_ITECH_IT8500
src_libdrivers_la_SOURCES += \
src/hardware/itech-it8500/protocol.h \
src/hardware/itech-it8500/protocol.c \
src/hardware/itech-it8500/api.c
endif
if HW_KECHENG_KC_330B if HW_KECHENG_KC_330B
src_libdrivers_la_SOURCES += \ src_libdrivers_la_SOURCES += \
src/hardware/kecheng-kc-330b/protocol.h \ src/hardware/kecheng-kc-330b/protocol.h \
@ -441,12 +358,6 @@ src_libdrivers_la_SOURCES += \
src/hardware/kern-scale/protocol.c \ src/hardware/kern-scale/protocol.c \
src/hardware/kern-scale/api.c src/hardware/kern-scale/api.c
endif endif
if HW_KINGST_LA2016
src_libdrivers_la_SOURCES += \
src/hardware/kingst-la2016/protocol.h \
src/hardware/kingst-la2016/protocol.c \
src/hardware/kingst-la2016/api.c
endif
if HW_KORAD_KAXXXXP if HW_KORAD_KAXXXXP
src_libdrivers_la_SOURCES += \ src_libdrivers_la_SOURCES += \
src/hardware/korad-kaxxxxp/protocol.h \ src/hardware/korad-kaxxxxp/protocol.h \
@ -477,36 +388,18 @@ src_libdrivers_la_SOURCES += \
src/hardware/manson-hcs-3xxx/protocol.c \ src/hardware/manson-hcs-3xxx/protocol.c \
src/hardware/manson-hcs-3xxx/api.c src/hardware/manson-hcs-3xxx/api.c
endif 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 if HW_MAYNUO_M97
src_libdrivers_la_SOURCES += \ src_libdrivers_la_SOURCES += \
src/hardware/maynuo-m97/protocol.h \ src/hardware/maynuo-m97/protocol.h \
src/hardware/maynuo-m97/protocol.c \ src/hardware/maynuo-m97/protocol.c \
src/hardware/maynuo-m97/api.c src/hardware/maynuo-m97/api.c
endif 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 if HW_MIC_985XX
src_libdrivers_la_SOURCES += \ src_libdrivers_la_SOURCES += \
src/hardware/mic-985xx/protocol.h \ src/hardware/mic-985xx/protocol.h \
src/hardware/mic-985xx/protocol.c \ src/hardware/mic-985xx/protocol.c \
src/hardware/mic-985xx/api.c src/hardware/mic-985xx/api.c
endif 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 if HW_MOTECH_LPS_30X
src_libdrivers_la_SOURCES += \ src_libdrivers_la_SOURCES += \
src/hardware/motech-lps-30x/protocol.h \ src/hardware/motech-lps-30x/protocol.h \
@ -537,30 +430,6 @@ src_libdrivers_la_SOURCES += \
src/hardware/pipistrello-ols/protocol.c \ src/hardware/pipistrello-ols/protocol.c \
src/hardware/pipistrello-ols/api.c src/hardware/pipistrello-ols/api.c
endif endif
if HW_RDTECH_DPS
src_libdrivers_la_SOURCES += \
src/hardware/rdtech-dps/protocol.h \
src/hardware/rdtech-dps/protocol.c \
src/hardware/rdtech-dps/api.c
endif
if HW_RDTECH_UM
src_libdrivers_la_SOURCES += \
src/hardware/rdtech-um/protocol.h \
src/hardware/rdtech-um/protocol.c \
src/hardware/rdtech-um/api.c
endif
if HW_RDTECH_TC
src_libdrivers_la_SOURCES += \
src/hardware/rdtech-tc/protocol.h \
src/hardware/rdtech-tc/protocol.c \
src/hardware/rdtech-tc/api.c
endif
if HW_RIGOL_DG
src_libdrivers_la_SOURCES += \
src/hardware/rigol-dg/protocol.h \
src/hardware/rigol-dg/protocol.c \
src/hardware/rigol-dg/api.c
endif
if HW_RIGOL_DS if HW_RIGOL_DS
src_libdrivers_la_SOURCES += \ src_libdrivers_la_SOURCES += \
src/hardware/rigol-ds/protocol.h \ src/hardware/rigol-ds/protocol.h \
@ -579,18 +448,6 @@ src_libdrivers_la_SOURCES += \
src/hardware/saleae-logic16/protocol.c \ src/hardware/saleae-logic16/protocol.c \
src/hardware/saleae-logic16/api.c src/hardware/saleae-logic16/api.c
endif endif
if HW_SALEAE_LOGIC_PRO
src_libdrivers_la_SOURCES += \
src/hardware/saleae-logic-pro/protocol.h \
src/hardware/saleae-logic-pro/protocol.c \
src/hardware/saleae-logic-pro/api.c
endif
if HW_SCPI_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 if HW_SCPI_PPS
src_libdrivers_la_SOURCES += \ src_libdrivers_la_SOURCES += \
src/hardware/scpi-pps/protocol.h \ src/hardware/scpi-pps/protocol.h \
@ -606,16 +463,8 @@ src_libdrivers_la_SOURCES += \
endif endif
if HW_SERIAL_LCR if HW_SERIAL_LCR
src_libdrivers_la_SOURCES += \ src_libdrivers_la_SOURCES += \
src/hardware/serial-lcr/protocol.h \
src/hardware/serial-lcr/protocol.c \
src/hardware/serial-lcr/api.c src/hardware/serial-lcr/api.c
endif endif
if HW_SIGLENT_SDS
src_libdrivers_la_SOURCES += \
src/hardware/siglent-sds/protocol.h \
src/hardware/siglent-sds/protocol.c \
src/hardware/siglent-sds/api.c
endif
if HW_SYSCLK_LWLA if HW_SYSCLK_LWLA
src_libdrivers_la_SOURCES += \ src_libdrivers_la_SOURCES += \
src/hardware/sysclk-lwla/lwla.h \ src/hardware/sysclk-lwla/lwla.h \
@ -626,12 +475,6 @@ src_libdrivers_la_SOURCES += \
src/hardware/sysclk-lwla/protocol.c \ src/hardware/sysclk-lwla/protocol.c \
src/hardware/sysclk-lwla/api.c src/hardware/sysclk-lwla/api.c
endif 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 if HW_TELEINFO
src_libdrivers_la_SOURCES += \ src_libdrivers_la_SOURCES += \
src/hardware/teleinfo/protocol.h \ src/hardware/teleinfo/protocol.h \
@ -656,18 +499,18 @@ src_libdrivers_la_SOURCES += \
src/hardware/uni-t-dmm/protocol.c \ src/hardware/uni-t-dmm/protocol.c \
src/hardware/uni-t-dmm/api.c src/hardware/uni-t-dmm/api.c
endif endif
if HW_UNI_T_UT181A
src_libdrivers_la_SOURCES += \
src/hardware/uni-t-ut181a/protocol.h \
src/hardware/uni-t-ut181a/protocol.c \
src/hardware/uni-t-ut181a/api.c
endif
if HW_UNI_T_UT32X if HW_UNI_T_UT32X
src_libdrivers_la_SOURCES += \ src_libdrivers_la_SOURCES += \
src/hardware/uni-t-ut32x/protocol.h \ src/hardware/uni-t-ut32x/protocol.h \
src/hardware/uni-t-ut32x/protocol.c \ src/hardware/uni-t-ut32x/protocol.c \
src/hardware/uni-t-ut32x/api.c src/hardware/uni-t-ut32x/api.c
endif 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 if HW_YOKOGAWA_DLM
src_libdrivers_la_SOURCES += \ src_libdrivers_la_SOURCES += \
src/hardware/yokogawa-dlm/protocol.h \ src/hardware/yokogawa-dlm/protocol.h \
@ -686,12 +529,6 @@ src_libdrivers_la_SOURCES += \
src/hardware/zeroplus-logic-cube/protocol.c \ src/hardware/zeroplus-logic-cube/protocol.c \
src/hardware/zeroplus-logic-cube/api.c src/hardware/zeroplus-logic-cube/api.c
endif endif
if HW_ZKETECH_EBD_USB
src_libdrivers_la_SOURCES += \
src/hardware/zketech-ebd-usb/protocol.h \
src/hardware/zketech-ebd-usb/protocol.c \
src/hardware/zketech-ebd-usb/api.c
endif
libsigrok_la_LIBADD = src/libdrivers.lo $(SR_EXTRA_LIBS) $(LIBSIGROK_LIBS) libsigrok_la_LIBADD = src/libdrivers.lo $(SR_EXTRA_LIBS) $(LIBSIGROK_LIBS)
libsigrok_la_LDFLAGS = -version-info $(SR_LIB_VERSION) -no-undefined libsigrok_la_LDFLAGS = -version-info $(SR_LIB_VERSION) -no-undefined
@ -707,7 +544,7 @@ noinst_HEADERS = src/libsigrok-internal.h
pkgconfigdir = $(libdir)/pkgconfig pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libsigrok.pc pkgconfig_DATA = libsigrok.pc
mimeappdir = $(datadir)/mime/packages mimeappdir = $(datadir)/mime/application
mimeapp_DATA = contrib/vnd.sigrok.session.xml mimeapp_DATA = contrib/vnd.sigrok.session.xml
mimeicondir = $(datadir)/icons/hicolor/48x48/mimetypes mimeicondir = $(datadir)/icons/hicolor/48x48/mimetypes
@ -744,9 +581,7 @@ EXTRA_DIST = \
contrib/libsigrok.png \ contrib/libsigrok.png \
contrib/libsigrok.svg \ contrib/libsigrok.svg \
contrib/vnd.sigrok.session.xml \ contrib/vnd.sigrok.session.xml \
contrib/60-libsigrok.rules \ contrib/z60_libsigrok.rules
contrib/61-libsigrok-plugdev.rules \
contrib/61-libsigrok-uaccess.rules
if HAVE_CHECK if HAVE_CHECK
TESTS = tests/main TESTS = tests/main
@ -769,8 +604,7 @@ tests_main_SOURCES = \
tests/driver_all.c \ tests/driver_all.c \
tests/device.c \ tests/device.c \
tests/trigger.c \ tests/trigger.c \
tests/analog.c \ tests/analog.c
tests/conv.c
tests_main_LDADD = libsigrok.la $(SR_EXTRA_LIBS) $(TESTS_LIBS) tests_main_LDADD = libsigrok.la $(SR_EXTRA_LIBS) $(TESTS_LIBS)
@ -802,7 +636,7 @@ nodist_bindings_cxx_libsigrokcxx_la_include_HEADERS = \
pkgconfig_DATA += bindings/cxx/libsigrokcxx.pc pkgconfig_DATA += bindings/cxx/libsigrokcxx.pc
doxy/xml/index.xml: include/libsigrok/libsigrok.h doxy/xml/index.xml: include/libsigrok/libsigrok.h
$(AM_V_GEN)cd $(srcdir) && SRCDIR=$(abs_srcdir)/ BUILDDIR=$(abs_builddir)/ doxygen Doxyfile 2>/dev/null $(AM_V_GEN)cd $(srcdir) && BUILDDIR=$(abs_builddir)/ doxygen Doxyfile 2>/dev/null
bindings/swig/enums.i: bindings/cxx/enums.timestamp bindings/swig/enums.i: bindings/cxx/enums.timestamp
bindings/cxx/enums.cpp: bindings/cxx/enums.timestamp bindings/cxx/enums.cpp: bindings/cxx/enums.timestamp
@ -837,7 +671,7 @@ CPPXMLDOC = bindings/cxx/doxy/xml/index.xml
$(CPPXMLDOC): bindings/cxx/include/libsigrokcxx/libsigrokcxx.hpp \ $(CPPXMLDOC): bindings/cxx/include/libsigrokcxx/libsigrokcxx.hpp \
bindings/cxx/enums.timestamp bindings/cxx/enums.timestamp
$(AM_V_GEN)cd $(srcdir)/bindings/cxx && SRCDIR=$(abs_srcdir)/bindings/cxx/ BUILDDIR=$(abs_builddir)/bindings/cxx/ doxygen Doxyfile 2>/dev/null $(AM_V_GEN)cd $(srcdir)/bindings/cxx && BUILDDIR=$(abs_builddir)/bindings/cxx/ doxygen Doxyfile 2>/dev/null
# Macro definitions to be used by the SWIG parser. # Macro definitions to be used by the SWIG parser.
swig_defs = -Dnoexcept= -Dprivate=protected -DG_GNUC_BEGIN_IGNORE_DEPRECATIONS= -DG_GNUC_END_IGNORE_DEPRECATIONS= swig_defs = -Dnoexcept= -Dprivate=protected -DG_GNUC_BEGIN_IGNORE_DEPRECATIONS= -DG_GNUC_END_IGNORE_DEPRECATIONS=
@ -885,7 +719,7 @@ python-clean:
-$(AM_V_at)$(setup_py) clean --all 2>/dev/null -$(AM_V_at)$(setup_py) clean --all 2>/dev/null
python-doc: python-doc:
$(AM_V_at)cd $(srcdir)/$(PDIR) && SRCDIR="$(abs_srcdir)/$(PDIR)/" BUILDDIR="$(abs_builddir)/$(PDIR)/" doxygen Doxyfile 2>/dev/null $(AM_V_at)cd $(srcdir)/$(PDIR) && BUILDDIR="$(abs_builddir)/$(PDIR)/" doxygen Doxyfile 2>/dev/null
BUILD_EXTRA += python-build BUILD_EXTRA += python-build
INSTALL_EXTRA += python-install INSTALL_EXTRA += python-install
@ -1002,7 +836,7 @@ java-clean:
-$(AM_V_at)rm -fr $(JDIR)/doxy -$(AM_V_at)rm -fr $(JDIR)/doxy
java-doc: java-doc:
$(AM_V_at)cd $(srcdir)/$(JDIR) && SRCDIR="$(abs_srcdir)/$(JDIR)/" BUILDDIR="$(abs_builddir)/$(JDIR)/" doxygen Doxyfile $(AM_V_at)cd $(srcdir)/$(JDIR) && BUILDDIR="$(abs_builddir)/$(JDIR)/" doxygen Doxyfile
BUILD_EXTRA += java-build BUILD_EXTRA += java-build
INSTALL_EXTRA += java-install INSTALL_EXTRA += java-install

2
NEWS
View File

@ -205,7 +205,7 @@ Note: This release DOES change the libsigrok API. That means it is NOT
- LeCroy LogicStudio - LeCroy LogicStudio
- mcupro Logic16 clone - mcupro Logic16 clone
- Pipistrello OLS - Pipistrello OLS
- Sysclk LWLA1016 - SysClk LWLA1016
- Oscilloscopes: - Oscilloscopes:
- Rigol/Agilent DS1000Z series - Rigol/Agilent DS1000Z series
- Yokogawa DLM2000 series - Yokogawa DLM2000 series

10
README
View File

@ -38,16 +38,12 @@ Requirements for the C library:
- pkg-config >= 0.22 - pkg-config >= 0.22
- libglib >= 2.32.0 - libglib >= 2.32.0
- libzip >= 0.10 - libzip >= 0.10
- libtirpc (optional, used by VXI, fallback when glibc >= 2.26)
- libserialport >= 0.1.1 (optional, used by some drivers) - libserialport >= 0.1.1 (optional, used by some drivers)
- librevisa >= 0.0.20130412 (optional, used by some drivers) - librevisa >= 0.0.20130412 (optional, used by some drivers)
- libusb-1.0 >= 1.0.16 (optional, used by some drivers) - libusb-1.0 >= 1.0.16 (optional, used by some drivers)
- hidapi >= 0.8.0 (optional, used for some HID based "serial cables") - libftdi >= 0.16 or libftdi1 >= 1.0 (optional, used by some drivers)
- bluez/libbluetooth >= 4.0 (optional, used for Bluetooth/BLE communication)
- libftdi1 >= 1.0 (optional, used by some drivers)
- libgpib (optional, used by some drivers) - libgpib (optional, used by some drivers)
- libieee1284 (optional, used by some drivers) - libieee1284 (optional, used by some drivers)
- libgio >= 2.32.0 (optional, used by some drivers)
- check >= 0.9.4 (optional, only needed to run unit tests) - check >= 0.9.4 (optional, only needed to run unit tests)
- doxygen (optional, only needed for the C API docs) - doxygen (optional, only needed for the C API docs)
- graphviz (optional, only needed for the C API docs) - graphviz (optional, only needed for the C API docs)
@ -79,7 +75,7 @@ Requirements for the Python bindings:
Requirements for the Ruby bindings: Requirements for the Ruby bindings:
- libsigrokcxx >= 0.4.0 (the libsigrok C++ bindings, see above) - libsigrokcxx >= 0.4.0 (the libsigrok C++ bindings, see above)
- Ruby >= 2.5.0 (including development files!) - Ruby >= 1.9.3 (including development files!)
- SWIG >= 3.0.8 - SWIG >= 3.0.8
- YARD (optional, only needed for the Ruby API docs) - YARD (optional, only needed for the Ruby API docs)
@ -152,7 +148,7 @@ Mailing list
IRC IRC
--- ---
You can find the sigrok developers in the #sigrok IRC channel on Libera.Chat. You can find the sigrok developers in the #sigrok IRC channel on Freenode.
Website Website

View File

@ -14,7 +14,6 @@ the device is connected to the PC (usually via USB), before it can be used.
The default locations where libsigrok expects the firmware files are: The default locations where libsigrok expects the firmware files are:
$SIGROK_FIRMWARE_DIR (environment variable)
$HOME/.local/share/sigrok-firmware $HOME/.local/share/sigrok-firmware
$prefix/share/sigrok-firmware $prefix/share/sigrok-firmware
/usr/local/share/sigrok-firmware /usr/local/share/sigrok-firmware
@ -37,11 +36,6 @@ The following drivers/devices require a firmware upload upon connection:
'sigrok-firmware' repository/project under a license which allows us 'sigrok-firmware' repository/project under a license which allows us
to redistribute them. 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 - fx2lafw: Logic analyzers based on the Cypress FX2(LP) chip need the
firmware files from the 'sigrok-firmware-fx2lafw' repository/project. firmware files from the 'sigrok-firmware-fx2lafw' repository/project.
The firmware is written from scratch and licensed under the GNU GPLv2+. The firmware is written from scratch and licensed under the GNU GPLv2+.
@ -69,11 +63,6 @@ The following drivers/devices require a firmware upload upon connection:
These can be extracted from the vendor's Linux application using a tool These can be extracted from the vendor's Linux application using a tool
from our 'sigrok-util' repository/project. 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: - sysclk-lwla:
- The Sysclk LWLA1034 requires various bitstream files. - The Sysclk LWLA1034 requires various bitstream files.
@ -84,12 +73,6 @@ The following drivers/devices require a firmware upload upon connection:
These can be extracted from the vendor's Windows drivers using a tool These can be extracted from the vendor's Windows drivers using a tool
from our 'sigrok-util' repository/project. 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: The following drivers/devices do not need any firmware upload:
- agilent-dmm - agilent-dmm
@ -98,73 +81,54 @@ The following drivers/devices do not need any firmware upload:
- atten-pps3xxx - atten-pps3xxx
- baylibre-acme - baylibre-acme
- beaglelogic - beaglelogic
- brymen-bm86x
- brymen-dmm
- cem-dt-885x - cem-dt-885x
- center-3xx (including all subdrivers) - center-3xx (including all subdrivers)
- chronovu-la - chronovu-la
- colead-slm - colead-slm
- conrad-digi-35-cpu - conrad-digi-35-cpu
- demo - demo
- fluke-45
- fluke-dmm - fluke-dmm
- ftdi-la - ftdi-la
- gmc-mh-1x-2x (including all subdrivers) - gmc-mh-1x-2x (including all subdrivers)
- gwinstek-gds-800 - gwinstek-gds-800
- gwinstek-gpd
- hameg-hmo - hameg-hmo
- hantek-4032l
- hp-3457a - hp-3457a
- hp-3478a
- hung-chang-dso-2100 - hung-chang-dso-2100
- ikalogic-scanalogic2 - ikalogic-scanalogic2
- ikalogic-scanaplus - ikalogic-scanaplus
- ipdbg-la
- kecheng-kc-330b - kecheng-kc-330b
- kern-scale - kern-scale
- korad-kaxxxxp
- lascar-el-usb - lascar-el-usb
- lecroy-xstream
- link-mso19 - link-mso19
- manson-hcs-3xxx - manson-hcs-3xxx
- maynuo-m97 - maynuo-m97
- mic-985xx (including all subdrivers) - mic-985xx (including all subdrivers)
- microchip-pickit2
- mooshimeter-dmm
- motech-lps-30x - motech-lps-30x
- norma-dmm - norma-dmm
- openbench-logic-sniffer - openbench-logic-sniffer
- pce-322a - pce-322a
- pipistrello-ols - pipistrello-ols
- rdtech-dps
- rigol-dg
- rigol-ds - rigol-ds
- rohde-schwarz-sme-0x
- scpi-dmm
- scpi-pps - scpi-pps
- serial-dmm (including all subdrivers) - serial-dmm (including all subdrivers)
- serial-lcr (including all subdrivers) - serial-lcr (including all subdrivers)
- siglent-sds
- teleinfo - teleinfo
- testo - testo
- tondaj-sl-814 - tondaj-sl-814
- uni-t-dmm (including all subdrivers) - uni-t-dmm (including all subdrivers)
- uni-t-ut32x - uni-t-ut32x
- victor-dmm
- yokogawa-dlm - yokogawa-dlm
- zeroplus-logic-cube - zeroplus-logic-cube
- zketech-ebd-usb
Specifying serial ports Specifying serial ports
----------------------- -----------------------
Many devices supported by libsigrok use serial port based cables (real RS232 Many devices supported by libsigrok use serial port based cables (real RS232
or USB-to-serial ones, CDC class) to connect to a PC. These serial cables are or USB-to-serial ones) to connect to a PC.
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 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 to (e.g. using the 'conn' option in sigrok-cli). It is not possible to scan
@ -173,43 +137,51 @@ for such devices without specifying a serial port.
Example: Example:
$ sigrok-cli --driver <somedriver>:conn=/dev/ttyUSB0 ... $ 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 ...
Formal syntax for serial communication: The following drivers/devices require a serial port specification:
- COM ports (RS232, USB CDC): - agilent-dmm
conn=<com-port> - appa-55ii
- USB HID cables: - atten-pps3xxx
conn=hid[/<chip>] - brymen-dmm
conn=hid[/<chip>]/usb=<bus>.<dev>[.<if>] - cem-dt-885x
conn=hid[/<chip>]/raw=<path> - center-3xx (including all subdrivers)
conn=hid[/<chip>]/sn=<serno> - colead-slm
conn=hid[/<chip>]/iokit=<path> - conrad-digi-35-cpu
chip can be: bu86x, ch9325, cp2110, victor - fluke-dmm
path may contain slashes - gmc-mh-1x-2x (including all subdrivers)
path and serno are "greedy" (span to the end of the spec) - hameg-hmo
- Bluetooth Classic and Bluetooth Low Energy (BLE): - link-mso19
conn=bt/<conn>/<addr> - mic-985xx (including all subdrivers)
conn can be: rfcomm, ble122, nrf51, cc254x - norma-dmm
addr can be "dense" or separated, bt/cc254x/0123456789ab or - openbench-logic-sniffer
bt/rfcomm/11-22-33-44-55-66 or bt/ble122/88:6b:12:34:56:78 - rigol-ds (for RS232; not required for USBTMC or TCP)
(note that colons may not be available when the conn= spec is taken - serial-dmm (including all subdrivers)
from a string that separates fields by colon, e.g. in the "--driver - serial-lcr (including all subdrivers)
<name>:conn=<spec>" example, that is why the dense form and the use - teleinfo
of dashes for separation are supported) - tondaj-sl-814
Some of the drivers implement a default for the connection. Some of the The following drivers/devices do not require a serial port specification:
drivers can auto-detect USB connected devices.
Beyond strict serial communication over COM ports (discussed above), the - asix-sigma
conn= property can also address specific USB devices, as well as specify TCP - brymen-bm86x
or VXI communication parameters. See these examples: - chronovu-la
- demo
$ sigrok-cli --driver <somedriver>:conn=<vid>.<pid> ... - fx2lafw
$ sigrok-cli --driver <somedriver>:conn=tcp-raw/<ipaddr>/<port> ... - hantek-dso
$ sigrok-cli --driver <somedriver>:conn=vxi/<ipaddr> ... - ikalogic-scanalogic2
$ sigrok-cli --driver <somedriver>:conn=usbtmc/<bus>.<addr> ... - 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
Specifying serial port parameters Specifying serial port parameters
@ -240,53 +212,33 @@ For USB-to-serial based devices, we recommended using our udev rules file
(see below for details). (see below for details).
Permissions for USB devices (udev rules files) Permissions for USB devices (udev rules file)
---------------------------------------------- ---------------------------------------------
When using USB-based devices supported by libsigrok, the user running the When using USB-based devices supported by libsigrok, the user running the
libsigrok frontend (e.g. sigrok-cli) has to have (read/write) permissions libsigrok frontend (e.g. sigrok-cli) has to have (read/write) permissions
for the respective USB device. for the respective USB device.
On Linux, this is accomplished using udev rules. libsigrok ships a rules On Linux, this is accomplished using either 'chmod' (not recommended) or
file containing all supported devices which can be detected reliably using the udev rules file shipped with libsigrok (recommended).
(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/60-libsigrok.rules. This file just contains The file is available in contrib/z60_libsigrok.rules. It contains entries
the list of devices and flags these devices with ID_SIGROK="1". Access is for all libsigrok-supported (USB-based) devices and changes their group
granted by the 61-libsigrok-plugdev.rules or 61-libsigrok-uaccess.rules files, to 'plugdev' and the permissions to '664'.
allowing access to members of the plugdev group or to currently logged in
users, respectively.
When using a libsigrok package from your favorite Linux distribution, the When using a libsigrok package from your favorite Linux distribution, the
files should already be installed in /usr/lib/udev/rules.d/, i.e. packager will have already taken care of properly installing the udev file
60-libsigrok.rules and one of the access granting rules files. Use of in the correct (distro-specific) place, and you don't have to do anything.
61-libsigrok-uaccess.rules is encouraged on systemd distributions. The packager might also have adapted 'plugdev' and '664' as needed.
The access policy can be locally overridden by placing appropriate rules in
/etc/udev/rules.d/, disabling or ammending the default policy. See the
udev documentation, e.g. man 7 udev, for details.
If you're building from source, you need to copy the file to the place If you're building from source, you need to copy the file to the place
where udev will read these rules. Local rules should go to /etc/udev/rules.d. where your distro expects such files. This is beyond the scope of this README,
Keep the file naming, otherwise interaction between the libsigrok rules and but generally the location could be e.g. /etc/udev/rules.d, or maybe
rules shipped by the system will be broken. /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.
Please consult the udev docs for details. Please consult the udev docs of your distro for details.
Non-default drivers for commodity chips
---------------------------------------
Some vendors include common USB chips in their products yet assign device
specific VID:PID pairs. Which results in the necessity for extra steps
before the serial port can be used:
- GW Instek VCP, found in GDM-8000 and probably other meters: Install the
vendors Windows driver to get access to a COM port. Or force the driver
assignment on Linux:
# modprobe cp210x
# echo 2184 0030 > /sys/bus/usb-serial/drivers/cp210x/new_id
Cypress FX2 based devices Cypress FX2 based devices
@ -308,11 +260,9 @@ UNI-T DMM (and rebranded models) cables
UNI-T multimeters (and rebranded devices, e.g. some Voltcraft models) can UNI-T multimeters (and rebranded devices, e.g. some Voltcraft models) can
ship with different PC connectivity cables: 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 Hoitek HE2325U chip, USB VID/PID 04fa:2490)
- UT-D04 (USB/HID cable with WCH CH9325 chip, USB VID/PID 1a86:e008) - UT-D04 (USB/HID cable with WCH CH9325 chip, USB VID/PID 1a86:e008)
- UT-D07 (Bluetooth adapter, ISSC BL79 BLETR chip) - UT-D02 (RS232 cable)
- 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) The above cables are all physically compatible (same IR connector shape)
with all/most currently known UNI-T multimeters. For example, you can with all/most currently known UNI-T multimeters. For example, you can
@ -387,12 +337,7 @@ a short list for convenience:
- BBC Goertz Metrawatt M2110: Briefly press the "Start/Reset" button on the - BBC Goertz Metrawatt M2110: Briefly press the "Start/Reset" button on the
interface panel on top. interface panel on top.
- Brymen BM257s: Press HOLD during power-on.
- Digitek DT4000ZC: Briefly press the "RS232" button. - 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: - Gossen Metrawatt Metrahit 1x/2x devices, driver gmc-mh-1x-2x-rs232:
- Power on the device with the "DATA" button pressed. - Power on the device with the "DATA" button pressed.
- Metrahit 2x devices must be configured for the respective interface type. - Metrahit 2x devices must be configured for the respective interface type.
@ -404,14 +349,6 @@ a short list for convenience:
'SI232 online' (28-29S) or 'SI232 store' (22-26x). The interface must 'SI232 online' (28-29S) or 'SI232 store' (22-26x). The interface must
be configured to the same baud rate as the host (default 9600). be configured to the same baud rate as the host (default 9600).
Multimeter and interface must be configured to the same address. Multimeter and interface must be configured to the same address.
- GW Instek GDM-397: Press the "REL/RS232C (USB)" button for roughly 1 second.
- GW Instek VCP: See the discussion on manual driver assignment to common
USB to UART chips with non-default USB identification.
- MASTECH MS6514: Press the "Setup/PC-Link" button for roughly 3 seconds.
- Meterman 38XR: Press the "RS232" button.
- Metrix MX56C: Press the PRINT button to have the meter send acquisition
data via IR. Hold the PRINT button to adjust the meter's transmission
interval.
- Norma DM950: If the interface doesn't work (e.g. USB-RS232 converter), power - Norma DM950: If the interface doesn't work (e.g. USB-RS232 converter), power
on the device with "FUNC" pressed (to power the interface from the DMM). on the device with "FUNC" pressed (to power the interface from the DMM).
- PCE PCE-DM32: Briefly press the "RS232" button. - PCE PCE-DM32: Briefly press the "RS232" button.
@ -422,7 +359,6 @@ a short list for convenience:
- UNI-T UT61B/C/D: Press the "REL/RS232/USB" button for roughly 1 second. - UNI-T UT61B/C/D: Press the "REL/RS232/USB" button for roughly 1 second.
- UNI-T UT71x: Press the "SEND/-/MAXMIN" button for roughly 1 second. - UNI-T UT71x: Press the "SEND/-/MAXMIN" button for roughly 1 second.
Briefly pressing the "EXIT" button leaves this mode again. Briefly pressing the "EXIT" button leaves this mode again.
- UNI-T UT181A: In the "SETUP" menu set "Communication" to "ON".
- UNI-T UT325: Briefly press the "SEND" button (as per manual). However, it - UNI-T UT325: Briefly press the "SEND" button (as per manual). However, it
appears that in practice you don't have to press the button (at least on appears that in practice you don't have to press the button (at least on
some versions of the device), simply connect the device via USB. some versions of the device), simply connect the device via USB.
@ -471,84 +407,3 @@ Example:
$ sigrok-cli --driver ols:conn=/dev/ttyACM0 ... $ sigrok-cli --driver ols:conn=/dev/ttyACM0 ...
JTAGulator
----------
The Grand Idea Studio JTAGulator also implements the SUMP protocol and
thus is covered by the OLS driver. See the vendor's wiki on details how
to enable the Logic Analyzer mode of operation.
https://github.com/grandideastudio/jtagulator/wiki/Logic-Analyzer
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,5 +1,3 @@
#include <config.h>
const DataType *ConfigKey::data_type() const const DataType *ConfigKey::data_type() const
{ {
const struct sr_key_info *info = sr_key_info_get(SR_KEY_CONFIG, id()); const struct sr_key_info *info = sr_key_info_get(SR_KEY_CONFIG, id());
@ -8,7 +6,7 @@ const DataType *ConfigKey::data_type() const
return DataType::get(info->datatype); return DataType::get(info->datatype);
} }
std::string ConfigKey::identifier() const string ConfigKey::identifier() const
{ {
const struct sr_key_info *info = sr_key_info_get(SR_KEY_CONFIG, id()); const struct sr_key_info *info = sr_key_info_get(SR_KEY_CONFIG, id());
if (!info) if (!info)
@ -16,7 +14,7 @@ std::string ConfigKey::identifier() const
return valid_string(info->id); return valid_string(info->id);
} }
std::string ConfigKey::description() const string ConfigKey::description() const
{ {
const struct sr_key_info *info = sr_key_info_get(SR_KEY_CONFIG, id()); const struct sr_key_info *info = sr_key_info_get(SR_KEY_CONFIG, id());
if (!info) if (!info)
@ -24,7 +22,7 @@ std::string ConfigKey::description() const
return valid_string(info->name); return valid_string(info->name);
} }
const ConfigKey *ConfigKey::get_by_identifier(std::string identifier) const ConfigKey *ConfigKey::get_by_identifier(string identifier)
{ {
const struct sr_key_info *info = sr_key_info_name_get(SR_KEY_CONFIG, identifier.c_str()); const struct sr_key_info *info = sr_key_info_name_get(SR_KEY_CONFIG, identifier.c_str());
if (!info) if (!info)
@ -32,6 +30,8 @@ const ConfigKey *ConfigKey::get_by_identifier(std::string identifier)
return get(info->key); return get(info->key);
} }
#include <config.h>
#ifndef HAVE_STOI_STOD #ifndef HAVE_STOI_STOD
/* Fallback implementation of stoi and stod */ /* Fallback implementation of stoi and stod */
@ -70,12 +70,12 @@ static inline double stod( const std::string& str )
} }
#endif #endif
Glib::VariantBase ConfigKey::parse_string(std::string value, enum sr_datatype dt) Glib::VariantBase ConfigKey::parse_string(string value) const
{ {
GVariant *variant; GVariant *variant;
uint64_t p, q; uint64_t p, q;
switch (dt) switch (data_type()->id())
{ {
case SR_T_UINT64: case SR_T_UINT64:
check(sr_parse_sizestring(value.c_str(), &p)); check(sr_parse_sizestring(value.c_str(), &p));
@ -90,7 +90,7 @@ Glib::VariantBase ConfigKey::parse_string(std::string value, enum sr_datatype dt
case SR_T_FLOAT: case SR_T_FLOAT:
try { try {
variant = g_variant_new_double(stod(value)); variant = g_variant_new_double(stod(value));
} catch (invalid_argument&) { } catch (invalid_argument) {
throw Error(SR_ERR_ARG); throw Error(SR_ERR_ARG);
} }
break; break;
@ -105,7 +105,7 @@ Glib::VariantBase ConfigKey::parse_string(std::string value, enum sr_datatype dt
case SR_T_INT32: case SR_T_INT32:
try { try {
variant = g_variant_new_int32(stoi(value)); variant = g_variant_new_int32(stoi(value));
} catch (invalid_argument&) { } catch (invalid_argument) {
throw Error(SR_ERR_ARG); throw Error(SR_ERR_ARG);
} }
break; break;
@ -116,8 +116,3 @@ Glib::VariantBase ConfigKey::parse_string(std::string value, enum sr_datatype dt
return Glib::VariantBase(variant, false); 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,11 +1,10 @@
/** Data type used for this configuration key. */ /** Data type used for this configuration key. */
const DataType *data_type() const; const DataType *data_type() const;
/** String identifier for this configuration key, suitable for CLI use. */ /** String identifier for this configuration key, suitable for CLI use. */
std::string identifier() const; string identifier() const;
/** Description of this configuration key. */ /** Description of this configuration key. */
std::string description() const; string description() const;
/** Get configuration key by string identifier. */ /** Get configuration key by string identifier. */
static const ConfigKey *get_by_identifier(std::string identifier); static const ConfigKey *get_by_identifier(string identifier);
/** Parse a string argument into the appropriate type for this key. */ /** Parse a string argument into the appropriate type for this key. */
static Glib::VariantBase parse_string(std::string value, enum sr_datatype dt); Glib::VariantBase parse_string(string value) const;
Glib::VariantBase parse_string(std::string value) const;

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@ -18,9 +18,8 @@
*/ */
/* Needed for isascii(), as used in the GNU libstdc++ headers */ /* Needed for isascii(), as used in the GNU libstdc++ headers */
/* Needed in strutil.c for POSIX.1-2008 locale functions */
#ifndef _XOPEN_SOURCE #ifndef _XOPEN_SOURCE
#define _XOPEN_SOURCE 700 #define _XOPEN_SOURCE 600
#endif #endif
#include <config.h> #include <config.h>
@ -32,8 +31,6 @@
namespace sigrok namespace sigrok
{ {
using namespace std;
/** Helper function to translate C errors to C++ exceptions. */ /** Helper function to translate C errors to C++ exceptions. */
static void check(int result) static void check(int result)
{ {
@ -131,19 +128,19 @@ Context::Context() :
if (struct sr_dev_driver **driver_list = sr_driver_list(_structure)) if (struct sr_dev_driver **driver_list = sr_driver_list(_structure))
for (int i = 0; driver_list[i]; i++) { for (int i = 0; driver_list[i]; i++) {
unique_ptr<Driver> driver {new Driver{driver_list[i]}}; unique_ptr<Driver> driver {new Driver{driver_list[i]}};
_drivers.emplace(driver->name(), move(driver)); _drivers.insert(make_pair(driver->name(), move(driver)));
} }
if (const struct sr_input_module **input_list = sr_input_list()) if (const struct sr_input_module **input_list = sr_input_list())
for (int i = 0; input_list[i]; i++) { for (int i = 0; input_list[i]; i++) {
unique_ptr<InputFormat> input {new InputFormat{input_list[i]}}; unique_ptr<InputFormat> input {new InputFormat{input_list[i]}};
_input_formats.emplace(input->name(), move(input)); _input_formats.insert(make_pair(input->name(), move(input)));
} }
if (const struct sr_output_module **output_list = sr_output_list()) if (const struct sr_output_module **output_list = sr_output_list())
for (int i = 0; output_list[i]; i++) { for (int i = 0; output_list[i]; i++) {
unique_ptr<OutputFormat> output {new OutputFormat{output_list[i]}}; unique_ptr<OutputFormat> output {new OutputFormat{output_list[i]}};
_output_formats.emplace(output->name(), move(output)); _output_formats.insert(make_pair(output->name(), move(output)));
} }
} }
@ -160,10 +157,11 @@ string Context::lib_version()
map<string, shared_ptr<Driver>> Context::drivers() map<string, shared_ptr<Driver>> Context::drivers()
{ {
map<string, shared_ptr<Driver>> result; map<string, shared_ptr<Driver>> result;
for (const auto &entry: _drivers) { for (const auto &entry: _drivers)
{
const auto &name = entry.first; const auto &name = entry.first;
const auto &driver = entry.second; const auto &driver = entry.second;
result.emplace(name, driver->share_owned_by(shared_from_this())); result.insert({name, driver->share_owned_by(shared_from_this())});
} }
return result; return result;
} }
@ -171,47 +169,23 @@ map<string, shared_ptr<Driver>> Context::drivers()
map<string, shared_ptr<InputFormat>> Context::input_formats() map<string, shared_ptr<InputFormat>> Context::input_formats()
{ {
map<string, shared_ptr<InputFormat>> result; map<string, shared_ptr<InputFormat>> result;
for (const auto &entry: _input_formats) { for (const auto &entry: _input_formats)
{
const auto &name = entry.first; const auto &name = entry.first;
const auto &input_format = entry.second; const auto &input_format = entry.second;
result.emplace(name, input_format->share_owned_by(shared_from_this())); result.insert({name, input_format->share_owned_by(shared_from_this())});
} }
return result; return result;
} }
shared_ptr<InputFormat> Context::input_format_match(string filename)
{
const struct sr_input *input;
const struct sr_input_module *imod;
int rc;
/*
* Have the input module looked up for the specified file.
* Failed lookup (or "successful lookup" with an empty result)
* are non-fatal. Free the sr_input that was created by the
* lookup routine, but grab the input module kind and return an
* InputFormat instance to the application. This works because
* the application passes a filename, no input data got buffered
* in the sr_input that we release.
*/
input = NULL;
rc = sr_input_scan_file(filename.c_str(), &input);
if (rc != SR_OK)
return nullptr;
if (!input)
return nullptr;
imod = sr_input_module_get(input);
sr_input_free(input);
return shared_ptr<InputFormat>{new InputFormat{imod}, default_delete<InputFormat>{}};
}
map<string, shared_ptr<OutputFormat>> Context::output_formats() map<string, shared_ptr<OutputFormat>> Context::output_formats()
{ {
map<string, shared_ptr<OutputFormat>> result; map<string, shared_ptr<OutputFormat>> result;
for (const auto &entry: _output_formats) { for (const auto &entry: _output_formats)
{
const auto &name = entry.first; const auto &name = entry.first;
const auto &output_format = entry.second; const auto &output_format = entry.second;
result.emplace(name, output_format->share_owned_by(shared_from_this())); result.insert({name, output_format->share_owned_by(shared_from_this())});
} }
return result; return result;
} }
@ -239,9 +213,12 @@ static int call_log_callback(void *cb_data, int loglevel,
auto *const callback = static_cast<LogCallbackFunction *>(cb_data); auto *const callback = static_cast<LogCallbackFunction *>(cb_data);
try { try
{
(*callback)(LogLevel::get(loglevel), message.get()); (*callback)(LogLevel::get(loglevel), message.get());
} catch (Error &e) { }
catch (Error e)
{
return e.result; return e.result;
} }
@ -304,7 +281,8 @@ shared_ptr<Packet> Context::create_meta_packet(
map<const ConfigKey *, Glib::VariantBase> config) map<const ConfigKey *, Glib::VariantBase> config)
{ {
auto meta = g_new0(struct sr_datafeed_meta, 1); auto meta = g_new0(struct sr_datafeed_meta, 1);
for (const auto &input : config) { for (const auto &input : config)
{
const auto &key = input.first; const auto &key = input.first;
const auto &value = input.second; const auto &value = input.second;
auto *const output = g_new(struct sr_config, 1); auto *const output = g_new(struct sr_config, 1);
@ -334,7 +312,7 @@ shared_ptr<Packet> Context::create_logic_packet(
shared_ptr<Packet> Context::create_analog_packet( shared_ptr<Packet> Context::create_analog_packet(
vector<shared_ptr<Channel> > channels, vector<shared_ptr<Channel> > channels,
const float *data_pointer, unsigned int num_samples, const Quantity *mq, float *data_pointer, unsigned int num_samples, const Quantity *mq,
const Unit *unit, vector<const QuantityFlag *> mqflags) const Unit *unit, vector<const QuantityFlag *> mqflags)
{ {
auto analog = g_new0(struct sr_datafeed_analog, 1); auto analog = g_new0(struct sr_datafeed_analog, 1);
@ -372,21 +350,13 @@ shared_ptr<Packet> Context::create_analog_packet(
spec->spec_digits = 0; spec->spec_digits = 0;
analog->num_samples = num_samples; analog->num_samples = num_samples;
analog->data = (float*)data_pointer; analog->data = data_pointer;
auto packet = g_new(struct sr_datafeed_packet, 1); auto packet = g_new(struct sr_datafeed_packet, 1);
packet->type = SR_DF_ANALOG; packet->type = SR_DF_ANALOG;
packet->payload = analog; packet->payload = analog;
return shared_ptr<Packet>{new Packet{nullptr, packet}, default_delete<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) shared_ptr<Session> Context::load_session(string filename)
{ {
return shared_ptr<Session>{ return shared_ptr<Session>{
@ -476,14 +446,16 @@ vector<shared_ptr<HardwareDevice>> Driver::scan(
map<const ConfigKey *, Glib::VariantBase> options) map<const ConfigKey *, Glib::VariantBase> options)
{ {
/* Initialise the driver if not yet done. */ /* Initialise the driver if not yet done. */
if (!_initialized) { if (!_initialized)
{
check(sr_driver_init(_parent->_structure, _structure)); check(sr_driver_init(_parent->_structure, _structure));
_initialized = true; _initialized = true;
} }
/* Translate scan options to GSList of struct sr_config pointers. */ /* Translate scan options to GSList of struct sr_config pointers. */
GSList *option_list = nullptr; GSList *option_list = nullptr;
for (const auto &entry : options) { for (const auto &entry : options)
{
const auto &key = entry.first; const auto &key = entry.first;
const auto &value = entry.second; const auto &value = entry.second;
auto *const config = g_new(struct sr_config, 1); auto *const config = g_new(struct sr_config, 1);
@ -501,7 +473,8 @@ vector<shared_ptr<HardwareDevice>> Driver::scan(
/* Create device objects. */ /* Create device objects. */
vector<shared_ptr<HardwareDevice>> result; vector<shared_ptr<HardwareDevice>> result;
for (GSList *device = device_list; device; device = device->next) { for (GSList *device = device_list; device; device = device->next)
{
auto *const sdi = static_cast<struct sr_dev_inst *>(device->data); auto *const sdi = static_cast<struct sr_dev_inst *>(device->data);
shared_ptr<HardwareDevice> hwdev { shared_ptr<HardwareDevice> hwdev {
new HardwareDevice{shared_from_this(), sdi}, new HardwareDevice{shared_from_this(), sdi},
@ -597,22 +570,23 @@ Device::Device(struct sr_dev_inst *structure) :
Configurable(sr_dev_inst_driver_get(structure), structure, nullptr), Configurable(sr_dev_inst_driver_get(structure), structure, nullptr),
_structure(structure) _structure(structure)
{ {
for (GSList *entry = sr_dev_inst_channels_get(structure); entry; entry = entry->next) { for (GSList *entry = sr_dev_inst_channels_get(structure); entry; entry = entry->next)
{
auto *const ch = static_cast<struct sr_channel *>(entry->data); auto *const ch = static_cast<struct sr_channel *>(entry->data);
unique_ptr<Channel> channel {new Channel{ch}}; unique_ptr<Channel> channel {new Channel{ch}};
_channels.emplace(ch, move(channel)); _channels.insert(make_pair(ch, move(channel)));
} }
for (GSList *entry = sr_dev_inst_channel_groups_get(structure); entry; entry = entry->next) { for (GSList *entry = sr_dev_inst_channel_groups_get(structure); entry; entry = entry->next)
{
auto *const cg = static_cast<struct sr_channel_group *>(entry->data); auto *const cg = static_cast<struct sr_channel_group *>(entry->data);
unique_ptr<ChannelGroup> group {new ChannelGroup{this, cg}}; unique_ptr<ChannelGroup> group {new ChannelGroup{this, cg}};
_channel_groups.emplace(group->name(), move(group)); _channel_groups.insert(make_pair(group->name(), move(group)));
} }
} }
Device::~Device() Device::~Device()
{ {}
}
string Device::vendor() const string Device::vendor() const
{ {
@ -658,10 +632,11 @@ map<string, shared_ptr<ChannelGroup>>
Device::channel_groups() Device::channel_groups()
{ {
map<string, shared_ptr<ChannelGroup>> result; map<string, shared_ptr<ChannelGroup>> result;
for (const auto &entry: _channel_groups) { for (const auto &entry: _channel_groups)
{
const auto &name = entry.first; const auto &name = entry.first;
const auto &channel_group = entry.second; const auto &channel_group = entry.second;
result.emplace(name, channel_group->share_owned_by(get_shared_from_this())); result.insert({name, channel_group->share_owned_by(get_shared_from_this())});
} }
return result; return result;
} }
@ -720,7 +695,7 @@ shared_ptr<Channel> UserDevice::add_channel(unsigned int index,
GSList *const last = g_slist_last(sr_dev_inst_channels_get(Device::_structure)); GSList *const last = g_slist_last(sr_dev_inst_channels_get(Device::_structure));
auto *const ch = static_cast<struct sr_channel *>(last->data); auto *const ch = static_cast<struct sr_channel *>(last->data);
unique_ptr<Channel> channel {new Channel{ch}}; unique_ptr<Channel> channel {new Channel{ch}};
_channels.emplace(ch, move(channel)); _channels.insert(make_pair(ch, move(channel)));
return get_channel(ch); return get_channel(ch);
} }
@ -943,10 +918,9 @@ Session::Session(shared_ptr<Context> context, string filename) :
for (GSList *dev = dev_list; dev; dev = dev->next) { for (GSList *dev = dev_list; dev; dev = dev->next) {
auto *const sdi = static_cast<struct sr_dev_inst *>(dev->data); auto *const sdi = static_cast<struct sr_dev_inst *>(dev->data);
unique_ptr<SessionDevice> device {new SessionDevice{sdi}}; unique_ptr<SessionDevice> device {new SessionDevice{sdi}};
_owned_devices.emplace(sdi, move(device)); _owned_devices.insert(make_pair(sdi, move(device)));
} }
_context->_session = this; _context->_session = this;
g_slist_free(dev_list);
} }
Session::~Session() Session::~Session()
@ -981,7 +955,6 @@ vector<shared_ptr<Device>> Session::devices()
auto *const sdi = static_cast<struct sr_dev_inst *>(dev->data); auto *const sdi = static_cast<struct sr_dev_inst *>(dev->data);
result.push_back(get_device(sdi)); result.push_back(get_device(sdi));
} }
g_slist_free(dev_list);
return result; return result;
} }
@ -1326,48 +1299,6 @@ vector<const QuantityFlag *> Analog::mq_flags() const
return QuantityFlag::flags_from_mask(_structure->meaning->mqflags); return QuantityFlag::flags_from_mask(_structure->meaning->mqflags);
} }
shared_ptr<Logic> Analog::get_logic_via_threshold(float threshold,
uint8_t *data_ptr) const
{
auto datafeed = g_new(struct sr_datafeed_logic, 1);
datafeed->length = num_samples();
datafeed->unitsize = 1;
if (data_ptr)
datafeed->data = data_ptr;
else
datafeed->data = g_malloc(datafeed->length);
shared_ptr<Logic> logic =
shared_ptr<Logic>{new Logic{datafeed}, default_delete<Logic>{}};
check(sr_a2l_threshold(_structure, threshold,
(uint8_t*)datafeed->data, datafeed->length));
return logic;
}
shared_ptr<Logic> Analog::get_logic_via_schmitt_trigger(float lo_thr,
float hi_thr, uint8_t *state, uint8_t *data_ptr) const
{
auto datafeed = g_new(struct sr_datafeed_logic, 1);
datafeed->length = num_samples();
datafeed->unitsize = 1;
if (data_ptr)
datafeed->data = data_ptr;
else
datafeed->data = g_malloc(datafeed->length);
shared_ptr<Logic> logic =
shared_ptr<Logic>{new Logic{datafeed}, default_delete<Logic>{}};
check(sr_a2l_schmitt_trigger(_structure, lo_thr, hi_thr, state,
(uint8_t*)datafeed->data, datafeed->length));
return logic;
}
Rational::Rational(const struct sr_rational *structure) : Rational::Rational(const struct sr_rational *structure) :
_structure(structure) _structure(structure)
{ {
@ -1430,14 +1361,15 @@ map<string, shared_ptr<Option>> InputFormat::options()
{ {
map<string, shared_ptr<Option>> result; map<string, shared_ptr<Option>> result;
if (const struct sr_option **options = sr_input_options_get(_structure)) { if (const struct sr_option **options = sr_input_options_get(_structure))
{
shared_ptr<const struct sr_option *> option_array shared_ptr<const struct sr_option *> option_array
{options, &sr_input_options_free}; {options, &sr_input_options_free};
for (int i = 0; options[i]; i++) { for (int i = 0; options[i]; i++) {
shared_ptr<Option> opt { shared_ptr<Option> opt {
new Option{options[i], option_array}, new Option{options[i], option_array},
default_delete<Option>{}}; default_delete<Option>{}};
result.emplace(opt->id(), move(opt)); result.insert({opt->id(), move(opt)});
} }
} }
return result; return result;
@ -1460,7 +1392,8 @@ Input::Input(shared_ptr<Context> context, const struct sr_input *structure) :
shared_ptr<InputDevice> Input::device() shared_ptr<InputDevice> Input::device()
{ {
if (!_device) { if (!_device)
{
auto sdi = sr_input_dev_inst_get(_structure); auto sdi = sr_input_dev_inst_get(_structure);
if (!sdi) if (!sdi)
throw Error(SR_ERR_NA); throw Error(SR_ERR_NA);
@ -1550,28 +1483,6 @@ vector<Glib::VariantBase> Option::values() const
return result; return result;
} }
Glib::VariantBase Option::parse_string(string value)
{
enum sr_datatype dt;
Glib::VariantBase dflt = default_value();
GVariant *tmpl = dflt.gobj();
if (g_variant_is_of_type(tmpl, G_VARIANT_TYPE_UINT64)) {
dt = SR_T_UINT64;
} else if (g_variant_is_of_type(tmpl, G_VARIANT_TYPE_STRING)) {
dt = SR_T_STRING;
} else if (g_variant_is_of_type(tmpl, G_VARIANT_TYPE_BOOLEAN)) {
dt = SR_T_BOOL;
} else if (g_variant_is_of_type(tmpl, G_VARIANT_TYPE_DOUBLE)) {
dt = SR_T_FLOAT;
} else if (g_variant_is_of_type(tmpl, G_VARIANT_TYPE_INT32)) {
dt = SR_T_INT32;
} else {
throw Error(SR_ERR_BUG);
}
return ConfigKey::parse_string(value, dt);
}
OutputFormat::OutputFormat(const struct sr_output_module *structure) : OutputFormat::OutputFormat(const struct sr_output_module *structure) :
_structure(structure) _structure(structure)
{ {
@ -1604,14 +1515,15 @@ map<string, shared_ptr<Option>> OutputFormat::options()
{ {
map<string, shared_ptr<Option>> result; map<string, shared_ptr<Option>> result;
if (const struct sr_option **options = sr_output_options_get(_structure)) { if (const struct sr_option **options = sr_output_options_get(_structure))
{
shared_ptr<const struct sr_option *> option_array shared_ptr<const struct sr_option *> option_array
{options, &sr_output_options_free}; {options, &sr_output_options_free};
for (int i = 0; options[i]; i++) { for (int i = 0; options[i]; i++) {
shared_ptr<Option> opt { shared_ptr<Option> opt {
new Option{options[i], option_array}, new Option{options[i], option_array},
default_delete<Option>{}}; default_delete<Option>{}};
result.emplace(opt->id(), move(opt)); result.insert({opt->id(), move(opt)});
} }
} }
return result; return result;
@ -1663,20 +1575,18 @@ Output::~Output()
check(sr_output_free(_structure)); check(sr_output_free(_structure));
} }
shared_ptr<OutputFormat> Output::format()
{
return _format;
}
string Output::receive(shared_ptr<Packet> packet) string Output::receive(shared_ptr<Packet> packet)
{ {
GString *out; GString *out;
check(sr_output_send(_structure, packet->_structure, &out)); check(sr_output_send(_structure, packet->_structure, &out));
if (out) { if (out)
{
auto result = string(out->str, out->str + out->len); auto result = string(out->str, out->str + out->len);
g_string_free(out, true); g_string_free(out, true);
return result; return result;
} else { }
else
{
return string(); return string();
} }
} }

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -94,18 +94,10 @@ VECTOR(std::shared_ptr<sigrok::HardwareDevice>, HardwareDevice)
"java.util.Map<JKey, JValue>" "java.util.Map<JKey, JValue>"
%typemap(javain, %typemap(javain,
/* SWIG 4.0.0 changed the std::map wrappers in an incompatible way. */
#if SWIG_VERSION >= 0x040000
pre=" $javaclassname temp$javainput = new $javaclassname();
for (java.util.Map.Entry<JKey, JValue> entry : $javainput.entrySet())
temp$javainput.put(entry.getKey(), entry.getValue());",
pgcppname="temp$javainput")
#else
pre=" $javaclassname temp$javainput = new $javaclassname(); pre=" $javaclassname temp$javainput = new $javaclassname();
for (java.util.Map.Entry<JKey, JValue> entry : $javainput.entrySet()) for (java.util.Map.Entry<JKey, JValue> entry : $javainput.entrySet())
temp$javainput.set(entry.getKey(), entry.getValue());", temp$javainput.set(entry.getKey(), entry.getValue());",
pgcppname="temp$javainput") pgcppname="temp$javainput")
#endif
std::map< CKey, CValue > "$javaclassname.getCPtr(temp$javainput)" std::map< CKey, CValue > "$javaclassname.getCPtr(temp$javainput)"
%typemap(javaout) std::map< CKey, CValue > { %typemap(javaout) std::map< CKey, CValue > {

File diff suppressed because it is too large Load Diff

View File

@ -45,8 +45,6 @@ which provides access to the error code and description."
%module(docstring=DOCSTRING) classes %module(docstring=DOCSTRING) classes
%{ %{
#include "config.h"
#include <stdio.h> #include <stdio.h>
#include <pygobject.h> #include <pygobject.h>
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
@ -55,6 +53,8 @@ which provides access to the error code and description."
PyObject *PyGObject_lib; PyObject *PyGObject_lib;
PyObject *GLib; PyObject *GLib;
#include "config.h"
#if PYGOBJECT_FLAGS_SIGNED #if PYGOBJECT_FLAGS_SIGNED
typedef gint pyg_flags_type; typedef gint pyg_flags_type;
#else #else
@ -112,9 +112,6 @@ typedef guint pyg_flags_type;
g_free(value); g_free(value);
} }
/* Use the same typemap above for Glib::VariantContainerBase */
%apply Glib::VariantBase { Glib::VariantContainerBase }
/* Map from callable PyObject to LogCallbackFunction */ /* Map from callable PyObject to LogCallbackFunction */
%typecheck(SWIG_TYPECHECK_POINTER) sigrok::LogCallbackFunction { %typecheck(SWIG_TYPECHECK_POINTER) sigrok::LogCallbackFunction {
$1 = PyCallable_Check($input); $1 = PyCallable_Check($input);
@ -340,14 +337,7 @@ Glib::VariantBase python_to_variant_by_key(PyObject *input, const sigrok::Config
return Glib::Variant<double>::create(PyFloat_AsDouble(input)); return Glib::Variant<double>::create(PyFloat_AsDouble(input));
else if (type == SR_T_INT32 && PyInt_Check(input)) else if (type == SR_T_INT32 && PyInt_Check(input))
return Glib::Variant<gint32>::create(PyInt_AsLong(input)); return Glib::Variant<gint32>::create(PyInt_AsLong(input));
else if ((type == SR_T_RATIONAL_VOLT) && PyTuple_Check(input) && (PyTuple_Size(input) == 2)) { else
PyObject *numObj = PyTuple_GetItem(input, 0);
PyObject *denomObj = PyTuple_GetItem(input, 1);
if ((PyInt_Check(numObj) || PyLong_Check(numObj)) && (PyInt_Check(denomObj) || PyLong_Check(denomObj))) {
const std::vector<guint64> v = {(guint64)PyInt_AsLong(numObj), (guint64)PyInt_AsLong(denomObj)};
return Glib::Variant< std::vector<guint64> >::create(v);
}
}
throw sigrok::Error(SR_ERR_ARG); throw sigrok::Error(SR_ERR_ARG);
} }
@ -400,7 +390,6 @@ std::map<std::string, Glib::VariantBase> dict_to_map_options(PyObject *dict,
/* Ignore these methods, we will override them below. */ /* Ignore these methods, we will override them below. */
%ignore sigrok::Analog::data; %ignore sigrok::Analog::data;
%ignore sigrok::Logic::data;
%ignore sigrok::Driver::scan; %ignore sigrok::Driver::scan;
%ignore sigrok::InputFormat::create_input; %ignore sigrok::InputFormat::create_input;
%ignore sigrok::OutputFormat::create_output; %ignore sigrok::OutputFormat::create_output;
@ -559,42 +548,4 @@ 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" %include "doc_end.i"

View File

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

View File

@ -46,7 +46,7 @@ for compound in index.findall('compound'):
if language == 'python': if language == 'python':
print('%%feature("docstring") %s "%s";' % (class_name, brief)) print('%%feature("docstring") %s "%s";' % (class_name, brief))
elif language == 'ruby': elif language == 'ruby':
print('%%feature("docstring") %s "Document-class: %s\\n%s\\n";' % (class_name, class_name.replace("sigrok", "Sigrok", 1), brief)) print('%%feature("docstring") %s "/* Document-class: %s\\n%s */\\n";' % (class_name, class_name.replace("sigrok", "Sigrok", 1), brief))
elif language == 'java': elif language == 'java':
print('%%typemap(javaclassmodifiers) %s "/** %s */\npublic class"' % ( print('%%typemap(javaclassmodifiers) %s "/** %s */\npublic class"' % (
class_name, brief)) class_name, brief))
@ -77,10 +77,10 @@ for compound in index.findall('compound'):
for name, desc in parameters.items()]) + '";') for name, desc in parameters.items()]) + '";')
if language == 'ruby' and kind == 'public-func': if language == 'ruby' and kind == 'public-func':
print(str.join('\n', [ print(str.join('\n', [
'%%feature("docstring") %s::%s "%s' % ( '%%feature("docstring") %s::%s "/* %s' % (
class_name, member_name, brief)] + [ class_name, member_name, brief)] + [
'@param %s %s' % (name, desc) '@param %s %s' % (name, desc)
for name, desc in parameters.items()]) + '\\n";') for name, desc in parameters.items()]) + ' */\\n";')
elif language == 'java' and kind == 'public-func': elif language == 'java' and kind == 'public-func':
print(str.join('\n', [ print(str.join('\n', [
'%%javamethodmodifiers %s::%s "/** %s' % ( '%%javamethodmodifiers %s::%s "/** %s' % (
@ -111,4 +111,4 @@ for compound in index.findall('compound'):
print('%}') print('%}')
elif language == 'ruby' and constants: elif language == 'ruby' and constants:
for member_name, brief in constants: for member_name, brief in constants:
print('%%feature("docstring") %s::%s "%s\\n";' % (class_name, member_name, brief)) print('%%feature("docstring") %s::%s "/* %s */\\n";' % (class_name, member_name, brief))

View File

@ -96,18 +96,11 @@ SR_PKGLIBS_RUBY=
SR_EXTRA_LIBS= SR_EXTRA_LIBS=
SR_EXTRA_CXX_LIBS= SR_EXTRA_CXX_LIBS=
SR_ARG_OPT_PKG([libserialport], [LIBSERIALPORT], , SR_ARG_OPT_PKG([libserialport], [LIBSERIALPORT], [NEED_SERIAL],
[libserialport >= 0.1.1]) [libserialport >= 0.1.1])
SR_ARG_OPT_PKG([libftdi], [LIBFTDI], , [libftdi1 >= 1.0]) SR_ARG_OPT_PKG([libftdi], [LIBFTDI],,
[libftdi1 >= 1.0], [libftdi >= 0.16])
# 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])
SR_ARG_OPT_PKG([libnettle], [LIBNETTLE], , [nettle])
# FreeBSD comes with an "integrated" libusb-1.0-style USB API. # FreeBSD comes with an "integrated" libusb-1.0-style USB API.
# This means libusb-1.0 is always available; no need to check for it. # This means libusb-1.0 is always available; no need to check for it.
@ -138,25 +131,6 @@ SR_ARG_OPT_CHECK([libieee1284], [LIBIEEE1284],, [
AS_IF([test "x$sr_have_libieee1284" = xyes], AS_IF([test "x$sr_have_libieee1284" = xyes],
[SR_PREPEND([SR_EXTRA_LIBS], [-lieee1284])]) [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 ## ## Feature checks ##
###################### ######################
@ -188,25 +162,13 @@ AS_CASE([$host_os], [mingw*], [SR_PREPEND([SR_EXTRA_LIBS], [-lws2_32])])
SR_SEARCH_LIBS([SR_EXTRA_LIBS], [pow], [m]) SR_SEARCH_LIBS([SR_EXTRA_LIBS], [pow], [m])
# RPC is only needed for VXI support. # RPC is only needed for VXI support.
AC_CACHE_CHECK([for SunRPC support], [sr_cv_have_sunrpc], AC_CACHE_CHECK([for RPC support], [sr_cv_have_rpc],
[AC_LINK_IFELSE([AC_LANG_PROGRAM( [AC_LINK_IFELSE([AC_LANG_PROGRAM(
[[#include <rpc/rpc.h>]m4_newline[CLIENT *rpc_test(void);]], [[#include <rpc/rpc.h>]m4_newline[CLIENT *rpc_test(void);]],
[[(void) clnt_create("", 0, 0, "");]])], [[(void) clnt_create("", 0, 0, "");]])],
[RPC_CFLAGS=""; RPC_LIBS=""; sr_cv_have_sunrpc=yes], [sr_cv_have_rpc=yes], [sr_cv_have_rpc=no])])
[sr_cv_have_sunrpc=no])])
PKG_CHECK_MODULES([TIRPC],
[libtirpc],
[RPC_CFLAGS=$TIRPC_CFLAGS; SR_PREPEND([SR_EXTRA_LIBS], [$TIRPC_LIBS]); sr_cv_have_tirpc=yes],
[sr_cv_have_tirpc=no])
AS_IF([test "x$sr_cv_have_sunrpc" = xyes -o "x$sr_cv_have_tirpc" = xyes],
[sr_cv_have_rpc=yes], [sr_cv_have_rpc=no])
AC_SUBST(RPC_CFLAGS)
AC_SUBST(RPC_LIBS)
AS_IF([test "x$sr_cv_have_rpc" = xyes], AS_IF([test "x$sr_cv_have_rpc" = xyes],
[AC_DEFINE([HAVE_RPC], [1], [Specifies whether we have RPC support (either by SunRPC or libtirpc).])]) [AC_DEFINE([HAVE_RPC], [1], [Specifies whether we have RPC support.])])
# VXI support is only compiled if RPC support was found. # VXI support is only compiled if RPC support was found.
AM_CONDITIONAL([NEED_RPC], [test "x$sr_cv_have_rpc" = xyes]) AM_CONDITIONAL([NEED_RPC], [test "x$sr_cv_have_rpc" = xyes])
@ -257,83 +219,62 @@ m4_define([_SR_DRIVER], [
m4_define([SR_DRIVER], m4_define([SR_DRIVER],
[_SR_DRIVER([$1], [$2], m4_expand([AS_TR_CPP([HW_$2])]), [$3])]) [_SR_DRIVER([$1], [$2], m4_expand([AS_TR_CPP([HW_$2])]), [$3])])
SR_DRIVER([Agilent DMM], [agilent-dmm], [serial_comm]) SR_DRIVER([Agilent DMM], [agilent-dmm], [libserialport])
SR_DRIVER([Appa 55II], [appa-55ii], [serial_comm]) SR_DRIVER([Appa 55II], [appa-55ii], [libserialport])
SR_DRIVER([Arachnid Labs Re:load Pro], [arachnid-labs-re-load-pro], [serial_comm]) SR_DRIVER([Arachnid Labs Re:load Pro], [arachnid-labs-re-load-pro], [libserialport])
SR_DRIVER([ASIX SIGMA/SIGMA2], [asix-sigma], [libftdi]) SR_DRIVER([ASIX SIGMA/SIGMA2], [asix-sigma], [libftdi])
SR_DRIVER([Atten PPS3xxx], [atten-pps3xxx], [serial_comm]) SR_DRIVER([Atten PPS3xxx], [atten-pps3xxx], [libserialport])
SR_DRIVER([BayLibre ACME], [baylibre-acme], [sys_timerfd_h]) SR_DRIVER([BayLibre ACME], [baylibre-acme], [sys_timerfd_h])
SR_DRIVER([BeagleLogic], [beaglelogic], [sys_mman_h sys_ioctl_h]) SR_DRIVER([BeagleLogic], [beaglelogic], [sys_mman_h sys_ioctl_h])
SR_DRIVER([CEM DT-885x], [cem-dt-885x], [serial_comm]) SR_DRIVER([Brymen BM86x], [brymen-bm86x], [libusb])
SR_DRIVER([Center 3xx], [center-3xx], [serial_comm]) 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([ChronoVu LA], [chronovu-la], [libusb libftdi]) SR_DRIVER([ChronoVu LA], [chronovu-la], [libusb libftdi])
SR_DRIVER([Colead SLM], [colead-slm], [serial_comm]) SR_DRIVER([Colead SLM], [colead-slm], [libserialport])
SR_DRIVER([Conrad DIGI 35 CPU], [conrad-digi-35-cpu], [serial_comm]) SR_DRIVER([Conrad DIGI 35 CPU], [conrad-digi-35-cpu], [libserialport])
SR_DRIVER([dcttech usbrelay], [dcttech-usbrelay], [libhidapi])
SR_DRIVER([demo], [demo]) SR_DRIVER([demo], [demo])
SR_DRIVER([DreamSourceLab DSLogic], [dreamsourcelab-dslogic], [libusb]) SR_DRIVER([Fluke DMM], [fluke-dmm], [libserialport])
SR_DRIVER([Fluke 45], [fluke-45])
SR_DRIVER([Fluke DMM], [fluke-dmm], [serial_comm])
SR_DRIVER([FTDI LA], [ftdi-la], [libusb libftdi]) SR_DRIVER([FTDI LA], [ftdi-la], [libusb libftdi])
SR_DRIVER([fx2lafw], [fx2lafw], [libusb]) SR_DRIVER([fx2lafw], [fx2lafw], [libusb])
SR_DRIVER([GMC MH 1x/2x], [gmc-mh-1x-2x], [serial_comm]) SR_DRIVER([GMC MH 1x/2x], [gmc-mh-1x-2x], [libserialport])
SR_DRIVER([GW Instek GDS-800], [gwinstek-gds-800], [serial_comm]) SR_DRIVER([GW Instek GDS-800], [gwinstek-gds-800], [libserialport])
SR_DRIVER([GW Instek GPD], [gwinstek-gpd], [serial_comm]) SR_DRIVER([Hameg HMO], [hameg-hmo], [libserialport])
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 6xxx], [hantek-6xxx], [libusb])
SR_DRIVER([Hantek DSO], [hantek-dso], [libusb]) SR_DRIVER([Hantek DSO], [hantek-dso], [libusb])
SR_DRIVER([HP 3457A], [hp-3457a]) SR_DRIVER([HP 3457A], [hp-3457a])
SR_DRIVER([HP 3478A], [hp-3478a], [libgpib])
SR_DRIVER([hp-59306a], [hp-59306a])
SR_DRIVER([Hung-Chang DSO-2100], [hung-chang-dso-2100], [libieee1284]) SR_DRIVER([Hung-Chang DSO-2100], [hung-chang-dso-2100], [libieee1284])
SR_DRIVER([Ikalogic Scanalogic-2], [ikalogic-scanalogic2], [libusb]) SR_DRIVER([Ikalogic Scanalogic-2], [ikalogic-scanalogic2], [libusb])
SR_DRIVER([Ikalogic Scanaplus], [ikalogic-scanaplus], [libftdi]) SR_DRIVER([Ikalogic Scanaplus], [ikalogic-scanaplus], [libftdi])
SR_DRIVER([Ikalogic ScanaQuad], [ikalogic-scanaquad], [libftdi])
SR_DRIVER([IPDBG LA], [ipdbg-la])
SR_DRIVER([ITECH IT8500], [itech-it8500], [serial_comm])
SR_DRIVER([Kecheng KC-330B], [kecheng-kc-330b], [libusb]) SR_DRIVER([Kecheng KC-330B], [kecheng-kc-330b], [libusb])
SR_DRIVER([KERN scale], [kern-scale], [serial_comm]) SR_DRIVER([KERN scale], [kern-scale], [libserialport])
SR_DRIVER([Kingst LA2016], [kingst-la2016], [libusb]) SR_DRIVER([Korad KAxxxxP], [korad-kaxxxxp], [libserialport])
SR_DRIVER([Korad KAxxxxP], [korad-kaxxxxp], [serial_comm])
SR_DRIVER([Lascar EL-USB], [lascar-el-usb], [libusb]) SR_DRIVER([Lascar EL-USB], [lascar-el-usb], [libusb])
SR_DRIVER([LeCroy LogicStudio], [lecroy-logicstudio], [libusb]) SR_DRIVER([LeCroy LogicStudio], [lecroy-logicstudio], [libusb])
SR_DRIVER([LeCroy X-Stream], [lecroy-xstream]) SR_DRIVER([LeCroy X-Stream], [lecroy-xstream])
SR_DRIVER([Manson HCS-3xxx], [manson-hcs-3xxx], [serial_comm]) SR_DRIVER([Manson HCS-3xxx], [manson-hcs-3xxx], [libserialport])
SR_DRIVER([Mastech MS6514], [mastech-ms6514], [serial_comm])
SR_DRIVER([maynuo-m97], [maynuo-m97]) SR_DRIVER([maynuo-m97], [maynuo-m97])
SR_DRIVER([MIC 985xx], [mic-985xx], [serial_comm]) SR_DRIVER([MIC 985xx], [mic-985xx], [libserialport])
SR_DRIVER([Microchip PICkit2], [microchip-pickit2], [libusb]) SR_DRIVER([Motech LPS 30x], [motech-lps-30x], [libserialport])
SR_DRIVER([Mooshimeter DMM], [mooshimeter-dmm], [bluetooth_comm libgio]) SR_DRIVER([Norma DMM], [norma-dmm], [libserialport])
SR_DRIVER([Motech LPS 30x], [motech-lps-30x], [serial_comm]) SR_DRIVER([OpenBench Logic Sniffer], [openbench-logic-sniffer], [libserialport])
SR_DRIVER([Norma DMM], [norma-dmm], [serial_comm]) SR_DRIVER([PCE PCE-322A], [pce-322a], [libserialport])
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([Pipistrello-OLS], [pipistrello-ols], [libftdi])
SR_DRIVER([RDTech DPSxxxx/DPHxxxx], [rdtech-dps], [serial_comm])
SR_DRIVER([RDTech UMXX], [rdtech-um], [serial_comm])
SR_DRIVER([RDTech TCXX], [rdtech-tc], [serial_comm libnettle])
SR_DRIVER([Rigol DS], [rigol-ds]) SR_DRIVER([Rigol DS], [rigol-ds])
SR_DRIVER([Rigol DG], [rigol-dg]) 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 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([SCPI PPS], [scpi-pps])
SR_DRIVER([serial DMM], [serial-dmm], [serial_comm]) SR_DRIVER([serial DMM], [serial-dmm], [libserialport])
SR_DRIVER([serial LCR], [serial-lcr], [serial_comm]) SR_DRIVER([serial LCR], [serial-lcr], [libserialport])
SR_DRIVER([Siglent SDS], [siglent-sds])
SR_DRIVER([Sysclk LWLA], [sysclk-lwla], [libusb]) SR_DRIVER([Sysclk LWLA], [sysclk-lwla], [libusb])
SR_DRIVER([Sysclk SLA5032], [sysclk-sla5032], [libusb]) SR_DRIVER([Teleinfo], [teleinfo], [libserialport])
SR_DRIVER([Teleinfo], [teleinfo], [serial_comm])
SR_DRIVER([Testo], [testo], [libusb]) SR_DRIVER([Testo], [testo], [libusb])
SR_DRIVER([Tondaj SL-814], [tondaj-sl-814], [serial_comm]) SR_DRIVER([Tondaj SL-814], [tondaj-sl-814], [libserialport])
SR_DRIVER([UNI-T DMM], [uni-t-dmm], [libusb]) SR_DRIVER([UNI-T DMM], [uni-t-dmm], [libusb])
SR_DRIVER([UNI-T UT181A], [uni-t-ut181a], [serial_comm]) SR_DRIVER([UNI-T UT32x], [uni-t-ut32x], [libusb])
SR_DRIVER([UNI-T UT32x], [uni-t-ut32x], [serial_comm]) SR_DRIVER([Victor DMM], [victor-dmm], [libusb])
SR_DRIVER([Yokogawa DL/DLM], [yokogawa-dlm]) SR_DRIVER([Yokogawa DL/DLM], [yokogawa-dlm])
SR_DRIVER([ZEROPLUS Logic Cube], [zeroplus-logic-cube], [libusb]) SR_DRIVER([ZEROPLUS Logic Cube], [zeroplus-logic-cube], [libusb])
SR_DRIVER([ZKETECH EBD-USB], [zketech-ebd-usb], [serial_comm])
############################### ###############################
## Language bindings setup ## ## Language bindings setup ##
@ -457,7 +398,7 @@ AS_IF([test "x$HAVE_PYMOD_NUMPY" != xyes],
[SR_APPEND([sr_python_missing], [', '], [numpy])]) [SR_APPEND([sr_python_missing], [', '], [numpy])])
# The Python bindings use SWIG to generate code. # The Python bindings use SWIG to generate code.
AC_CHECK_PROGS([SWIG], [swig swig4.0 swig3.0 swig2.0]) AC_CHECK_PROGS([SWIG], [swig swig3.0 swig2.0])
AS_IF([test "x$SWIG" != x], AS_IF([test "x$SWIG" != x],
AC_MSG_CHECKING([for $SWIG version]) AC_MSG_CHECKING([for $SWIG version])
[SWIG_VERSION=`$SWIG -version 2>&1 | sed -n 's/SWIG Version //p'`] [SWIG_VERSION=`$SWIG -version 2>&1 | sed -n 's/SWIG Version //p'`]
@ -495,8 +436,8 @@ sr_rbminor=${sr_rbminor%%.*}
# The Ruby bindings need Ruby development files. # The Ruby bindings need Ruby development files.
SR_PKG_CHECK([ruby_dev], [SR_PKGLIBS_RUBY], SR_PKG_CHECK([ruby_dev], [SR_PKGLIBS_RUBY],
[ruby >= 2.5.0], [ruby],
[ruby-$sr_rbmajor.$sr_rbminor >= 2.5.0]) [ruby-$sr_rbmajor.$sr_rbminor])
AS_IF([test "x$sr_have_ruby_dev" != xyes], AS_IF([test "x$sr_have_ruby_dev" != xyes],
[SR_APPEND([sr_ruby_missing], [', '], [Headers])]) [SR_APPEND([sr_ruby_missing], [', '], [Headers])])
@ -648,19 +589,10 @@ Detected libraries (optional):
$sr_pkglibs_summary $sr_pkglibs_summary
Enabled hardware drivers: Enabled hardware drivers:
$sr_driver_summary $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: Enabled SCPI backends:
- TCP............................. yes - TCP............................. yes
- SunRPC ......................... $sr_cv_have_sunrpc
- TI-RPC ......................... $sr_cv_have_tirpc
- RPC............................. $sr_cv_have_rpc - RPC............................. $sr_cv_have_rpc
- serial.......................... $sr_have_serial_comm - serial.......................... $sr_have_libserialport
- VISA............................ $sr_have_librevisa - VISA............................ $sr_have_librevisa
- GPIB............................ $sr_have_libgpib - GPIB............................ $sr_have_libgpib
- USBTMC.......................... $sr_have_libusb - USBTMC.......................... $sr_have_libusb
@ -672,24 +604,3 @@ Enabled language bindings:
- Java............................ $BINDINGS_JAVA$sr_report_java - Java............................ $BINDINGS_JAVA$sr_report_java
_EOF _EOF
# Emit a warning if the C++ bindings are not being built.
AM_COND_IF([BINDINGS_CXX], [], [
cat >&AS_MESSAGE_FD <<_EOF
===============================================================================
WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
===============================================================================
=== ===
=== The libsigrok C++ bindings are not being built since you ===
=== are missing one or more dependencies (see above)! ===
=== ===
=== This means you won't be able to compile frontends that require ===
=== the C++ bindings (such as PulseView)! You also won't be able to build ===
=== other bindings and frontends using those (such as sigrok-meter)! ===
=== ===
===============================================================================
WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
===============================================================================
_EOF
])

View File

@ -1,354 +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/>.
##
#
# 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"
# 34460A
ATTRS{idVendor}=="0957", ATTRS{idProduct}=="1b07", 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 (FT232R)
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", ENV{ID_SIGROK}="1"
# Dangerous Prototypes Buspirate (v4)
ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="fb00", ENV{ID_SIGROK}="1"
# dcttech.com USB relay card, and other V-USB based firmware
ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="05df", 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"
# GW-Instek GDM-9061 (USBTMC mode)
ATTRS{idVendor}=="2184", ATTRS{idProduct}=="0059", 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 (FT232H)
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6014", ENV{ID_SIGROK}="1"
# ftdi-la (TIAO USB Multi Protocol Adapter (TUMPA))
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8a98", ENV{ID_SIGROK}="1"
# Kecheng KC-330B
ATTRS{idVendor}=="1041", ATTRS{idProduct}=="8101", ENV{ID_SIGROK}="1"
# Keysight USBTMC-connected devices
# 34465A
ATTRS{idVendor}=="2a8d", ATTRS{idProduct}=="0101", ENV{ID_SIGROK}="1"
# Kingst LA2016
ATTRS{idVendor}=="77a1", ATTRS{idProduct}=="01a2", 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 (FT2232H)
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6010", ENV{ID_SIGROK}="1"
# ftdi-la (FT4232H)
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6011", ENV{ID_SIGROK}="1"
# MIC 98581
# MIC 98583
# Tondaj SL-814
ATTRS{idVendor}=="067b", ATTRS{idProduct}=="2303", ENV{ID_SIGROK}="1"
# Microchip PICkit2
ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="0033", 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 DG1000z series
ATTRS{idVendor}=="1ab1", ATTRS{idProduct}=="0642", ENV{ID_SIGROK}="1"
# Rigol DG800 and DG900 series
ATTRS{idVendor}=="1ab1", ATTRS{idProduct}=="0643", 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

@ -1,31 +0,0 @@
##
## 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

@ -1,32 +0,0 @@
##
## 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"

243
contrib/z60_libsigrok.rules Normal file
View File

@ -0,0 +1,243 @@
##
## 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

@ -80,22 +80,15 @@ enum sr_error_code {
/* Update sr_strerror()/sr_strerror_name() (error.c) upon changes! */ /* Update sr_strerror()/sr_strerror_name() (error.c) upon changes! */
}; };
/** Ternary return type for DMM/LCR/etc packet parser validity checks. */
enum sr_valid_code {
SR_PACKET_INVALID = -1, /**< Certainly invalid. */
SR_PACKET_VALID = 0, /**< Certainly valid. */
SR_PACKET_NEED_RX = +1, /**< Need more RX data. */
};
#define SR_MAX_CHANNELNAME_LEN 32 #define SR_MAX_CHANNELNAME_LEN 32
/* Handy little macros */ /* Handy little macros */
#define SR_HZ(n) (n) #define SR_HZ(n) (n)
#define SR_KHZ(n) ((n) * UINT64_C(1000)) #define SR_KHZ(n) ((n) * (uint64_t)(1000ULL))
#define SR_MHZ(n) ((n) * UINT64_C(1000000)) #define SR_MHZ(n) ((n) * (uint64_t)(1000000ULL))
#define SR_GHZ(n) ((n) * UINT64_C(1000000000)) #define SR_GHZ(n) ((n) * (uint64_t)(1000000000ULL))
#define SR_HZ_TO_NS(n) (UINT64_C(1000000000) / (n)) #define SR_HZ_TO_NS(n) ((uint64_t)(1000000000ULL) / (n))
/** libsigrok loglevels. */ /** libsigrok loglevels. */
enum sr_loglevel { enum sr_loglevel {
@ -240,10 +233,6 @@ enum sr_mq {
SR_MQ_MASS, SR_MQ_MASS,
/** Harmonic ratio */ /** Harmonic ratio */
SR_MQ_HARMONIC_RATIO, SR_MQ_HARMONIC_RATIO,
/** Energy. */
SR_MQ_ENERGY,
/** Electric charge. */
SR_MQ_ELECTRIC_CHARGE,
/* Update sr_key_info_mq[] (hwdriver.c) upon changes! */ /* Update sr_key_info_mq[] (hwdriver.c) upon changes! */
}; };
@ -301,7 +290,7 @@ enum sr_unit {
SR_UNIT_VOLT_AMPERE, SR_UNIT_VOLT_AMPERE,
/** Real power [W]. */ /** Real power [W]. */
SR_UNIT_WATT, SR_UNIT_WATT,
/** Energy (consumption) in watt hour [Wh]. */ /** Consumption [Wh]. */
SR_UNIT_WATT_HOUR, SR_UNIT_WATT_HOUR,
/** Wind speed in meters per second. */ /** Wind speed in meters per second. */
SR_UNIT_METER_SECOND, SR_UNIT_METER_SECOND,
@ -335,12 +324,6 @@ enum sr_unit {
SR_UNIT_TOLA, SR_UNIT_TOLA,
/** Pieces (number of items). */ /** Pieces (number of items). */
SR_UNIT_PIECE, SR_UNIT_PIECE,
/** Energy in joule. */
SR_UNIT_JOULE,
/** Electric charge in coulomb. */
SR_UNIT_COULOMB,
/** Electric charge in ampere hour [Ah]. */
SR_UNIT_AMPERE_HOUR,
/* /*
* Update unit_strings[] (analog.c) and fancyprint() (output/analog.c) * Update unit_strings[] (analog.c) and fancyprint() (output/analog.c)
@ -667,11 +650,11 @@ struct sr_key_info {
/** Configuration capabilities. */ /** Configuration capabilities. */
enum sr_configcap { enum sr_configcap {
/** Value can be read. */ /** Value can be read. */
SR_CONF_GET = (1UL << 31), SR_CONF_GET = (1 << 31),
/** Value can be written. */ /** Value can be written. */
SR_CONF_SET = (1UL << 30), SR_CONF_SET = (1 << 30),
/** Possible values can be enumerated. */ /** Possible values can be enumerated. */
SR_CONF_LIST = (1UL << 29), SR_CONF_LIST = (1 << 29),
}; };
/** Configuration keys */ /** Configuration keys */
@ -720,15 +703,6 @@ enum sr_configkey {
/** The device can act as a function generator. */ /** The device can act as a function generator. */
SR_CONF_SIGNAL_GENERATOR, SR_CONF_SIGNAL_GENERATOR,
/** The device can measure power. */
SR_CONF_POWERMETER,
/**
* The device can switch between multiple sources, e.g. a relay actuator
* or multiplexer.
*/
SR_CONF_MULTIPLEXER,
/* Update sr_key_info_config[] (hwdriver.c) upon changes! */ /* Update sr_key_info_config[] (hwdriver.c) upon changes! */
/*--- Driver scan options -------------------------------------------*/ /*--- Driver scan options -------------------------------------------*/
@ -774,16 +748,6 @@ enum sr_configkey {
*/ */
SR_CONF_MODBUSADDR, SR_CONF_MODBUSADDR,
/**
* User specified forced driver attachment to unknown devices.
*
* By design the interpretation of the string depends on the
* specific driver. It typically would be either a replacement
* '*IDN?' response value, or a sub-driver name. But could also
* be anything else and totally arbitrary.
*/
SR_CONF_FORCE_DETECT,
/* Update sr_key_info_config[] (hwdriver.c) upon changes! */ /* Update sr_key_info_config[] (hwdriver.c) upon changes! */
/*--- Device (or channel group) configuration -----------------------*/ /*--- Device (or channel group) configuration -----------------------*/
@ -989,8 +953,6 @@ enum sr_configkey {
* Channel regulation * Channel regulation
* get: "CV", "CC" or "UR", denoting constant voltage, constant current * get: "CV", "CC" or "UR", denoting constant voltage, constant current
* or unregulated. * 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, SR_CONF_REGULATION,
@ -1021,68 +983,6 @@ enum sr_configkey {
/** Trigger level. */ /** Trigger level. */
SR_CONF_TRIGGER_LEVEL, SR_CONF_TRIGGER_LEVEL,
/** Under-voltage condition threshold. */
SR_CONF_UNDER_VOLTAGE_CONDITION_THRESHOLD,
/**
* Which external clock source to use if the device supports
* multiple external clock channels.
*/
SR_CONF_EXTERNAL_CLOCK_SOURCE,
/** 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,
/** Phase of a source signal. */
SR_CONF_PHASE,
/** Duty cycle of a source signal. */
SR_CONF_DUTY_CYCLE,
/**
* Current power.
* @arg type: double
* @arg get: get measured power
*/
SR_CONF_POWER,
/**
* Power target.
* @arg type: double
* @arg get: get power target
* @arg set: change power target
*/
SR_CONF_POWER_TARGET,
/**
* Resistance target.
* @arg type: double
* @arg get: get resistance target
* @arg set: change resistance target
*/
SR_CONF_RESISTANCE_TARGET,
/* Update sr_key_info_config[] (hwdriver.c) upon changes! */ /* Update sr_key_info_config[] (hwdriver.c) upon changes! */
/*--- Special stuff -------------------------------------------------*/ /*--- Special stuff -------------------------------------------------*/

View File

@ -50,14 +50,6 @@ SR_API GSList *sr_buildinfo_libs_get(void);
SR_API char *sr_buildinfo_host_get(void); SR_API char *sr_buildinfo_host_get(void);
SR_API char *sr_buildinfo_scpi_backends_get(void); SR_API char *sr_buildinfo_scpi_backends_get(void);
/*--- conversion.c ----------------------------------------------------------*/
SR_API int sr_a2l_threshold(const struct sr_datafeed_analog *analog,
float threshold, uint8_t *output, uint64_t count);
SR_API int sr_a2l_schmitt_trigger(const struct sr_datafeed_analog *analog,
float lo_thr, float hi_thr, uint8_t *state, uint8_t *output,
uint64_t count);
/*--- log.c -----------------------------------------------------------------*/ /*--- log.c -----------------------------------------------------------------*/
typedef int (*sr_log_callback)(void *cb_data, int loglevel, typedef int (*sr_log_callback)(void *cb_data, int loglevel,
@ -67,7 +59,6 @@ SR_API int sr_log_loglevel_set(int loglevel);
SR_API int sr_log_loglevel_get(void); SR_API int sr_log_loglevel_get(void);
SR_API int sr_log_callback_set(sr_log_callback cb, void *cb_data); SR_API int sr_log_callback_set(sr_log_callback cb, void *cb_data);
SR_API int sr_log_callback_set_default(void); SR_API int sr_log_callback_set_default(void);
SR_API int sr_log_callback_get(sr_log_callback *cb, void **cb_data);
/*--- device.c --------------------------------------------------------------*/ /*--- device.c --------------------------------------------------------------*/
@ -154,10 +145,6 @@ SR_API int sr_session_is_running(struct sr_session *session);
SR_API int sr_session_stopped_callback_set(struct sr_session *session, SR_API int sr_session_stopped_callback_set(struct sr_session *session,
sr_session_stopped_callback cb, void *cb_data); sr_session_stopped_callback cb, void *cb_data);
SR_API int sr_packet_copy(const struct sr_datafeed_packet *packet,
struct sr_datafeed_packet **copy);
SR_API void sr_packet_free(struct sr_datafeed_packet *packet);
/*--- input/input.c ---------------------------------------------------------*/ /*--- input/input.c ---------------------------------------------------------*/
SR_API const struct sr_input_module **sr_input_list(void); SR_API const struct sr_input_module **sr_input_list(void);
@ -168,12 +155,13 @@ SR_API const char *const *sr_input_extensions_get(
const struct sr_input_module *imod); const struct sr_input_module *imod);
SR_API const struct sr_input_module *sr_input_find(char *id); SR_API const struct sr_input_module *sr_input_find(char *id);
SR_API const struct sr_option **sr_input_options_get(const struct sr_input_module *imod); SR_API const struct sr_option **sr_input_options_get(const struct sr_input_module *imod);
SR_API gboolean sr_output_test_flag(const struct sr_output_module *omod,
uint64_t flag);
SR_API void sr_input_options_free(const struct sr_option **options); SR_API void sr_input_options_free(const struct sr_option **options);
SR_API struct sr_input *sr_input_new(const struct sr_input_module *imod, SR_API struct sr_input *sr_input_new(const struct sr_input_module *imod,
GHashTable *options); GHashTable *options);
SR_API int sr_input_scan_buffer(GString *buf, const struct sr_input **in); SR_API int sr_input_scan_buffer(GString *buf, const struct sr_input **in);
SR_API int sr_input_scan_file(const char *filename, const struct sr_input **in); SR_API int sr_input_scan_file(const char *filename, const struct sr_input **in);
SR_API const struct sr_input_module *sr_input_module_get(const struct sr_input *in);
SR_API struct sr_dev_inst *sr_input_dev_inst_get(const struct sr_input *in); SR_API struct sr_dev_inst *sr_input_dev_inst_get(const struct sr_input *in);
SR_API int sr_input_send(const struct sr_input *in, GString *buf); SR_API int sr_input_send(const struct sr_input *in, GString *buf);
SR_API int sr_input_end(const struct sr_input *in); SR_API int sr_input_end(const struct sr_input *in);
@ -194,8 +182,6 @@ SR_API void sr_output_options_free(const struct sr_option **opts);
SR_API const struct sr_output *sr_output_new(const struct sr_output_module *omod, SR_API const struct sr_output *sr_output_new(const struct sr_output_module *omod,
GHashTable *params, const struct sr_dev_inst *sdi, GHashTable *params, const struct sr_dev_inst *sdi,
const char *filename); const char *filename);
SR_API gboolean sr_output_test_flag(const struct sr_output_module *omod,
uint64_t flag);
SR_API int sr_output_send(const struct sr_output *o, SR_API int sr_output_send(const struct sr_output *o,
const struct sr_datafeed_packet *packet, GString **out); const struct sr_datafeed_packet *packet, GString **out);
SR_API int sr_output_free(const struct sr_output *o); SR_API int sr_output_free(const struct sr_output *o);
@ -235,8 +221,6 @@ typedef int (*sr_resource_close_callback)(struct sr_resource *res,
typedef gssize (*sr_resource_read_callback)(const struct sr_resource *res, typedef gssize (*sr_resource_read_callback)(const struct sr_resource *res,
void *buf, size_t count, void *cb_data); void *buf, size_t count, void *cb_data);
SR_API GSList *sr_resourcepaths_get(int res_type);
SR_API int sr_resource_set_hooks(struct sr_context *ctx, SR_API int sr_resource_set_hooks(struct sr_context *ctx,
sr_resource_open_callback open_cb, sr_resource_open_callback open_cb,
sr_resource_close_callback close_cb, sr_resource_close_callback close_cb,
@ -253,12 +237,6 @@ SR_API uint64_t sr_parse_timestring(const char *timestring);
SR_API gboolean sr_parse_boolstring(const char *boolstring); SR_API gboolean sr_parse_boolstring(const char *boolstring);
SR_API int sr_parse_period(const char *periodstr, uint64_t *p, uint64_t *q); SR_API int sr_parse_period(const char *periodstr, uint64_t *p, uint64_t *q);
SR_API int sr_parse_voltage(const char *voltstr, uint64_t *p, uint64_t *q); SR_API int sr_parse_voltage(const char *voltstr, uint64_t *p, uint64_t *q);
SR_API int sr_sprintf_ascii(char *buf, const char *format, ...);
SR_API int sr_vsprintf_ascii(char *buf, const char *format, va_list args);
SR_API int sr_snprintf_ascii(char *buf, size_t buf_size,
const char *format, ...);
SR_API int sr_vsnprintf_ascii(char *buf, size_t buf_size,
const char *format, va_list args);
SR_API int sr_parse_rational(const char *str, struct sr_rational *ret); SR_API int sr_parse_rational(const char *str, struct sr_rational *ret);
/*--- version.c -------------------------------------------------------------*/ /*--- version.c -------------------------------------------------------------*/

View File

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

View File

@ -88,9 +88,6 @@ static struct unit_mq_string unit_strings[] = {
{ SR_UNIT_MOMME, "momme" }, { SR_UNIT_MOMME, "momme" },
{ SR_UNIT_TOLA, "tola" }, { SR_UNIT_TOLA, "tola" },
{ SR_UNIT_PIECE, "pcs" }, { SR_UNIT_PIECE, "pcs" },
{ SR_UNIT_JOULE, "J" },
{ SR_UNIT_COULOMB, "C" },
{ SR_UNIT_AMPERE_HOUR, "Ah" },
ALL_ZERO ALL_ZERO
}; };
@ -160,8 +157,8 @@ SR_PRIV int sr_analog_init(struct sr_datafeed_analog *analog,
/** /**
* Convert an analog datafeed payload to an array of floats. * Convert an analog datafeed payload to an array of floats.
* *
* The caller must provide the #outbuf space for the conversion result, * Sufficient memory for outbuf must have been pre-allocated by the caller,
* and is expected to free allocated space after use. * who is also responsible for freeing it when no longer needed.
* *
* @param[in] analog The analog payload to convert. Must not be NULL. * @param[in] analog The analog payload to convert. Must not be NULL.
* analog->data, analog->meaning, and analog->encoding * analog->data, analog->meaning, and analog->encoding
@ -177,206 +174,126 @@ SR_PRIV int sr_analog_init(struct sr_datafeed_analog *analog,
SR_API int sr_analog_to_float(const struct sr_datafeed_analog *analog, SR_API int sr_analog_to_float(const struct sr_datafeed_analog *analog,
float *outbuf) float *outbuf)
{ {
size_t count; float offset;
gboolean host_bigendian; unsigned int b, i, count;
gboolean input_float, input_signed, input_bigendian; gboolean bigendian;
size_t input_unitsize;
double scale, offset, value;
const uint8_t *data8;
gboolean input_is_native;
char type_text[10];
if (!analog || !analog->data || !analog->meaning || !analog->encoding) if (!analog || !(analog->data) || !(analog->meaning)
return SR_ERR_ARG; || !(analog->encoding) || !outbuf)
if (!outbuf)
return SR_ERR_ARG; return SR_ERR_ARG;
count = analog->num_samples * g_slist_length(analog->meaning->channels); count = analog->num_samples * g_slist_length(analog->meaning->channels);
/*
* Determine properties of the input data's and the host's
* native formats, to simplify test conditions below.
* Error messages for unsupported input property combinations
* will only be seen by developers and maintainers of input
* formats or acquisition device drivers. Terse output is
* acceptable there, users shall never see them.
*/
#ifdef WORDS_BIGENDIAN #ifdef WORDS_BIGENDIAN
host_bigendian = TRUE; bigendian = TRUE;
#else #else
host_bigendian = FALSE; bigendian = FALSE;
#endif #endif
input_float = analog->encoding->is_float;
input_signed = analog->encoding->is_signed;
input_bigendian = analog->encoding->is_bigendian;
input_unitsize = analog->encoding->unitsize;
/* if (!analog->encoding->is_float) {
* Prepare the iteration over the sample data: Get the common float offset = analog->encoding->offset.p / (float)analog->encoding->offset.q;
* scale/offset factors which apply to all individual values. float scale = analog->encoding->scale.p / (float)analog->encoding->scale.q;
* Position the read pointer on the first byte of input data. gboolean is_signed = analog->encoding->is_signed;
*/ gboolean is_bigendian = analog->encoding->is_bigendian;
offset = analog->encoding->offset.p; int8_t *data8 = (int8_t *)(analog->data);
offset /= analog->encoding->offset.q; int16_t *data16 = (int16_t *)(analog->data);
scale = analog->encoding->scale.p; int32_t *data32 = (int32_t *)(analog->data);
scale /= analog->encoding->scale.q;
data8 = analog->data;
/* switch (analog->encoding->unitsize) {
* Immediately handle the special case where input data needs case 1:
* no conversion because it already is in the application's if (is_signed) {
* native format. Do apply scale/offset though when applicable for (unsigned int i = 0; i < count; i++) {
* on our way out. outbuf[i] = scale * data8[i];
*/ outbuf[i] += offset;
input_is_native = input_float && }
input_unitsize == sizeof(outbuf[0]) && } else {
input_bigendian == host_bigendian; for (unsigned int i = 0; i < count; i++) {
if (input_is_native) { outbuf[i] = scale * R8(data8 + i);
memcpy(outbuf, data8, count * sizeof(outbuf[0])); outbuf[i] += offset;
if (scale != 1.0 || offset != 0.0) {
while (count--) {
*outbuf *= scale;
*outbuf += offset;
outbuf++;
} }
} }
return SR_OK; break;
case 2:
if (is_signed && is_bigendian) {
for (unsigned int i = 0; i < count; i++) {
outbuf[i] = scale * RB16S(&data16[i]);
outbuf[i] += offset;
} }
} else if (is_bigendian) {
/* for (unsigned int i = 0; i < count; i++) {
* Accept sample values in different widths and data types and outbuf[i] = scale * RB16(&data16[i]);
* endianess formats (floating point or signed or unsigned outbuf[i] += offset;
* integer, in either endianess, for a set of supported widths).
* Common scale/offset factors apply to all sample values.
*
* Do most internal calculations on double precision values.
* Only trim the result data to single precision, since that's
* the routine's result data type in its public API which needs
* to be kept for compatibility. It remains an option for later
* to add another public routine which returns double precision
* result data, call sites could migrate at their own pace.
*/
if (input_float && input_unitsize == sizeof(float)) {
float (*reader)(const uint8_t **p);
if (input_bigendian)
reader = read_fltbe_inc;
else
reader = read_fltle_inc;
while (count--) {
value = reader(&data8);
value *= scale;
value += offset;
*outbuf++ = value;
} }
return SR_OK; } else if (is_signed) {
for (unsigned int i = 0; i < count; i++) {
outbuf[i] = scale * RL16S(&data16[i]);
outbuf[i] += offset;
} }
if (input_float && input_unitsize == sizeof(double)) { } else {
double (*reader)(const uint8_t **p); for (unsigned int i = 0; i < count; i++) {
if (input_bigendian) outbuf[i] = scale * RL16(&data16[i]);
reader = read_dblbe_inc; outbuf[i] += offset;
else
reader = read_dblle_inc;
while (count--) {
value = reader(&data8);
value *= scale;
value += offset;
*outbuf++ = value;
} }
return SR_OK;
} }
if (input_float) { break;
snprintf(type_text, sizeof(type_text), "%c%zu%s", case 4:
'f', input_unitsize * 8, input_bigendian ? "be" : "le"); if (is_signed && is_bigendian) {
sr_err("Unsupported type for analog-to-float conversion: %s.", for (unsigned int i = 0; i < count; i++) {
type_text); outbuf[i] = scale * RB32S(&data32[i]);
outbuf[i] += offset;
}
} else if (is_bigendian) {
for (unsigned int i = 0; i < count; i++) {
outbuf[i] = scale * RB32(&data32[i]);
outbuf[i] += offset;
}
} else if (is_signed) {
for (unsigned int i = 0; i < count; i++) {
outbuf[i] = scale * RL32S(&data32[i]);
outbuf[i] += offset;
}
} else {
for (unsigned int i = 0; i < count; i++) {
outbuf[i] = scale * RL32(&data32[i]);
outbuf[i] += offset;
}
}
break;
default:
sr_err("Unsupported unit size '%d' for analog-to-float"
" conversion.", analog->encoding->unitsize);
return SR_ERR; return SR_ERR;
} }
return SR_OK;
}
if (input_unitsize == sizeof(uint8_t) && input_signed) { if (analog->encoding->unitsize == sizeof(float)
int8_t (*reader)(const uint8_t **p); && analog->encoding->is_bigendian == bigendian
reader = read_i8_inc; && analog->encoding->scale.p == 1
while (count--) { && analog->encoding->scale.q == 1
value = reader(&data8); && analog->encoding->offset.p / (float)analog->encoding->offset.q == 0) {
value *= scale; /* The data is already in the right format. */
value += offset; memcpy(outbuf, analog->data, count * sizeof(float));
*outbuf++ = value; } else {
} for (i = 0; i < count; i += analog->encoding->unitsize) {
return SR_OK; for (b = 0; b < analog->encoding->unitsize; b++) {
} if (analog->encoding->is_bigendian == bigendian)
if (input_unitsize == sizeof(uint8_t)) { ((uint8_t *)outbuf)[i + b] =
uint8_t (*reader)(const uint8_t **p); ((uint8_t *)analog->data)[i * analog->encoding->unitsize + b];
reader = read_u8_inc;
while (count--) {
value = reader(&data8);
value *= scale;
value += offset;
*outbuf++ = value;
}
return SR_OK;
}
if (input_unitsize == sizeof(uint16_t) && input_signed) {
int16_t (*reader)(const uint8_t **p);
if (input_bigendian)
reader = read_i16be_inc;
else else
reader = read_i16le_inc; ((uint8_t *)outbuf)[i + (analog->encoding->unitsize - b)] =
while (count--) { ((uint8_t *)analog->data)[i * analog->encoding->unitsize + b];
value = reader(&data8);
value *= scale;
value += offset;
*outbuf++ = value;
} }
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);
outbuf[i] += offset;
}
}
return SR_OK; return SR_OK;
} }
if (input_unitsize == sizeof(uint16_t)) {
uint16_t (*reader)(const uint8_t **p);
if (input_bigendian)
reader = read_u16be_inc;
else
reader = read_u16le_inc;
while (count--) {
value = reader(&data8);
value *= scale;
value += offset;
*outbuf++ = value;
}
return SR_OK;
}
if (input_unitsize == sizeof(uint32_t) && input_signed) {
int32_t (*reader)(const uint8_t **p);
if (input_bigendian)
reader = read_i32be_inc;
else
reader = read_i32le_inc;
while (count--) {
value = reader(&data8);
value *= scale;
value += offset;
*outbuf++ = value;
}
return SR_OK;
}
if (input_unitsize == sizeof(uint32_t)) {
uint32_t (*reader)(const uint8_t **p);
if (input_bigendian)
reader = read_u32be_inc;
else
reader = read_u32le_inc;
while (count--) {
value = reader(&data8);
value *= scale;
value += offset;
*outbuf++ = value;
}
return SR_OK;
}
snprintf(type_text, sizeof(type_text), "%c%zu%s",
input_float ? 'f' : input_signed ? 'i' : 'u',
input_unitsize * 8, input_bigendian ? "be" : "le");
sr_err("Unsupported type for analog-to-float conversion: %s.",
type_text);
return SR_ERR;
}
/** /**
* Scale a float value to the appropriate SI prefix. * Scale a float value to the appropriate SI prefix.
@ -449,9 +366,12 @@ SR_API gboolean sr_analog_si_prefix_friendly(enum sr_unit unit)
for (i = 0; i < ARRAY_SIZE(prefix_friendly_units); i++) for (i = 0; i < ARRAY_SIZE(prefix_friendly_units); i++)
if (unit == prefix_friendly_units[i]) if (unit == prefix_friendly_units[i])
return TRUE; break;
if (unit != prefix_friendly_units[i])
return FALSE; return FALSE;
return TRUE;
} }
/** /**
@ -635,8 +555,8 @@ SR_API int sr_rational_mult(struct sr_rational *res, const struct sr_rational *a
return SR_ERR_ARG; return SR_ERR_ARG;
} }
res->p = (int64_t)p; res->p = (int64_t)(p);
res->q = (uint64_t)q; res->q = (uint64_t)(q);
return SR_OK; return SR_OK;
@ -686,8 +606,9 @@ SR_API int sr_rational_mult(struct sr_rational *res, const struct sr_rational *a
* @param[out] res Result. * @param[out] res Result.
* *
* @retval SR_OK Success. * @retval SR_OK Success.
* @retval SR_ERR_ARG Division by zero, denominator of divisor too large, * @retval SR_ERR_ARG Division by zero.
* or resulting value too large. * @retval SR_ERR_ARG Denominator of divisor too large.
* @retval SR_ERR_ARG Resulting value too large.
* *
* @since 0.5.0 * @since 0.5.0
*/ */

View File

@ -63,8 +63,8 @@
* @section sec_irc IRC * @section sec_irc IRC
* *
* You can find the sigrok developers in the * You can find the sigrok developers in the
* <a href="ircs://irc.libera.chat/#sigrok">\#sigrok</a> * <a href="irc://chat.freenode.net/sigrok">\#sigrok</a>
* IRC channel on Libera.Chat. * IRC channel on Freenode.
* *
* @section sec_website Website * @section sec_website Website
* *
@ -153,25 +153,9 @@ SR_API GSList *sr_buildinfo_libs_get(void)
m = g_slist_append(m, g_strdup_printf("%s", CONF_LIBUSB_1_0_VERSION)); m = g_slist_append(m, g_strdup_printf("%s", CONF_LIBUSB_1_0_VERSION));
#else #else
lv = libusb_get_version(); lv = libusb_get_version();
m = g_slist_append(m, g_strdup_printf("%d.%d.%d.%d%s API 0x%08x", m = g_slist_append(m, g_strdup_printf("%d.%d.%d.%d%s",
lv->major, lv->minor, lv->micro, lv->nano, lv->rc, lv->major, lv->minor, lv->micro, lv->nano, lv->rc));
#if defined(LIBUSB_API_VERSION)
LIBUSB_API_VERSION
#elif defined(LIBUSBX_API_VERSION)
LIBUSBX_API_VERSION
#endif #endif
));
#endif
l = g_slist_append(l, m);
#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); l = g_slist_append(l, m);
#endif #endif
#ifdef HAVE_LIBFTDI #ifdef HAVE_LIBFTDI
@ -215,7 +199,7 @@ SR_API char *sr_buildinfo_scpi_backends_get(void)
#if HAVE_RPC #if HAVE_RPC
g_string_append_printf(s, "RPC, "); g_string_append_printf(s, "RPC, ");
#endif #endif
#ifdef HAVE_SERIAL_COMM #ifdef HAVE_LIBSERIALPORT
g_string_append_printf(s, "serial, "); g_string_append_printf(s, "serial, ");
#endif #endif
#ifdef HAVE_LIBREVISA #ifdef HAVE_LIBREVISA
@ -242,7 +226,8 @@ static void print_versions(void)
char *str; char *str;
const char *lib, *version; const char *lib, *version;
sr_dbg("libsigrok %s/%s.", sr_dbg("libsigrok %s/%s (rt: %s/%s).",
SR_PACKAGE_VERSION_STRING, SR_LIB_VERSION_STRING,
sr_package_version_string_get(), sr_lib_version_string_get()); sr_package_version_string_get(), sr_lib_version_string_get());
s = g_string_sized_new(200); s = g_string_sized_new(200);
@ -270,17 +255,6 @@ static void print_versions(void)
g_free(str); g_free(str);
} }
static void print_resourcepaths(void)
{
GSList *l, *l_orig;
sr_dbg("Firmware search paths:");
l_orig = sr_resourcepaths_get(SR_RESOURCE_FIRMWARE);
for (l = l_orig; l; l = l->next)
sr_dbg(" - %s", (const char *)l->data);
g_slist_free_full(l_orig, g_free);
}
/** /**
* Sanity-check all libsigrok drivers. * Sanity-check all libsigrok drivers.
* *
@ -335,10 +309,7 @@ static int sanity_check_all_drivers(const struct sr_context *ctx)
sr_err("No dev_list in driver %d ('%s').", i, d); sr_err("No dev_list in driver %d ('%s').", i, d);
errors++; errors++;
} }
if (!drivers[i]->dev_clear) { /* Note: dev_clear() is optional. */
sr_err("No dev_clear in driver %d ('%s').", i, d);
errors++;
}
/* Note: config_get() is optional. */ /* Note: config_get() is optional. */
if (!drivers[i]->config_set) { if (!drivers[i]->config_set) {
sr_err("No config_set in driver %d ('%s').", i, d); sr_err("No config_set in driver %d ('%s').", i, d);
@ -555,8 +526,6 @@ SR_API int sr_init(struct sr_context **ctx)
print_versions(); print_versions();
print_resourcepaths();
if (!ctx) { if (!ctx) {
sr_err("%s(): libsigrok context was NULL.", __func__); sr_err("%s(): libsigrok context was NULL.", __func__);
return SR_ERR; return SR_ERR;
@ -568,22 +537,22 @@ SR_API int sr_init(struct sr_context **ctx)
if (sanity_check_all_drivers(context) < 0) { if (sanity_check_all_drivers(context) < 0) {
sr_err("Internal driver error(s), aborting."); sr_err("Internal driver error(s), aborting.");
goto done; return ret;
} }
if (sanity_check_all_input_modules() < 0) { if (sanity_check_all_input_modules() < 0) {
sr_err("Internal input module error(s), aborting."); sr_err("Internal input module error(s), aborting.");
goto done; return ret;
} }
if (sanity_check_all_output_modules() < 0) { if (sanity_check_all_output_modules() < 0) {
sr_err("Internal output module error(s), aborting."); sr_err("Internal output module error(s), aborting.");
goto done; return ret;
} }
if (sanity_check_all_transform_modules() < 0) { if (sanity_check_all_transform_modules() < 0) {
sr_err("Internal transform module error(s), aborting."); sr_err("Internal transform module error(s), aborting.");
goto done; return ret;
} }
#ifdef _WIN32 #ifdef _WIN32
@ -601,20 +570,6 @@ SR_API int sr_init(struct sr_context **ctx)
ret = SR_ERR; ret = SR_ERR;
goto done; 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 #endif
sr_resource_set_hooks(context, NULL, NULL, NULL, NULL); sr_resource_set_hooks(context, NULL, NULL, NULL, NULL);
@ -622,7 +577,9 @@ SR_API int sr_init(struct sr_context **ctx)
context = NULL; context = NULL;
ret = SR_OK; ret = SR_OK;
#if defined(HAVE_LIBUSB_1_0) || defined(_WIN32)
done: done:
#endif
g_free(context); g_free(context);
return ret; return ret;
} }
@ -650,9 +607,6 @@ SR_API int sr_exit(struct sr_context *ctx)
WSACleanup(); WSACleanup();
#endif #endif
#ifdef HAVE_LIBHIDAPI
hid_exit();
#endif
#ifdef HAVE_LIBUSB_1_0 #ifdef HAVE_LIBUSB_1_0
libusb_exit(ctx->libusb_ctx); libusb_exit(ctx->libusb_ctx);
#endif #endif

View File

@ -1,105 +0,0 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2020 Andreas Sandberg <andreas@sandberg.pp.se>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <glib.h>
#include <libsigrok/libsigrok.h>
#include "libsigrok-internal.h"
SR_PRIV int bv_get_value(float *out, const struct binary_value_spec *spec, const void *data, size_t length)
{
float value;
if (!out || !spec || !data)
return SR_ERR_ARG;
#define VALUE_TYPE(T, R, L) \
case T: \
if (spec->offset + (L) > length) \
return SR_ERR_DATA; \
value = R(data + spec->offset); \
break
switch (spec->type) {
VALUE_TYPE(BVT_UINT8, R8, 1);
VALUE_TYPE(BVT_BE_UINT16, RB16, 2);
VALUE_TYPE(BVT_BE_UINT32, RB32, 4);
VALUE_TYPE(BVT_BE_UINT64, RB64, 8);
VALUE_TYPE(BVT_BE_FLOAT, RBFL, 4);
VALUE_TYPE(BVT_LE_UINT16, RL16, 2);
VALUE_TYPE(BVT_LE_UINT32, RL32, 4);
VALUE_TYPE(BVT_LE_UINT64, RL64, 8);
VALUE_TYPE(BVT_LE_FLOAT, RLFL, 4);
default:
return SR_ERR_ARG;
}
#undef VALUE_TYPE
*out = value * spec->scale;
return SR_OK;
}
SR_PRIV int bv_send_analog_channel(const struct sr_dev_inst *sdi, struct sr_channel *ch,
const struct binary_analog_channel *bac, const void *data, size_t length)
{
int err;
struct sr_analog_encoding encoding;
struct sr_analog_meaning meaning;
struct sr_analog_spec spec;
struct sr_datafeed_analog analog;
struct sr_datafeed_packet packet = {
.type = SR_DF_ANALOG,
.payload = &analog,
};
float value;
err = bv_get_value(&value, &bac->spec, data, length);
if (err != SR_OK)
goto err_out;
err = sr_analog_init(&analog, &encoding, &meaning, &spec, bac->digits);
if (err != SR_OK)
goto err_out;
meaning.mq = bac->mq;
meaning.unit = bac->unit;
meaning.mqflags = 0;
meaning.channels = g_slist_append(NULL, ch);
spec.spec_digits = bac->digits;
analog.data = &value;
analog.num_samples = 1;
err = sr_session_send(sdi, &packet);
if (err != SR_OK)
goto err_free;
return SR_OK;
err_free:
g_slist_free(meaning.channels);
err_out:
return err;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,109 +0,0 @@
/*
* 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"
/** @cond PRIVATE */
#define LOG_PREFIX "conv"
/** @endcond */
/**
* 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 hi_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,12 +18,10 @@
*/ */
#include <config.h> #include <config.h>
#include <glib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <glib.h>
#include <libsigrok/libsigrok.h> #include <libsigrok/libsigrok.h>
#include "libsigrok-internal.h" #include "libsigrok-internal.h"
#include "scpi.h"
/** @cond PRIVATE */ /** @cond PRIVATE */
#define LOG_PREFIX "device" #define LOG_PREFIX "device"
@ -62,7 +60,7 @@ SR_PRIV struct sr_channel *sr_channel_new(struct sr_dev_inst *sdi,
{ {
struct sr_channel *ch; struct sr_channel *ch;
ch = g_malloc0(sizeof(*ch)); ch = g_malloc0(sizeof(struct sr_channel));
ch->sdi = sdi; ch->sdi = sdi;
ch->index = index; ch->index = index;
ch->type = type; ch->type = type;
@ -75,32 +73,6 @@ SR_PRIV struct sr_channel *sr_channel_new(struct sr_dev_inst *sdi,
return ch; return ch;
} }
/**
* Release a previously allocated struct sr_channel.
*
* @param[in] ch Pointer to struct sr_channel.
*
* @private
*/
SR_PRIV void sr_channel_free(struct sr_channel *ch)
{
if (!ch)
return;
g_free(ch->name);
g_free(ch->priv);
g_free(ch);
}
/**
* Wrapper around sr_channel_free(), suitable for glib iterators.
*
* @private
*/
SR_PRIV void sr_channel_free_cb(void *p)
{
sr_channel_free(p);
}
/** /**
* Set the name of the specified channel. * Set the name of the specified channel.
* *
@ -163,18 +135,10 @@ SR_API int sr_dev_channel_enable(struct sr_channel *channel, gboolean state)
return SR_OK; return SR_OK;
} }
/** /* Returns the next enabled channel, wrapping around if necessary. */
* Returns the next enabled channel, wrapping around if necessary. /** @private */
*
* @param[in] sdi The device instance the channel is connected to.
* Must not be NULL.
* @param[in] cur_channel The current channel.
*
* @return A pointer to the next enabled channel of this device.
*
* @private
*/
SR_PRIV struct sr_channel *sr_next_enabled_channel(const struct sr_dev_inst *sdi, SR_PRIV struct sr_channel *sr_next_enabled_channel(const struct sr_dev_inst *sdi,
struct sr_channel *cur_channel) struct sr_channel *cur_channel)
{ {
struct sr_channel *next_channel; struct sr_channel *next_channel;
@ -192,69 +156,6 @@ SR_PRIV struct sr_channel *sr_next_enabled_channel(const struct sr_dev_inst *sdi
return next_channel; return next_channel;
} }
/**
* Compare two channels, return whether they differ.
*
* The channels' names and types are checked. The enabled state is not
* considered a condition for difference. The test is motivated by the
* desire to detect changes in the configuration of acquisition setups
* between re-reads of an input file.
*
* @param[in] ch1 First channel.
* @param[in] ch2 Second channel.
*
* @return TRUE upon differences or unexpected input, FALSE otherwise.
*
* @private
*/
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.
*
* @private
*/
SR_PRIV gboolean sr_channel_lists_differ(GSList *l1, GSList *l2)
{
struct sr_channel *ch1, *ch2;
while (l1 && l2) {
ch1 = l1->data;
ch2 = l2->data;
l1 = l1->next;
l2 = l2->next;
if (!ch1 || !ch2)
return TRUE;
if (sr_channels_differ(ch1, ch2))
return TRUE;
if (ch1->index != ch2->index)
return TRUE;
}
if (l1 || l2)
return TRUE;
return FALSE;
}
/** /**
* Determine whether the specified device instance has the specified * Determine whether the specified device instance has the specified
* capability. * capability.
@ -407,7 +308,7 @@ SR_API struct sr_dev_inst *sr_dev_inst_user_new(const char *vendor,
{ {
struct sr_dev_inst *sdi; struct sr_dev_inst *sdi;
sdi = g_malloc0(sizeof(*sdi)); sdi = g_malloc0(sizeof(struct sr_dev_inst));
sdi->vendor = g_strdup(vendor); sdi->vendor = g_strdup(vendor);
sdi->model = g_strdup(model); sdi->model = g_strdup(model);
@ -420,7 +321,6 @@ SR_API struct sr_dev_inst *sr_dev_inst_user_new(const char *vendor,
/** /**
* Add a new channel to the specified device instance. * Add a new channel to the specified device instance.
* *
* @param[in] sdi Device instance to use. Must not be NULL.
* @param[in] index @copydoc sr_channel::index * @param[in] index @copydoc sr_channel::index
* @param[in] type @copydoc sr_channel::type * @param[in] type @copydoc sr_channel::type
* @param[in] name @copydoc sr_channel::name * @param[in] name @copydoc sr_channel::name
@ -456,7 +356,9 @@ SR_PRIV void sr_dev_inst_free(struct sr_dev_inst *sdi)
for (l = sdi->channels; l; l = l->next) { for (l = sdi->channels; l; l = l->next) {
ch = l->data; ch = l->data;
sr_channel_free(ch); g_free(ch->name);
g_free(ch->priv);
g_free(ch);
} }
g_slist_free(sdi->channels); g_slist_free(sdi->channels);
@ -498,7 +400,7 @@ SR_PRIV struct sr_usb_dev_inst *sr_usb_dev_inst_new(uint8_t bus,
{ {
struct sr_usb_dev_inst *udi; struct sr_usb_dev_inst *udi;
udi = g_malloc0(sizeof(*udi)); udi = g_malloc0(sizeof(struct sr_usb_dev_inst));
udi->bus = bus; udi->bus = bus;
udi->address = address; udi->address = address;
udi->devhdl = hdl; udi->devhdl = hdl;
@ -521,7 +423,7 @@ SR_PRIV void sr_usb_dev_inst_free(struct sr_usb_dev_inst *usb)
#endif #endif
#ifdef HAVE_SERIAL_COMM #ifdef HAVE_LIBSERIALPORT
/** /**
* Allocate and init a struct for a serial device instance. * Allocate and init a struct for a serial device instance.
@ -547,7 +449,7 @@ SR_PRIV struct sr_serial_dev_inst *sr_serial_dev_inst_new(const char *port,
{ {
struct sr_serial_dev_inst *serial; struct sr_serial_dev_inst *serial;
serial = g_malloc0(sizeof(*serial)); serial = g_malloc0(sizeof(struct sr_serial_dev_inst));
serial->port = g_strdup(port); serial->port = g_strdup(port);
if (serialcomm) if (serialcomm)
serial->serialcomm = g_strdup(serialcomm); serial->serialcomm = g_strdup(serialcomm);
@ -579,7 +481,7 @@ SR_PRIV struct sr_usbtmc_dev_inst *sr_usbtmc_dev_inst_new(const char *device)
{ {
struct sr_usbtmc_dev_inst *usbtmc; struct sr_usbtmc_dev_inst *usbtmc;
usbtmc = g_malloc0(sizeof(*usbtmc)); usbtmc = g_malloc0(sizeof(struct sr_usbtmc_dev_inst));
usbtmc->device = g_strdup(device); usbtmc->device = g_strdup(device);
usbtmc->fd = -1; usbtmc->fd = -1;
@ -627,40 +529,27 @@ SR_API GSList *sr_dev_list(const struct sr_dev_driver *driver)
*/ */
SR_API int sr_dev_clear(const struct sr_dev_driver *driver) SR_API int sr_dev_clear(const struct sr_dev_driver *driver)
{ {
int ret;
if (!driver) { if (!driver) {
sr_err("Invalid driver."); sr_err("Invalid driver.");
return SR_ERR_ARG; return SR_ERR_ARG;
} }
if (!driver->context) { if (driver->dev_clear)
/* ret = driver->dev_clear(driver);
* Driver was never initialized, nothing to do. else
* ret = std_dev_clear(driver, NULL);
* No log message since this usually gets called for all
* drivers, whether they were initialized or not.
*/
return SR_OK;
}
/* No log message here, too verbose and not very useful. */ return ret;
return driver->dev_clear(driver);
} }
/** /**
* Open the specified device instance. * Open the specified device.
*
* If the device instance is already open (sdi->status == SR_ST_ACTIVE),
* SR_ERR will be returned and no re-opening of the device will be attempted.
*
* If opening was successful, sdi->status is set to SR_ST_ACTIVE, otherwise
* it will be left unchanged.
* *
* @param sdi Device instance to use. Must not be NULL. * @param sdi Device instance to use. Must not be NULL.
* *
* @retval SR_OK Success. * @return SR_OK upon success, a negative error code upon errors.
* @retval SR_ERR_ARG Invalid arguments.
* @retval SR_ERR Device instance was already active, or other error.
* *
* @since 0.2.0 * @since 0.2.0
*/ */
@ -669,59 +558,32 @@ SR_API int sr_dev_open(struct sr_dev_inst *sdi)
int ret; int ret;
if (!sdi || !sdi->driver || !sdi->driver->dev_open) if (!sdi || !sdi->driver || !sdi->driver->dev_open)
return SR_ERR_ARG;
if (sdi->status == SR_ST_ACTIVE) {
sr_err("%s: Device instance already active, can't re-open.",
sdi->driver->name);
return SR_ERR; return SR_ERR;
}
sr_dbg("%s: Opening device instance.", sdi->driver->name);
ret = sdi->driver->dev_open(sdi); ret = sdi->driver->dev_open(sdi);
if (ret == SR_OK)
sdi->status = SR_ST_ACTIVE;
return ret; return ret;
} }
/** /**
* Close the specified device instance. * Close the specified device.
*
* If the device instance is not open (sdi->status != SR_ST_ACTIVE),
* SR_ERR_DEV_CLOSED will be returned and no closing will be attempted.
*
* Note: sdi->status will be set to SR_ST_INACTIVE, regardless of whether
* there are any errors during closing of the device instance (any errors
* will be reported via error code and log message, though).
* *
* @param sdi Device instance to use. Must not be NULL. * @param sdi Device instance to use. Must not be NULL.
* *
* @retval SR_OK Success. * @return SR_OK upon success, a negative error code upon errors.
* @retval SR_ERR_ARG Invalid arguments.
* @retval SR_ERR_DEV_CLOSED Device instance was not active.
* @retval SR_ERR Other error.
* *
* @since 0.2.0 * @since 0.2.0
*/ */
SR_API int sr_dev_close(struct sr_dev_inst *sdi) SR_API int sr_dev_close(struct sr_dev_inst *sdi)
{ {
int ret;
if (!sdi || !sdi->driver || !sdi->driver->dev_close) if (!sdi || !sdi->driver || !sdi->driver->dev_close)
return SR_ERR_ARG; return SR_ERR;
if (sdi->status != SR_ST_ACTIVE) { ret = sdi->driver->dev_close(sdi);
sr_err("%s: Device instance not active, can't close.",
sdi->driver->name);
return SR_ERR_DEV_CLOSED;
}
sdi->status = SR_ST_INACTIVE; return ret;
sr_dbg("%s: Closing device instance.", sdi->driver->name);
return sdi->driver->dev_close(sdi);
} }
/** /**
@ -812,24 +674,19 @@ SR_API const char *sr_dev_inst_connid_get(const struct sr_dev_inst *sdi)
#ifdef HAVE_LIBUSB_1_0 #ifdef HAVE_LIBUSB_1_0
struct drv_context *drvc; struct drv_context *drvc;
int cnt, i, a, b; int cnt, i, a, b;
char conn_id_usb[64]; char connection_id[64];
struct sr_usb_dev_inst *usb; struct sr_usb_dev_inst *usb;
struct libusb_device **devlist; struct libusb_device **devlist;
#endif #endif
#ifdef HAVE_SERIAL_COMM
struct sr_serial_dev_inst *serial;
#endif
struct sr_scpi_dev_inst *scpi;
char *conn_id_scpi;
if (!sdi) if (!sdi)
return NULL; return NULL;
#ifdef HAVE_SERIAL_COMM #ifdef HAVE_LIBSERIALPORT
struct sr_serial_dev_inst *serial;
if ((!sdi->connection_id) && (sdi->inst_type == SR_INST_SERIAL)) { if ((!sdi->connection_id) && (sdi->inst_type == SR_INST_SERIAL)) {
/* connection_id isn't populated, let's do that for serial devices. */ /* connection_id isn't populated, let's do that here. */
serial = sdi->conn; serial = sdi->conn;
((struct sr_dev_inst *)sdi)->connection_id = g_strdup(serial->port); ((struct sr_dev_inst *)sdi)->connection_id = g_strdup(serial->port);
@ -838,7 +695,7 @@ SR_API const char *sr_dev_inst_connid_get(const struct sr_dev_inst *sdi)
#ifdef HAVE_LIBUSB_1_0 #ifdef HAVE_LIBUSB_1_0
if ((!sdi->connection_id) && (sdi->inst_type == SR_INST_USB)) { if ((!sdi->connection_id) && (sdi->inst_type == SR_INST_USB)) {
/* connection_id isn't populated, let's do that for USB devices. */ /* connection_id isn't populated, let's do that here. */
drvc = sdi->driver->context; drvc = sdi->driver->context;
usb = sdi->conn; usb = sdi->conn;
@ -856,10 +713,8 @@ SR_API const char *sr_dev_inst_connid_get(const struct sr_dev_inst *sdi)
if (b != usb->bus || a != usb->address) if (b != usb->bus || a != usb->address)
continue; continue;
if (usb_get_port_path(devlist[i], conn_id_usb, sizeof(conn_id_usb)) < 0) usb_get_port_path(devlist[i], connection_id, sizeof(connection_id));
continue; ((struct sr_dev_inst *)sdi)->connection_id = g_strdup(connection_id);
((struct sr_dev_inst *)sdi)->connection_id = g_strdup(conn_id_usb);
break; break;
} }
@ -867,15 +722,6 @@ SR_API const char *sr_dev_inst_connid_get(const struct sr_dev_inst *sdi)
} }
#endif #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; 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) if (info->is_dc)
analog->meaning->mqflags |= SR_MQFLAG_DC; analog->meaning->mqflags |= SR_MQFLAG_DC;
if (info->is_diode) if (info->is_diode)
analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC; analog->meaning->mqflags |= SR_MQFLAG_DIODE;
if (info->is_peak_max) if (info->is_peak_max)
analog->meaning->mqflags |= SR_MQFLAG_MAX; analog->meaning->mqflags |= SR_MQFLAG_MAX;
if (info->is_peak_min) if (info->is_peak_min)
@ -446,7 +446,7 @@ static gboolean flags_valid(const struct asycii_info *info)
return TRUE; return TRUE;
} }
#ifdef HAVE_SERIAL_COMM #ifdef HAVE_LIBSERIALPORT
/** /**
* Arrange for the reception of another measurement from the DMM. * Arrange for the reception of another measurement from the DMM.
* *
@ -455,6 +455,8 @@ static gboolean flags_valid(const struct asycii_info *info)
* without the PC's intervention. * without the PC's intervention.
* *
* @param[in] serial The serial connection. * @param[in] serial The serial connection.
*
* @private
*/ */
SR_PRIV int sr_asycii_packet_request(struct sr_serial_dev_inst *serial) SR_PRIV int sr_asycii_packet_request(struct sr_serial_dev_inst *serial)
{ {
@ -517,7 +519,7 @@ SR_PRIV int sr_asycii_parse(const uint8_t *buf, float *floatval,
int ret, exponent; int ret, exponent;
struct asycii_info *info_local; struct asycii_info *info_local;
info_local = info; info_local = (struct asycii_info *)info;
/* Don't print byte 15. That one contains the carriage return. */ /* Don't print byte 15. That one contains the carriage return. */
sr_dbg("DMM packet: \"%.15s\"", buf); sr_dbg("DMM packet: \"%.15s\"", buf);

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->mq = SR_MQ_VOLTAGE;
analog->meaning->unit = SR_UNIT_VOLT; analog->meaning->unit = SR_UNIT_VOLT;
if ((analog->meaning->mqflags & (SR_MQFLAG_DC | SR_MQFLAG_AC)) == 0) if ((analog->meaning->mqflags & (SR_MQFLAG_DC | SR_MQFLAG_AC)) == 0)
analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC; analog->meaning->mqflags |= SR_MQFLAG_DIODE;
} }
if (buf[14] & 2) { if (buf[14] & 2) {
analog->meaning->mq = SR_MQ_CURRENT; analog->meaning->mq = SR_MQ_CURRENT;

File diff suppressed because it is too large Load Diff

View File

@ -1,457 +0,0 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@gmail.com>
* Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
* Copyright (C) 2019-2020 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
*
* Protocol parser for Brymen BM850s DMM packets. 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/PD02BM850s_protocolDL.html
* http://brymen.com/product-html/images/DownloadList/ProtocolList/BM850-BM850a-BM850s_List/BM850-BM850a-BM850s-500000-count-DMM-protocol-BC85X-BC85Xa.zip
*
* Implementor's notes on the protocol:
* - The BM85x devices require a low RTS pulse after COM port open and
* before communication of requests and responses. The vendor doc
* recommends 100ms pulse width including delays around it. Without
* that RTS pulse the meter won't respond to requests.
* - The request has a three byte header (DLE, STX, command code), two
* bytes command arguments, and three bytes tail (checksum, DLE, ETX).
* The checksum spans the area (including) the command code and args.
* The checksum value is the XOR across all payload bytes. Exclusively
* command 0x00 is used (initiate next measurement response) which does
* not need arguments (passes all-zero values).
* - The response has a four byte header (DLE, STX, command code, payload
* size), the respective number of payload data bytes, and a three byte
* tail (checksum, DLE, ETX). The checksum spans the range after the
* length field and before the checksum field. Command 0 response data
* payload consists of a four byte flags field and a text field for
* measurement values (floating point with exponent in ASCII).
* - Special cases of response data:
* - The text field which carries the measurement value also contains
* whitespace which may break simple text to number conversion. Like
* 10 02 00 0f 07 00 00 00 20 30 2e 30 30 33 32 20 45 2b 30 46 10 03
* which translates to: 07 00 00 00 " 0.0032 E+0". Text for overload
* conditions can be shorter which results in variable packet length.
* Some meter functions provide unexpected text for their values.
* - The reference impedance for decibel measurements looks wrong and
* requires special treatment to isolate the 4..1200R value:
* bfunc 80 20 00 00, text " 0. 800 E+1" (reference, 800R)
* The decibel measurement values use an unexpected scale.
* bfunc 00 20 00 00, text "-0.3702 E-1" (measurement, -37.02dBm)
* The reference value gets sent (sometimes) in a DMM response when
* the meter's function is entered, or the reference value changes.
* The 'bfunc' flags combination allows telling packet types apart.
* - Temperature measurements put the C/F unit between the mantissa
* and the exponent, which needs to get removed: " 0.0217CE+3"
* - Diode measurements appear to exclusively provide the 'Volt' flag
* but no 'Diode' flag. The display shows ".diod" for a moment but
* this information is no longer available when voltage measurements
* are seen.
*/
#include <config.h>
#include <ctype.h>
#include <math.h>
#include <libsigrok/libsigrok.h>
#include "libsigrok-internal.h"
#include <string.h>
#define LOG_PREFIX "brymen-bm85x"
#define STX 0x02
#define ETX 0x03
#define DLE 0x10
#define CMD_GET_READING 0
#define PKT_HEAD_LEN 4
#define PKT_DATA_MAX 15
#define PKT_TAIL_LEN 3
#define PKT_BFUNC_LEN 4
static uint8_t bm85x_crc(const uint8_t *buf, size_t len)
{
uint8_t crc;
crc = 0;
while (len--)
crc ^= *buf++;
return crc;
}
#ifdef HAVE_SERIAL_COMM
/** Meter's specific activity after port open and before data exchange. */
SR_PRIV int brymen_bm85x_after_open(struct sr_serial_dev_inst *serial)
{
int rts_toggle_delay_us;
/*
* The device requires an RTS *pulse* before communication.
* The vendor's documentation recommends the following sequence:
* Open the COM port, wait for 100ms, set RTS=1, wait for 100ms,
* set RTS=0, wait for 100ms, set RTS=1, configure bitrate and
* frame format, transmit request data, receive response data.
*/
rts_toggle_delay_us = 100 * 1000; /* 100ms */
g_usleep(rts_toggle_delay_us);
serial_set_handshake(serial, 1, -1);
g_usleep(rts_toggle_delay_us);
serial_set_handshake(serial, 0, -1);
g_usleep(rts_toggle_delay_us);
serial_set_handshake(serial, 1, -1);
g_usleep(rts_toggle_delay_us);
return SR_OK;
}
static int bm85x_send_command(struct sr_serial_dev_inst *serial,
uint8_t cmd, uint8_t arg1, uint8_t arg2)
{
uint8_t buf[8];
uint8_t crc, *wrptr, *crcptr;
size_t wrlen;
int ret;
wrptr = &buf[0];
write_u8_inc(&wrptr, DLE);
write_u8_inc(&wrptr, STX);
crcptr = wrptr;
write_u8_inc(&wrptr, cmd);
write_u8_inc(&wrptr, arg1);
write_u8_inc(&wrptr, arg2);
crc = bm85x_crc(crcptr, wrptr - crcptr);
write_u8_inc(&wrptr, crc);
write_u8_inc(&wrptr, DLE);
write_u8_inc(&wrptr, ETX);
wrlen = wrptr - &buf[0];
ret = serial_write_nonblocking(serial, &buf[0], wrlen);
if (ret < 0)
return ret;
if ((size_t)ret != wrlen)
return SR_ERR_IO;
return SR_OK;
}
/** Initiate reception of another meter's reading. */
SR_PRIV int brymen_bm85x_packet_request(struct sr_serial_dev_inst *serial)
{
return bm85x_send_command(serial, CMD_GET_READING, 0, 0);
}
#endif
/**
* Check Brymen BM85x DMM packet for validity.
*
* @param[in] st The DMM driver's internal state.
* @param[in] buf The data bytes received so far.
* @param[in] len The received data's length (byte count).
* @param[out] pkt_len The packet's calculated total size (when valid).
*
* The BM850s protocol uses packets of variable length. A minimum amount
* of RX data provides the packet header, which communicates the payload
* size, which allows to determine the packet's total size. Callers of
* this validity checker can learn how much data will get consumed when
* a valid packet got received and processed. The packet size is not
* known in advance.
*
* @returns SR_OK when the packet is valid.
* @returns SR_ERR* (below zero) when the packet is invalid.
* @returns Greater 0 when packet is incomplete, more data is needed.
*/
SR_PRIV int brymen_bm85x_packet_valid(void *st,
const uint8_t *buf, size_t len, size_t *pkt_len)
{
size_t plen;
uint8_t cmd, crc;
(void)st;
/* Four header bytes: DLE, STX, command, payload length. */
if (len < PKT_HEAD_LEN)
return SR_PACKET_NEED_RX;
if (read_u8_inc(&buf) != DLE)
return SR_PACKET_INVALID;
if (read_u8_inc(&buf) != STX)
return SR_PACKET_INVALID;
cmd = read_u8_inc(&buf);
/* Non-fatal, happens with OL pending during connect. */
if (cmd == 0x01)
cmd = 0x00;
if (cmd != CMD_GET_READING)
return SR_PACKET_INVALID;
plen = read_u8_inc(&buf);
if (plen > PKT_DATA_MAX)
return SR_PACKET_INVALID;
len -= PKT_HEAD_LEN;
/* Checksum spans bfunc and value text. Length according to header. */
if (len < plen + PKT_TAIL_LEN)
return SR_PACKET_NEED_RX;
crc = bm85x_crc(buf, plen);
buf += plen;
len -= plen;
/* Three tail bytes: checksum, DLE, ETX. */
if (len < PKT_TAIL_LEN)
return SR_PACKET_NEED_RX;
if (read_u8_inc(&buf) != crc)
return SR_PACKET_INVALID;
if (read_u8_inc(&buf) != DLE)
return SR_PACKET_INVALID;
if (read_u8_inc(&buf) != ETX)
return SR_PACKET_INVALID;
/*
* Only return the total packet length when the receive buffer
* was found to be valid. For invalid packets it's preferred to
* have the caller keep trying to sync to the packet stream.
*/
if (pkt_len)
*pkt_len = PKT_HEAD_LEN + plen + PKT_TAIL_LEN;
return SR_PACKET_VALID;
}
struct bm85x_flags {
gboolean is_batt, is_db, is_perc, is_hz, is_amp, is_beep;
gboolean is_ohm, is_temp_f, is_temp_c, is_diode, is_cap;
gboolean is_volt, is_dc, is_ac;
};
static int bm85x_parse_flags(const uint8_t *bfunc, struct bm85x_flags *flags)
{
if (!bfunc || !flags)
return SR_ERR_ARG;
memset(flags, 0, sizeof(*flags));
flags->is_batt = bfunc[3] & (1u << 7);
if ((bfunc[3] & 0x7f) != 0)
return SR_ERR_ARG;
if ((bfunc[2] & 0xff) != 0)
return SR_ERR_ARG;
if ((bfunc[1] & 0xc0) != 0)
return SR_ERR_ARG;
flags->is_db = bfunc[1] & (1u << 5);
if ((bfunc[1] & 0x10) != 0)
return SR_ERR_ARG;
flags->is_perc = bfunc[1] & (1u << 3);
flags->is_hz = bfunc[1] & (1u << 2);
flags->is_amp = bfunc[1] & (1u << 1);
flags->is_beep = bfunc[1] & (1u << 0);
flags->is_ohm = bfunc[0] & (1u << 7);
flags->is_temp_f = bfunc[0] & (1u << 6);
flags->is_temp_c = bfunc[0] & (1u << 5);
flags->is_diode = bfunc[0] & (1u << 4);
flags->is_cap = bfunc[0] & (1u << 3);
flags->is_volt = bfunc[0] & (1u << 2);
flags->is_dc = bfunc[0] & (1u << 1);
flags->is_ac = bfunc[0] & (1u << 0);
return SR_OK;
}
static int bm85x_parse_value(char *txt, double *val, int *digits)
{
char *src, *dst, c;
int ret;
/*
* See above comment on whitespace in response's number text.
* The caller provides a NUL terminated writable text copy.
* Go for low hanging fruit first (OL condition). Eliminate
* whitespace then and do the number conversion.
*/
if (strstr(txt, "+OL")) {
*val = +INFINITY;
return SR_OK;
}
if (strstr(txt, "-OL")) {
*val = -INFINITY;
return SR_OK;
}
if (strstr(txt, "OL")) {
*val = INFINITY;
return SR_OK;
}
src = txt;
dst = txt;
while (*src) {
c = *src++;
if (c == ' ')
continue;
*dst++ = c;
}
*dst = '\0';
ret = sr_atod_ascii_digits(txt, val, digits);
if (ret != SR_OK)
return ret;
return SR_OK;
}
static int bm85x_parse_payload(const uint8_t *p, size_t l,
double *val, struct sr_datafeed_analog *analog)
{
const uint8_t *bfunc;
char text_buf[PKT_DATA_MAX], *text;
size_t text_len;
int ret;
struct bm85x_flags flags;
int digits;
char *parse;
/* Get a bfunc bits reference, and a writable value text. */
bfunc = &p[0];
text_len = l - PKT_BFUNC_LEN;
memcpy(text_buf, &p[PKT_BFUNC_LEN], text_len);
text_buf[text_len] = '\0';
text = &text_buf[0];
sr_dbg("DMM bfunc %02x %02x %02x %02x, text \"%s\"",
bfunc[0], bfunc[1], bfunc[2], bfunc[3], text);
/* Check 'bfunc' bitfield first, text interpretation depends on it. */
ret = bm85x_parse_flags(bfunc, &flags);
if (ret != SR_OK)
return ret;
/* Parse the text after potential normalization/transformation. */
if (flags.is_db && flags.is_ohm) {
static const char *prefix = " 0.";
static const char *suffix = " E";
/* See above comment on dBm reference value text. */
if (strncmp(text, prefix, strlen(prefix)) != 0)
return SR_ERR_DATA;
text += strlen(prefix);
text_len -= strlen(prefix);
parse = strstr(text, suffix);
if (!parse)
return SR_ERR_DATA;
*parse = '\0';
}
if (flags.is_temp_f || flags.is_temp_c) {
/* See above comment on temperature value text. */
parse = strchr(text, flags.is_temp_f ? 'F' : 'C');
if (!parse)
return SR_ERR_DATA;
*parse = ' ';
}
digits = 0;
ret = bm85x_parse_value(text, val, &digits);
if (ret != SR_OK)
return ret;
/* Fill in MQ and flags result details. */
analog->meaning->mqflags = 0;
if (flags.is_volt) {
analog->meaning->mq = SR_MQ_VOLTAGE;
analog->meaning->unit = SR_UNIT_VOLT;
}
if (flags.is_amp) {
analog->meaning->mq = SR_MQ_CURRENT;
analog->meaning->unit = SR_UNIT_AMPERE;
}
if (flags.is_ohm) {
if (flags.is_db)
analog->meaning->mq = SR_MQ_RESISTANCE;
else if (flags.is_beep)
analog->meaning->mq = SR_MQ_CONTINUITY;
else
analog->meaning->mq = SR_MQ_RESISTANCE;
analog->meaning->unit = SR_UNIT_OHM;
}
if (flags.is_hz) {
analog->meaning->mq = SR_MQ_FREQUENCY;
analog->meaning->unit = SR_UNIT_HERTZ;
}
if (flags.is_perc) {
analog->meaning->mq = SR_MQ_DUTY_CYCLE;
analog->meaning->unit = SR_UNIT_PERCENTAGE;
}
if (flags.is_cap) {
analog->meaning->mq = SR_MQ_CAPACITANCE;
analog->meaning->unit = SR_UNIT_FARAD;
}
if (flags.is_temp_f) {
analog->meaning->mq = SR_MQ_TEMPERATURE;
analog->meaning->unit = SR_UNIT_FAHRENHEIT;
}
if (flags.is_temp_c) {
analog->meaning->mq = SR_MQ_TEMPERATURE;
analog->meaning->unit = SR_UNIT_CELSIUS;
}
if (flags.is_db && !flags.is_ohm) {
/* See above comment on dBm measurements scale. */
analog->meaning->mq = SR_MQ_POWER;
analog->meaning->unit = SR_UNIT_DECIBEL_MW;
*val *= 1000;
digits -= 3;
}
if (flags.is_diode) {
/* See above comment on diode measurement responses. */
analog->meaning->mq = SR_MQ_VOLTAGE;
analog->meaning->unit = SR_UNIT_VOLT;
analog->meaning->mqflags |= SR_MQFLAG_DIODE;
analog->meaning->mqflags |= SR_MQFLAG_DC;
}
if (flags.is_ac)
analog->meaning->mqflags |= SR_MQFLAG_AC;
if (flags.is_dc)
analog->meaning->mqflags |= SR_MQFLAG_DC;
analog->encoding->digits = digits;
analog->spec->spec_digits = digits;
if (flags.is_batt)
sr_warn("Low battery!");
return SR_OK;
}
SR_PRIV int brymen_bm85x_parse(void *st, const uint8_t *buf, size_t len,
double *val, struct sr_datafeed_analog *analog, void *info)
{
const uint8_t *pl_ptr;
size_t pl_len;
(void)st;
(void)info;
if (!buf || !len)
return SR_ERR_DATA;
if (!val || !analog)
return SR_ERR_DATA;
if (brymen_bm85x_packet_valid(NULL, buf, len, NULL) != SR_PACKET_VALID)
return SR_ERR_DATA;
pl_ptr = &buf[PKT_HEAD_LEN];
pl_len = len - PKT_HEAD_LEN - PKT_TAIL_LEN;
return bm85x_parse_payload(pl_ptr, pl_len, val, analog);
}

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -302,7 +302,7 @@ static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
if (info->is_auto) if (info->is_auto)
analog->meaning->mqflags |= SR_MQFLAG_AUTORANGE; analog->meaning->mqflags |= SR_MQFLAG_AUTORANGE;
if (info->is_diode) if (info->is_diode)
analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC; analog->meaning->mqflags |= SR_MQFLAG_DIODE;
if (info->is_hold) if (info->is_hold)
analog->meaning->mqflags |= SR_MQFLAG_HOLD; analog->meaning->mqflags |= SR_MQFLAG_HOLD;
if (info->is_rel) if (info->is_rel)
@ -353,7 +353,7 @@ SR_PRIV int sr_fs9721_parse(const uint8_t *buf, float *floatval,
int ret, exponent = 0; int ret, exponent = 0;
struct fs9721_info *info_local; struct fs9721_info *info_local;
info_local = info; info_local = (struct fs9721_info *)info;
if ((ret = parse_value(buf, floatval, &exponent)) != SR_OK) { if ((ret = parse_value(buf, floatval, &exponent)) != SR_OK) {
sr_dbg("Error parsing value: %d.", ret); sr_dbg("Error parsing value: %d.", ret);
@ -373,7 +373,7 @@ SR_PRIV void sr_fs9721_00_temp_c(struct sr_datafeed_analog *analog, void *info)
{ {
struct fs9721_info *info_local; struct fs9721_info *info_local;
info_local = info; info_local = (struct fs9721_info *)info;
/* User-defined FS9721_LP3 flag 'c2c1_00' means temperature (C). */ /* User-defined FS9721_LP3 flag 'c2c1_00' means temperature (C). */
if (info_local->is_c2c1_00) { if (info_local->is_c2c1_00) {
@ -386,7 +386,7 @@ SR_PRIV void sr_fs9721_01_temp_c(struct sr_datafeed_analog *analog, void *info)
{ {
struct fs9721_info *info_local; struct fs9721_info *info_local;
info_local = info; info_local = (struct fs9721_info *)info;
/* User-defined FS9721_LP3 flag 'c2c1_01' means temperature (C). */ /* User-defined FS9721_LP3 flag 'c2c1_01' means temperature (C). */
if (info_local->is_c2c1_01) { if (info_local->is_c2c1_01) {
@ -399,7 +399,7 @@ SR_PRIV void sr_fs9721_10_temp_c(struct sr_datafeed_analog *analog, void *info)
{ {
struct fs9721_info *info_local; struct fs9721_info *info_local;
info_local = info; info_local = (struct fs9721_info *)info;
/* User-defined FS9721_LP3 flag 'c2c1_10' means temperature (C). */ /* User-defined FS9721_LP3 flag 'c2c1_10' means temperature (C). */
if (info_local->is_c2c1_10) { if (info_local->is_c2c1_10) {
@ -412,7 +412,7 @@ SR_PRIV void sr_fs9721_01_10_temp_f_c(struct sr_datafeed_analog *analog, void *i
{ {
struct fs9721_info *info_local; struct fs9721_info *info_local;
info_local = info; info_local = (struct fs9721_info *)info;
/* User-defined FS9721_LP3 flag 'c2c1_01' means temperature (F). */ /* User-defined FS9721_LP3 flag 'c2c1_01' means temperature (F). */
if (info_local->is_c2c1_01) { if (info_local->is_c2c1_01) {
@ -431,7 +431,7 @@ SR_PRIV void sr_fs9721_max_c_min(struct sr_datafeed_analog *analog, void *info)
{ {
struct fs9721_info *info_local; struct fs9721_info *info_local;
info_local = info; info_local = (struct fs9721_info *)info;
/* User-defined FS9721_LP3 flag 'c2c1_00' means MAX. */ /* User-defined FS9721_LP3 flag 'c2c1_00' means MAX. */
if (info_local->is_c2c1_00) if (info_local->is_c2c1_00)

View File

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

View File

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

View File

@ -22,6 +22,7 @@
* *
* Metex 14-bytes ASCII protocol parser. * Metex 14-bytes ASCII protocol parser.
* *
* @internal
* This should work for various multimeters which use this kind of protocol, * This should work for various multimeters which use this kind of protocol,
* even though there is some variation in which modes each DMM supports. * even though there is some variation in which modes each DMM supports.
* *
@ -85,7 +86,7 @@ static int parse_value(const uint8_t *buf, struct metex14_info *info,
return SR_OK; return SR_OK;
/* Bytes 2-8: Sign, value (up to 5 digits) and decimal point */ /* Bytes 2-8: Sign, value (up to 5 digits) and decimal point */
sr_atof_ascii((const char *)&valstr, result); sscanf((const char *)&valstr, "%f", result);
dot_pos = strcspn(valstr, "."); dot_pos = strcspn(valstr, ".");
if (dot_pos < cnt) if (dot_pos < cnt)
@ -145,14 +146,8 @@ static void parse_flags(const char *buf, struct metex14_info *info)
info->is_kilo = info->is_hertz = TRUE; info->is_kilo = info->is_hertz = TRUE;
else if (!g_ascii_strcasecmp(u, "C")) else if (!g_ascii_strcasecmp(u, "C"))
info->is_celsius = TRUE; info->is_celsius = TRUE;
else if (!g_ascii_strcasecmp(u, "F"))
info->is_fahrenheit = TRUE;
else if (!g_ascii_strcasecmp(u, "DB")) else if (!g_ascii_strcasecmp(u, "DB"))
info->is_decibel = TRUE; info->is_decibel = TRUE;
else if (!g_ascii_strcasecmp(u, "dBm"))
info->is_decibel_mw = TRUE;
else if (!g_ascii_strcasecmp(u, "W"))
info->is_watt = TRUE;
else if (!g_ascii_strcasecmp(u, "")) else if (!g_ascii_strcasecmp(u, ""))
info->is_unitless = TRUE; info->is_unitless = TRUE;
@ -161,25 +156,15 @@ static void parse_flags(const char *buf, struct metex14_info *info)
(!strncmp(buf, " ", 2) && info->is_ohm); (!strncmp(buf, " ", 2) && info->is_ohm);
info->is_capacity = !strncmp(buf, "CA", 2) || info->is_capacity = !strncmp(buf, "CA", 2) ||
(!strncmp(buf, " ", 2) && info->is_farad); (!strncmp(buf, " ", 2) && info->is_farad);
info->is_temperature = !strncmp(buf, "TE", 2) || info->is_temperature = !strncmp(buf, "TE", 2);
info->is_celsius || info->is_fahrenheit;
info->is_diode = !strncmp(buf, "DI", 2) || info->is_diode = !strncmp(buf, "DI", 2) ||
(!strncmp(buf, " ", 2) && info->is_volt && info->is_milli); (!strncmp(buf, " ", 2) && info->is_volt && info->is_milli);
info->is_frequency = !strncmp(buf, "FR", 2) || info->is_frequency = !strncmp(buf, "FR", 2) ||
(!strncmp(buf, " ", 2) && info->is_hertz); (!strncmp(buf, " ", 2) && info->is_hertz);
info->is_gain = !strncmp(buf, "DB", 2) && info->is_decibel; info->is_gain = !strncmp(buf, "DB", 2);
info->is_power = (!strncmp(buf, "dB", 2) && info->is_decibel_mw) ||
((!strncmp(buf, "WT", 2) && info->is_watt));
info->is_power_factor = !strncmp(buf, "CO", 2) && info->is_unitless;
info->is_hfe = !strncmp(buf, "HF", 2) || info->is_hfe = !strncmp(buf, "HF", 2) ||
(!strncmp(buf, " ", 2) && !info->is_ampere &&!info->is_volt && (!strncmp(buf, " ", 2) && !info->is_volt && !info->is_ohm &&
!info->is_resistance && !info->is_capacity && !info->is_frequency && !info->is_logic && !info->is_farad && !info->is_hertz);
!info->is_temperature && !info->is_power && !info->is_power_factor &&
!info->is_gain && !info->is_logic && !info->is_diode);
info->is_min = !strncmp(buf, "MN", 2);
info->is_max = !strncmp(buf, "MX", 2);
info->is_avg = !strncmp(buf, "AG", 2);
/* /*
* Note: * Note:
* - Protocol doesn't distinguish "resistance" from "beep" mode. * - Protocol doesn't distinguish "resistance" from "beep" mode.
@ -193,12 +178,8 @@ static void parse_flags(const char *buf, struct metex14_info *info)
static void handle_flags(struct sr_datafeed_analog *analog, float *floatval, static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
int *exponent, const struct metex14_info *info) int *exponent, const struct metex14_info *info)
{ {
int factor; int factor = 0;
(void)exponent;
/* Factors */ /* Factors */
factor = 0;
if (info->is_pico) if (info->is_pico)
factor -= 12; factor -= 12;
if (info->is_nano) if (info->is_nano)
@ -212,6 +193,7 @@ static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
if (info->is_mega) if (info->is_mega)
factor += 6; factor += 6;
*floatval *= powf(10, factor); *floatval *= powf(10, factor);
*exponent += factor;
/* Measurement modes */ /* Measurement modes */
if (info->is_volt) { if (info->is_volt) {
@ -234,32 +216,14 @@ static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
analog->meaning->mq = SR_MQ_CAPACITANCE; analog->meaning->mq = SR_MQ_CAPACITANCE;
analog->meaning->unit = SR_UNIT_FARAD; analog->meaning->unit = SR_UNIT_FARAD;
} }
if (info->is_temperature) { if (info->is_celsius) {
analog->meaning->mq = SR_MQ_TEMPERATURE; analog->meaning->mq = SR_MQ_TEMPERATURE;
if (info->is_celsius)
analog->meaning->unit = SR_UNIT_CELSIUS; analog->meaning->unit = SR_UNIT_CELSIUS;
else if (info->is_fahrenheit)
analog->meaning->unit = SR_UNIT_FAHRENHEIT;
else
analog->meaning->unit = SR_UNIT_UNITLESS;
} }
if (info->is_diode) { if (info->is_diode) {
analog->meaning->mq = SR_MQ_VOLTAGE; analog->meaning->mq = SR_MQ_VOLTAGE;
analog->meaning->unit = SR_UNIT_VOLT; analog->meaning->unit = SR_UNIT_VOLT;
} }
if (info->is_power) {
analog->meaning->mq = SR_MQ_POWER;
if (info->is_decibel_mw)
analog->meaning->unit = SR_UNIT_DECIBEL_MW;
else if (info->is_watt)
analog->meaning->unit = SR_UNIT_WATT;
else
analog->meaning->unit = SR_UNIT_UNITLESS;
}
if (info->is_power_factor) {
analog->meaning->mq = SR_MQ_POWER_FACTOR;
analog->meaning->unit = SR_UNIT_UNITLESS;
}
if (info->is_gain) { if (info->is_gain) {
analog->meaning->mq = SR_MQ_GAIN; analog->meaning->mq = SR_MQ_GAIN;
analog->meaning->unit = SR_UNIT_DECIBEL_VOLT; analog->meaning->unit = SR_UNIT_DECIBEL_VOLT;
@ -279,13 +243,7 @@ static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
if (info->is_dc) if (info->is_dc)
analog->meaning->mqflags |= SR_MQFLAG_DC; analog->meaning->mqflags |= SR_MQFLAG_DC;
if (info->is_diode) if (info->is_diode)
analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC; analog->meaning->mqflags |= SR_MQFLAG_DIODE;
if (info->is_min)
analog->meaning->mqflags |= SR_MQFLAG_MIN;
if (info->is_max)
analog->meaning->mqflags |= SR_MQFLAG_MAX;
if (info->is_avg)
analog->meaning->mqflags |= SR_MQFLAG_AVG;
} }
static gboolean flags_valid(const struct metex14_info *info) static gboolean flags_valid(const struct metex14_info *info)
@ -328,23 +286,14 @@ static gboolean flags_valid(const struct metex14_info *info)
return TRUE; return TRUE;
} }
#ifdef HAVE_SERIAL_COMM #ifdef HAVE_LIBSERIALPORT
SR_PRIV int sr_metex14_packet_request(struct sr_serial_dev_inst *serial) SR_PRIV int sr_metex14_packet_request(struct sr_serial_dev_inst *serial)
{ {
const uint8_t wbuf = 'D'; const uint8_t wbuf = 'D';
size_t wrlen;
int ret;
sr_spew("Requesting DMM packet."); sr_spew("Requesting DMM packet.");
wrlen = sizeof(wbuf); return (serial_write_nonblocking(serial, &wbuf, 1) == 1) ? SR_OK : SR_ERR;
ret = serial_write_blocking(serial, &wbuf, wrlen, 0);
if (ret < 0)
return ret;
if ((size_t)ret != wrlen)
return SR_ERR_IO;
return SR_OK;
} }
#endif #endif
@ -364,25 +313,6 @@ SR_PRIV gboolean sr_metex14_packet_valid(const uint8_t *buf)
return TRUE; return TRUE;
} }
SR_PRIV gboolean sr_metex14_4packets_valid(const uint8_t *buf)
{
struct metex14_info info;
size_t ch_idx;
const uint8_t *ch_buf;
ch_buf = buf;
for (ch_idx = 0; ch_idx < 4; ch_idx++) {
if (ch_buf[13] != '\r')
return FALSE;
memset(&info, 0x00, sizeof(info));
parse_flags((const char *)ch_buf, &info);
if (!flags_valid(&info))
return FALSE;
ch_buf += METEX14_PACKET_SIZE;
}
return TRUE;
}
/** /**
* Parse a protocol packet. * Parse a protocol packet.
* *
@ -404,7 +334,7 @@ SR_PRIV int sr_metex14_parse(const uint8_t *buf, float *floatval,
int ret, exponent = 0; int ret, exponent = 0;
struct metex14_info *info_local; struct metex14_info *info_local;
info_local = info; info_local = (struct metex14_info *)info;
/* Don't print byte 13. That one contains the carriage return. */ /* Don't print byte 13. That one contains the carriage return. */
sr_dbg("DMM packet: \"%.13s\"", buf); sr_dbg("DMM packet: \"%.13s\"", buf);
@ -424,34 +354,3 @@ SR_PRIV int sr_metex14_parse(const uint8_t *buf, float *floatval,
return SR_OK; return SR_OK;
} }
/**
* Parse one out of four values of a four-display Metex14 variant.
*
* The caller's 'info' parameter can be used to track the channel index,
* as long as the information is kept across calls to the 14-byte packet
* parse routine (which clears the 'info' container).
*
* Since analog values have further details in the 'analog' parameter,
* passing multiple values per parse routine call is problematic. So we
* prefer the approach of passing one value per call, which is most
* reliable and shall fit every similar device with multiple displays.
*
* The meters which use this parse routine send one 14-byte packet per
* display. Each packet has the regular Metex14 layout.
*/
SR_PRIV int sr_metex14_4packets_parse(const uint8_t *buf, float *floatval,
struct sr_datafeed_analog *analog, void *info)
{
struct metex14_info *info_local;
size_t ch_idx;
const uint8_t *ch_buf;
int rc;
info_local = info;
ch_idx = info_local->ch_idx;
ch_buf = buf + ch_idx * METEX14_PACKET_SIZE;
rc = sr_metex14_parse(ch_buf, floatval, analog, info);
info_local->ch_idx = ch_idx + 1;
return rc;
}

View File

@ -1,457 +0,0 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2020 Peter Skarpetis <peters@skarpetis.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/>.
*/
/*
* Meterman 38XR protocol parser
*
* Communication parameters: Unidirectional, 9600/8n1
*
* The user guide can be downloaded from:
* https://assets.tequipment.net/assets/1/26/Documents/38XR_Manual.pdf
*
* Protocol is described in a PDF available at:
* https://www.elfadistrelec.fi/Web/Downloads/od/es/fj38XR-Serial-Output-Codes.pdf
*
* There is also a disussion about the protocol at the NI forum:
* https://forums.ni.com/t5/Digital-Multimeters-DMMs-and/Meterman-DMM/td-p/179597?profile.language=en
*
* EEVBlog discussion thread about the meter
* https://www.eevblog.com/forum/chat/meterman-38xr/
*/
/**
* @file
*
* Meterman 38XR ASCII protocol parser.
*/
#include <config.h>
#include <glib.h>
#include <libsigrok/libsigrok.h>
#include "libsigrok-internal.h"
#include <math.h>
#include <string.h>
#define LOG_PREFIX "mm38xr"
#define METERMAN_DIGITS_OVERLOAD 0xb0dd
#define METERMAN_DIGITS_BAD_INPUT_JACK 0xbaab
#define METERMAN_BARGRAPH_NO_SEGMENTS = 0x2a
enum mm38xr_func_code {
FUNC_CODE_UNUSED = 0x01,
FUNC_CODE_TEMPERATURE_FARENHEIGHT = 0x02,
FUNC_CODE_CURRENT_4_20_MAMPS = 0x03, /* 4-20 mA */
FUNC_CODE_DIODE_TEST = 0x04,
FUNC_CODE_INDUCTANCE_HENRIES = 0x05,
FUNC_CODE_TEMPERATURE_CELSIUS = 0x06,
FUNC_CODE_CURRENT_UAMPS = 0x07, /* uA */
FUNC_CODE_RESISTANCE_OHMS = 0x08,
FUNC_CODE_INDUCTANCE_MHENRIES = 0x09, /* mH */
FUNC_CODE_CURRENT_10_AMPS = 0x0a,
FUNC_CODE_CAPACITANCE = 0x0b,
FUNC_CODE_VOLTS_DC = 0x0c,
FUNC_CODE_LOGIC = 0x0d,
FUNC_CODE_CURRENT_MAMPS = 0x0e, /* mA */
FUNC_CODE_FREQUENCY_HZ = 0x0f, /* and duty cycle */
FUNC_CODE_VOLTS_AC = 0x10, /* and dBm */
};
enum mm38xr_meas_mode {
/* This is used to index into the digits and exponent arrays below. */
MEAS_MODE_VOLTS,
MEAS_MODE_RESISTANCE_OHMS,
MEAS_MODE_CURRENT_UAMPS, /* uA */
MEAS_MODE_CURRENT_MAMPS, /* mA */
MEAS_MODE_CURRENT_AMPS,
MEAS_MODE_CAPACITANCE,
MEAS_MODE_DIODE_TEST,
MEAS_MODE_TEMPERATURE_C,
MEAS_MODE_TEMPERATURE_F,
MEAS_MODE_FREQUENCY_HZ,
MEAS_MODE_INDUCTANCE_H,
MEAS_MODE_INDUCTANCE_MH, /* mH */
MEAS_MODE_DBM,
MEAS_MODE_DUTY_CYCLE,
MEAS_MODE_CONTINUITY,
/* For internal purposes. */
MEAS_MODE_UNDEFINED,
};
enum mm38xr_adcd_mode {
ACDC_MODE_NONE = 1000,
ACDC_MODE_DC,
ACDC_MODE_AC,
ACDC_MODE_AC_AND_DC,
};
struct meterman_info {
enum mm38xr_func_code functioncode; /* columns 0, 1 */
unsigned int reading; /* columns 2,3,4,5; LCD digits */
unsigned int bargraphsegments; /* columns 6, 7; max 40 segments, 0x2A = no bargraph */
size_t rangecode; /* column 8 */
unsigned int ampsfunction; /* column 9 */
unsigned int peakstatus; /* column 10 */
unsigned int rflag_h; /* column 11 */
unsigned int rflag_l; /* column 12 */
/* calculated values */
enum mm38xr_meas_mode meas_mode;
enum mm38xr_adcd_mode acdc;
};
static const int decimal_digits[][7] = {
[MEAS_MODE_VOLTS] = { 1, 3, 2, 1, 0, 0, 0, },
[MEAS_MODE_RESISTANCE_OHMS] = { 2, 3, 4, 2, 3, 1, 0, },
[MEAS_MODE_CURRENT_UAMPS] = { 2, 1, 0, 0, 0, 0, 0, },
[MEAS_MODE_CURRENT_MAMPS] = { 3, 2, 1, 0, 0, 0, 0, },
[MEAS_MODE_CURRENT_AMPS] = { 3, 0, 0, 0, 0, 0, 0, },
[MEAS_MODE_CAPACITANCE] = { 2, 1, 3, 2, 1, 0, 0, },
[MEAS_MODE_DIODE_TEST] = { 0, 3, 0, 0, 0, 0, 0, },
[MEAS_MODE_TEMPERATURE_C] = { 0, 0, 0, 0, 0, 0, 0, },
[MEAS_MODE_TEMPERATURE_F] = { 0, 0, 0, 0, 0, 0, 0, },
[MEAS_MODE_FREQUENCY_HZ] = { 2, 1, 3, 2, 1, 3, 2, },
[MEAS_MODE_INDUCTANCE_H] = { 0, 0, 0, 3, 2, 0, 0, },
[MEAS_MODE_INDUCTANCE_MH] = { 3, 2, 1, 0, 0, 0, 0, },
[MEAS_MODE_DBM] = { 2, 2, 2, 2, 2, 2, 2, },
[MEAS_MODE_DUTY_CYCLE] = { 2, 2, 2, 2, 2, 2, 2, },
[MEAS_MODE_CONTINUITY] = { 0, 0, 0, 0, 0, 1, 0, },
};
static const int units_exponents[][7] = {
[MEAS_MODE_VOLTS] = { -3, 0, 0, 0, 0, 0, 0, },
[MEAS_MODE_RESISTANCE_OHMS] = { 6, 6, 6, 3, 3, 0, 0, },
[MEAS_MODE_CURRENT_UAMPS] = { -6, -6, 0, 0, 0, 0, 0, },
[MEAS_MODE_CURRENT_MAMPS] = { -3, -3, -3, 0, 0, 0, 0, },
[MEAS_MODE_CURRENT_AMPS] = { 0, 0, 0, 0, 0, 0, 0, },
[MEAS_MODE_CAPACITANCE] = { -9, -9, -6, -6, -6, 0, 0, },
[MEAS_MODE_DIODE_TEST] = { 0, 0, 0, 0, 0, 0, 0, },
[MEAS_MODE_TEMPERATURE_C] = { 0, 0, 0, 0, 0, 0, 0, },
[MEAS_MODE_TEMPERATURE_F] = { 0, 0, 0, 0, 0, 0, 0, },
[MEAS_MODE_FREQUENCY_HZ] = { 0, 0, 3, 3, 3, 6, 6, },
[MEAS_MODE_INDUCTANCE_H] = { 0, 0, 0, 0, 0, 0, 0, },
[MEAS_MODE_INDUCTANCE_MH] = { -3, -3, -3, 0, 0, 0, 0, },
[MEAS_MODE_DBM] = { 0, 0, 0, 0, 0, 0, 0, },
[MEAS_MODE_DUTY_CYCLE] = { 0, 0, 0, 0, 0, 0, 0, },
[MEAS_MODE_CONTINUITY] = { 0, 0, 0, 0, 0, 0, 0, },
};
/* Assumes caller has already checked data fall within 0..9 and A..F */
static uint32_t meterman_38xr_hexnibble_to_uint(uint8_t v)
{
return (v <= '9') ? v - '0' : v - 'A' + 10;
}
static uint32_t meterman_38xr_func_code(const uint8_t *buf)
{
uint32_t v;
v = meterman_38xr_hexnibble_to_uint(buf[0]) << 4 |
meterman_38xr_hexnibble_to_uint(buf[1]);
return v;
}
static uint32_t meterman_38xr_barsegments(const uint8_t *buf)
{
uint32_t v;
v = meterman_38xr_hexnibble_to_uint(buf[6]) << 4 |
meterman_38xr_hexnibble_to_uint(buf[7]);
return v;
}
static uint32_t meterman_38xr_reading(const uint8_t *buf)
{
uint32_t v;
if (buf[2] > 'A') { /* overload */
v = meterman_38xr_hexnibble_to_uint(buf[2]) << 12 |
meterman_38xr_hexnibble_to_uint(buf[3]) << 8 |
meterman_38xr_hexnibble_to_uint(buf[4]) << 4 |
meterman_38xr_hexnibble_to_uint(buf[5]) << 0;
} else {
v = meterman_38xr_hexnibble_to_uint(buf[2]) * 1000 +
meterman_38xr_hexnibble_to_uint(buf[3]) * 100 +
meterman_38xr_hexnibble_to_uint(buf[4]) * 10 +
meterman_38xr_hexnibble_to_uint(buf[5]) * 1;
}
return v;
}
static gboolean meterman_38xr_is_negative(struct meterman_info *mi)
{
if (mi->rflag_l == 0x01)
return TRUE;
if (mi->meas_mode == MEAS_MODE_DBM && mi->rflag_l == 0x05)
return TRUE;
return FALSE;
}
static int currentACDC(struct meterman_info *mi)
{
if (mi->ampsfunction == 0x01)
return ACDC_MODE_AC;
if (mi->ampsfunction == 0x02)
return ACDC_MODE_AC_AND_DC;
return ACDC_MODE_DC;
}
static int meterman_38xr_decode(const uint8_t *buf, struct meterman_info *mi)
{
if (!meterman_38xr_packet_valid(buf))
return SR_ERR;
mi->functioncode = meterman_38xr_func_code(buf);
if (mi->functioncode < 2 || mi->functioncode > 0x10)
return SR_ERR;
mi->reading = meterman_38xr_reading(buf);
mi->bargraphsegments = meterman_38xr_barsegments(buf);
mi->rangecode = meterman_38xr_hexnibble_to_uint(buf[8]);
if (mi->rangecode > 6)
return SR_ERR;
mi->ampsfunction = meterman_38xr_hexnibble_to_uint(buf[9]);
mi->peakstatus = meterman_38xr_hexnibble_to_uint(buf[10]);
mi->rflag_h = meterman_38xr_hexnibble_to_uint(buf[11]);
mi->rflag_l = meterman_38xr_hexnibble_to_uint(buf[12]);
mi->acdc = ACDC_MODE_NONE;
switch (mi->functioncode) {
case FUNC_CODE_TEMPERATURE_FARENHEIGHT:
mi->meas_mode = MEAS_MODE_TEMPERATURE_F;
break;
case FUNC_CODE_CURRENT_4_20_MAMPS:
mi->meas_mode = MEAS_MODE_CURRENT_MAMPS;
mi->acdc = currentACDC(mi);
break;
case FUNC_CODE_DIODE_TEST:
mi->meas_mode = MEAS_MODE_DIODE_TEST;
mi->acdc = ACDC_MODE_DC;
break;
case FUNC_CODE_INDUCTANCE_HENRIES:
mi->meas_mode = MEAS_MODE_INDUCTANCE_H;
break;
case FUNC_CODE_TEMPERATURE_CELSIUS:
mi->meas_mode = MEAS_MODE_TEMPERATURE_C;
break;
case FUNC_CODE_CURRENT_UAMPS:
mi->meas_mode = MEAS_MODE_CURRENT_UAMPS;
mi->acdc = currentACDC(mi);
break;
case FUNC_CODE_RESISTANCE_OHMS:
mi->meas_mode = (mi->rflag_l == 0x08)
? MEAS_MODE_CONTINUITY
: MEAS_MODE_RESISTANCE_OHMS;
break;
case FUNC_CODE_INDUCTANCE_MHENRIES:
mi->meas_mode = MEAS_MODE_INDUCTANCE_MH;
break;
case FUNC_CODE_CURRENT_10_AMPS:
mi->meas_mode = MEAS_MODE_CURRENT_AMPS;
mi->acdc = currentACDC(mi);
break;
case FUNC_CODE_CAPACITANCE:
mi->meas_mode = MEAS_MODE_CAPACITANCE;
break;
case FUNC_CODE_VOLTS_DC:
mi->meas_mode = MEAS_MODE_VOLTS;
mi->acdc = (mi->rflag_l == 0x02)
? ACDC_MODE_AC_AND_DC : ACDC_MODE_DC;
break;
case FUNC_CODE_CURRENT_MAMPS:
mi->meas_mode = MEAS_MODE_CURRENT_MAMPS;
mi->acdc = currentACDC(mi);
break;
case FUNC_CODE_FREQUENCY_HZ:
mi->meas_mode = (mi->rflag_h == 0x0B)
? MEAS_MODE_DUTY_CYCLE
: MEAS_MODE_FREQUENCY_HZ;
break;
case FUNC_CODE_VOLTS_AC:
mi->meas_mode = (mi->rflag_l == 0x04 || mi->rflag_l == 0x05)
? MEAS_MODE_DBM : MEAS_MODE_VOLTS;
mi->acdc = ACDC_MODE_AC;
break;
default:
mi->meas_mode = MEAS_MODE_UNDEFINED;
return SR_ERR;
}
return SR_OK;
}
SR_PRIV gboolean meterman_38xr_packet_valid(const uint8_t *buf)
{
size_t i;
uint32_t fcode;
if ((buf[13] != '\r') || (buf[14] != '\n'))
return FALSE;
/* Check for all hex digits */
for (i = 0; i < 13; i++) {
if (buf[i] < '0')
return FALSE;
if (buf[i] > '9' && buf[i] < 'A')
return FALSE;
if (buf[i] > 'F')
return FALSE;
}
fcode = meterman_38xr_func_code(buf);
if (fcode < 0x01 || fcode > 0x10)
return FALSE;
return TRUE;
}
SR_PRIV int meterman_38xr_parse(const uint8_t *buf, float *floatval,
struct sr_datafeed_analog *analog, void *info)
{
gboolean is_overload, is_bad_jack;
int exponent;
int digits;
struct meterman_info mi;
(void)info;
if (meterman_38xr_decode(buf, &mi) != SR_OK)
return SR_ERR;
if (mi.meas_mode != MEAS_MODE_CONTINUITY) {
is_overload = mi.reading == METERMAN_DIGITS_OVERLOAD;
is_bad_jack = mi.reading == METERMAN_DIGITS_BAD_INPUT_JACK;
if (is_overload || is_bad_jack) {
sr_spew("Over limit.");
*floatval = INFINITY; /* overload */
return SR_OK;
}
}
switch (mi.meas_mode) {
case MEAS_MODE_VOLTS:
analog->meaning->mq = SR_MQ_VOLTAGE;
analog->meaning->unit = SR_UNIT_VOLT;
break;
case MEAS_MODE_RESISTANCE_OHMS:
analog->meaning->mq = SR_MQ_RESISTANCE;
analog->meaning->unit = SR_UNIT_OHM;
break;
case MEAS_MODE_CURRENT_UAMPS:
case MEAS_MODE_CURRENT_MAMPS:
case MEAS_MODE_CURRENT_AMPS:
analog->meaning->mq = SR_MQ_CURRENT;
analog->meaning->unit = SR_UNIT_AMPERE;
break;
case MEAS_MODE_CAPACITANCE:
analog->meaning->mq = SR_MQ_CAPACITANCE;
analog->meaning->unit = SR_UNIT_FARAD;
break;
case MEAS_MODE_DIODE_TEST:
analog->meaning->mq = SR_MQ_VOLTAGE;
analog->meaning->unit = SR_UNIT_VOLT;
analog->meaning->mqflags |= SR_MQFLAG_DIODE;
break;
case MEAS_MODE_TEMPERATURE_C:
analog->meaning->mq = SR_MQ_TEMPERATURE;
analog->meaning->unit = SR_UNIT_CELSIUS;
break;
case MEAS_MODE_TEMPERATURE_F:
analog->meaning->mq = SR_MQ_TEMPERATURE;
analog->meaning->unit = SR_UNIT_FAHRENHEIT;
break;
case MEAS_MODE_FREQUENCY_HZ:
analog->meaning->mq = SR_MQ_FREQUENCY;
analog->meaning->unit = SR_UNIT_HERTZ;
break;
case MEAS_MODE_INDUCTANCE_H:
analog->meaning->mq = SR_MQ_SERIES_INDUCTANCE;
analog->meaning->unit = SR_UNIT_HENRY;
break;
case MEAS_MODE_INDUCTANCE_MH:
analog->meaning->mq = SR_MQ_SERIES_INDUCTANCE;
analog->meaning->unit = SR_UNIT_HENRY;
break;
case MEAS_MODE_DBM:
analog->meaning->mq = SR_MQ_VOLTAGE;
analog->meaning->unit = SR_UNIT_DECIBEL_MW;
analog->meaning->mqflags |= SR_MQFLAG_AC;
break;
case MEAS_MODE_DUTY_CYCLE:
analog->meaning->mq = SR_MQ_DUTY_CYCLE;
analog->meaning->unit = SR_UNIT_PERCENTAGE;
break;
case MEAS_MODE_CONTINUITY:
analog->meaning->mq = SR_MQ_CONTINUITY;
analog->meaning->unit = SR_UNIT_BOOLEAN;
*floatval = (mi.reading == METERMAN_DIGITS_OVERLOAD) ? 0.0 : 1.0;
break;
default:
return SR_ERR;
}
switch (mi.acdc) {
case ACDC_MODE_DC:
analog->meaning->mqflags |= SR_MQFLAG_DC;
break;
case ACDC_MODE_AC:
analog->meaning->mqflags |= SR_MQFLAG_AC;
break;
case ACDC_MODE_AC_AND_DC:
analog->meaning->mqflags |= SR_MQFLAG_DC | SR_MQFLAG_AC;
break;
default:
break;
}
if (mi.peakstatus == 0x02 || mi.peakstatus == 0x0a)
analog->meaning->mqflags |= SR_MQFLAG_MAX;
if (mi.peakstatus == 0x03 || mi.peakstatus == 0x0b)
analog->meaning->mqflags |= SR_MQFLAG_MIN;
if (mi.rflag_h == 0x0a || mi.peakstatus == 0x0b)
analog->meaning->mqflags |= SR_MQFLAG_AUTORANGE;
if (mi.meas_mode != MEAS_MODE_CONTINUITY) {
digits = decimal_digits[mi.meas_mode][mi.rangecode];
exponent = units_exponents[mi.meas_mode][mi.rangecode];
*floatval = mi.reading;
if (meterman_38xr_is_negative(&mi)) {
*floatval *= -1.0f;
}
*floatval *= powf(10, -digits);
*floatval *= powf(10, exponent);
}
analog->encoding->digits = 4;
analog->spec->spec_digits = 4;
return SR_OK;
}

View File

@ -1,374 +0,0 @@
/*
* 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;
}

View File

@ -1,389 +0,0 @@
/*
* 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

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

View File

@ -360,7 +360,7 @@ static void handle_flags(struct sr_datafeed_analog *analog,
if (info->is_auto) if (info->is_auto)
analog->meaning->mqflags |= SR_MQFLAG_AUTORANGE; analog->meaning->mqflags |= SR_MQFLAG_AUTORANGE;
if (info->is_diode) if (info->is_diode)
analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC; analog->meaning->mqflags |= SR_MQFLAG_DIODE;
if (info->is_hold) if (info->is_hold)
/* /*
* Note: HOLD only affects the number displayed on the LCD, * Note: HOLD only affects the number displayed on the LCD,
@ -410,7 +410,7 @@ SR_PRIV int sr_vc870_parse(const uint8_t *buf, float *floatval,
int ret, exponent = 0; int ret, exponent = 0;
struct vc870_info *info_local; struct vc870_info *info_local;
info_local = info; info_local = (struct vc870_info *)info;
memset(info_local, 0, sizeof(struct vc870_info)); memset(info_local, 0, sizeof(struct vc870_info));
if (!sr_vc870_packet_valid(buf)) if (!sr_vc870_packet_valid(buf))

View File

@ -1,288 +0,0 @@
/*
* 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,34 +0,0 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2017 Marcus Comstedt <marcus@mc.pp.se>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <glib.h>
#include <libsigrok/libsigrok.h>
#include "libsigrok-internal.h"
/*
* This marks the start of the driver list. This file must be linked
* before any actual drivers.
*/
SR_PRIV const struct sr_dev_driver *sr_driver_list__start[]
SR_DRIVER_LIST_NOREORDER
__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,34 +0,0 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2017 Marcus Comstedt <marcus@mc.pp.se>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <glib.h>
#include <libsigrok/libsigrok.h>
#include "libsigrok-internal.h"
/*
* This marks the end of the driver list. This file must be linked
* after any actual drivers.
*/
SR_PRIV const struct sr_dev_driver *sr_driver_list__stop[]
SR_DRIVER_LIST_NOREORDER
__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,7 +3,6 @@
* *
* Copyright (C) 2016 Lars-Peter Clausen <lars@metafoo.de> * Copyright (C) 2016 Lars-Peter Clausen <lars@metafoo.de>
* Copyright (C) 2016 Aurelien Jacobs <aurel@gnuage.org> * Copyright (C) 2016 Aurelien Jacobs <aurel@gnuage.org>
* Copyright (C) 2017 Marcus Comstedt <marcus@mc.pp.se>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -27,19 +26,22 @@
/* /*
* sr_driver_list is a special section contains pointers to all the hardware * sr_driver_list is a special section contains pointers to all the hardware
* drivers built into the library. The __start and __stop symbols are * drivers built into the library. The __start and __stop symbols are
* created from driver_list_start.c and driver_list_stop.c, and point to the * auto-generated by the linker (OSX needs a little help) and point to the start
* start and end of the section. They are used to iterate over the list of * and end of the section. They are used to iterate over the list of all
* all drivers. * drivers.
*/ */
SR_PRIV extern const struct sr_dev_driver *sr_driver_list__start[]; #ifdef __APPLE__
SR_PRIV extern const struct sr_dev_driver *sr_driver_list__stop[]; 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
/** /** @private
* Initialize the driver list in a fresh libsigrok context. * Initialize the driver list in a fresh libsigrok context.
* *
* @param ctx Pointer to a libsigrok context struct. Must not be NULL. * @param ctx Pointer to a libsigrok context struct. Must not be NULL.
*
* @private
*/ */
SR_API void sr_drivers_init(struct sr_context *ctx) SR_API void sr_drivers_init(struct sr_context *ctx)
{ {
@ -47,8 +49,8 @@ SR_API void sr_drivers_init(struct sr_context *ctx)
array = g_array_new(TRUE, FALSE, sizeof(struct sr_dev_driver *)); array = g_array_new(TRUE, FALSE, sizeof(struct sr_dev_driver *));
#ifdef HAVE_DRIVERS #ifdef HAVE_DRIVERS
for (const struct sr_dev_driver **drivers = sr_driver_list__start + 1; for (struct sr_dev_driver **drivers = &__start_sr_driver_list;
drivers < sr_driver_list__stop; drivers++) drivers < &__stop_sr_driver_list; drivers++)
g_array_append_val(array, *drivers); g_array_append_val(array, *drivers);
#endif #endif
ctx->driver_list = (struct sr_dev_driver **)array->data; ctx->driver_list = (struct sr_dev_driver **)array->data;

View File

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

View File

@ -51,7 +51,11 @@ static const uint64_t samplerates[] = {
}; };
static const char *data_sources[] = { 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[]; extern const struct agdmm_job agdmm_jobs_live[];
@ -60,7 +64,6 @@ extern const struct agdmm_recv agdmm_recvs_u123x[];
extern const struct agdmm_recv agdmm_recvs_u124x[]; extern const struct agdmm_recv agdmm_recvs_u124x[];
extern const struct agdmm_recv agdmm_recvs_u124xc[]; extern const struct agdmm_recv agdmm_recvs_u124xc[];
extern const struct agdmm_recv agdmm_recvs_u125x[]; extern const struct agdmm_recv agdmm_recvs_u125x[];
extern const struct agdmm_recv agdmm_recvs_u127x[];
extern const struct agdmm_recv agdmm_recvs_u128x[]; extern const struct agdmm_recv agdmm_recvs_u128x[];
/* This works on all the Agilent U12xxA series, although the /* This works on all the Agilent U12xxA series, although the
@ -87,11 +90,6 @@ static const struct agdmm_profile supported_agdmm[] = {
{ AGILENT_U1252, "U1252B", 3, agdmm_jobs_live, NULL, agdmm_recvs_u125x }, { AGILENT_U1252, "U1252B", 3, agdmm_jobs_live, NULL, agdmm_recvs_u125x },
{ AGILENT_U1253, "U1253B", 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 },
{ AGILENT_U1273AX, "U1273AX", 3, agdmm_jobs_live, NULL, agdmm_recvs_u127x },
{ KEYSIGHT_U1281, "U1281A", 3, agdmm_jobs_live, agdmm_jobs_log, agdmm_recvs_u128x }, { 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 }, { KEYSIGHT_U1282, "U1282A", 3, agdmm_jobs_live, agdmm_jobs_log, agdmm_recvs_u128x },
ALL_ZERO ALL_ZERO
@ -131,6 +129,7 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
if (serial_open(serial, SERIAL_RDWR) != SR_OK) if (serial_open(serial, SERIAL_RDWR) != SR_OK)
return NULL; return NULL;
serial_flush(serial);
if (serial_write_blocking(serial, "*IDN?\r\n", 7, SERIAL_WRITE_TIMEOUT_MS) < 7) { if (serial_write_blocking(serial, "*IDN?\r\n", 7, SERIAL_WRITE_TIMEOUT_MS) < 7) {
sr_err("Unable to send identification string."); sr_err("Unable to send identification string.");
return NULL; return NULL;
@ -188,22 +187,25 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
return std_scan_complete(di, devices); return std_scan_complete(di, devices);
} }
static int config_get(uint32_t key, GVariant **data, static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) const struct sr_channel_group *cg)
{ {
struct dev_context *devc; struct dev_context *devc;
int ret;
(void)cg; (void)cg;
devc = sdi->priv; devc = sdi->priv;
ret = SR_OK;
switch (key) { switch (key) {
case SR_CONF_SAMPLERATE: case SR_CONF_SAMPLERATE:
*data = g_variant_new_uint64(devc->cur_samplerate); *data = g_variant_new_uint64(devc->cur_samplerate);
break; break;
case SR_CONF_LIMIT_SAMPLES: case SR_CONF_LIMIT_SAMPLES:
case SR_CONF_LIMIT_MSEC: case SR_CONF_LIMIT_MSEC:
return sr_sw_limits_config_get(&devc->limits, key, data); ret = sr_sw_limits_config_get(&devc->limits, key, data);
break;
case SR_CONF_DATA_SOURCE: case SR_CONF_DATA_SOURCE:
*data = g_variant_new_string(data_sources[devc->data_source]); *data = g_variant_new_string(data_sources[devc->data_source]);
break; break;
@ -211,54 +213,91 @@ static int config_get(uint32_t key, GVariant **data,
return SR_ERR_NA; return SR_ERR_NA;
} }
return SR_OK; return ret;
} }
static int config_set(uint32_t key, GVariant *data, static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) const struct sr_channel_group *cg)
{ {
struct dev_context *devc; struct dev_context *devc;
uint64_t samplerate; uint64_t samplerate;
int idx; const char *tmp_str;
unsigned int i;
int ret;
(void)cg; (void)cg;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv; devc = sdi->priv;
ret = SR_OK;
switch (key) { switch (key) {
case SR_CONF_SAMPLERATE: case SR_CONF_SAMPLERATE:
samplerate = g_variant_get_uint64(data); samplerate = g_variant_get_uint64(data);
if (samplerate < samplerates[0] || samplerate > samplerates[1]) if (samplerate < samplerates[0] || samplerate > samplerates[1])
return SR_ERR_ARG; ret = SR_ERR_ARG;
else
devc->cur_samplerate = g_variant_get_uint64(data); devc->cur_samplerate = g_variant_get_uint64(data);
break; break;
case SR_CONF_LIMIT_SAMPLES: case SR_CONF_LIMIT_SAMPLES:
case SR_CONF_LIMIT_MSEC: case SR_CONF_LIMIT_MSEC:
return sr_sw_limits_config_set(&devc->limits, key, data); ret = sr_sw_limits_config_set(&devc->limits, key, data);
case SR_CONF_DATA_SOURCE:
if ((idx = std_str_idx(data, ARRAY_AND_SIZE(data_sources))) < 0)
return SR_ERR_ARG;
devc->data_source = idx;
break; break;
case SR_CONF_DATA_SOURCE: {
tmp_str = g_variant_get_string(data, NULL);
for (i = 0; i < ARRAY_SIZE(data_sources); i++)
if (!strcmp(tmp_str, data_sources[i])) {
devc->data_source = i;
break;
}
if (i == ARRAY_SIZE(data_sources))
return SR_ERR;
break;
}
default: default:
return SR_ERR_NA; 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)
{
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; return SR_OK;
} }
static int config_list(uint32_t key, GVariant **data, if (key == SR_CONF_DEVICE_OPTIONS && !sdi) {
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
{ drvopts, ARRAY_SIZE(drvopts), sizeof(uint32_t));
return SR_OK;
}
if (!sdi || cg)
return SR_ERR_ARG;
switch (key) { switch (key) {
case SR_CONF_SCAN_OPTIONS:
case SR_CONF_DEVICE_OPTIONS: case SR_CONF_DEVICE_OPTIONS:
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts); *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
break;
case SR_CONF_SAMPLERATE: case SR_CONF_SAMPLERATE:
*data = std_gvar_samplerates_steps(ARRAY_AND_SIZE(samplerates)); 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);
break; break;
case SR_CONF_DATA_SOURCE: case SR_CONF_DATA_SOURCE:
*data = g_variant_new_strv(ARRAY_AND_SIZE(data_sources)); *data = g_variant_new_strv(data_sources, ARRAY_SIZE(data_sources));
break; break;
default: default:
return SR_ERR_NA; return SR_ERR_NA;
@ -272,6 +311,9 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
struct dev_context *devc = sdi->priv; struct dev_context *devc = sdi->priv;
struct sr_serial_dev_inst *serial; struct sr_serial_dev_inst *serial;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc->cur_channel = sr_next_enabled_channel(sdi, NULL); devc->cur_channel = sr_next_enabled_channel(sdi, NULL);
devc->cur_conf = sr_next_enabled_channel(sdi, NULL); devc->cur_conf = sr_next_enabled_channel(sdi, NULL);
devc->cur_sample = 1; devc->cur_sample = 1;
@ -296,6 +338,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
sr_sw_limits_acquisition_start(&devc->limits); sr_sw_limits_acquisition_start(&devc->limits);
std_session_send_df_header(sdi); std_session_send_df_header(sdi);
/* Poll every 10ms, or whenever some data comes in. */
serial = sdi->conn; serial = sdi->conn;
serial_source_add(sdi->session, serial, G_IO_IN, 10, serial_source_add(sdi->session, serial, G_IO_IN, 10,
agdmm_receive_data, (void *)sdi); agdmm_receive_data, (void *)sdi);
@ -311,7 +354,7 @@ static struct sr_dev_driver agdmm_driver_info = {
.cleanup = std_cleanup, .cleanup = std_cleanup,
.scan = scan, .scan = scan,
.dev_list = std_dev_list, .dev_list = std_dev_list,
.dev_clear = std_dev_clear, .dev_clear = NULL,
.config_get = config_get, .config_get = config_get,
.config_set = config_set, .config_set = config_set,
.config_list = config_list, .config_list = config_list,

View File

@ -200,7 +200,7 @@ SR_PRIV int agdmm_receive_data(int fd, int revents, void *cb_data)
} }
if (sr_sw_limits_check(&devc->limits) || stop) if (sr_sw_limits_check(&devc->limits) || stop)
sr_dev_acquisition_stop(sdi); sdi->driver->dev_acquisition_stop(sdi);
else else
dispatch(sdi); dispatch(sdi);
@ -574,12 +574,6 @@ static int recv_conf_u123x(const struct sr_dev_inst *sdi, GMatchInfo *match)
devc->cur_mqflags[i] = 0; devc->cur_mqflags[i] = 0;
devc->cur_exponent[i] = 0; devc->cur_exponent[i] = 0;
devc->cur_digits[i] = 3 - resolution; 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")) { } else if (!strcmp(mstr, "UA")) {
devc->cur_mq[i] = SR_MQ_CURRENT; devc->cur_mq[i] = SR_MQ_CURRENT;
devc->cur_unit[i] = SR_UNIT_AMPERE; devc->cur_unit[i] = SR_UNIT_AMPERE;
@ -606,15 +600,9 @@ static int recv_conf_u123x(const struct sr_dev_inst *sdi, GMatchInfo *match)
} else if (!strcmp(mstr, "DIOD")) { } else if (!strcmp(mstr, "DIOD")) {
devc->cur_mq[i] = SR_MQ_VOLTAGE; devc->cur_mq[i] = SR_MQ_VOLTAGE;
devc->cur_unit[i] = SR_UNIT_VOLT; devc->cur_unit[i] = SR_UNIT_VOLT;
devc->cur_mqflags[i] = SR_MQFLAG_DIODE | SR_MQFLAG_DC; devc->cur_mqflags[i] = SR_MQFLAG_DIODE;
devc->cur_exponent[i] = 0; devc->cur_exponent[i] = 0;
devc->cur_digits[i] = 3; 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")) { } else if (!strcmp(mstr, "CAP")) {
devc->cur_mq[i] = SR_MQ_CAPACITANCE; devc->cur_mq[i] = SR_MQ_CAPACITANCE;
devc->cur_unit[i] = SR_UNIT_FARAD; devc->cur_unit[i] = SR_UNIT_FARAD;
@ -637,8 +625,6 @@ static int recv_conf_u123x(const struct sr_dev_inst *sdi, GMatchInfo *match)
devc->cur_mqflags[i] |= SR_MQFLAG_RMS; devc->cur_mqflags[i] |= SR_MQFLAG_RMS;
} else if (!strcmp(mstr, "DC")) { } else if (!strcmp(mstr, "DC")) {
devc->cur_mqflags[i] |= SR_MQFLAG_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 { } else {
sr_dbg("Unknown first argument '%s'.", mstr); sr_dbg("Unknown first argument '%s'.", mstr);
} }
@ -646,13 +632,6 @@ static int recv_conf_u123x(const struct sr_dev_inst *sdi, GMatchInfo *match)
} else } else
devc->cur_mqflags[i] &= ~(SR_MQFLAG_AC | SR_MQFLAG_DC); devc->cur_mqflags[i] &= ~(SR_MQFLAG_AC | SR_MQFLAG_DC);
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; return JOB_CONF;
} }
@ -759,7 +738,7 @@ static int recv_conf_u124x_5x(const struct sr_dev_inst *sdi, GMatchInfo *match)
} else if (!strcmp(mstr, "DIOD")) { } else if (!strcmp(mstr, "DIOD")) {
devc->cur_mq[i] = SR_MQ_VOLTAGE; devc->cur_mq[i] = SR_MQ_VOLTAGE;
devc->cur_unit[i] = SR_UNIT_VOLT; devc->cur_unit[i] = SR_UNIT_VOLT;
devc->cur_mqflags[i] = SR_MQFLAG_DIODE | SR_MQFLAG_DC; devc->cur_mqflags[i] = SR_MQFLAG_DIODE;
devc->cur_exponent[i] = 0; devc->cur_exponent[i] = 0;
if (devc->profile->model == KEYSIGHT_U1281 || if (devc->profile->model == KEYSIGHT_U1281 ||
devc->profile->model == KEYSIGHT_U1282) { devc->profile->model == KEYSIGHT_U1282) {
@ -892,7 +871,7 @@ static int recv_log(const struct sr_dev_inst *sdi, GMatchInfo *match,
if (mstr[12] & 1) mqflags |= SR_MQFLAG_AVG; if (mstr[12] & 1) mqflags |= SR_MQFLAG_AVG;
if (mstr[12] & 2) mqflags |= SR_MQFLAG_MIN; if (mstr[12] & 2) mqflags |= SR_MQFLAG_MIN;
if (mstr[12] & 4) mqflags |= SR_MQFLAG_MAX; if (mstr[12] & 4) mqflags |= SR_MQFLAG_MAX;
if (function == 5) mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC; if (function == 5) mqflags |= SR_MQFLAG_DIODE;
g_free(mstr); g_free(mstr);
mq = mqs[function]; mq = mqs[function];
@ -1038,24 +1017,12 @@ SR_PRIV const struct agdmm_recv agdmm_recvs_u125x[] = {
{ "^\"(\\d\\d.{18}\\d)\"$", recv_stat_u125x }, { "^\"(\\d\\d.{18}\\d)\"$", recv_stat_u125x },
{ "^\\*([0-9])$", recv_switch }, { "^\\*([0-9])$", recv_switch },
{ "^([-+][0-9]\\.[0-9]{8}E[-+][0-9]{2})$", recv_fetc }, { "^([-+][0-9]\\.[0-9]{8}E[-+][0-9]{2})$", recv_fetc },
{ "^\"(VOLT|CURR|RES|CONT|COND|CAP|FREQ) ([-+][0-9\\.E\\-+]+),([-+][0-9]\\.[0-9]{6}E([-+][0-9]{2}))\"$", recv_conf_u124x_5x }, { "^\"(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]{6}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]{6}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]{6}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 },
{ "^\"(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 }, { "^\"(T[0-9]:[A-Z]+) ([A-Z]+)\"$", recv_conf_u124x_5x },
{ "^\"(DIOD|PULS:[PN]DUT)\"$", recv_conf_u124x_5x }, { "^\"(DIOD)\"$", 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 ALL_ZERO
}; };

View File

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

View File

@ -79,9 +79,11 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
sr_info("Probing serial port %s.", conn); sr_info("Probing serial port %s.", conn);
serial_flush(serial);
/* Let's get a bit of data and see if we can find a packet. */ /* Let's get a bit of data and see if we can find a packet. */
if (serial_stream_detect(serial, buf, &len, 25, if (serial_stream_detect(serial, buf, &len, 25,
appa_55ii_packet_valid, NULL, NULL, 500) != SR_OK) appa_55ii_packet_valid, 500, 9600) != SR_OK)
goto scan_cleanup; goto scan_cleanup;
sr_info("Found device on port %s.", conn); sr_info("Found device on port %s.", conn);
@ -107,8 +109,8 @@ scan_cleanup:
return std_scan_complete(di, devices); return std_scan_complete(di, devices);
} }
static int config_get(uint32_t key, GVariant **data, static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) const struct sr_channel_group *cg)
{ {
struct dev_context *devc = sdi->priv; struct dev_context *devc = sdi->priv;
@ -128,25 +130,35 @@ static int config_get(uint32_t key, GVariant **data,
return SR_OK; return SR_OK;
} }
static int config_set(uint32_t key, GVariant *data, static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) const struct sr_channel_group *cg)
{ {
struct dev_context *devc; struct dev_context *devc;
int idx; const char *tmp_str;
unsigned int i;
(void)cg; (void)cg;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv; devc = sdi->priv;
switch (key) { switch (key) {
case SR_CONF_LIMIT_SAMPLES: case SR_CONF_LIMIT_SAMPLES:
case SR_CONF_LIMIT_MSEC: case SR_CONF_LIMIT_MSEC:
return sr_sw_limits_config_set(&devc->limits, key, data); return sr_sw_limits_config_set(&devc->limits, key, data);
case SR_CONF_DATA_SOURCE: case SR_CONF_DATA_SOURCE: {
if ((idx = std_str_idx(data, ARRAY_AND_SIZE(data_sources))) < 0) tmp_str = g_variant_get_string(data, NULL);
return SR_ERR_ARG; for (i = 0; i < ARRAY_SIZE(data_sources); i++)
devc->data_source = idx; if (!strcmp(tmp_str, data_sources[i])) {
devc->data_source = i;
break; break;
}
if (i == ARRAY_SIZE(data_sources))
return SR_ERR;
break;
}
default: default:
return SR_ERR_NA; return SR_ERR_NA;
} }
@ -154,15 +166,26 @@ static int config_set(uint32_t key, GVariant *data,
return SR_OK; return SR_OK;
} }
static int config_list(uint32_t key, GVariant **data, static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) const struct sr_channel_group *cg)
{ {
(void)cg;
switch (key) { switch (key) {
case SR_CONF_SCAN_OPTIONS: case SR_CONF_SCAN_OPTIONS:
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
break;
case SR_CONF_DEVICE_OPTIONS: case SR_CONF_DEVICE_OPTIONS:
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts); 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;
case SR_CONF_DATA_SOURCE: case SR_CONF_DATA_SOURCE:
*data = g_variant_new_strv(ARRAY_AND_SIZE(data_sources)); *data = g_variant_new_strv(data_sources, ARRAY_SIZE(data_sources));
break; break;
default: default:
return SR_ERR_NA; return SR_ERR_NA;
@ -177,12 +200,16 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
struct dev_context *devc; struct dev_context *devc;
serial = sdi->conn; serial = sdi->conn;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv; devc = sdi->priv;
sr_sw_limits_acquisition_start(&devc->limits); sr_sw_limits_acquisition_start(&devc->limits);
std_session_send_df_header(sdi); std_session_send_df_header(sdi);
/* Poll every 50ms, or whenever some data comes in. */
serial_source_add(sdi->session, serial, G_IO_IN, 50, serial_source_add(sdi->session, serial, G_IO_IN, 50,
appa_55ii_receive_data, (void *)sdi); appa_55ii_receive_data, (void *)sdi);
@ -197,7 +224,7 @@ static struct sr_dev_driver appa_55ii_driver_info = {
.cleanup = std_cleanup, .cleanup = std_cleanup,
.scan = scan, .scan = scan,
.dev_list = std_dev_list, .dev_list = std_dev_list,
.dev_clear = std_dev_clear, .dev_clear = NULL,
.config_get = config_get, .config_get = config_get,
.config_set = config_set, .config_set = config_set,
.config_list = config_list, .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) if (devc->data_source != DATA_SOURCE_MEMORY)
return; return;
sr_dev_acquisition_stop(sdi); sdi->driver->dev_acquisition_stop(sdi);
} }
static const uint8_t *appa_55ii_parse_data(struct sr_dev_inst *sdi, static const uint8_t *appa_55ii_parse_data(struct sr_dev_inst *sdi,
@ -309,7 +309,7 @@ SR_PRIV int appa_55ii_receive_data(int fd, int revents, void *cb_data)
} }
if (sr_sw_limits_check(&devc->limits)) { if (sr_sw_limits_check(&devc->limits)) {
sr_dev_acquisition_stop(sdi); sdi->driver->dev_acquisition_stop(sdi);
return TRUE; return TRUE;
} }

View File

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

View File

@ -25,7 +25,6 @@
#define CMD_VERSION "version\r\n" #define CMD_VERSION "version\r\n"
#define CMD_MONITOR "monitor 200\r\n" #define CMD_MONITOR "monitor 200\r\n"
#define CMD_MONITOR_STOP "monitor 0\r\n"
static const uint32_t scanopts[] = { static const uint32_t scanopts[] = {
SR_CONF_CONN, SR_CONF_CONN,
@ -44,7 +43,7 @@ static const uint32_t devopts[] = {
static const uint32_t devopts_cg[] = { static const uint32_t devopts_cg[] = {
SR_CONF_ENABLED | SR_CONF_SET, SR_CONF_ENABLED | SR_CONF_SET,
SR_CONF_REGULATION | SR_CONF_GET | SR_CONF_LIST, SR_CONF_REGULATION | SR_CONF_GET,
SR_CONF_VOLTAGE | SR_CONF_GET, SR_CONF_VOLTAGE | SR_CONF_GET,
SR_CONF_CURRENT | SR_CONF_GET, SR_CONF_CURRENT | SR_CONF_GET,
SR_CONF_CURRENT_LIMIT | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, SR_CONF_CURRENT_LIMIT | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
@ -54,12 +53,6 @@ static const uint32_t devopts_cg[] = {
SR_CONF_OVER_TEMPERATURE_PROTECTION_ACTIVE | SR_CONF_GET, SR_CONF_OVER_TEMPERATURE_PROTECTION_ACTIVE | SR_CONF_GET,
SR_CONF_UNDER_VOLTAGE_CONDITION | SR_CONF_GET, SR_CONF_UNDER_VOLTAGE_CONDITION | SR_CONF_GET,
SR_CONF_UNDER_VOLTAGE_CONDITION_ACTIVE | SR_CONF_GET, SR_CONF_UNDER_VOLTAGE_CONDITION_ACTIVE | SR_CONF_GET,
SR_CONF_UNDER_VOLTAGE_CONDITION_THRESHOLD | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
};
static const char *regulation[] = {
/* CC mode only. */
"CC",
}; };
static GSList *scan(struct sr_dev_driver *di, GSList *options) static GSList *scan(struct sr_dev_driver *di, GSList *options)
@ -99,18 +92,7 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
if (serial_open(serial, SERIAL_RDWR) != SR_OK) if (serial_open(serial, SERIAL_RDWR) != SR_OK)
return NULL; return NULL;
/* serial_flush(serial);
* First stop potentially running monitoring and wait for 50ms before
* next command can be sent.
*/
if (serial_write_blocking(serial, CMD_MONITOR_STOP,
strlen(CMD_MONITOR_STOP), serial_timeout(serial,
strlen(CMD_MONITOR_STOP))) < (int)strlen(CMD_MONITOR_STOP)) {
sr_dbg("Unable to write while probing for hardware.");
serial_close(serial);
return NULL;
}
g_usleep(50 * 1000);
if (serial_write_blocking(serial, CMD_VERSION, if (serial_write_blocking(serial, CMD_VERSION,
strlen(CMD_VERSION), serial_timeout(serial, strlen(CMD_VERSION), serial_timeout(serial,
@ -153,7 +135,7 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
ch = sr_channel_new(sdi, 0, SR_CHANNEL_ANALOG, TRUE, "V"); ch = sr_channel_new(sdi, 0, SR_CHANNEL_ANALOG, TRUE, "V");
cg->channels = g_slist_append(cg->channels, ch); cg->channels = g_slist_append(cg->channels, ch);
ch = sr_channel_new(sdi, 1, SR_CHANNEL_ANALOG, TRUE, "I"); ch = sr_channel_new(sdi, 0, SR_CHANNEL_ANALOG, TRUE, "I");
cg->channels = g_slist_append(cg->channels, ch); cg->channels = g_slist_append(cg->channels, ch);
devc = g_malloc0(sizeof(struct dev_context)); devc = g_malloc0(sizeof(struct dev_context));
@ -168,34 +150,64 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
static int config_list(uint32_t key, GVariant **data, static int config_list(uint32_t key, GVariant **data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{ {
GVariantBuilder gvb;
int ret;
/* Always available. */
if (key == SR_CONF_SCAN_OPTIONS) {
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
return SR_OK;
}
if (key == SR_CONF_DEVICE_OPTIONS && !sdi) {
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
drvopts, ARRAY_SIZE(drvopts), sizeof(uint32_t));
return SR_OK;
}
if (!sdi)
return SR_ERR_ARG;
ret = SR_OK;
if (!cg) { if (!cg) {
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts); /* 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;
}
} else { } else {
switch (key) { switch (key) {
case SR_CONF_DEVICE_OPTIONS: case SR_CONF_DEVICE_OPTIONS:
*data = std_gvar_array_u32(ARRAY_AND_SIZE(devopts_cg)); *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
break; devopts_cg, ARRAY_SIZE(devopts_cg), sizeof(uint32_t));
case SR_CONF_REGULATION:
*data = std_gvar_array_str(ARRAY_AND_SIZE(regulation));
break; break;
case SR_CONF_CURRENT_LIMIT: case SR_CONF_CURRENT_LIMIT:
*data = std_gvar_min_max_step(0.0, 6.0, 0.001); g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
break; /* Min, max, step. */
case SR_CONF_UNDER_VOLTAGE_CONDITION_THRESHOLD: g_variant_builder_add_value(&gvb, g_variant_new_double(0.0));
*data = std_gvar_min_max_step(0.0, 60.0, 0.001); 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);
break; break;
default: default:
return SR_ERR_NA; return SR_ERR_NA;
} }
} }
return SR_OK; return ret;
} }
static int config_get(uint32_t key, GVariant **data, static int config_get(uint32_t key, GVariant **data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{ {
struct dev_context *devc; struct dev_context *devc;
int ret;
float fvalue; float fvalue;
(void)cg; (void)cg;
@ -211,6 +223,7 @@ static int config_get(uint32_t key, GVariant **data,
* - SR_CONF_ENABLED (state cannot be queried, only set) * - SR_CONF_ENABLED (state cannot be queried, only set)
*/ */
ret = SR_OK;
switch (key) { switch (key) {
case SR_CONF_LIMIT_SAMPLES: case SR_CONF_LIMIT_SAMPLES:
case SR_CONF_LIMIT_MSEC: case SR_CONF_LIMIT_MSEC:
@ -245,59 +258,48 @@ static int config_get(uint32_t key, GVariant **data,
*data = g_variant_new_boolean(devc->otp_active); *data = g_variant_new_boolean(devc->otp_active);
break; break;
case SR_CONF_UNDER_VOLTAGE_CONDITION: case SR_CONF_UNDER_VOLTAGE_CONDITION:
if (reloadpro_get_under_voltage_threshold(sdi, &fvalue) == SR_OK) *data = g_variant_new_boolean(TRUE); /* Always on. */
*data = g_variant_new_boolean(fvalue != 0.0);
break; break;
case SR_CONF_UNDER_VOLTAGE_CONDITION_ACTIVE: case SR_CONF_UNDER_VOLTAGE_CONDITION_ACTIVE:
*data = g_variant_new_boolean(devc->uvc_active); *data = g_variant_new_boolean(devc->uvc_active);
break; break;
case SR_CONF_UNDER_VOLTAGE_CONDITION_THRESHOLD:
if (reloadpro_get_under_voltage_threshold(sdi, &fvalue) == SR_OK)
*data = g_variant_new_double(fvalue);
break;
default: default:
return SR_ERR_NA; return SR_ERR_NA;
} }
return SR_OK; return ret;
} }
static int config_set(uint32_t key, GVariant *data, static int config_set(uint32_t key, GVariant *data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{ {
struct dev_context *devc; struct dev_context *devc;
int ret;
(void)cg; (void)cg;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv; devc = sdi->priv;
ret = SR_OK;
switch (key) { switch (key) {
case SR_CONF_LIMIT_SAMPLES: case SR_CONF_LIMIT_SAMPLES:
case SR_CONF_LIMIT_MSEC: case SR_CONF_LIMIT_MSEC:
return sr_sw_limits_config_set(&devc->limits, key, data); return sr_sw_limits_config_set(&devc->limits, key, data);
case SR_CONF_ENABLED: case SR_CONF_ENABLED:
return reloadpro_set_on_off(sdi, g_variant_get_boolean(data)); ret = reloadpro_set_on_off(sdi, g_variant_get_boolean(data));
break;
case SR_CONF_CURRENT_LIMIT: case SR_CONF_CURRENT_LIMIT:
return reloadpro_set_current_limit(sdi, g_variant_get_double(data)); ret = reloadpro_set_current_limit(sdi,
case SR_CONF_UNDER_VOLTAGE_CONDITION_THRESHOLD:
return reloadpro_set_under_voltage_threshold(sdi,
g_variant_get_double(data)); g_variant_get_double(data));
break;
default: default:
return SR_ERR_NA; ret = SR_ERR_NA;
} }
return SR_OK; return ret;
}
static int dev_close(struct sr_dev_inst *sdi)
{
if (serial_write_blocking(sdi->conn, CMD_MONITOR_STOP,
strlen(CMD_MONITOR_STOP), serial_timeout(sdi->conn,
strlen(CMD_MONITOR_STOP))) < (int)strlen(CMD_MONITOR_STOP)) {
sr_dbg("Unable to stop monitoring.");
}
return std_serial_dev_close(sdi);
} }
static int dev_acquisition_start(const struct sr_dev_inst *sdi) static int dev_acquisition_start(const struct sr_dev_inst *sdi)
@ -306,9 +308,10 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
struct dev_context *devc; struct dev_context *devc;
struct sr_serial_dev_inst *serial; struct sr_serial_dev_inst *serial;
devc = sdi->priv; if (sdi->status != SR_ST_ACTIVE)
devc->acquisition_running = TRUE; return SR_ERR_DEV_CLOSED;
devc = sdi->priv;
serial = sdi->conn; serial = sdi->conn;
/* Send the 'monitor <ms>' command (doesn't have a reply). */ /* Send the 'monitor <ms>' command (doesn't have a reply). */
@ -319,34 +322,19 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
return SR_ERR; return SR_ERR;
} }
/* Poll every 100ms, or whenever some data comes in. */
serial_source_add(sdi->session, serial, G_IO_IN, 100,
reloadpro_receive_data, (void *)sdi);
sr_sw_limits_acquisition_start(&devc->limits); sr_sw_limits_acquisition_start(&devc->limits);
std_session_send_df_header(sdi); std_session_send_df_header(sdi);
memset(devc->buf, 0, RELOADPRO_BUFSIZE); memset(devc->buf, 0, RELOADPRO_BUFSIZE);
devc->buflen = 0; devc->buflen = 0;
g_mutex_init(&devc->acquisition_mutex);
serial_source_add(sdi->session, serial, G_IO_IN, 100,
reloadpro_receive_data, (void *)sdi);
return SR_OK; return SR_OK;
} }
static int dev_acquisition_stop(struct sr_dev_inst *sdi)
{
struct dev_context *devc;
int ret;
devc = sdi->priv;
devc->acquisition_running = FALSE;
ret = std_serial_dev_acquisition_stop(sdi);
g_mutex_clear(&devc->acquisition_mutex);
return ret;
}
static struct sr_dev_driver arachnid_labs_re_load_pro_driver_info = { static struct sr_dev_driver arachnid_labs_re_load_pro_driver_info = {
.name = "arachnid-labs-re-load-pro", .name = "arachnid-labs-re-load-pro",
.longname = "Arachnid Labs Re:load Pro", .longname = "Arachnid Labs Re:load Pro",
@ -355,14 +343,13 @@ static struct sr_dev_driver arachnid_labs_re_load_pro_driver_info = {
.cleanup = std_cleanup, .cleanup = std_cleanup,
.scan = scan, .scan = scan,
.dev_list = std_dev_list, .dev_list = std_dev_list,
.dev_clear = std_dev_clear,
.config_get = config_get, .config_get = config_get,
.config_set = config_set, .config_set = config_set,
.config_list = config_list, .config_list = config_list,
.dev_open = std_serial_dev_open, .dev_open = std_serial_dev_open,
.dev_close = dev_close, .dev_close = std_serial_dev_close,
.dev_acquisition_start = dev_acquisition_start, .dev_acquisition_start = dev_acquisition_start,
.dev_acquisition_stop = dev_acquisition_stop, .dev_acquisition_stop = std_serial_dev_acquisition_stop,
.context = NULL, .context = NULL,
}; };
SR_REGISTER_DEV_DRIVER(arachnid_labs_re_load_pro_driver_info); SR_REGISTER_DEV_DRIVER(arachnid_labs_re_load_pro_driver_info);

View File

@ -18,21 +18,18 @@
*/ */
#include <config.h> #include <config.h>
#include <math.h>
#include <string.h> #include <string.h>
#include "protocol.h" #include "protocol.h"
#define READ_TIMEOUT_MS 500 #define READ_TIMEOUT_MS 1000
static int send_cmd(const struct sr_dev_inst *sdi, const char *cmd, static int send_cmd(const struct sr_dev_inst *sdi, const char *cmd,
char *replybuf, int replybufsize) char *replybuf, int replybufsize)
{ {
char *bufptr; char *bufptr;
int len, ret; int len, ret;
struct dev_context *devc;
struct sr_serial_dev_inst *serial; struct sr_serial_dev_inst *serial;
devc = sdi->priv;
serial = sdi->conn; serial = sdi->conn;
/* Send the command (blocking, with timeout). */ /* Send the command (blocking, with timeout). */
@ -43,7 +40,6 @@ static int send_cmd(const struct sr_dev_inst *sdi, const char *cmd,
return SR_ERR; return SR_ERR;
} }
if (!devc->acquisition_running) {
/* Read the reply (blocking, with timeout). */ /* Read the reply (blocking, with timeout). */
memset(replybuf, 0, replybufsize); memset(replybuf, 0, replybufsize);
bufptr = replybuf; bufptr = replybuf;
@ -60,165 +56,66 @@ static int send_cmd(const struct sr_dev_inst *sdi, const char *cmd,
sr_err("Device replied with an error: '%s'.", bufptr); sr_err("Device replied with an error: '%s'.", bufptr);
return SR_ERR; return SR_ERR;
} }
}
return ret; return ret;
} }
SR_PRIV int reloadpro_set_current_limit(const struct sr_dev_inst *sdi, SR_PRIV int reloadpro_set_current_limit(const struct sr_dev_inst *sdi,
float current_limit) float current)
{ {
struct dev_context *devc;
int ret, ma; int ret, ma;
char buf[100]; char buf[100];
char *cmd; char *cmd;
devc = sdi->priv; if (current < 0 || current > 6) {
sr_err("The current limit must be 0-6 A (was %f A).", current);
if (current_limit < 0 || current_limit > 6) {
sr_err("The current limit must be 0-6 A (was %f A).", current_limit);
return SR_ERR_ARG; return SR_ERR_ARG;
} }
/* Hardware expects current limit in mA, integer (0..6000). */ /* Hardware expects current in mA, integer (0..6000). */
ma = (int)round(current_limit * 1000); ma = (int)(current * 1000);
sr_err("Setting current limit to %f A (%d mA).", current, ma);
cmd = g_strdup_printf("set %d\n", ma); cmd = g_strdup_printf("set %d\n", ma);
g_mutex_lock(&devc->acquisition_mutex); if ((ret = send_cmd(sdi, cmd, (char *)&buf, sizeof(buf))) < 0) {
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); sr_err("Error sending current limit command: %d.", ret);
g_free(cmd);
return SR_ERR; return SR_ERR;
} }
g_free(cmd);
return SR_OK; return SR_OK;
} }
SR_PRIV int reloadpro_set_on_off(const struct sr_dev_inst *sdi, gboolean on) SR_PRIV int reloadpro_set_on_off(const struct sr_dev_inst *sdi, gboolean on)
{ {
struct dev_context *devc;
int ret; int ret;
char buf[100]; char buf[100];
const char *cmd; const char *cmd;
devc = sdi->priv;
cmd = (on) ? "on\n" : "off\n"; cmd = (on) ? "on\n" : "off\n";
g_mutex_lock(&devc->acquisition_mutex); if ((ret = send_cmd(sdi, cmd, (char *)&buf, sizeof(buf))) < 0) {
ret = send_cmd(sdi, cmd, (char *)&buf, sizeof(buf));
g_mutex_unlock(&devc->acquisition_mutex);
if (ret < 0) {
sr_err("Error sending on/off command: %d.", ret); sr_err("Error sending on/off command: %d.", ret);
return SR_ERR; return SR_ERR;
} }
return SR_OK;
}
SR_PRIV int reloadpro_set_under_voltage_threshold(const struct sr_dev_inst *sdi,
float voltage)
{
struct dev_context *devc;
int ret, mv;
char buf[100];
char *cmd;
devc = sdi->priv;
if (voltage < 0 || voltage > 60) {
sr_err("The under voltage threshold must be 0-60 V (was %f V).",
voltage);
return SR_ERR_ARG;
}
/* Hardware expects voltage in mV, integer (0..60000). */
mv = (int)round(voltage * 1000);
sr_spew("Setting under voltage threshold to %f V (%d mV).", voltage, mv);
cmd = g_strdup_printf("uvlo %d\n", mv);
g_mutex_lock(&devc->acquisition_mutex);
ret = send_cmd(sdi, cmd, (char *)&buf, sizeof(buf));
g_mutex_unlock(&devc->acquisition_mutex);
g_free(cmd);
if (ret < 0) {
sr_err("Error sending under voltage threshold command: %d.", ret);
return SR_ERR;
}
return SR_OK; return SR_OK;
} }
SR_PRIV int reloadpro_get_current_limit(const struct sr_dev_inst *sdi, SR_PRIV int reloadpro_get_current_limit(const struct sr_dev_inst *sdi,
float *current_limit) float *current)
{ {
struct dev_context *devc;
int ret; int ret;
char buf[100]; char buf[100];
gint64 end_time;
devc = sdi->priv;
g_mutex_lock(&devc->acquisition_mutex);
if ((ret = send_cmd(sdi, "set\n", (char *)&buf, sizeof(buf))) < 0) { if ((ret = send_cmd(sdi, "set\n", (char *)&buf, sizeof(buf))) < 0) {
sr_err("Error sending current limit query: %d.", ret); sr_err("Error sending current limit query: %d.", ret);
return SR_ERR; return SR_ERR;
} }
if (devc->acquisition_running) { /* Hardware sends current in mA, integer (0..6000). */
end_time = g_get_monotonic_time () + 5 * G_TIME_SPAN_SECOND; *current = g_ascii_strtod(buf + 4, NULL) / 1000;
if (!g_cond_wait_until(&devc->current_limit_cond,
&devc->acquisition_mutex, end_time)) {
/* Timeout has passed. */
g_mutex_unlock(&devc->acquisition_mutex);
return SR_ERR;
}
} else {
/* Hardware sends current limit in mA, integer (0..6000). */
devc->current_limit = g_ascii_strtod(buf + 4, NULL) / 1000;
}
g_mutex_unlock(&devc->acquisition_mutex);
if (current_limit)
*current_limit = devc->current_limit;
return SR_OK;
}
SR_PRIV int reloadpro_get_under_voltage_threshold(const struct sr_dev_inst *sdi,
float *uvc_threshold)
{
struct dev_context *devc;
int ret;
char buf[100];
gint64 end_time;
devc = sdi->priv;
g_mutex_lock(&devc->acquisition_mutex);
if ((ret = send_cmd(sdi, "uvlo\n", (char *)&buf, sizeof(buf))) < 0) {
sr_err("Error sending under voltage threshold query: %d.", ret);
return SR_ERR;
}
if (devc->acquisition_running) {
end_time = g_get_monotonic_time () + 5 * G_TIME_SPAN_SECOND;
if (!g_cond_wait_until(&devc->uvc_threshold_cond,
&devc->acquisition_mutex, end_time)) {
/* Timeout has passed. */
g_mutex_unlock(&devc->acquisition_mutex);
return SR_ERR;
}
} else {
/* Hardware sends voltage in mV, integer (0..60000). */
devc->uvc_threshold = g_ascii_strtod(buf + 5, NULL) / 1000;
}
g_mutex_unlock(&devc->acquisition_mutex);
if (uvc_threshold)
*uvc_threshold = devc->uvc_threshold;
return SR_OK; return SR_OK;
} }
@ -226,47 +123,29 @@ SR_PRIV int reloadpro_get_under_voltage_threshold(const struct sr_dev_inst *sdi,
SR_PRIV int reloadpro_get_voltage_current(const struct sr_dev_inst *sdi, SR_PRIV int reloadpro_get_voltage_current(const struct sr_dev_inst *sdi,
float *voltage, float *current) float *voltage, float *current)
{ {
struct dev_context *devc;
int ret; int ret;
char buf[100]; char buf[100];
char **tokens; char **tokens;
gint64 end_time;
devc = sdi->priv;
g_mutex_lock(&devc->acquisition_mutex);
if ((ret = send_cmd(sdi, "read\n", (char *)&buf, sizeof(buf))) < 0) { if ((ret = send_cmd(sdi, "read\n", (char *)&buf, sizeof(buf))) < 0) {
sr_err("Error sending voltage/current query: %d.", ret); sr_err("Error sending voltage/current query: %d.", ret);
return SR_ERR; return SR_ERR;
} }
if (devc->acquisition_running) {
end_time = g_get_monotonic_time () + 5 * G_TIME_SPAN_SECOND;
if (!g_cond_wait_until(&devc->voltage_cond,
&devc->acquisition_mutex, end_time)) {
/* Timeout has passed. */
g_mutex_unlock(&devc->acquisition_mutex);
return SR_ERR;
}
} else {
/* Reply: "read <current> <voltage>". */ /* Reply: "read <current> <voltage>". */
tokens = g_strsplit((const char *)&buf, " ", 3); tokens = g_strsplit((const char *)&buf, " ", 3);
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) if (voltage)
*voltage = devc->voltage; *voltage = g_ascii_strtod(tokens[2], NULL) / 1000;
if (current) if (current)
*current = devc->current; *current = g_ascii_strtod(tokens[1], NULL) / 1000;
g_strfreev(tokens);
return SR_OK; return SR_OK;
} }
static void handle_packet(const struct sr_dev_inst *sdi) static void handle_packet(const struct sr_dev_inst *sdi)
{ {
float voltage, current;
struct sr_datafeed_packet packet; struct sr_datafeed_packet packet;
struct sr_datafeed_analog analog; struct sr_datafeed_analog analog;
struct sr_analog_encoding encoding; struct sr_analog_encoding encoding;
@ -281,49 +160,12 @@ static void handle_packet(const struct sr_dev_inst *sdi)
if (g_str_has_prefix((const char *)devc->buf, "overtemp")) { if (g_str_has_prefix((const char *)devc->buf, "overtemp")) {
sr_warn("Overtemperature condition!"); sr_warn("Overtemperature condition!");
devc->otp_active = TRUE; devc->otp_active = TRUE;
sr_session_send_meta(sdi, SR_CONF_OVER_TEMPERATURE_PROTECTION_ACTIVE,
g_variant_new_boolean(TRUE));
return; return;
} }
if (g_str_has_prefix((const char *)devc->buf, "undervolt")) { if (g_str_has_prefix((const char *)devc->buf, "undervolt")) {
sr_warn("Undervoltage condition!"); sr_warn("Undervoltage condition!");
devc->uvc_active = TRUE; devc->uvc_active = TRUE;
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; return;
} }
@ -333,13 +175,14 @@ static void handle_packet(const struct sr_dev_inst *sdi)
} }
tokens = g_strsplit((const char *)devc->buf, " ", 3); tokens = g_strsplit((const char *)devc->buf, " ", 3);
devc->voltage = g_ascii_strtod(tokens[2], NULL) / 1000; voltage = g_ascii_strtod(tokens[2], NULL) / 1000;
devc->current = g_ascii_strtod(tokens[1], NULL) / 1000; current = g_ascii_strtod(tokens[1], NULL) / 1000;
g_strfreev(tokens); g_strfreev(tokens);
g_cond_signal(&devc->voltage_cond);
/* Begin frame. */ /* Begin frame. */
std_session_send_df_frame_begin(sdi); packet.type = SR_DF_FRAME_BEGIN;
packet.payload = NULL;
sr_session_send(sdi, &packet);
sr_analog_init(&analog, &encoding, &meaning, &spec, 4); sr_analog_init(&analog, &encoding, &meaning, &spec, 4);
@ -354,8 +197,7 @@ static void handle_packet(const struct sr_dev_inst *sdi)
meaning.mq = SR_MQ_VOLTAGE; meaning.mq = SR_MQ_VOLTAGE;
meaning.mqflags = SR_MQFLAG_DC; meaning.mqflags = SR_MQFLAG_DC;
meaning.unit = SR_UNIT_VOLT; meaning.unit = SR_UNIT_VOLT;
encoding.digits = 3; analog.data = &voltage;
analog.data = &devc->voltage;
sr_session_send(sdi, &packet); sr_session_send(sdi, &packet);
g_slist_free(l); g_slist_free(l);
@ -366,13 +208,14 @@ static void handle_packet(const struct sr_dev_inst *sdi)
meaning.mq = SR_MQ_CURRENT; meaning.mq = SR_MQ_CURRENT;
meaning.mqflags = SR_MQFLAG_DC; meaning.mqflags = SR_MQFLAG_DC;
meaning.unit = SR_UNIT_AMPERE; meaning.unit = SR_UNIT_AMPERE;
encoding.digits = 3; analog.data = &current;
analog.data = &devc->current;
sr_session_send(sdi, &packet); sr_session_send(sdi, &packet);
g_slist_free(l); g_slist_free(l);
/* End frame. */ /* End frame. */
std_session_send_df_frame_end(sdi); packet.type = SR_DF_FRAME_END;
packet.payload = NULL;
sr_session_send(sdi, &packet);
sr_sw_limits_update_samples_read(&devc->limits, 1); sr_sw_limits_update_samples_read(&devc->limits, 1);
} }
@ -382,35 +225,27 @@ static void handle_new_data(const struct sr_dev_inst *sdi)
int len; int len;
struct dev_context *devc; struct dev_context *devc;
struct sr_serial_dev_inst *serial; struct sr_serial_dev_inst *serial;
char *buf;
devc = sdi->priv; devc = sdi->priv;
serial = sdi->conn; serial = sdi->conn;
/* Try to get as much data as the buffer can hold. */
len = RELOADPRO_BUFSIZE - devc->buflen; len = RELOADPRO_BUFSIZE - devc->buflen;
buf = devc->buf; len = serial_read_nonblocking(serial, devc->buf + devc->buflen, len);
g_mutex_lock(&devc->acquisition_mutex); if (len == 0)
if (serial_readline(serial, &buf, &len, 250) != SR_OK) {
g_mutex_unlock(&devc->acquisition_mutex);
return;
}
if (len == 0) {
g_mutex_unlock(&devc->acquisition_mutex);
return; /* No new bytes, nothing to do. */ return; /* No new bytes, nothing to do. */
}
if (len < 0) { if (len < 0) {
sr_err("Serial port read error: %d.", len); sr_err("Serial port read error: %d.", len);
g_mutex_unlock(&devc->acquisition_mutex);
return; return;
} }
devc->buflen += len; devc->buflen += len;
if (g_str_has_suffix((const char *)devc->buf, "\n")) {
handle_packet(sdi); handle_packet(sdi);
g_mutex_unlock(&devc->acquisition_mutex);
memset(devc->buf, 0, RELOADPRO_BUFSIZE); memset(devc->buf, 0, RELOADPRO_BUFSIZE);
devc->buflen = 0; devc->buflen = 0;
} }
}
SR_PRIV int reloadpro_receive_data(int fd, int revents, void *cb_data) SR_PRIV int reloadpro_receive_data(int fd, int revents, void *cb_data)
{ {
@ -428,7 +263,7 @@ SR_PRIV int reloadpro_receive_data(int fd, int revents, void *cb_data)
handle_new_data(sdi); handle_new_data(sdi);
if (sr_sw_limits_check(&devc->limits)) if (sr_sw_limits_check(&devc->limits))
sr_dev_acquisition_stop(sdi); sdi->driver->dev_acquisition_stop(sdi);
return TRUE; return TRUE;
} }

View File

@ -25,40 +25,24 @@
#include <libsigrok/libsigrok.h> #include <libsigrok/libsigrok.h>
#include "libsigrok-internal.h" #include "libsigrok-internal.h"
#define LOG_PREFIX "arachnid-labs-re-load-pro" #define LOG_PREFIX "re-load-pro"
#define RELOADPRO_BUFSIZE 100 #define RELOADPRO_BUFSIZE 100
/** Private, per-device-instance driver context. */
struct dev_context { struct dev_context {
struct sr_sw_limits limits; struct sr_sw_limits limits;
uint8_t buf[RELOADPRO_BUFSIZE];
char buf[RELOADPRO_BUFSIZE];
int buflen; int buflen;
float current_limit;
float voltage;
float current;
gboolean otp_active; gboolean otp_active;
gboolean uvc_active; gboolean uvc_active;
float uvc_threshold;
gboolean acquisition_running;
GMutex acquisition_mutex;
GCond current_limit_cond;
GCond voltage_cond;
GCond uvc_threshold_cond;
}; };
SR_PRIV int reloadpro_set_current_limit(const struct sr_dev_inst *sdi, SR_PRIV int reloadpro_set_current_limit(const struct sr_dev_inst *sdi,
float current); float current);
SR_PRIV int reloadpro_set_on_off(const struct sr_dev_inst *sdi, gboolean on); SR_PRIV int reloadpro_set_on_off(const struct sr_dev_inst *sdi, gboolean on);
SR_PRIV int reloadpro_set_under_voltage_threshold(const struct sr_dev_inst *sdi,
float uvc_threshold);
SR_PRIV int reloadpro_get_current_limit(const struct sr_dev_inst *sdi, SR_PRIV int reloadpro_get_current_limit(const struct sr_dev_inst *sdi,
float *current_limit); float *current);
SR_PRIV int reloadpro_get_under_voltage_threshold(const struct sr_dev_inst *sdi,
float *uvc_threshold);
SR_PRIV int reloadpro_get_voltage_current(const struct sr_dev_inst *sdi, SR_PRIV int reloadpro_get_voltage_current(const struct sr_dev_inst *sdi,
float *voltage, float *current); float *voltage, float *current);
SR_PRIV int reloadpro_receive_data(int fd, int revents, void *cb_data); SR_PRIV int reloadpro_receive_data(int fd, int revents, void *cb_data);

View File

@ -4,7 +4,6 @@
* Copyright (C) 2010-2012 Håvard Espeland <gus@ping.uio.no>, * Copyright (C) 2010-2012 Håvard Espeland <gus@ping.uio.no>,
* Copyright (C) 2010 Martin Stensgård <mastensg@ping.uio.no> * Copyright (C) 2010 Martin Stensgård <mastensg@ping.uio.no>
* Copyright (C) 2010 Carl Henrik Lunde <chlunde@ping.uio.no> * Copyright (C) 2010 Carl Henrik Lunde <chlunde@ping.uio.no>
* Copyright (C) 2020 Gerhard Sittig <gerhard.sittig@gmx.net>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -20,23 +19,23 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/*
* ASIX SIGMA/SIGMA2 logic analyzer driver
*/
#include <config.h> #include <config.h>
#include "protocol.h" #include "protocol.h"
/* /*
* Channels are labelled 1-16, see this vendor's image of the cable: * Channel numbers seem to go from 1-16, according to this image:
* http://tools.asix.net/img/sigma_sigmacab_pins_720.jpg (TI/TO are * http://tools.asix.net/img/sigma_sigmacab_pins_720.jpg
* additional trigger in/out signals). * (the cable has two additional GND pins, and a TI and TO pin)
*/ */
static const char *channel_names[] = { static const char *channel_names[] = {
"1", "2", "3", "4", "5", "6", "7", "8", "1", "2", "3", "4", "5", "6", "7", "8",
"9", "10", "11", "12", "13", "14", "15", "16", "9", "10", "11", "12", "13", "14", "15", "16",
}; };
static const uint32_t scanopts[] = {
SR_CONF_CONN,
};
static const uint32_t drvopts[] = { static const uint32_t drvopts[] = {
SR_CONF_LOGIC_ANALYZER, SR_CONF_LOGIC_ANALYZER,
}; };
@ -44,232 +43,116 @@ static const uint32_t drvopts[] = {
static const uint32_t devopts[] = { static const uint32_t devopts[] = {
SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET, SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET,
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET, SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
SR_CONF_CONN | SR_CONF_GET,
SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
SR_CONF_EXTERNAL_CLOCK | SR_CONF_GET | SR_CONF_SET, #if ASIX_SIGMA_WITH_TRIGGER
SR_CONF_EXTERNAL_CLOCK_SOURCE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
SR_CONF_CLOCK_EDGE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
SR_CONF_TRIGGER_MATCH | SR_CONF_LIST, SR_CONF_TRIGGER_MATCH | SR_CONF_LIST,
SR_CONF_CAPTURE_RATIO | SR_CONF_GET | SR_CONF_SET, SR_CONF_CAPTURE_RATIO | SR_CONF_GET | SR_CONF_SET,
/* Consider SR_CONF_TRIGGER_PATTERN (SR_T_STRING, GET/SET) support. */ #endif
};
static const char *ext_clock_edges[] = {
[SIGMA_CLOCK_EDGE_RISING] = "rising",
[SIGMA_CLOCK_EDGE_FALLING] = "falling",
[SIGMA_CLOCK_EDGE_EITHER] = "either",
}; };
#if ASIX_SIGMA_WITH_TRIGGER
static const int32_t trigger_matches[] = { static const int32_t trigger_matches[] = {
SR_TRIGGER_ZERO, SR_TRIGGER_ZERO,
SR_TRIGGER_ONE, SR_TRIGGER_ONE,
SR_TRIGGER_RISING, SR_TRIGGER_RISING,
SR_TRIGGER_FALLING, SR_TRIGGER_FALLING,
}; };
#endif
static void clear_helper(struct dev_context *devc)
{
(void)sigma_force_close(devc);
}
static int dev_clear(const struct sr_dev_driver *di) static int dev_clear(const struct sr_dev_driver *di)
{ {
return std_dev_clear_with_callback(di, return std_dev_clear(di, sigma_clear_helper);
(std_dev_clear_callback)clear_helper);
}
static gboolean bus_addr_in_devices(int bus, int addr, GSList *devs)
{
struct sr_usb_dev_inst *usb;
for (/* EMPTY */; devs; devs = devs->next) {
usb = devs->data;
if (usb->bus == bus && usb->address == addr)
return TRUE;
}
return FALSE;
}
static gboolean known_vid_pid(const struct libusb_device_descriptor *des)
{
gboolean is_sigma, is_omega;
if (des->idVendor != USB_VENDOR_ASIX)
return FALSE;
is_sigma = des->idProduct == USB_PRODUCT_SIGMA;
is_omega = des->idProduct == USB_PRODUCT_OMEGA;
if (!is_sigma && !is_omega)
return FALSE;
return TRUE;
} }
static GSList *scan(struct sr_dev_driver *di, GSList *options) static GSList *scan(struct sr_dev_driver *di, GSList *options)
{ {
struct drv_context *drvc;
libusb_context *usbctx;
const char *conn;
GSList *l, *conn_devices;
struct sr_config *src;
GSList *devices;
libusb_device **devlist, *devitem;
int bus, addr;
struct libusb_device_descriptor des;
struct libusb_device_handle *hdl;
int ret;
char conn_id[20];
char serno_txt[16];
char *end;
unsigned long serno_num, serno_pre;
enum asix_device_type dev_type;
const char *dev_text;
struct sr_dev_inst *sdi; struct sr_dev_inst *sdi;
struct dev_context *devc; struct dev_context *devc;
size_t devidx, chidx; struct ftdi_device_list *devlist;
char serial_txt[10];
uint32_t serial;
int ret;
unsigned int i;
drvc = di->context; (void)options;
usbctx = drvc->sr_ctx->libusb_ctx;
/* Find all devices which match an (optional) conn= spec. */ devc = g_malloc0(sizeof(struct dev_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;
}
}
conn_devices = NULL;
if (conn)
conn_devices = sr_usb_find(usbctx, conn);
if (conn && !conn_devices)
return NULL;
/* Find all ASIX logic analyzers (which match the connection spec). */ ftdi_init(&devc->ftdic);
devices = NULL;
libusb_get_device_list(usbctx, &devlist);
for (devidx = 0; devlist[devidx]; devidx++) {
devitem = devlist[devidx];
/* Check for connection match if a user spec was given. */ /* Look for SIGMAs. */
bus = libusb_get_bus_number(devitem);
addr = libusb_get_device_address(devitem);
if (conn && !bus_addr_in_devices(bus, addr, conn_devices))
continue;
snprintf(conn_id, sizeof(conn_id), "%d.%d", bus, addr);
/* if ((ret = ftdi_usb_find_all(&devc->ftdic, &devlist,
* Check for known VID:PID pairs. Get the serial number, USB_VENDOR, USB_PRODUCT)) <= 0) {
* to then derive the device type from it. if (ret < 0)
*/ sr_err("ftdi_usb_find_all(): %d", ret);
libusb_get_device_descriptor(devitem, &des); goto free;
if (!known_vid_pid(&des))
continue;
if (!des.iSerialNumber) {
sr_warn("Cannot get serial number (index 0).");
continue;
}
ret = libusb_open(devitem, &hdl);
if (ret < 0) {
sr_warn("Cannot open USB device %04x.%04x: %s.",
des.idVendor, des.idProduct,
libusb_error_name(ret));
continue;
}
ret = libusb_get_string_descriptor_ascii(hdl,
des.iSerialNumber,
(unsigned char *)serno_txt, sizeof(serno_txt));
if (ret < 0) {
sr_warn("Cannot get serial number (%s).",
libusb_error_name(ret));
libusb_close(hdl);
continue;
}
libusb_close(hdl);
/*
* All ASIX logic analyzers have a serial number, which
* reads as a hex number, and tells the device type.
*/
ret = sr_atoul_base(serno_txt, &serno_num, &end, 16);
if (ret != SR_OK || !end || *end) {
sr_warn("Cannot interpret serial number %s.", serno_txt);
continue;
}
dev_type = ASIX_TYPE_NONE;
dev_text = NULL;
serno_pre = serno_num >> 16;
switch (serno_pre) {
case 0xa601:
dev_type = ASIX_TYPE_SIGMA;
dev_text = "SIGMA";
sr_info("Found SIGMA, serno %s.", serno_txt);
break;
case 0xa602:
dev_type = ASIX_TYPE_SIGMA;
dev_text = "SIGMA2";
sr_info("Found SIGMA2, serno %s.", serno_txt);
break;
case 0xa603:
dev_type = ASIX_TYPE_OMEGA;
dev_text = "OMEGA";
sr_info("Found OMEGA, serno %s.", serno_txt);
if (!ASIX_WITH_OMEGA) {
sr_warn("OMEGA support is not implemented yet.");
continue;
}
break;
default:
sr_warn("Unknown serno %s, skipping.", serno_txt);
continue;
} }
/* Create a device instance, add it to the result set. */ /* Make sure it's a version 1 or 2 SIGMA. */
ftdi_usb_get_strings(&devc->ftdic, devlist->dev, NULL, 0, NULL, 0,
serial_txt, sizeof(serial_txt));
sscanf(serial_txt, "%x", &serial);
sdi = g_malloc0(sizeof(*sdi)); if (serial < 0xa6010000 || serial > 0xa602ffff) {
devices = g_slist_append(devices, sdi); sr_err("Only SIGMA and SIGMA2 are supported "
sdi->status = SR_ST_INITIALIZING; "in this version of libsigrok.");
sdi->vendor = g_strdup("ASIX"); goto free;
sdi->model = g_strdup(dev_text); }
sdi->serial_num = g_strdup(serno_txt);
sdi->connection_id = g_strdup(conn_id);
for (chidx = 0; chidx < ARRAY_SIZE(channel_names); chidx++)
sr_channel_new(sdi, chidx, SR_CHANNEL_LOGIC,
TRUE, channel_names[chidx]);
devc = g_malloc0(sizeof(*devc)); sr_info("Found ASIX SIGMA - Serial: %s", serial_txt);
sdi->priv = devc;
devc->id.vid = des.idVendor; devc->cur_samplerate = samplerates[0];
devc->id.pid = des.idProduct; devc->limit_msec = 0;
devc->id.serno = serno_num; devc->limit_samples = 0;
devc->id.prefix = serno_pre; devc->cur_firmware = -1;
devc->id.type = dev_type; devc->num_channels = 0;
sr_sw_limits_init(&devc->limit.config); devc->samples_per_event = 0;
devc->capture_ratio = 50; devc->capture_ratio = 50;
devc->use_triggers = FALSE; devc->use_triggers = 0;
/* Get current hardware configuration (or use defaults). */ /* Register SIGMA device. */
(void)sigma_fetch_hw_config(sdi); sdi = g_malloc0(sizeof(struct sr_dev_inst));
} sdi->status = SR_ST_INITIALIZING;
libusb_free_device_list(devlist, 1); sdi->vendor = g_strdup(USB_VENDOR_NAME);
g_slist_free_full(conn_devices, (GDestroyNotify)sr_usb_dev_inst_free); sdi->model = g_strdup(USB_MODEL_NAME);
return std_scan_complete(di, devices); 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));
free:
ftdi_deinit(&devc->ftdic);
g_free(devc);
return NULL;
} }
static int dev_open(struct sr_dev_inst *sdi) static int dev_open(struct sr_dev_inst *sdi)
{ {
struct dev_context *devc; struct dev_context *devc;
int ret;
devc = sdi->priv; devc = sdi->priv;
if (devc->id.type == ASIX_TYPE_OMEGA && !ASIX_WITH_OMEGA) { /* Make sure it's an ASIX SIGMA. */
sr_err("OMEGA support is not implemented yet."); if ((ret = ftdi_usb_open_desc(&devc->ftdic,
return SR_ERR_NA; USB_VENDOR, USB_PRODUCT, USB_DESCRIPTION, NULL)) < 0) {
sr_err("ftdi_usb_open failed: %s",
ftdi_get_error_string(&devc->ftdic));
return 0;
} }
return sigma_force_open(sdi); sdi->status = SR_ST_ACTIVE;
return SR_OK;
} }
static int dev_close(struct sr_dev_inst *sdi) static int dev_close(struct sr_dev_inst *sdi)
@ -278,14 +161,19 @@ static int dev_close(struct sr_dev_inst *sdi)
devc = sdi->priv; devc = sdi->priv;
return sigma_force_close(devc); /* TODO */
if (sdi->status == SR_ST_ACTIVE)
ftdi_usb_close(&devc->ftdic);
sdi->status = SR_ST_INACTIVE;
return SR_OK;
} }
static int config_get(uint32_t key, GVariant **data, static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) const struct sr_channel_group *cg)
{ {
struct dev_context *devc; struct dev_context *devc;
const char *clock_text;
(void)cg; (void)cg;
@ -294,29 +182,20 @@ static int config_get(uint32_t key, GVariant **data,
devc = sdi->priv; devc = sdi->priv;
switch (key) { switch (key) {
case SR_CONF_CONN:
*data = g_variant_new_string(sdi->connection_id);
break;
case SR_CONF_SAMPLERATE: case SR_CONF_SAMPLERATE:
*data = g_variant_new_uint64(devc->clock.samplerate); *data = g_variant_new_uint64(devc->cur_samplerate);
break;
case SR_CONF_EXTERNAL_CLOCK:
*data = g_variant_new_boolean(devc->clock.use_ext_clock);
break;
case SR_CONF_EXTERNAL_CLOCK_SOURCE:
clock_text = channel_names[devc->clock.clock_pin];
*data = g_variant_new_string(clock_text);
break;
case SR_CONF_CLOCK_EDGE:
clock_text = ext_clock_edges[devc->clock.clock_edge];
*data = g_variant_new_string(clock_text);
break; break;
case SR_CONF_LIMIT_MSEC: case SR_CONF_LIMIT_MSEC:
*data = g_variant_new_uint64(devc->limit_msec);
break;
case SR_CONF_LIMIT_SAMPLES: case SR_CONF_LIMIT_SAMPLES:
return sr_sw_limits_config_get(&devc->limit.config, key, data); *data = g_variant_new_uint64(devc->limit_samples);
break;
#if ASIX_SIGMA_WITH_TRIGGER
case SR_CONF_CAPTURE_RATIO: case SR_CONF_CAPTURE_RATIO:
*data = g_variant_new_uint64(devc->capture_ratio); *data = g_variant_new_uint64(devc->capture_ratio);
break; break;
#endif
default: default:
return SR_ERR_NA; return SR_ERR_NA;
} }
@ -324,85 +203,83 @@ static int config_get(uint32_t key, GVariant **data,
return SR_OK; return SR_OK;
} }
static int config_set(uint32_t key, GVariant *data, static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) const struct sr_channel_group *cg)
{ {
struct dev_context *devc; struct dev_context *devc;
uint64_t tmp;
int ret; int ret;
uint64_t want_rate, have_rate;
int idx;
(void)cg; (void)cg;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv; devc = sdi->priv;
ret = SR_OK;
switch (key) { switch (key) {
case SR_CONF_SAMPLERATE: case SR_CONF_SAMPLERATE:
want_rate = g_variant_get_uint64(data); ret = sigma_set_samplerate(sdi, g_variant_get_uint64(data));
ret = sigma_normalize_samplerate(want_rate, &have_rate);
if (ret != SR_OK)
return ret;
if (have_rate != want_rate) {
char *text_want, *text_have;
text_want = sr_samplerate_string(want_rate);
text_have = sr_samplerate_string(have_rate);
sr_info("Adjusted samplerate %s to %s.",
text_want, text_have);
g_free(text_want);
g_free(text_have);
}
devc->clock.samplerate = have_rate;
break;
case SR_CONF_EXTERNAL_CLOCK:
devc->clock.use_ext_clock = g_variant_get_boolean(data);
break;
case SR_CONF_EXTERNAL_CLOCK_SOURCE:
idx = std_str_idx(data, ARRAY_AND_SIZE(channel_names));
if (idx < 0)
return SR_ERR_ARG;
devc->clock.clock_pin = idx;
break;
case SR_CONF_CLOCK_EDGE:
idx = std_str_idx(data, ARRAY_AND_SIZE(ext_clock_edges));
if (idx < 0)
return SR_ERR_ARG;
devc->clock.clock_edge = idx;
break; break;
case SR_CONF_LIMIT_MSEC: case SR_CONF_LIMIT_MSEC:
tmp = g_variant_get_uint64(data);
if (tmp > 0)
devc->limit_msec = g_variant_get_uint64(data);
else
ret = SR_ERR;
break;
case SR_CONF_LIMIT_SAMPLES: case SR_CONF_LIMIT_SAMPLES:
return sr_sw_limits_config_set(&devc->limit.config, key, data); tmp = g_variant_get_uint64(data);
devc->limit_samples = tmp;
devc->limit_msec = sigma_limit_samples_to_msec(devc, tmp);
break;
#if ASIX_SIGMA_WITH_TRIGGER
case SR_CONF_CAPTURE_RATIO: case SR_CONF_CAPTURE_RATIO:
devc->capture_ratio = g_variant_get_uint64(data); tmp = g_variant_get_uint64(data);
if (tmp > 100)
return SR_ERR;
devc->capture_ratio = tmp;
break; break;
#endif
default: default:
return SR_ERR_NA; ret = SR_ERR_NA;
} }
return SR_OK; return ret;
} }
static int config_list(uint32_t key, GVariant **data, static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) const struct sr_channel_group *cg)
{ {
GVariant *gvar;
GVariantBuilder gvb;
(void)cg;
switch (key) { switch (key) {
case SR_CONF_SCAN_OPTIONS:
case SR_CONF_DEVICE_OPTIONS: case SR_CONF_DEVICE_OPTIONS:
if (cg) if (!sdi)
return SR_ERR_NA; *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
return STD_CONFIG_LIST(key, data, sdi, cg, drvopts, ARRAY_SIZE(drvopts), sizeof(uint32_t));
scanopts, drvopts, devopts); else
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
break;
case SR_CONF_SAMPLERATE: case SR_CONF_SAMPLERATE:
*data = sigma_get_samplerates_list(); g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
break; gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), samplerates,
case SR_CONF_EXTERNAL_CLOCK_SOURCE: samplerates_count, sizeof(samplerates[0]));
*data = g_variant_new_strv(ARRAY_AND_SIZE(channel_names)); g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar);
break; *data = g_variant_builder_end(&gvb);
case SR_CONF_CLOCK_EDGE:
*data = g_variant_new_strv(ARRAY_AND_SIZE(ext_clock_edges));
break; break;
#if ASIX_SIGMA_WITH_TRIGGER
case SR_CONF_TRIGGER_MATCH: case SR_CONF_TRIGGER_MATCH:
*data = std_gvar_array_i32(ARRAY_AND_SIZE(trigger_matches)); *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
trigger_matches, ARRAY_SIZE(trigger_matches),
sizeof(int32_t));
break; break;
#endif
default: default:
return SR_ERR_NA; return SR_ERR_NA;
} }
@ -413,194 +290,118 @@ static int config_list(uint32_t key, GVariant **data,
static int dev_acquisition_start(const struct sr_dev_inst *sdi) static int dev_acquisition_start(const struct sr_dev_inst *sdi)
{ {
struct dev_context *devc; struct dev_context *devc;
uint16_t pindis_mask; struct clockselect_50 clockselect;
uint8_t async, div; int triggerpin, ret;
int ret; uint8_t triggerselect;
size_t triggerpin;
uint8_t trigsel2;
struct triggerinout triggerinout_conf; struct triggerinout triggerinout_conf;
struct triggerlut lut; struct triggerlut lut;
uint8_t regval, cmd_bytes[4], *wrptr; uint8_t regval;
uint8_t clock_bytes[sizeof(clockselect)];
size_t clock_idx;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv; devc = sdi->priv;
/* Convert caller's trigger spec to driver's internal format. */ if (sigma_convert_trigger(sdi) != SR_OK) {
ret = sigma_convert_trigger(sdi); sr_err("Failed to configure triggers.");
if (ret != SR_OK) { return SR_ERR;
sr_err("Could not configure triggers.");
return ret;
} }
/* /* If the samplerate has not been set, default to 200 kHz. */
* Setup the device's samplerate from the value which up to now if (devc->cur_firmware == -1) {
* just got checked and stored. As a byproduct this can pick and if ((ret = sigma_set_samplerate(sdi, SR_KHZ(200))) != SR_OK)
* send firmware to the device, reduce the number of available return ret;
* logic channels, etc.
*
* Determine an acquisition timeout from optionally configured
* sample count or time limits. Which depends on the samplerate.
* Force 50MHz samplerate when external clock is in use.
*/
if (devc->clock.use_ext_clock) {
if (devc->clock.samplerate != SR_MHZ(50))
sr_info("External clock, forcing 50MHz samplerate.");
devc->clock.samplerate = SR_MHZ(50);
} }
ret = sigma_set_samplerate(sdi);
if (ret != SR_OK)
return ret;
ret = sigma_set_acquire_timeout(devc);
if (ret != SR_OK)
return ret;
/* Enter trigger programming mode. */ /* Enter trigger programming mode. */
trigsel2 = TRGSEL2_RESET; sigma_set_register(WRITE_TRIGGER_SELECT1, 0x20, devc);
ret = sigma_set_register(devc, WRITE_TRIGGER_SELECT2, trigsel2);
if (ret != SR_OK)
return ret;
trigsel2 = 0; triggerselect = 0;
if (devc->clock.samplerate >= SR_MHZ(100)) { if (devc->cur_samplerate >= SR_MHZ(100)) {
/* 100 and 200 MHz mode. */ /* 100 and 200 MHz mode. */
/* TODO Decipher the 0x81 magic number's purpose. */ sigma_set_register(WRITE_TRIGGER_SELECT1, 0x81, devc);
ret = sigma_set_register(devc, WRITE_TRIGGER_SELECT2, 0x81);
if (ret != SR_OK)
return ret;
/* Find which pin to trigger on from mask. */ /* Find which pin to trigger on from mask. */
for (triggerpin = 0; triggerpin < 8; triggerpin++) { for (triggerpin = 0; triggerpin < 8; triggerpin++)
if (devc->trigger.risingmask & BIT(triggerpin)) if ((devc->trigger.risingmask | devc->trigger.fallingmask) &
(1 << triggerpin))
break; break;
if (devc->trigger.fallingmask & BIT(triggerpin))
break;
}
/* Set trigger pin and light LED on trigger. */ /* Set trigger pin and light LED on trigger. */
trigsel2 = triggerpin & TRGSEL2_PINS_MASK; triggerselect = (1 << LEDSEL1) | (triggerpin & 0x7);
trigsel2 |= TRGSEL2_LEDSEL1;
/* Default rising edge. */ /* Default rising edge. */
/* TODO Documentation disagrees, bit set means _rising_ edge. */
if (devc->trigger.fallingmask) if (devc->trigger.fallingmask)
trigsel2 |= TRGSEL2_PINPOL_RISE; triggerselect |= 1 << 3;
} else if (devc->clock.samplerate <= SR_MHZ(50)) { } else if (devc->cur_samplerate <= SR_MHZ(50)) {
/* 50MHz firmware modes. */ /* All other modes. */
sigma_build_basic_trigger(&lut, devc);
/* Translate application specs to hardware perspective. */ sigma_write_trigger_lut(&lut, devc);
ret = sigma_build_basic_trigger(devc, &lut);
if (ret != SR_OK)
return ret;
/* Communicate resulting register values to the device. */ triggerselect = (1 << LEDSEL1) | (1 << LEDSEL0);
ret = sigma_write_trigger_lut(devc, &lut);
if (ret != SR_OK)
return ret;
trigsel2 = TRGSEL2_LEDSEL1 | TRGSEL2_LEDSEL0;
} }
/* Setup trigger in and out pins to default values. */ /* Setup trigger in and out pins to default values. */
memset(&triggerinout_conf, 0, sizeof(triggerinout_conf)); memset(&triggerinout_conf, 0, sizeof(struct triggerinout));
triggerinout_conf.trgout_bytrigger = TRUE; triggerinout_conf.trgout_bytrigger = 1;
triggerinout_conf.trgout_enable = TRUE; triggerinout_conf.trgout_enable = 1;
/* TODO
* Verify the correctness of this implementation. The previous
* version used to assign to a C language struct with bit fields
* which is highly non-portable and hard to guess the resulting
* raw memory layout or wire transfer content. The C struct's
* field names did not match the vendor documentation's names.
* Which means that I could not verify "on paper" either. Let's
* re-visit this code later during research for trigger support.
*/
wrptr = cmd_bytes;
regval = 0;
if (triggerinout_conf.trgout_bytrigger)
regval |= TRGOPT_TRGOOUTEN;
write_u8_inc(&wrptr, regval);
regval &= ~TRGOPT_CLEAR_MASK;
if (triggerinout_conf.trgout_enable)
regval |= TRGOPT_TRGOEN;
write_u8_inc(&wrptr, regval);
ret = sigma_write_register(devc, WRITE_TRIGGER_OPTION,
cmd_bytes, wrptr - cmd_bytes);
if (ret != SR_OK)
return ret;
/* Leave trigger programming mode. */ sigma_write_register(WRITE_TRIGGER_OPTION,
ret = sigma_set_register(devc, WRITE_TRIGGER_SELECT2, trigsel2); (uint8_t *) &triggerinout_conf,
if (ret != SR_OK) sizeof(struct triggerinout), devc);
return ret;
/* /* Go back to normal mode. */
* Samplerate dependent clock and channels configuration. Some sigma_set_register(WRITE_TRIGGER_SELECT1, triggerselect, devc);
* channels by design are not available at higher clock rates.
* Register layout differs between firmware variants (depth 1 /* Set clock select register. */
* with LSB channel mask above 50MHz, depth 4 with more details clockselect.async = 0;
* up to 50MHz). clockselect.fraction = 1 - 1; /* Divider 1. */
* clockselect.disabled_channels = 0x0000; /* All channels enabled. */
* Derive a mask where bits are set for unavailable channels. if (devc->cur_samplerate == SR_MHZ(200)) {
* Either send the single byte, or the full byte sequence. /* Enable 4 channels. */
*/ clockselect.disabled_channels = 0xf0ff;
pindis_mask = ~BITS_MASK(devc->interp.num_channels); } else if (devc->cur_samplerate == SR_MHZ(100)) {
if (devc->clock.samplerate > SR_MHZ(50)) { /* Enable 8 channels. */
ret = sigma_set_register(devc, WRITE_CLOCK_SELECT, clockselect.disabled_channels = 0x00ff;
pindis_mask & 0xff);
} else { } else {
wrptr = cmd_bytes; /*
/* Select 50MHz base clock, and divider. */ * 50 MHz mode, or fraction thereof. The 50MHz reference
async = 0; * can get divided by any integer in the range 1 to 256.
div = SR_MHZ(50) / devc->clock.samplerate - 1; * Divider minus 1 gets written to the hardware.
if (devc->clock.use_ext_clock) { * (The driver lists a discrete set of sample rates, but
async = CLKSEL_CLKSEL8; * all of them fit the above description.)
div = devc->clock.clock_pin + 1; */
switch (devc->clock.clock_edge) { clockselect.fraction = SR_MHZ(50) / devc->cur_samplerate - 1;
case SIGMA_CLOCK_EDGE_RISING:
div |= CLKSEL_RISING;
break;
case SIGMA_CLOCK_EDGE_FALLING:
div |= CLKSEL_FALLING;
break;
case SIGMA_CLOCK_EDGE_EITHER:
div |= CLKSEL_RISING;
div |= CLKSEL_FALLING;
break;
} }
} clock_idx = 0;
write_u8_inc(&wrptr, async); clock_bytes[clock_idx++] = clockselect.async;
write_u8_inc(&wrptr, div); clock_bytes[clock_idx++] = clockselect.fraction;
write_u16be_inc(&wrptr, pindis_mask); clock_bytes[clock_idx++] = clockselect.disabled_channels & 0xff;
ret = sigma_write_register(devc, WRITE_CLOCK_SELECT, clock_bytes[clock_idx++] = clockselect.disabled_channels >> 8;
cmd_bytes, wrptr - cmd_bytes); sigma_write_register(WRITE_CLOCK_SELECT, clock_bytes, clock_idx, devc);
}
if (ret != SR_OK)
return ret;
/* Setup maximum post trigger time. */ /* Setup maximum post trigger time. */
ret = sigma_set_register(devc, WRITE_POST_TRIGGER, sigma_set_register(WRITE_POST_TRIGGER,
(devc->capture_ratio * 255) / 100); (devc->capture_ratio * 255) / 100, devc);
if (ret != SR_OK)
return ret;
/* Start acqusition. */ /* Start acqusition. */
devc->start_time = g_get_monotonic_time();
regval = WMR_TRGRES | WMR_SDRAMWRITEEN; regval = WMR_TRGRES | WMR_SDRAMWRITEEN;
if (devc->use_triggers) #if ASIX_SIGMA_WITH_TRIGGER
regval |= WMR_TRGEN; regval |= WMR_TRGEN;
ret = sigma_set_register(devc, WRITE_MODE, regval); #endif
if (ret != SR_OK) sigma_set_register(WRITE_MODE, regval, devc);
return ret;
ret = std_session_send_df_header(sdi); std_session_send_df_header(sdi);
if (ret != SR_OK)
return ret;
/* Add capture source. */ /* Add capture source. */
ret = sr_session_source_add(sdi->session, -1, 0, 10, sr_session_source_add(sdi->session, -1, 0, 10, sigma_receive_data, (void *)sdi);
sigma_receive_data, (void *)sdi);
if (ret != SR_OK)
return ret;
devc->state = SIGMA_CAPTURE; devc->state.state = SIGMA_CAPTURE;
return SR_OK; return SR_OK;
} }
@ -610,20 +411,9 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi)
struct dev_context *devc; struct dev_context *devc;
devc = sdi->priv; devc = sdi->priv;
devc->state.state = SIGMA_IDLE;
/* 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 == SIGMA_CAPTURE) {
devc->state = SIGMA_STOPPING;
} else {
devc->state = SIGMA_IDLE;
(void)sr_session_source_remove(sdi->session, -1);
}
return SR_OK; return SR_OK;
} }

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,6 @@
* Copyright (C) 2010-2012 Håvard Espeland <gus@ping.uio.no>, * Copyright (C) 2010-2012 Håvard Espeland <gus@ping.uio.no>,
* Copyright (C) 2010 Martin Stensgård <mastensg@ping.uio.no> * Copyright (C) 2010 Martin Stensgård <mastensg@ping.uio.no>
* Copyright (C) 2010 Carl Henrik Lunde <chlunde@ping.uio.no> * Copyright (C) 2010 Carl Henrik Lunde <chlunde@ping.uio.no>
* Copyright (C) 2020 Gerhard Sittig <gerhard.sittig@gmx.net>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -31,86 +30,33 @@
#include <libsigrok/libsigrok.h> #include <libsigrok/libsigrok.h>
#include "libsigrok-internal.h" #include "libsigrok-internal.h"
/*
* Triggers are not working in this implementation. Stop claiming
* support for the feature which effectively is not available, until
* the implementation got fixed. Yet keep the code in place and allow
* developers to turn on this switch during development.
*/
#define ASIX_SIGMA_WITH_TRIGGER 0
#define LOG_PREFIX "asix-sigma" #define LOG_PREFIX "asix-sigma"
/* Experimental support for OMEGA (scan only, operation is ENOIMPL). */ #define USB_VENDOR 0xa600
#define ASIX_WITH_OMEGA 0 #define USB_PRODUCT 0xa000
#define USB_DESCRIPTION "ASIX SIGMA"
#define USB_VENDOR_ASIX 0xa600 #define USB_VENDOR_NAME "ASIX"
#define USB_PRODUCT_SIGMA 0xa000 #define USB_MODEL_NAME "SIGMA"
#define USB_PRODUCT_OMEGA 0xa004
enum asix_device_type {
ASIX_TYPE_NONE,
ASIX_TYPE_SIGMA,
ASIX_TYPE_OMEGA,
};
/* Mask to isolate one bit, mask to span a number of bits. */
#define BIT(pos) (1UL << (pos))
#define BITS_MASK(count) ((1UL << (count)) - 1)
#define HI4(b) (((b) >> 4) & 0x0f)
#define LO4(b) (((b) >> 0) & 0x0f)
/*
* FPGA commands are 8bits wide. The upper nibble is a command opcode,
* the lower nibble can carry operand values. 8bit register addresses
* and 8bit data values get communicated in two steps.
*/
/* Register access. */
#define REG_ADDR_LOW (0x0 << 4)
#define REG_ADDR_HIGH (0x1 << 4)
#define REG_DATA_LOW (0x2 << 4)
#define REG_DATA_HIGH_WRITE (0x3 << 4)
#define REG_READ_ADDR (0x4 << 4)
#define REG_ADDR_ADJUST BIT(0) /* Auto adjust register address. */
#define REG_ADDR_DOWN BIT(1) /* 1 decrement, 0 increment. */
#define REG_ADDR_INC (REG_ADDR_ADJUST)
#define REG_ADDR_DEC (REG_ADDR_ADJUST | REG_ADDR_DOWN)
/* Sample memory access. */
#define REG_DRAM_WAIT_ACK (0x5 << 4) /* Wait for completion. */
#define REG_DRAM_BLOCK (0x6 << 4) /* DRAM to BRAM, plus bank select. */
#define REG_DRAM_BLOCK_BEGIN (0x8 << 4) /* Read first BRAM bytes. */
#define REG_DRAM_BLOCK_DATA (0xa << 4) /* Read full BRAM block. */
#define REG_DRAM_SEL_N (0x1 << 4) /* Bank select, added to 6/8/a. */
#define REG_DRAM_SEL_BOOL(b) ((b) ? REG_DRAM_SEL_N : 0)
/*
* Registers at a specific address can have different meanings depending
* on whether data is read or written. This is why direction is part of
* the programming language identifiers.
*
* The vendor documentation suggests that in addition to the first 16
* register addresses which implement the logic analyzer's feature set,
* there are 240 more registers in the 16 to 255 address range which
* are available to applications and plugin features. Can libsigrok's
* asix-sigma driver store configuration data there, to avoid expensive
* operations (think: firmware re-load).
*
* Update: The documentation may be incorrect, or the FPGA netlist may
* be incomplete. Experiments show that registers beyond 0x0f can get
* accessed, USB communication passes, but data bytes are always 0xff.
* Are several firmware versions around, and the documentation does not
* match the one that ships with sigrok?
*/
enum sigma_write_register { enum sigma_write_register {
WRITE_CLOCK_SELECT = 0, WRITE_CLOCK_SELECT = 0,
WRITE_TRIGGER_SELECT = 1, WRITE_TRIGGER_SELECT0 = 1,
WRITE_TRIGGER_SELECT2 = 2, WRITE_TRIGGER_SELECT1 = 2,
WRITE_MODE = 3, WRITE_MODE = 3,
WRITE_MEMROW = 4, WRITE_MEMROW = 4,
WRITE_POST_TRIGGER = 5, WRITE_POST_TRIGGER = 5,
WRITE_TRIGGER_OPTION = 6, WRITE_TRIGGER_OPTION = 6,
WRITE_PIN_VIEW = 7, WRITE_PIN_VIEW = 7,
/* Unassigned register locations. */
WRITE_TEST = 15, WRITE_TEST = 15,
/* Reserved for plugin features. */
REG_PLUGIN_START = 16,
REG_PLUGIN_STOP = 256,
}; };
enum sigma_read_register { enum sigma_read_register {
@ -126,97 +72,58 @@ enum sigma_read_register {
READ_PIN_CHANGE_HIGH = 9, READ_PIN_CHANGE_HIGH = 9,
READ_BLOCK_LAST_TS_LOW = 10, READ_BLOCK_LAST_TS_LOW = 10,
READ_BLOCK_LAST_TS_HIGH = 11, READ_BLOCK_LAST_TS_HIGH = 11,
READ_BLOCK_TS_OVERRUN = 12, READ_PIN_VIEW = 12,
READ_PIN_VIEW = 13,
/* Unassigned register location. */
READ_TEST = 15, READ_TEST = 15,
/* Reserved for plugin features. See above. */
}; };
#define CLKSEL_CLKSEL8 BIT(0) #define REG_ADDR_LOW (0x0 << 4)
#define CLKSEL_PINMASK BITS_MASK(4) #define REG_ADDR_HIGH (0x1 << 4)
#define CLKSEL_RISING BIT(4) #define REG_DATA_LOW (0x2 << 4)
#define CLKSEL_FALLING BIT(5) #define REG_DATA_HIGH_WRITE (0x3 << 4)
#define REG_READ_ADDR (0x4 << 4)
#define REG_DRAM_WAIT_ACK (0x5 << 4)
#define TRGSEL_SELINC_MASK BITS_MASK(2) /* Bit (1 << 4) can be low or high (double buffer / cache) */
#define TRGSEL_SELINC_SHIFT 0 #define REG_DRAM_BLOCK (0x6 << 4)
#define TRGSEL_SELRES_MASK BITS_MASK(2) #define REG_DRAM_BLOCK_BEGIN (0x8 << 4)
#define TRGSEL_SELRES_SHIFT 2 #define REG_DRAM_BLOCK_DATA (0xa << 4)
#define TRGSEL_SELA_MASK BITS_MASK(2)
#define TRGSEL_SELA_SHIFT 4
#define TRGSEL_SELB_MASK BITS_MASK(2)
#define TRGSEL_SELB_SHIFT 6
#define TRGSEL_SELC_MASK BITS_MASK(2)
#define TRGSEL_SELC_SHIFT 8
#define TRGSEL_SELPRESC_MASK BITS_MASK(4)
#define TRGSEL_SELPRESC_SHIFT 12
enum trgsel_selcode_t { #define LEDSEL0 6
TRGSEL_SELCODE_LEVEL = 0, #define LEDSEL1 7
TRGSEL_SELCODE_FALL = 1,
TRGSEL_SELCODE_RISE = 2,
TRGSEL_SELCODE_EVENT = 3,
TRGSEL_SELCODE_NEVER = 3,
};
#define TRGSEL2_PINS_MASK BITS_MASK(3) #define NEXT_REG 1
#define TRGSEL2_PINPOL_RISE BIT(3)
#define TRGSEL2_LUT_ADDR_MASK BITS_MASK(4) #define EVENTS_PER_CLUSTER 7
#define TRGSEL2_LUT_WRITE BIT(4)
#define TRGSEL2_RESET BIT(5) #define CHUNK_SIZE 1024
#define TRGSEL2_LEDSEL0 BIT(6)
#define TRGSEL2_LEDSEL1 BIT(7)
/* WRITE_MODE register fields. */ /* WRITE_MODE register fields. */
#define WMR_SDRAMWRITEEN BIT(0) #define WMR_SDRAMWRITEEN (1 << 0)
#define WMR_SDRAMREADEN BIT(1) #define WMR_SDRAMREADEN (1 << 1)
#define WMR_TRGRES BIT(2) #define WMR_TRGRES (1 << 2)
#define WMR_TRGEN BIT(3) #define WMR_TRGEN (1 << 3)
#define WMR_FORCESTOP BIT(4) #define WMR_FORCESTOP (1 << 4)
#define WMR_TRGSW BIT(5) #define WMR_TRGSW (1 << 5)
/* not used: bit position 6 */ /* not used: bit position 6 */
#define WMR_SDRAMINIT BIT(7) #define WMR_SDRAMINIT (1 << 7)
/* READ_MODE register fields. */ /* READ_MODE register fields. */
#define RMR_SDRAMWRITEEN BIT(0) #define RMR_SDRAMWRITEEN (1 << 0)
#define RMR_SDRAMREADEN BIT(1) #define RMR_SDRAMREADEN (1 << 1)
/* not used: bit position 2 */ /* not used: bit position 2 */
#define RMR_TRGEN BIT(3) #define RMR_TRGEN (1 << 3)
#define RMR_ROUND BIT(4) #define RMR_ROUND (1 << 4)
#define RMR_TRIGGERED BIT(5) #define RMR_TRIGGERED (1 << 5)
#define RMR_POSTTRIGGERED BIT(6) #define RMR_POSTTRIGGERED (1 << 6)
/* not used: bit position 7 */ /* not used: bit position 7 */
/*
* Trigger options. First and second write are similar, but _some_
* positions change their meaning.
*/
#define TRGOPT_TRGIEN BIT(7)
#define TRGOPT_TRGOEN BIT(6)
#define TRGOPT_TRGOINEN BIT(5) /* 1st write */
#define TRGOPT_TRGINEG TRGOPT1_TRGOINEN /* 2nd write */
#define TRGOPT_TRGOEVNTEN BIT(4) /* 1st write */
#define TRGOPT_TRGOPIN TRGOPT1_TRGOEVNTEN /* 2nd write */
#define TRGOPT_TRGOOUTEN BIT(3) /* 1st write */
#define TRGOPT_TRGOLONG TRGOPT1_TRGOOUTEN /* 2nd write */
#define TRGOPT_TRGOUTR_OUT BIT(1)
#define TRGOPT_TRGOUTR_EN BIT(0)
#define TRGOPT_CLEAR_MASK (TRGOPT_TRGOINEN | TRGOPT_TRGOEVNTEN | TRGOPT_TRGOOUTEN)
/* /*
* Layout of the sample data DRAM, which will be downloaded to the PC: * Layout of the sample data DRAM, which will be downloaded to the PC:
* *
* Sigma memory is organized in 32K rows. Each row contains 64 clusters. * Sigma memory is organized in 32K rows. Each row contains 64 clusters.
* Each cluster contains a timestamp (16bit) and 7 events (16bits each). * Each cluster contains a timestamp (16bit) and 7 samples (16bits each).
* Events contain 16 bits of sample data (potentially taken at multiple * Total memory size is 32K x 64 x 8 x 2 bytes == 32 MB (256 Mbit).
* sample points, see below).
*
* Total memory size is 32K x 64 x 8 x 2 bytes == 32 MiB (256 Mbit). The
* size of a memory row is 1024 bytes. Assuming x16 organization of the
* memory array, address specs (sample count, trigger position) are kept
* in 24bit entities. The upper 15 bit address the "row", the lower 9 bit
* refer to the "event" within the row. Because there is one timestamp for
* seven events each, one memory row can hold up to 64x7 == 448 events.
* *
* Sample data is represented in 16bit quantities. The first sample in * Sample data is represented in 16bit quantities. The first sample in
* the cluster corresponds to the cluster's timestamp. Each next sample * the cluster corresponds to the cluster's timestamp. Each next sample
@ -224,50 +131,80 @@ enum trgsel_selcode_t {
* one sample period, according to the samplerate). In the absence of * one sample period, according to the samplerate). In the absence of
* pin level changes, no data is provided (RLE compression). A cluster * pin level changes, no data is provided (RLE compression). A cluster
* is enforced for each 64K ticks of the timestamp, to reliably handle * is enforced for each 64K ticks of the timestamp, to reliably handle
* rollover and determine the next timestamp of the next cluster. * rollover and determination of the next timestamp of the next cluster.
* *
* For samplerates up to 50MHz, an event directly translates to one set
* of sample data at a single sample point, spanning up to 16 channels.
* For samplerates of 100MHz, there is one 16 bit entity for each 20ns * For samplerates of 100MHz, there is one 16 bit entity for each 20ns
* period (50MHz rate). The 16 bit memory contains 2 samples of up to * period (50MHz rate). The 16 bit memory contains 2 samples of up to
* 8 channels. Bits of multiple samples are interleaved. For samplerates * 8 channels. Bits of multiple samples are interleaved. For samplerates
* of 200MHz one 16bit entity contains 4 samples of up to 4 channels, * of 200MHz one 16bit entity contains 4 samples of up to 4 channels,
* each 5ns apart. * each 5ns apart.
*
* Memory addresses (sample count, trigger position) are kept in 24bit
* entities. The upper 15 bit refer to the "row", the lower 9 bit refer
* to the "event" within the row. Because there is one timestamp for
* seven samples each, one memory row can hold up to 64x7 == 448 samples.
*/ */
#define ROW_COUNT 32768 /* One "DRAM cluster" contains a timestamp and 7 samples, 16b total. */
#define ROW_LENGTH_BYTES 1024
#define ROW_LENGTH_U16 (ROW_LENGTH_BYTES / sizeof(uint16_t))
#define ROW_SHIFT 9 /* log2 of u16 count */
#define ROW_MASK BITS_MASK(ROW_SHIFT)
#define EVENTS_PER_CLUSTER 7
#define CLUSTERS_PER_ROW (ROW_LENGTH_U16 / (1 + EVENTS_PER_CLUSTER))
#define EVENTS_PER_ROW (CLUSTERS_PER_ROW * EVENTS_PER_CLUSTER)
struct sigma_dram_line {
struct sigma_dram_cluster { struct sigma_dram_cluster {
uint16_t timestamp; uint8_t timestamp_lo;
uint16_t samples[EVENTS_PER_CLUSTER]; uint8_t timestamp_hi;
} cluster[CLUSTERS_PER_ROW]; struct {
uint8_t sample_hi;
uint8_t sample_lo;
} samples[7];
};
/* One "DRAM line" contains 64 "DRAM clusters", 1024b total. */
struct sigma_dram_line {
struct sigma_dram_cluster cluster[64];
};
struct clockselect_50 {
uint8_t async;
uint8_t fraction;
uint16_t disabled_channels;
}; };
/* The effect of all these are still a bit unclear. */ /* The effect of all these are still a bit unclear. */
struct triggerinout { struct triggerinout {
gboolean trgout_resistor_enable, trgout_resistor_pullup; uint8_t trgout_resistor_enable : 1;
gboolean trgout_resistor_enable2, trgout_resistor_pullup2; uint8_t trgout_resistor_pullup : 1;
gboolean trgout_bytrigger, trgout_byevent, trgout_bytriggerin; uint8_t reserved1 : 1;
gboolean trgout_long, trgout_pin; /* 1ms pulse, 1k resistor */ uint8_t trgout_bytrigger : 1;
gboolean trgin_negate, trgout_enable, trgin_enable; uint8_t trgout_byevent : 1;
uint8_t trgout_bytriggerin : 1;
uint8_t reserved2 : 2;
/* Should be set same as the first two */
uint8_t trgout_resistor_enable2 : 1;
uint8_t trgout_resistor_pullup2 : 1;
uint8_t reserved3 : 1;
uint8_t trgout_long : 1;
uint8_t trgout_pin : 1; /* Use 1k resistor. Pullup? */
uint8_t trgin_negate : 1;
uint8_t trgout_enable : 1;
uint8_t trgin_enable : 1;
}; };
struct triggerlut { struct triggerlut {
/* The actual LUTs. */
uint16_t m0d[4], m1d[4], m2d[4]; uint16_t m0d[4], m1d[4], m2d[4];
uint16_t m3q, m3s, m4; uint16_t m3, m3s, m4;
/* Parameters should be sent as a single register write. */
struct { struct {
uint8_t selpresc; uint8_t selc : 2;
uint8_t sela, selb, selc; uint8_t selpresc : 6;
uint8_t selinc, selres;
uint16_t cmpa, cmpb; uint8_t selinc : 2;
uint8_t selres : 2;
uint8_t sela : 2;
uint8_t selb : 2;
uint16_t cmpb;
uint16_t cmpa;
} params; } params;
}; };
@ -306,120 +243,49 @@ enum triggerfunc {
FUNC_NXOR, FUNC_NXOR,
}; };
enum sigma_firmware_idx { struct sigma_state {
SIGMA_FW_NONE,
SIGMA_FW_50MHZ,
SIGMA_FW_100MHZ,
SIGMA_FW_200MHZ,
SIGMA_FW_SYNC,
SIGMA_FW_FREQ,
};
enum ext_clock_edge_t {
SIGMA_CLOCK_EDGE_RISING,
SIGMA_CLOCK_EDGE_FALLING,
SIGMA_CLOCK_EDGE_EITHER,
};
struct submit_buffer;
struct dev_context {
struct {
uint16_t vid, pid;
uint32_t serno;
uint16_t prefix;
enum asix_device_type type;
} id;
struct {
struct ftdi_context ctx;
gboolean is_open, must_close;
} ftdi;
struct {
uint64_t samplerate;
gboolean use_ext_clock;
size_t clock_pin;
enum ext_clock_edge_t clock_edge;
} clock;
struct {
/*
* User specified configuration values, in contrast to
* internal arrangement of acquisition, and submission
* to the session feed.
*/
struct sr_sw_limits config;
struct sr_sw_limits acquire;
struct sr_sw_limits submit;
} limit;
enum sigma_firmware_idx firmware_idx;
struct sigma_sample_interp {
/* Interpretation of sample memory. */
size_t num_channels;
size_t samples_per_event;
struct {
uint16_t ts;
uint16_t sample;
} last;
struct sigma_location {
size_t raw, line, cluster, event;
} start, stop, trig, iter, trig_arm;
struct {
size_t lines_total, lines_done;
size_t lines_per_read; /* USB transfer limit */
size_t lines_rcvd;
struct sigma_dram_line *rcvd_lines;
struct sigma_dram_line *curr_line;
} fetch;
struct {
gboolean armed;
gboolean matched;
size_t evt_remain;
} trig_chk;
} interp;
uint64_t capture_ratio;
struct sigma_trigger trigger;
gboolean use_triggers;
gboolean late_trigger_timeout;
enum { enum {
SIGMA_UNINITIALIZED = 0, SIGMA_UNINITIALIZED = 0,
SIGMA_CONFIG,
SIGMA_IDLE, SIGMA_IDLE,
SIGMA_CAPTURE, SIGMA_CAPTURE,
SIGMA_STOPPING,
SIGMA_DOWNLOAD, SIGMA_DOWNLOAD,
} state; } state;
struct submit_buffer *buffer;
uint16_t lastts;
uint16_t lastsample;
}; };
/* "Automatic" and forced USB connection open/close support. */ /* Private, per-device-instance driver context. */
SR_PRIV int sigma_check_open(const struct sr_dev_inst *sdi); struct dev_context {
SR_PRIV int sigma_check_close(struct dev_context *devc); struct ftdi_context ftdic;
SR_PRIV int sigma_force_open(const struct sr_dev_inst *sdi); uint64_t cur_samplerate;
SR_PRIV int sigma_force_close(struct dev_context *devc); uint64_t limit_msec;
uint64_t limit_samples;
uint64_t sent_samples;
uint64_t start_time;
int cur_firmware;
int num_channels;
int cur_channels;
int samples_per_event;
int capture_ratio;
struct sigma_trigger trigger;
int use_triggers;
struct sigma_state state;
};
/* Save configuration across sessions, to reduce cost of continuation. */ extern SR_PRIV const uint64_t samplerates[];
SR_PRIV int sigma_store_hw_config(const struct sr_dev_inst *sdi); extern SR_PRIV const size_t samplerates_count;
SR_PRIV int sigma_fetch_hw_config(const struct sr_dev_inst *sdi);
/* Send register content (simple and complex) to the hardware. */ SR_PRIV int sigma_write_register(uint8_t reg, uint8_t *data, size_t len,
SR_PRIV int sigma_write_register(struct dev_context *devc, struct dev_context *devc);
uint8_t reg, uint8_t *data, size_t len); SR_PRIV int sigma_set_register(uint8_t reg, uint8_t value, struct dev_context *devc);
SR_PRIV int sigma_set_register(struct dev_context *devc, SR_PRIV int sigma_write_trigger_lut(struct triggerlut *lut, struct dev_context *devc);
uint8_t reg, uint8_t value); SR_PRIV void sigma_clear_helper(void *priv);
SR_PRIV int sigma_write_trigger_lut(struct dev_context *devc, SR_PRIV uint64_t sigma_limit_samples_to_msec(const struct dev_context *devc,
struct triggerlut *lut); uint64_t limit_samples);
SR_PRIV int sigma_set_samplerate(const struct sr_dev_inst *sdi, uint64_t samplerate);
/* Samplerate constraints check, get/set/list helpers. */
SR_PRIV int sigma_normalize_samplerate(uint64_t want_rate, uint64_t *have_rate);
SR_PRIV GVariant *sigma_get_samplerates_list(void);
/* Preparation of data acquisition, spec conversion, hardware configuration. */
SR_PRIV int sigma_set_samplerate(const struct sr_dev_inst *sdi);
SR_PRIV int sigma_set_acquire_timeout(struct dev_context *devc);
SR_PRIV int sigma_convert_trigger(const struct sr_dev_inst *sdi); SR_PRIV int sigma_convert_trigger(const struct sr_dev_inst *sdi);
SR_PRIV int sigma_build_basic_trigger(struct dev_context *devc,
struct triggerlut *lut);
/* Callback to periodically drive acuisition progress. */
SR_PRIV int sigma_receive_data(int fd, int revents, void *cb_data); SR_PRIV int sigma_receive_data(int fd, int revents, void *cb_data);
SR_PRIV int sigma_build_basic_trigger(struct triggerlut *lut, struct dev_context *devc);
#endif #endif

View File

@ -113,6 +113,8 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options, int modelid)
if (serial_open(serial, SERIAL_RDWR) != SR_OK) if (serial_open(serial, SERIAL_RDWR) != SR_OK)
return NULL; return NULL;
serial_flush(serial);
/* This is how the vendor software scans for hardware. */ /* This is how the vendor software scans for hardware. */
memset(packet, 0, PACKET_SIZE); memset(packet, 0, PACKET_SIZE);
packet[0] = 0xaa; packet[0] = 0xaa;
@ -180,19 +182,21 @@ static GSList *scan_3203(struct sr_dev_driver *di, GSList *options)
return scan(di, options, PPS_3203T_3S); return scan(di, options, PPS_3203T_3S);
} }
static int config_get(uint32_t key, GVariant **data, static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) const struct sr_channel_group *cg)
{ {
struct dev_context *devc; struct dev_context *devc;
struct sr_channel *ch; struct sr_channel *ch;
int channel; int channel, ret;
if (!sdi) if (!sdi)
return SR_ERR_ARG; return SR_ERR_ARG;
devc = sdi->priv; devc = sdi->priv;
ret = SR_OK;
if (!cg) { if (!cg) {
/* No channel group: global options. */
switch (key) { switch (key) {
case SR_CONF_CHANNEL_CONFIG: case SR_CONF_CHANNEL_CONFIG:
*data = g_variant_new_string(channel_modes[devc->channel_mode]); *data = g_variant_new_string(channel_modes[devc->channel_mode]);
@ -229,36 +233,64 @@ static int config_get(uint32_t key, GVariant **data,
} }
} }
return SR_OK; return ret;
} }
static int config_set(uint32_t key, GVariant *data, static int find_str(const char *str, const char **strings, int array_size)
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) {
int idx, i;
idx = -1;
for (i = 0; i < array_size; i++) {
if (!strcmp(str, strings[i])) {
idx = i;
break;
}
}
return idx;
}
static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
{ {
struct dev_context *devc; struct dev_context *devc;
struct sr_channel *ch; struct sr_channel *ch;
gdouble dval; gdouble dval;
int channel, ival; int channel, ret, ival;
const char *sval;
gboolean bval; gboolean bval;
devc = sdi->priv; if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
ret = SR_OK;
devc = sdi->priv;
if (!cg) { if (!cg) {
/* No channel group: global options. */
switch (key) { switch (key) {
case SR_CONF_CHANNEL_CONFIG: case SR_CONF_CHANNEL_CONFIG:
if ((ival = std_str_idx(data, ARRAY_AND_SIZE(channel_modes))) < 0) sval = g_variant_get_string(data, NULL);
return SR_ERR_ARG; if ((ival = find_str(sval, channel_modes,
if (devc->model->channel_modes && (1 << ival) == 0) ARRAY_SIZE(channel_modes))) == -1) {
return SR_ERR_ARG; /* Not supported on this model. */ ret = SR_ERR_ARG;
break;
}
if (devc->model->channel_modes && (1 << ival) == 0) {
/* Not supported on this model. */
ret = SR_ERR_ARG;
}
if (ival == devc->channel_mode_set) if (ival == devc->channel_mode_set)
break; /* Nothing to do. */ /* Nothing to do. */
break;
devc->channel_mode_set = ival; devc->channel_mode_set = ival;
devc->config_dirty = TRUE; devc->config_dirty = TRUE;
break; break;
case SR_CONF_OVER_CURRENT_PROTECTION_ENABLED: case SR_CONF_OVER_CURRENT_PROTECTION_ENABLED:
bval = g_variant_get_boolean(data); bval = g_variant_get_boolean(data);
if (bval == devc->over_current_protection_set) if (bval == devc->over_current_protection_set)
break; /* Nothing to do. */ /* Nothing to do. */
break;
devc->over_current_protection_set = bval; devc->over_current_protection_set = bval;
devc->config_dirty = TRUE; devc->config_dirty = TRUE;
break; break;
@ -266,6 +298,7 @@ static int config_set(uint32_t key, GVariant *data,
return SR_ERR_NA; return SR_ERR_NA;
} }
} else { } else {
/* Channel group specified: per-channel options. */
/* We only ever have one channel per channel group in this driver. */ /* We only ever have one channel per channel group in this driver. */
ch = cg->channels->data; ch = cg->channels->data;
channel = ch->index; channel = ch->index;
@ -274,85 +307,116 @@ static int config_set(uint32_t key, GVariant *data,
case SR_CONF_VOLTAGE_TARGET: case SR_CONF_VOLTAGE_TARGET:
dval = g_variant_get_double(data); dval = g_variant_get_double(data);
if (dval < 0 || dval > devc->model->channels[channel].voltage[1]) if (dval < 0 || dval > devc->model->channels[channel].voltage[1])
return SR_ERR_ARG; ret = SR_ERR_ARG;
devc->config[channel].output_voltage_max = dval; devc->config[channel].output_voltage_max = dval;
devc->config_dirty = TRUE; devc->config_dirty = TRUE;
break; break;
case SR_CONF_CURRENT_LIMIT: case SR_CONF_CURRENT_LIMIT:
dval = g_variant_get_double(data); dval = g_variant_get_double(data);
if (dval < 0 || dval > devc->model->channels[channel].current[1]) if (dval < 0 || dval > devc->model->channels[channel].current[1])
return SR_ERR_ARG; ret = SR_ERR_ARG;
devc->config[channel].output_current_max = dval; devc->config[channel].output_current_max = dval;
devc->config_dirty = TRUE; devc->config_dirty = TRUE;
break; break;
case SR_CONF_ENABLED: case SR_CONF_ENABLED:
bval = g_variant_get_boolean(data); bval = g_variant_get_boolean(data);
if (bval == devc->config[channel].output_enabled_set) if (bval == devc->config[channel].output_enabled_set)
break; /* Nothing to do. */ /* Nothing to do. */
break;
devc->config[channel].output_enabled_set = bval; devc->config[channel].output_enabled_set = bval;
devc->config_dirty = TRUE; devc->config_dirty = TRUE;
break; break;
default: default:
return SR_ERR_NA; ret = SR_ERR_NA;
} }
} }
return SR_OK; return ret;
} }
static int config_list(uint32_t key, GVariant **data, static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) const struct sr_channel_group *cg)
{ {
struct dev_context *devc; struct dev_context *devc;
struct sr_channel *ch; struct sr_channel *ch;
int channel; GVariant *gvar;
GVariantBuilder gvb;
int channel, ret, i;
devc = (sdi) ? sdi->priv : NULL; /* 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 (!cg) { if (key == SR_CONF_DEVICE_OPTIONS && !sdi) {
switch (key) { *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
case SR_CONF_SCAN_OPTIONS: drvopts, ARRAY_SIZE(drvopts), sizeof(uint32_t));
case SR_CONF_DEVICE_OPTIONS: return SR_OK;
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts); }
case SR_CONF_CHANNEL_CONFIG:
if (!devc || !devc->model) if (!sdi)
return SR_ERR_ARG; return SR_ERR_ARG;
devc = sdi->priv;
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;
case SR_CONF_CHANNEL_CONFIG:
if (devc->model->channel_modes == CHANMODE_INDEPENDENT) { if (devc->model->channel_modes == CHANMODE_INDEPENDENT) {
/* The 1-channel models. */ /* The 1-channel models. */
*data = g_variant_new_strv(channel_modes, 1); *data = g_variant_new_strv(channel_modes, 1);
} else { } else {
/* The other models support all modes. */ /* The other models support all modes. */
*data = g_variant_new_strv(ARRAY_AND_SIZE(channel_modes)); *data = g_variant_new_strv(channel_modes, ARRAY_SIZE(channel_modes));
} }
break; break;
default: default:
return SR_ERR_NA; return SR_ERR_NA;
} }
} else { } else {
/* Channel group specified: per-channel options. */
if (!sdi)
return SR_ERR_ARG;
/* We only ever have one channel per channel group in this driver. */ /* We only ever have one channel per channel group in this driver. */
ch = cg->channels->data; ch = cg->channels->data;
channel = ch->index; channel = ch->index;
switch (key) { switch (key) {
case SR_CONF_DEVICE_OPTIONS: case SR_CONF_DEVICE_OPTIONS:
*data = std_gvar_array_u32(ARRAY_AND_SIZE(devopts_cg)); *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
devopts_cg, ARRAY_SIZE(devopts_cg), sizeof(uint32_t));
break; break;
case SR_CONF_VOLTAGE_TARGET: case SR_CONF_VOLTAGE_TARGET:
if (!devc || !devc->model) g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
return SR_ERR_ARG; /* Min, max, step. */
*data = std_gvar_min_max_step_array(devc->model->channels[channel].voltage); 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);
break; break;
case SR_CONF_CURRENT_LIMIT: case SR_CONF_CURRENT_LIMIT:
if (!devc || !devc->model) g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
return SR_ERR_ARG; /* Min, max, step. */
*data = std_gvar_min_max_step_array(devc->model->channels[channel].current); 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);
break; break;
default: default:
return SR_ERR_NA; return SR_ERR_NA;
} }
} }
return SR_OK; return ret;
} }
static int dev_close(struct sr_dev_inst *sdi) static int dev_close(struct sr_dev_inst *sdi)
@ -360,7 +424,6 @@ static int dev_close(struct sr_dev_inst *sdi)
struct dev_context *devc; struct dev_context *devc;
devc = sdi->priv; devc = sdi->priv;
if (devc->config_dirty) if (devc->config_dirty)
/* Some configuration changes were queued up but didn't /* Some configuration changes were queued up but didn't
* get sent to the device, likely because we were never * get sent to the device, likely because we were never
@ -376,6 +439,9 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
struct sr_serial_dev_inst *serial; struct sr_serial_dev_inst *serial;
uint8_t packet[PACKET_SIZE]; uint8_t packet[PACKET_SIZE];
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv; devc = sdi->priv;
memset(devc->packet, 0x44, PACKET_SIZE); memset(devc->packet, 0x44, PACKET_SIZE);
devc->packet_size = 0; devc->packet_size = 0;
@ -400,6 +466,9 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi)
{ {
struct dev_context *devc; struct dev_context *devc;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv; devc = sdi->priv;
devc->acquisition_running = FALSE; devc->acquisition_running = FALSE;
@ -414,7 +483,7 @@ static struct sr_dev_driver atten_pps3203_driver_info = {
.cleanup = std_cleanup, .cleanup = std_cleanup,
.scan = scan_3203, .scan = scan_3203,
.dev_list = std_dev_list, .dev_list = std_dev_list,
.dev_clear = std_dev_clear, .dev_clear = NULL,
.config_get = config_get, .config_get = config_get,
.config_set = config_set, .config_set = config_set,
.config_list = config_list, .config_list = config_list,

View File

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

View File

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

View File

@ -166,10 +166,8 @@ SR_PRIV gboolean bl_acme_detect_probe(unsigned int addr,
probe_name_path(addr, path); probe_name_path(addr, path);
status = g_file_get_contents(path->str, &buf, &size, &err); status = g_file_get_contents(path->str, &buf, &size, &err);
if (!status) { if (!status) {
/* Don't log "No such file or directory" messages. */ sr_dbg("Name for probe %d can't be read: %s",
if (err->code != G_FILE_ERROR_NOENT) prb_num, err->message);
sr_dbg("Name for probe %d can't be read (%d): %s",
prb_num, err->code, err->message);
g_string_free(path, TRUE); g_string_free(path, TRUE);
g_error_free(err); g_error_free(err);
return ret; return ret;
@ -703,7 +701,7 @@ SR_PRIV void bl_acme_close_channel(struct sr_channel *ch)
SR_PRIV int bl_acme_receive_data(int fd, int revents, void *cb_data) SR_PRIV int bl_acme_receive_data(int fd, int revents, void *cb_data)
{ {
uint64_t nrexpiration; uint64_t nrexpiration;
struct sr_datafeed_packet packet; struct sr_datafeed_packet packet, framep;
struct sr_datafeed_analog analog; struct sr_datafeed_analog analog;
struct sr_analog_encoding encoding; struct sr_analog_encoding encoding;
struct sr_analog_meaning meaning; struct sr_analog_meaning meaning;
@ -759,7 +757,8 @@ SR_PRIV int bl_acme_receive_data(int fd, int revents, void *cb_data)
* accuracy. * accuracy.
*/ */
for (i = 0; i < nrexpiration; i++) { for (i = 0; i < nrexpiration; i++) {
std_session_send_df_frame_begin(sdi); framep.type = SR_DF_FRAME_BEGIN;
sr_session_send(sdi, &framep);
/* /*
* Due to different units used in each channel we're sending * Due to different units used in each channel we're sending
@ -787,13 +786,14 @@ SR_PRIV int bl_acme_receive_data(int fd, int revents, void *cb_data)
sr_session_send(sdi, &packet); sr_session_send(sdi, &packet);
} }
std_session_send_df_frame_end(sdi); framep.type = SR_DF_FRAME_END;
sr_session_send(sdi, &framep);
} }
sr_sw_limits_update_samples_read(&devc->limits, 1); sr_sw_limits_update_samples_read(&devc->limits, 1);
if (sr_sw_limits_check(&devc->limits)) { if (sr_sw_limits_check(&devc->limits)) {
sr_dev_acquisition_stop(sdi); sdi->driver->dev_acquisition_stop(sdi);
return TRUE; return TRUE;
} }

View File

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

View File

@ -1,7 +1,7 @@
/* /*
* This file is part of the libsigrok project. * This file is part of the libsigrok project.
* *
* Copyright (C) 2014-2017 Kumar Abhishek <abhishek@theembeddedkitchen.net> * Copyright (C) 2014 Kumar Abhishek <abhishek@theembeddedkitchen.net>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -21,25 +21,24 @@
#include "protocol.h" #include "protocol.h"
#include "beaglelogic.h" #include "beaglelogic.h"
/* Scan options */
static const uint32_t scanopts[] = { static const uint32_t scanopts[] = {
SR_CONF_CONN,
SR_CONF_NUM_LOGIC_CHANNELS, SR_CONF_NUM_LOGIC_CHANNELS,
}; };
static const uint32_t drvopts[] = { /* Hardware capabilities */
SR_CONF_LOGIC_ANALYZER,
};
static const uint32_t devopts[] = { static const uint32_t devopts[] = {
SR_CONF_LOGIC_ANALYZER,
SR_CONF_CONTINUOUS, SR_CONF_CONTINUOUS,
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET, SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET,
SR_CONF_TRIGGER_MATCH | SR_CONF_LIST, SR_CONF_TRIGGER_MATCH | SR_CONF_LIST,
SR_CONF_CAPTURE_RATIO | SR_CONF_GET | SR_CONF_SET, SR_CONF_CAPTURE_RATIO | SR_CONF_GET | SR_CONF_SET,
SR_CONF_NUM_LOGIC_CHANNELS | SR_CONF_GET, SR_CONF_NUM_LOGIC_CHANNELS | SR_CONF_GET,
}; };
static const int32_t trigger_matches[] = { /* Trigger matching capabilities */
static const int32_t soft_trigger_matches[] = {
SR_TRIGGER_ZERO, SR_TRIGGER_ZERO,
SR_TRIGGER_ONE, SR_TRIGGER_ONE,
SR_TRIGGER_RISING, SR_TRIGGER_RISING,
@ -59,79 +58,68 @@ static const uint64_t samplerates[] = {
SR_HZ(1), SR_HZ(1),
}; };
static struct dev_context *beaglelogic_devc_alloc(void)
{
struct dev_context *devc;
devc = g_malloc0(sizeof(struct dev_context));
/* Default non-zero values (if any) */
devc->fd = -1;
devc->limit_samples = (uint64_t)-1;
return devc;
}
static GSList *scan(struct sr_dev_driver *di, GSList *options) static GSList *scan(struct sr_dev_driver *di, GSList *options)
{ {
GSList *l; GSList *l;
struct sr_config *src; struct sr_config *src;
struct sr_dev_inst *sdi; struct sr_dev_inst *sdi;
struct dev_context *devc; struct dev_context *devc;
const char *conn;
gchar **params;
int i, maxch; int i, maxch;
maxch = NUM_CHANNELS; /* Probe for /dev/beaglelogic */
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);
}
/* Probe for /dev/beaglelogic if not connecting via TCP */
if (!conn) {
params = NULL;
if (!g_file_test(BEAGLELOGIC_DEV_NODE, G_FILE_TEST_EXISTS)) if (!g_file_test(BEAGLELOGIC_DEV_NODE, G_FILE_TEST_EXISTS))
return NULL; return NULL;
} else {
params = g_strsplit(conn, "/", 0);
if (!params || !params[1] || !params[2]) {
sr_err("Invalid Parameters.");
g_strfreev(params);
return NULL;
}
if (g_ascii_strncasecmp(params[0], "tcp", 3)) {
sr_err("Only TCP (tcp-raw) protocol is currently supported.");
g_strfreev(params);
return NULL;
}
}
maxch = (maxch > 8) ? NUM_CHANNELS : 8; sdi = g_malloc0(sizeof(struct sr_dev_inst));
sdi = g_new0(struct sr_dev_inst, 1);
sdi->status = SR_ST_INACTIVE; sdi->status = SR_ST_INACTIVE;
sdi->model = g_strdup("BeagleLogic"); sdi->model = g_strdup("BeagleLogic");
sdi->version = g_strdup("1.0"); sdi->version = g_strdup("1.0");
devc = g_malloc0(sizeof(struct dev_context)); /* Unless explicitly specified, keep max channels to 8 only */
maxch = 8;
/* Default non-zero values (if any) */ for (l = options; l; l = l->next) {
devc->fd = -1; src = l->data;
devc->limit_samples = 10000000; if (src->key == SR_CONF_NUM_LOGIC_CHANNELS)
devc->tcp_buffer = 0; maxch = g_variant_get_int32(src->data);
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);
} }
/* 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;
} else {
maxch = 8;
devc->sampleunit = BL_SAMPLEUNIT_8_BITS;
}
beaglelogic_set_sampleunit(devc);
beaglelogic_close(devc);
/* Signal */
sr_info("BeagleLogic device found at "BEAGLELOGIC_DEV_NODE);
/* Fill the channels */ /* Fill the channels */
for (i = 0; i < maxch; i++) for (i = 0; i < maxch; i++)
sr_channel_new(sdi, i, SR_CHANNEL_LOGIC, TRUE, sr_channel_new(sdi, i, SR_CHANNEL_LOGIC, TRUE,
@ -140,16 +128,6 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
sdi->priv = devc; sdi->priv = devc;
return std_scan_complete(di, g_slist_append(NULL, sdi)); return std_scan_complete(di, g_slist_append(NULL, sdi));
err_free:
g_free(sdi->model);
g_free(sdi->version);
g_free(devc->address);
g_free(devc->port);
g_free(devc);
g_free(sdi);
return NULL;
} }
static int dev_open(struct sr_dev_inst *sdi) static int dev_open(struct sr_dev_inst *sdi)
@ -157,39 +135,30 @@ static int dev_open(struct sr_dev_inst *sdi)
struct dev_context *devc = sdi->priv; struct dev_context *devc = sdi->priv;
/* Open BeagleLogic */ /* Open BeagleLogic */
if (devc->beaglelogic->open(devc)) if (beaglelogic_open_nonblock(devc))
return SR_ERR; return SR_ERR;
/* Set fd and local attributes */ /* Set fd and local attributes */
if (devc->beaglelogic == &beaglelogic_tcp_ops)
devc->pollfd.fd = devc->socket;
else
devc->pollfd.fd = devc->fd; devc->pollfd.fd = devc->fd;
devc->pollfd.events = G_IO_IN; devc->pollfd.events = G_IO_IN;
devc->pollfd.revents = 0; devc->pollfd.revents = 0;
/* Get the default attributes */ /* Get the default attributes */
devc->beaglelogic->get_samplerate(devc); beaglelogic_get_samplerate(devc);
devc->beaglelogic->get_sampleunit(devc); beaglelogic_get_sampleunit(devc);
devc->beaglelogic->get_buffersize(devc); beaglelogic_get_triggerflags(devc);
devc->beaglelogic->get_bufunitsize(devc); beaglelogic_get_buffersize(devc);
beaglelogic_get_bufunitsize(devc);
/* Set the triggerflags to default for continuous capture unless we
* explicitly limit samples using SR_CONF_LIMIT_SAMPLES */
devc->triggerflags = BL_TRIGGERFLAGS_CONTINUOUS;
devc->beaglelogic->set_triggerflags(devc);
/* Map the kernel capture FIFO for reads, saves 1 level of memcpy */ /* Map the kernel capture FIFO for reads, saves 1 level of memcpy */
if (devc->beaglelogic == &beaglelogic_native_ops) { if (beaglelogic_mmap(devc) != SR_OK) {
if (devc->beaglelogic->mmap(devc) != SR_OK) {
sr_err("Unable to map capture buffer"); sr_err("Unable to map capture buffer");
devc->beaglelogic->close(devc); beaglelogic_close(devc);
return SR_ERR; return SR_ERR;
} }
} else {
devc->tcp_buffer = g_malloc(TCP_BUFFER_SIZE);
}
/* We're good to go now */
sdi->status = SR_ST_ACTIVE;
return SR_OK; return SR_OK;
} }
@ -197,28 +166,17 @@ static int dev_close(struct sr_dev_inst *sdi)
{ {
struct dev_context *devc = sdi->priv; struct dev_context *devc = sdi->priv;
if (sdi->status == SR_ST_ACTIVE) {
/* Close the memory mapping and the file */ /* Close the memory mapping and the file */
if (devc->beaglelogic == &beaglelogic_native_ops) beaglelogic_munmap(devc);
devc->beaglelogic->munmap(devc); beaglelogic_close(devc);
devc->beaglelogic->close(devc); }
sdi->status = SR_ST_INACTIVE;
return SR_OK; return SR_OK;
} }
static void clear_helper(struct dev_context *devc) static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
{ const struct sr_channel_group *cg)
g_free(devc->tcp_buffer);
g_free(devc->address);
g_free(devc->port);
}
static int dev_clear(const struct sr_dev_driver *di)
{
return std_dev_clear_with_callback(di, (std_dev_clear_callback)clear_helper);
}
static int config_get(uint32_t key, GVariant **data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{ {
struct dev_context *devc = sdi->priv; struct dev_context *devc = sdi->priv;
@ -244,18 +202,21 @@ static int config_get(uint32_t key, GVariant **data,
return SR_OK; return SR_OK;
} }
static int config_set(uint32_t key, GVariant *data, static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) const struct sr_channel_group *cg)
{ {
struct dev_context *devc = sdi->priv; struct dev_context *devc = sdi->priv;
uint64_t tmp_u64; uint64_t tmp_u64;
(void)cg; (void)cg;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
switch (key) { switch (key) {
case SR_CONF_SAMPLERATE: case SR_CONF_SAMPLERATE:
devc->cur_samplerate = g_variant_get_uint64(data); devc->cur_samplerate = g_variant_get_uint64(data);
return devc->beaglelogic->set_samplerate(devc); return beaglelogic_set_samplerate(devc);
case SR_CONF_LIMIT_SAMPLES: case SR_CONF_LIMIT_SAMPLES:
tmp_u64 = g_variant_get_uint64(data); tmp_u64 = g_variant_get_uint64(data);
devc->limit_samples = tmp_u64; devc->limit_samples = tmp_u64;
@ -267,15 +228,17 @@ static int config_set(uint32_t key, GVariant *data,
sr_warn("Insufficient buffer space has been allocated."); sr_warn("Insufficient buffer space has been allocated.");
sr_warn("Please use \'echo <size in bytes> > "\ sr_warn("Please use \'echo <size in bytes> > "\
BEAGLELOGIC_SYSFS_ATTR(memalloc) \ BEAGLELOGIC_SYSFS_ATTR(memalloc) \
"\' to increase the buffer size, this"\ "\' as root to increase the buffer size, this"\
" capture is now truncated to %d Msamples", " capture is now truncated to %d Msamples",
devc->buffersize / devc->buffersize /
(SAMPLEUNIT_TO_BYTES(devc->sampleunit) * 1000000)); (SAMPLEUNIT_TO_BYTES(devc->sampleunit) * 1000000));
} }
return devc->beaglelogic->set_triggerflags(devc); return beaglelogic_set_triggerflags(devc);
case SR_CONF_CAPTURE_RATIO: case SR_CONF_CAPTURE_RATIO:
devc->capture_ratio = g_variant_get_uint64(data); devc->capture_ratio = g_variant_get_uint64(data);
break; if (devc->capture_ratio > 100)
return SR_ERR;
return SR_OK;
default: default:
return SR_ERR_NA; return SR_ERR_NA;
} }
@ -283,24 +246,43 @@ static int config_set(uint32_t key, GVariant *data,
return SR_OK; return SR_OK;
} }
static int config_list(uint32_t key, GVariant **data, static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) const struct sr_channel_group *cg)
{ {
int ret;
GVariant *gvar;
GVariantBuilder gvb;
(void)sdi;
(void)cg;
ret = SR_OK;
switch (key) { switch (key) {
case SR_CONF_SCAN_OPTIONS: case SR_CONF_SCAN_OPTIONS:
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
break;
case SR_CONF_DEVICE_OPTIONS: case SR_CONF_DEVICE_OPTIONS:
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts); *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
break;
case SR_CONF_SAMPLERATE: case SR_CONF_SAMPLERATE:
*data = std_gvar_samplerates_steps(ARRAY_AND_SIZE(samplerates)); 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);
break; break;
case SR_CONF_TRIGGER_MATCH: case SR_CONF_TRIGGER_MATCH:
*data = std_gvar_array_i32(ARRAY_AND_SIZE(trigger_matches)); *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
soft_trigger_matches, ARRAY_SIZE(soft_trigger_matches),
sizeof(int32_t));
break; break;
default: default:
return SR_ERR_NA; return SR_ERR_NA;
} }
return SR_OK; return ret;
} }
/* get a sane timeout for poll() */ /* get a sane timeout for poll() */
@ -310,33 +292,25 @@ static int config_list(uint32_t key, GVariant **data,
static int dev_acquisition_start(const struct sr_dev_inst *sdi) static int dev_acquisition_start(const struct sr_dev_inst *sdi)
{ {
struct dev_context *devc = sdi->priv; struct dev_context *devc = sdi->priv;
GSList *l;
struct sr_trigger *trigger; struct sr_trigger *trigger;
struct sr_channel *channel;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
/* Clear capture state */ /* Clear capture state */
devc->bytes_read = 0; devc->bytes_read = 0;
devc->offset = 0; devc->offset = 0;
/* Configure channels */ /* Configure channels */
devc->sampleunit = BL_SAMPLEUNIT_8_BITS; devc->sampleunit = g_slist_length(sdi->channels) > 8 ?
BL_SAMPLEUNIT_16_BITS : BL_SAMPLEUNIT_8_BITS;
for (l = sdi->channels; l; l = l->next) { beaglelogic_set_sampleunit(devc);
channel = l->data;
if (channel->index >= 8 && channel->enabled)
devc->sampleunit = BL_SAMPLEUNIT_16_BITS;
}
devc->beaglelogic->set_sampleunit(devc);
/* If continuous sampling, set the limit_samples to max possible value */
if (devc->triggerflags == BL_TRIGGERFLAGS_CONTINUOUS)
devc->limit_samples = UINT64_MAX;
/* Configure triggers & send header packet */ /* Configure triggers & send header packet */
if ((trigger = sr_session_trigger_get(sdi->session))) { if ((trigger = sr_session_trigger_get(sdi->session))) {
int pre_trigger_samples = 0; int pre_trigger_samples = 0;
if (devc->limit_samples > 0) if (devc->limit_samples > 0)
pre_trigger_samples = (devc->capture_ratio * devc->limit_samples) / 100; pre_trigger_samples = devc->capture_ratio * devc->limit_samples/100;
devc->stl = soft_trigger_logic_new(sdi, trigger, pre_trigger_samples); devc->stl = soft_trigger_logic_new(sdi, trigger, pre_trigger_samples);
if (!devc->stl) if (!devc->stl)
return SR_ERR_MALLOC; return SR_ERR_MALLOC;
@ -346,14 +320,9 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
std_session_send_df_header(sdi); std_session_send_df_header(sdi);
/* Trigger and add poll on file */ /* Trigger and add poll on file */
devc->beaglelogic->start(devc); beaglelogic_start(devc);
if (devc->beaglelogic == &beaglelogic_native_ops)
sr_session_source_add_pollfd(sdi->session, &devc->pollfd, sr_session_source_add_pollfd(sdi->session, &devc->pollfd,
BUFUNIT_TIMEOUT_MS(devc), beaglelogic_native_receive_data, BUFUNIT_TIMEOUT_MS(devc), beaglelogic_receive_data,
(void *)sdi);
else
sr_session_source_add_pollfd(sdi->session, &devc->pollfd,
BUFUNIT_TIMEOUT_MS(devc), beaglelogic_tcp_receive_data,
(void *)sdi); (void *)sdi);
return SR_OK; return SR_OK;
@ -363,14 +332,14 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi)
{ {
struct dev_context *devc = sdi->priv; struct dev_context *devc = sdi->priv;
/* Execute a stop on BeagleLogic */ if (sdi->status != SR_ST_ACTIVE)
devc->beaglelogic->stop(devc); return SR_ERR_DEV_CLOSED;
/* Flush the cache */ /* Execute a stop on BeagleLogic */
if (devc->beaglelogic == &beaglelogic_native_ops) beaglelogic_stop(devc);
/* lseek to offset 0, flushes the cache */
lseek(devc->fd, 0, SEEK_SET); lseek(devc->fd, 0, SEEK_SET);
else
beaglelogic_tcp_drain(devc);
/* Remove session source and send EOT packet */ /* Remove session source and send EOT packet */
sr_session_source_remove_pollfd(sdi->session, &devc->pollfd); sr_session_source_remove_pollfd(sdi->session, &devc->pollfd);
@ -387,7 +356,6 @@ static struct sr_dev_driver beaglelogic_driver_info = {
.cleanup = std_cleanup, .cleanup = std_cleanup,
.scan = scan, .scan = scan,
.dev_list = std_dev_list, .dev_list = std_dev_list,
.dev_clear = dev_clear,
.config_get = config_get, .config_get = config_get,
.config_set = config_set, .config_set = config_set,
.config_list = config_list, .config_list = config_list,

View File

@ -1,7 +1,7 @@
/* /*
* This file is part of the libsigrok project. * This file is part of the libsigrok project.
* *
* Copyright (C) 2014-2017 Kumar Abhishek <abhishek@theembeddedkitchen.net> * Copyright (C) 2014 Kumar Abhishek <abhishek@theembeddedkitchen.net>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -47,14 +47,12 @@
#define IOCTL_BL_GET_TRIGGER_FLAGS _IOR('k', 0x23, uint32_t) #define IOCTL_BL_GET_TRIGGER_FLAGS _IOR('k', 0x23, uint32_t)
#define IOCTL_BL_SET_TRIGGER_FLAGS _IOW('k', 0x23, uint32_t) #define IOCTL_BL_SET_TRIGGER_FLAGS _IOW('k', 0x23, uint32_t)
#define IOCTL_BL_GET_CUR_INDEX _IOR('k', 0x24, uint32_t)
#define IOCTL_BL_CACHE_INVALIDATE _IO('k', 0x25) #define IOCTL_BL_CACHE_INVALIDATE _IO('k', 0x25)
#define IOCTL_BL_GET_BUFFER_SIZE _IOR('k', 0x26, uint32_t) #define IOCTL_BL_GET_BUFFER_SIZE _IOR('k', 0x26, uint32_t)
#define IOCTL_BL_SET_BUFFER_SIZE _IOW('k', 0x26, uint32_t) #define IOCTL_BL_SET_BUFFER_SIZE _IOW('k', 0x26, uint32_t)
#define IOCTL_BL_GET_BUFUNIT_SIZE _IOR('k', 0x27, uint32_t) #define IOCTL_BL_GET_BUFUNIT_SIZE _IOR('k', 0x27, uint32_t)
#define IOCTL_BL_SET_BUFUNIT_SIZE _IOW('k', 0x27, uint32_t)
#define IOCTL_BL_FILL_TEST_PATTERN _IO('k', 0x28) #define IOCTL_BL_FILL_TEST_PATTERN _IO('k', 0x28)
@ -92,41 +90,120 @@ enum beaglelogic_sampleunit {
* SR_OK or SR_ERR * SR_OK or SR_ERR
*/ */
struct beaglelogic_ops { SR_PRIV int beaglelogic_open_nonblock(struct dev_context *devc);
int (*open)(struct dev_context *devc); SR_PRIV int beaglelogic_close(struct dev_context *devc);
int (*close)(struct dev_context *devc);
int (*get_buffersize)(struct dev_context *devc); SR_PRIV int beaglelogic_get_buffersize(struct dev_context *devc);
int (*set_buffersize)(struct dev_context *devc); SR_PRIV int beaglelogic_set_buffersize(struct dev_context *devc);
int (*get_samplerate)(struct dev_context *devc); SR_PRIV int beaglelogic_get_samplerate(struct dev_context *devc);
int (*set_samplerate)(struct dev_context *devc); SR_PRIV int beaglelogic_set_samplerate(struct dev_context *devc);
int (*get_sampleunit)(struct dev_context *devc); SR_PRIV int beaglelogic_get_sampleunit(struct dev_context *devc);
int (*set_sampleunit)(struct dev_context *devc); SR_PRIV int beaglelogic_set_sampleunit(struct dev_context *devc);
int (*get_triggerflags)(struct dev_context *devc); SR_PRIV int beaglelogic_get_triggerflags(struct dev_context *devc);
int (*set_triggerflags)(struct dev_context *devc); SR_PRIV int beaglelogic_set_triggerflags(struct dev_context *devc);
/* Start and stop the capture operation */ /* Start and stop the capture operation */
int (*start)(struct dev_context *devc); SR_PRIV int beaglelogic_start(struct dev_context *devc);
int (*stop)(struct dev_context *devc); SR_PRIV int beaglelogic_stop(struct dev_context *devc);
/* Get the last error size */ /* Get the last error size */
int (*get_lasterror)(struct dev_context *devc); SR_PRIV int beaglelogic_getlasterror(struct dev_context *devc);
/* Gets the unit size of the capture buffer (usually 4 or 8 MB) */ /* Gets the unit size of the capture buffer (usually 4 or 8 MB) */
int (*get_bufunitsize)(struct dev_context *devc); SR_PRIV int beaglelogic_get_bufunitsize(struct dev_context *devc);
int (*set_bufunitsize)(struct dev_context *devc);
int (*mmap)(struct dev_context *devc); SR_PRIV int beaglelogic_mmap(struct dev_context *devc);
int (*munmap)(struct dev_context *devc); SR_PRIV int beaglelogic_munmap(struct dev_context *devc);
};
SR_PRIV extern const struct beaglelogic_ops beaglelogic_native_ops; /* Sources */
SR_PRIV extern const struct beaglelogic_ops beaglelogic_tcp_ops; 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 int beaglelogic_tcp_detect(struct dev_context *devc); SR_PRIV inline int beaglelogic_close(struct dev_context *devc) {
SR_PRIV int beaglelogic_tcp_drain(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);
}
#endif #endif

View File

@ -1,155 +0,0 @@
/*
* 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;
ret = read(fd, buf, 16);
close(fd);
if (ret)
return SR_ERR;
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

@ -1,430 +0,0 @@
/*
* 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. * This file is part of the libsigrok project.
* *
* Copyright (C) 2014-2017 Kumar Abhishek <abhishek@theembeddedkitchen.net> * Copyright (C) 2014 Kumar Abhishek <abhishek@theembeddedkitchen.net>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -21,16 +21,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#ifdef _WIN32
#define _WIN32_WINNT 0x0501
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <sys/socket.h>
#endif
#include <errno.h>
#include "protocol.h" #include "protocol.h"
#include "beaglelogic.h"
/* Define data packet size independent of packet (bufunitsize bytes) size /* Define data packet size independent of packet (bufunitsize bytes) size
* from the BeagleLogic kernel module */ * from the BeagleLogic kernel module */
@ -41,7 +32,7 @@
* kernel buffers appropriately. It is up to the application which is * kernel buffers appropriately. It is up to the application which is
* using libsigrok to decide how to deal with the data. * using libsigrok to decide how to deal with the data.
*/ */
SR_PRIV int beaglelogic_native_receive_data(int fd, int revents, void *cb_data) SR_PRIV int beaglelogic_receive_data(int fd, int revents, void *cb_data)
{ {
const struct sr_dev_inst *sdi; const struct sr_dev_inst *sdi;
struct dev_context *devc; struct dev_context *devc;
@ -99,7 +90,7 @@ SR_PRIV int beaglelogic_native_receive_data(int fd, int revents, void *cb_data)
if ((devc->offset += packetsize) >= devc->buffersize) { if ((devc->offset += packetsize) >= devc->buffersize) {
/* One shot capture, we abort and settle with less than /* One shot capture, we abort and settle with less than
* the required number of samples */ * the required number of samples */
if (devc->triggerflags == BL_TRIGGERFLAGS_CONTINUOUS) if (devc->triggerflags)
devc->offset = 0; devc->offset = 0;
else else
packetsize = 0; packetsize = 0;
@ -116,90 +107,3 @@ SR_PRIV int beaglelogic_native_receive_data(int fd, int revents, void *cb_data)
return TRUE; return TRUE;
} }
SR_PRIV int beaglelogic_tcp_receive_data(int fd, int revents, void *cb_data)
{
const struct sr_dev_inst *sdi;
struct dev_context *devc;
struct sr_datafeed_packet packet;
struct sr_datafeed_logic logic;
int len;
int pre_trigger_samples;
int trigger_offset;
uint32_t packetsize;
uint64_t bytes_remaining;
if (!(sdi = cb_data) || !(devc = sdi->priv))
return TRUE;
packetsize = TCP_BUFFER_SIZE;
logic.unitsize = SAMPLEUNIT_TO_BYTES(devc->sampleunit);
if (revents == G_IO_IN) {
sr_info("In callback G_IO_IN");
len = recv(fd, devc->tcp_buffer, TCP_BUFFER_SIZE, 0);
if (len < 0) {
sr_err("Receive error: %s", g_strerror(errno));
return SR_ERR;
}
packetsize = len;
bytes_remaining = (devc->limit_samples * logic.unitsize) -
devc->bytes_read;
/* Configure data packet */
packet.type = SR_DF_LOGIC;
packet.payload = &logic;
logic.data = devc->tcp_buffer;
logic.length = MIN(packetsize, bytes_remaining);
if (devc->trigger_fired) {
/* Send the incoming transfer to the session bus. */
sr_session_send(sdi, &packet);
} else {
/* Check for trigger */
trigger_offset = soft_trigger_logic_check(devc->stl,
logic.data, packetsize, &pre_trigger_samples);
if (trigger_offset > -1) {
devc->bytes_read += pre_trigger_samples * logic.unitsize;
trigger_offset *= logic.unitsize;
logic.length = MIN(packetsize - trigger_offset,
bytes_remaining);
logic.data += trigger_offset;
sr_session_send(sdi, &packet);
devc->trigger_fired = TRUE;
}
}
/* Update byte count and offset (roll over if needed) */
devc->bytes_read += logic.length;
if ((devc->offset += packetsize) >= devc->buffersize) {
/* One shot capture, we abort and settle with less than
* the required number of samples */
if (devc->triggerflags == BL_TRIGGERFLAGS_CONTINUOUS)
devc->offset = 0;
else
packetsize = 0;
}
}
/* EOF Received or we have reached the limit */
if (devc->bytes_read >= devc->limit_samples * logic.unitsize ||
packetsize == 0) {
/* Send EOA Packet, stop polling */
std_session_send_df_end(sdi);
devc->beaglelogic->stop(devc);
/* Drain the receive buffer */
beaglelogic_tcp_drain(devc);
sr_session_source_remove_pollfd(sdi->session, &devc->pollfd);
}
return TRUE;
}

View File

@ -1,7 +1,7 @@
/* /*
* This file is part of the libsigrok project. * This file is part of the libsigrok project.
* *
* Copyright (C) 2014-2017 Kumar Abhishek <abhishek@theembeddedkitchen.net> * Copyright (C) 2014 Kumar Abhishek <abhishek@theembeddedkitchen.net>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -32,23 +32,12 @@
#define SAMPLEUNIT_TO_BYTES(x) ((x) == 1 ? 1 : 2) #define SAMPLEUNIT_TO_BYTES(x) ((x) == 1 ? 1 : 2)
#define TCP_BUFFER_SIZE (128 * 1024)
/** Private, per-device-instance driver context. */ /** Private, per-device-instance driver context. */
struct dev_context { struct dev_context {
/* Model-specific information */
int max_channels; int max_channels;
uint32_t fw_ver; uint32_t fw_ver;
/* Operations */
const struct beaglelogic_ops *beaglelogic;
/* TCP Settings */
char *address;
char *port;
int socket;
unsigned int read_timeout;
unsigned char *tcp_buffer;
/* Acquisition settings: see beaglelogic.h */ /* Acquisition settings: see beaglelogic.h */
uint64_t cur_samplerate; uint64_t cur_samplerate;
uint64_t limit_samples; uint64_t limit_samples;
@ -60,6 +49,7 @@ struct dev_context {
uint32_t bufunitsize; uint32_t bufunitsize;
uint32_t buffersize; uint32_t buffersize;
/* Operational state */
int fd; int fd;
GPollFD pollfd; GPollFD pollfd;
int last_error; int last_error;
@ -74,7 +64,6 @@ struct dev_context {
gboolean trigger_fired; gboolean trigger_fired;
}; };
SR_PRIV int beaglelogic_native_receive_data(int fd, int revents, void *cb_data); SR_PRIV int beaglelogic_receive_data(int fd, int revents, void *cb_data);
SR_PRIV int beaglelogic_tcp_receive_data(int fd, int revents, void *cb_data);
#endif #endif

View File

@ -0,0 +1,258 @@
/*
* 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

@ -0,0 +1,350 @@
/*
* 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

@ -1,7 +1,7 @@
/* /*
* This file is part of the libsigrok project. * This file is part of the libsigrok project.
* *
* Copyright (C) 2021 Frank Stettner <frank-stettner@gmx.net> * Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -17,26 +17,28 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef LIBSIGROK_HARDWARE_HP_59306A_PROTOCOL_H #ifndef LIBSIGROK_HARDWARE_BRYMEN_BM86X_PROTOCOL_H
#define LIBSIGROK_HARDWARE_HP_59306A_PROTOCOL_H #define LIBSIGROK_HARDWARE_BRYMEN_BM86X_PROTOCOL_H
#include <stdint.h> #include <stdint.h>
#include <glib.h> #include <glib.h>
#include <libsigrok/libsigrok.h> #include <libsigrok/libsigrok.h>
#include "libsigrok-internal.h" #include "libsigrok-internal.h"
#define LOG_PREFIX "hp-59306a" #define LOG_PREFIX "brymen-bm86x"
/** Private, per-device-instance driver context. */
struct dev_context { struct dev_context {
size_t channel_count; /* 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;
}; };
struct channel_group_context { SR_PRIV int brymen_bm86x_receive_data(int fd, int revents, void *cb_data);
/** The number of the channel group, as labled on the device. */
size_t number;
};
SR_PRIV int hp_59306a_switch_cg(const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg, gboolean enabled);
#endif #endif

View File

@ -0,0 +1,197 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@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>
#include "protocol.h"
static const uint32_t scanopts[] = {
SR_CONF_CONN,
SR_CONF_SERIALCOMM,
};
static const uint32_t devopts[] = {
SR_CONF_MULTIMETER,
SR_CONF_CONTINUOUS,
SR_CONF_LIMIT_SAMPLES | SR_CONF_SET,
SR_CONF_LIMIT_MSEC | SR_CONF_SET,
};
static GSList *brymen_scan(struct sr_dev_driver *di, const char *conn,
const char *serialcomm)
{
struct sr_dev_inst *sdi;
struct dev_context *devc;
struct sr_serial_dev_inst *serial;
GSList *devices;
int ret;
uint8_t buf[128];
size_t len;
serial = sr_serial_dev_inst_new(conn, serialcomm);
if (serial_open(serial, SERIAL_RDWR) != SR_OK)
return NULL;
sr_info("Probing port %s.", conn);
devices = NULL;
/* Request reading */
if ((ret = brymen_packet_request(serial)) < 0) {
sr_err("Unable to send command: %d.", ret);
goto scan_cleanup;
}
len = 128;
ret = brymen_stream_detect(serial, buf, &len, brymen_packet_length,
brymen_packet_is_valid, 1000, 9600);
if (ret != SR_OK)
goto scan_cleanup;
sr_info("Found device on port %s.", conn);
sdi = g_malloc0(sizeof(struct sr_dev_inst));
sdi->status = SR_ST_INACTIVE;
sdi->vendor = g_strdup("Brymen");
sdi->model = g_strdup("BM85x");
devc = g_malloc0(sizeof(struct dev_context));
sr_sw_limits_init(&devc->sw_limits);
sdi->inst_type = SR_INST_SERIAL;
sdi->conn = serial;
sdi->priv = devc;
sr_channel_new(sdi, 0, SR_CHANNEL_ANALOG, TRUE, "P1");
devices = g_slist_append(devices, sdi);
scan_cleanup:
serial_close(serial);
return std_scan_complete(di, devices);
}
static GSList *scan(struct sr_dev_driver *di, GSList *options)
{
struct sr_config *src;
GSList *devices, *l;
const char *conn, *serialcomm;
devices = NULL;
conn = serialcomm = NULL;
for (l = options; l; l = l->next) {
src = l->data;
switch (src->key) {
case SR_CONF_CONN:
conn = g_variant_get_string(src->data, NULL);
break;
case SR_CONF_SERIALCOMM:
serialcomm = g_variant_get_string(src->data, NULL);
break;
}
}
if (!conn)
return NULL;
if (serialcomm) {
/* Use the provided comm specs. */
devices = brymen_scan(di, conn, serialcomm);
} else {
/* But 9600/8n1 should work all of the time. */
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)
{
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;
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);
return SR_OK;
}
static struct sr_dev_driver brymen_bm857_driver_info = {
.name = "brymen-bm857",
.longname = "Brymen BM857",
.api_version = 1,
.init = std_init,
.cleanup = std_cleanup,
.scan = scan,
.dev_list = std_dev_list,
.dev_clear = NULL,
.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 = std_serial_dev_acquisition_stop,
.context = NULL,
};
SR_REGISTER_DEV_DRIVER(brymen_bm857_driver_info);

View File

@ -0,0 +1,290 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@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>
#include "protocol.h"
#define MAX_PACKET_LEN 22
/* Flags passed from the DMM. */
struct brymen_flags {
gboolean is_low_batt, is_decibel, is_duty_cycle, is_hertz, is_amp;
gboolean is_beep, is_ohm, is_fahrenheit, is_celsius, is_capacitance;
gboolean is_diode, is_volt, is_dc, is_ac;
};
struct bm850_command {
uint8_t dle;
uint8_t stx;
uint8_t cmd;
uint8_t arg[2];
uint8_t checksum;
uint8_t dle2;
uint8_t etx;
};
struct brymen_header {
uint8_t dle;
uint8_t stx;
uint8_t cmd;
uint8_t len;
};
struct brymen_tail {
uint8_t checksum;
uint8_t dle;
uint8_t etx;
};
/*
* We only have one command because we only support the BM-857. However, the
* driver is easily extensible to support more models, as the protocols are
* very similar.
*/
enum {
BM_CMD_REQUEST_READING = 0x00,
};
static int bm_send_command(uint8_t command, uint8_t arg1, uint8_t arg2,
struct sr_serial_dev_inst *serial)
{
struct bm850_command cmdout;
int written;
cmdout.dle = 0x10;
cmdout.stx = 0x02;
cmdout.cmd = command;
cmdout.arg[0] = arg1;
cmdout.arg[1] = arg2;
cmdout.checksum = arg1 ^ arg2;
cmdout.dle2 = 0x10;
cmdout.etx = 0x03;
/* TODO: How to compute the checksum? Hardware seems to ignore it. */
/* Request reading. */
written = serial_write_blocking(serial, &cmdout, sizeof(cmdout),
serial_timeout(serial, sizeof(cmdout)));
if (written != sizeof(cmdout))
return SR_ERR;
return SR_OK;
}
SR_PRIV int brymen_packet_request(struct sr_serial_dev_inst *serial)
{
return bm_send_command(BM_CMD_REQUEST_READING, 0, 0, serial);
}
SR_PRIV int brymen_packet_length(const uint8_t *buf, int *len)
{
struct brymen_header *hdr;
int packet_len;
size_t buflen;
buflen = *len;
hdr = (void *)buf;
/* Did we receive a complete header yet? */
if (buflen < sizeof(*hdr))
return PACKET_NEED_MORE_DATA;
if (hdr->dle != 0x10 || hdr->stx != 0x02)
return PACKET_INVALID_HEADER;
/* Our packet includes the header, the payload, and the tail. */
packet_len = sizeof(*hdr) + hdr->len + sizeof(struct brymen_tail);
/* In case we pick up an invalid header, limit our search. */
if (packet_len > MAX_PACKET_LEN) {
sr_spew("Header specifies an invalid payload length: %i.",
hdr->len);
return PACKET_INVALID_HEADER;
}
*len = packet_len;
sr_spew("Expecting a %d-byte packet.", *len);
return PACKET_HEADER_OK;
}
SR_PRIV gboolean brymen_packet_is_valid(const uint8_t *buf)
{
struct brymen_header *hdr;
struct brymen_tail *tail;
int i;
uint8_t chksum = 0;
uint8_t *payload;
payload = (uint8_t *)(buf + sizeof(struct brymen_header));
hdr = (void *)buf;
tail = (void *)(payload + hdr->len);
for (i = 0; i< hdr->len; i++)
chksum ^= payload[i];
if (tail->checksum != chksum) {
sr_dbg("Packet has invalid checksum 0x%.2x. Expected 0x%.2x.",
chksum, tail->checksum);
return FALSE;
}
return TRUE;
}
static int parse_value(const char *strbuf, int len, float *floatval)
{
int s, d;
char str[32];
if (strstr(strbuf, "OL")) {
sr_dbg("Overlimit.");
*floatval = INFINITY;
return SR_OK;
}
memset(str, 0, sizeof(str));
/* Spaces may interfere with parsing the exponent. Strip them. */
for (s = 0, d = 0; s < len; s++) {
if (strbuf[s] != ' ')
str[d++] = strbuf[s];
}
if (sr_atof_ascii(str, floatval) != SR_OK)
return SR_ERR;
return SR_OK;
}
static void parse_flags(const uint8_t *buf, struct brymen_flags *info)
{
info->is_low_batt = (buf[4 + 3] & (1 << 7)) != 0;
info->is_decibel = (buf[4 + 1] & (1 << 5)) != 0;
info->is_duty_cycle = (buf[4 + 1] & (1 << 3)) != 0;
info->is_hertz = (buf[4 + 1] & (1 << 2)) != 0;
info->is_amp = (buf[4 + 1] & (1 << 1)) != 0;
info->is_beep = (buf[4 + 1] & (1 << 0)) != 0;
info->is_ohm = (buf[4 + 0] & (1 << 7)) != 0;
info->is_fahrenheit = (buf[4 + 0] & (1 << 6)) != 0;
info->is_celsius = (buf[4 + 0] & (1 << 5)) != 0;
info->is_diode = (buf[4 + 0] & (1 << 4)) != 0;
info->is_capacitance = (buf[4 + 0] & (1 << 3)) != 0;
info->is_volt = (buf[4 + 0] & (1 << 2)) != 0;
info->is_dc = (buf[4 + 0] & (1 << 1)) != 0;
info->is_ac = (buf[4 + 0] & (1 << 0)) != 0;
}
SR_PRIV int brymen_parse(const uint8_t *buf, float *floatval,
struct sr_datafeed_analog *analog, void *info)
{
struct brymen_flags flags;
struct brymen_header *hdr;
uint8_t *bfunc;
int asciilen;
(void)info;
hdr = (void *)buf;
bfunc = (uint8_t *)(buf + sizeof(struct brymen_header));
analog->meaning->mqflags = 0;
/* Give some debug info about the package. */
asciilen = hdr->len - 4;
sr_dbg("DMM flags: %.2x %.2x %.2x %.2x",
bfunc[3], bfunc[2], bfunc[1], bfunc[0]);
/* Value is an ASCII string. */
sr_dbg("DMM packet: \"%.*s\"", asciilen, bfunc + 4);
parse_flags(buf, &flags);
if (parse_value((const char *)(bfunc + 4), asciilen, floatval) != SR_OK)
return SR_ERR;
if (flags.is_volt) {
analog->meaning->mq = SR_MQ_VOLTAGE;
analog->meaning->unit = SR_UNIT_VOLT;
}
if (flags.is_amp) {
analog->meaning->mq = SR_MQ_CURRENT;
analog->meaning->unit = SR_UNIT_AMPERE;
}
if (flags.is_ohm) {
if (flags.is_beep)
analog->meaning->mq = SR_MQ_CONTINUITY;
else
analog->meaning->mq = SR_MQ_RESISTANCE;
analog->meaning->unit = SR_UNIT_OHM;
}
if (flags.is_hertz) {
analog->meaning->mq = SR_MQ_FREQUENCY;
analog->meaning->unit = SR_UNIT_HERTZ;
}
if (flags.is_duty_cycle) {
analog->meaning->mq = SR_MQ_DUTY_CYCLE;
analog->meaning->unit = SR_UNIT_PERCENTAGE;
}
if (flags.is_capacitance) {
analog->meaning->mq = SR_MQ_CAPACITANCE;
analog->meaning->unit = SR_UNIT_FARAD;
}
if (flags.is_fahrenheit) {
analog->meaning->mq = SR_MQ_TEMPERATURE;
analog->meaning->unit = SR_UNIT_FAHRENHEIT;
}
if (flags.is_celsius) {
analog->meaning->mq = SR_MQ_TEMPERATURE;
analog->meaning->unit = SR_UNIT_CELSIUS;
}
if (flags.is_capacitance) {
analog->meaning->mq = SR_MQ_CAPACITANCE;
analog->meaning->unit = SR_UNIT_FARAD;
}
/*
* The high-end Brymen models have a configurable reference impedance.
* When the reference impedance is changed, the DMM sends one packet
* with the value of the new reference impedance. Both decibel and ohm
* flags are set in this case, so we must be careful to correctly
* identify the value as ohm, not dBmW.
*/
if (flags.is_decibel && !flags.is_ohm) {
analog->meaning->mq = SR_MQ_POWER;
analog->meaning->unit = SR_UNIT_DECIBEL_MW;
/*
* For some reason, dBm measurements are sent by the multimeter
* with a value three orders of magnitude smaller than the
* displayed value.
*/
*floatval *= 1000;
}
if (flags.is_diode)
analog->meaning->mqflags |= SR_MQFLAG_DIODE;
/* We can have both AC+DC in a single measurement. */
if (flags.is_ac)
analog->meaning->mqflags |= SR_MQFLAG_AC;
if (flags.is_dc)
analog->meaning->mqflags |= SR_MQFLAG_DC;
if (flags.is_low_batt)
sr_info("Low battery!");
return SR_OK;
}

View File

@ -0,0 +1,256 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@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>
#include "protocol.h"
static void handle_packet(const uint8_t *buf, struct sr_dev_inst *sdi)
{
float floatval;
struct dev_context *devc;
struct sr_datafeed_packet packet;
struct sr_datafeed_analog analog;
struct sr_analog_encoding encoding;
struct sr_analog_meaning meaning;
struct sr_analog_spec spec;
devc = sdi->priv;
/* TODO: Use proper 'digits' value for this device (and its modes). */
sr_analog_init(&analog, &encoding, &meaning, &spec, 2);
analog.num_samples = 1;
analog.meaning->mq = 0;
if (brymen_parse(buf, &floatval, &analog, NULL) != SR_OK)
return;
analog.data = &floatval;
analog.meaning->channels = sdi->channels;
if (analog.meaning->mq != 0) {
/* Got a measurement. */
packet.type = SR_DF_ANALOG;
packet.payload = &analog;
sr_session_send(sdi, &packet);
sr_sw_limits_update_samples_read(&devc->sw_limits, 1);
}
}
static void handle_new_data(struct sr_dev_inst *sdi)
{
struct dev_context *devc;
int len, status, offset = 0;
struct sr_serial_dev_inst *serial;
devc = sdi->priv;
serial = sdi->conn;
/* Try to get as much data as the buffer can hold. */
len = DMM_BUFSIZE - devc->buflen;
len = serial_read_nonblocking(serial, devc->buf + devc->buflen, len);
if (len < 1) {
sr_err("Serial port read error: %d.", len);
return;
}
devc->buflen += len;
status = PACKET_INVALID_HEADER;
/* Now look for packets in that data. */
while (status != PACKET_NEED_MORE_DATA) {
/* We don't have a header, look for one. */
if (devc->next_packet_len == 0) {
len = devc->buflen - offset;
status = brymen_packet_length(devc->buf + offset, &len);
if (status == PACKET_HEADER_OK) {
/* We know how large the packet will be. */
devc->next_packet_len = len;
} else if (status == PACKET_NEED_MORE_DATA) {
/* We didn't yet receive the full header. */
devc->next_packet_len = 0;
break;
} else {
/* Invalid header. Move on. */
devc->next_packet_len = 0;
offset++;
continue;
}
}
/* We know how the packet size, but did we receive all of it? */
if (devc->buflen - offset < devc->next_packet_len)
break;
/* We should have a full packet here, so we can check it. */
if (brymen_packet_is_valid(devc->buf + offset)) {
handle_packet(devc->buf + offset, sdi);
offset += devc->next_packet_len;
} else {
offset++;
}
/* We are done with this packet. Look for a new one. */
devc->next_packet_len = 0;
}
/* If we have any data left, move it to the beginning of our buffer. */
memmove(devc->buf, devc->buf + offset, devc->buflen - offset);
devc->buflen -= offset;
}
SR_PRIV int brymen_dmm_receive_data(int fd, int revents, void *cb_data)
{
struct sr_dev_inst *sdi;
struct dev_context *devc;
struct sr_serial_dev_inst *serial;
int ret;
(void)fd;
if (!(sdi = cb_data))
return TRUE;
if (!(devc = sdi->priv))
return TRUE;
serial = sdi->conn;
if (revents == G_IO_IN) {
/* Serial data arrived. */
handle_new_data(sdi);
} else {
/* Timeout, send another packet request. */
if ((ret = brymen_packet_request(serial)) < 0) {
sr_err("Failed to request packet: %d.", ret);
return FALSE;
}
}
if (sr_sw_limits_check(&devc->sw_limits))
sdi->driver->dev_acquisition_stop(sdi);
return TRUE;
}
/**
* Try to find a valid packet in a serial data stream.
*
* @param serial Previously initialized serial port structure.
* @param buf Buffer containing the bytes to write.
* @param buflen Size of the buffer.
* @param get_packet_size Callback that assesses the size of incoming packets.
* @param is_valid Callback that assesses whether the packet is valid or not.
* @param timeout_ms The timeout after which, if no packet is detected, to
* abort scanning.
* @param baudrate The baudrate of the serial port. This parameter is not
* critical, but it helps fine tune the serial port polling
* delay.
*
* @return SR_OK if a valid packet is found within the given timeout,
* SR_ERR upon failure.
*/
SR_PRIV int brymen_stream_detect(struct sr_serial_dev_inst *serial,
uint8_t *buf, size_t *buflen,
packet_length_t get_packet_size,
packet_valid_callback is_valid,
uint64_t timeout_ms, int baudrate)
{
int64_t start, time, byte_delay_us;
size_t ibuf, i, maxlen;
ssize_t len, stream_len;
int packet_len;
int status;
maxlen = *buflen;
sr_dbg("Detecting packets on %s (timeout = %" PRIu64
"ms, baudrate = %d).", serial->port, timeout_ms, baudrate);
/* Assume 8n1 transmission. That is 10 bits for every byte. */
byte_delay_us = 10 * ((1000 * 1000) / baudrate);
start = g_get_monotonic_time();
packet_len = i = ibuf = len = 0;
while (ibuf < maxlen) {
len = serial_read_nonblocking(serial, &buf[ibuf], maxlen - ibuf);
if (len > 0) {
ibuf += len;
sr_spew("Read %zd bytes.", len);
}
time = g_get_monotonic_time() - start;
time /= 1000;
stream_len = ibuf - i;
if (stream_len > 0 && packet_len == 0) {
/* How large of a packet are we expecting? */
packet_len = stream_len;
status = get_packet_size(&buf[i], &packet_len);
switch (status) {
case PACKET_HEADER_OK:
/* We know how much data we need to wait for. */
break;
case PACKET_NEED_MORE_DATA:
/* We did not receive the full header. */
packet_len = 0;
break;
case PACKET_INVALID_HEADER:
default:
/*
* We had enough data, but here was an error in
* parsing the header. Restart parsing from the
* next byte.
*/
packet_len = 0;
i++;
break;
}
}
if ((stream_len >= packet_len) && (packet_len != 0)) {
/* We have at least a packet's worth of data. */
if (is_valid(&buf[i])) {
sr_spew("Found valid %d-byte packet after "
"%" PRIu64 "ms.", packet_len, time);
*buflen = ibuf;
return SR_OK;
} else {
sr_spew("Got %d bytes, but not a valid "
"packet.", packet_len);
}
/* Not a valid packet. Continue searching. */
i++;
packet_len = 0;
}
if (time >= (int64_t)timeout_ms) {
/* Timeout */
sr_dbg("Detection timed out after %" PRIi64 "ms.", time);
break;
}
g_usleep(byte_delay_us);
}
*buflen = ibuf;
sr_err("Didn't find a valid packet (read %zu bytes).", ibuf);
return SR_ERR;
}

View File

@ -0,0 +1,75 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@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/>.
*/
#ifndef LIBSIGROK_HARDWARE_BRYMEN_DMM_PROTOCOL_H
#define LIBSIGROK_HARDWARE_BRYMEN_DMM_PROTOCOL_H
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <glib.h>
#include <libsigrok/libsigrok.h>
#include "libsigrok-internal.h"
#define LOG_PREFIX "brymen-dmm"
#define DMM_BUFSIZE 256
enum packet_len_status {
PACKET_HEADER_OK,
PACKET_NEED_MORE_DATA,
PACKET_INVALID_HEADER,
};
/** Private, per-device-instance driver context. */
struct dev_context {
struct sr_sw_limits sw_limits;
uint8_t buf[DMM_BUFSIZE];
int bufoffset;
int buflen;
int next_packet_len;
};
/**
* Callback that assesses the size and status of the incoming packet.
*
* @return PACKET_HEADER_OK - This is a proper packet header.
* PACKET_NEED_MORE_DATA The buffer does not contain the entire header.
* PACKET_INVALID_HEADER Not a valid start of packet.
*/
typedef int (*packet_length_t)(const uint8_t *buf, int *len);
SR_PRIV int brymen_dmm_receive_data(int fd, int revents, void *cb_data);
SR_PRIV int brymen_packet_request(struct sr_serial_dev_inst *serial);
SR_PRIV int brymen_packet_length(const uint8_t *buf, int *len);
SR_PRIV gboolean brymen_packet_is_valid(const uint8_t *buf);
SR_PRIV int brymen_parse(const uint8_t *buf, float *floatval,
struct sr_datafeed_analog *analog, void *info);
SR_PRIV int brymen_stream_detect(struct sr_serial_dev_inst *serial,
uint8_t *buf, size_t *buflen,
packet_length_t get_packet_size,
packet_valid_callback is_valid,
uint64_t timeout_ms, int baudrate);
#endif

View File

@ -125,10 +125,11 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
return std_scan_complete(di, devices); return std_scan_complete(di, devices);
} }
static int config_get(uint32_t key, GVariant **data, static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) const struct sr_channel_group *cg)
{ {
struct dev_context *devc; struct dev_context *devc;
GVariant *range[2];
uint64_t low, high; uint64_t low, high;
int tmp, ret; int tmp, ret;
@ -138,9 +139,7 @@ static int config_get(uint32_t key, GVariant **data,
return SR_ERR_ARG; return SR_ERR_ARG;
devc = sdi->priv; devc = sdi->priv;
ret = SR_OK; ret = SR_OK;
switch (key) { switch (key) {
case SR_CONF_LIMIT_SAMPLES: case SR_CONF_LIMIT_SAMPLES:
*data = g_variant_new_uint64(devc->limit_samples); *data = g_variant_new_uint64(devc->limit_samples);
@ -176,8 +175,11 @@ static int config_get(uint32_t key, GVariant **data,
*data = g_variant_new_boolean(tmp == SR_MQFLAG_MIN); *data = g_variant_new_boolean(tmp == SR_MQFLAG_MIN);
break; break;
case SR_CONF_SPL_MEASUREMENT_RANGE: case SR_CONF_SPL_MEASUREMENT_RANGE:
if ((ret = cem_dt_885x_meas_range_get(sdi, &low, &high)) == SR_OK) if ((ret = cem_dt_885x_meas_range_get(sdi, &low, &high)) == SR_OK) {
*data = std_gvar_tuple_u64(low, high); range[0] = g_variant_new_uint64(low);
range[1] = g_variant_new_uint64(high);
*data = g_variant_new_tuple(range, 2);
}
break; break;
case SR_CONF_POWER_OFF: case SR_CONF_POWER_OFF:
*data = g_variant_new_boolean(FALSE); *data = g_variant_new_boolean(FALSE);
@ -195,83 +197,148 @@ static int config_get(uint32_t key, GVariant **data,
return ret; return ret;
} }
static int config_set(uint32_t key, GVariant *data, static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) const struct sr_channel_group *cg)
{ {
struct dev_context *devc; struct dev_context *devc;
int tmp, idx; uint64_t tmp_u64, low, high;
unsigned int i;
int tmp, ret;
const char *tmp_str;
(void)cg; (void)cg;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv; devc = sdi->priv;
ret = SR_OK;
switch (key) { switch (key) {
case SR_CONF_LIMIT_SAMPLES: case SR_CONF_LIMIT_SAMPLES:
devc->limit_samples = g_variant_get_uint64(data); tmp_u64 = g_variant_get_uint64(data);
devc->limit_samples = tmp_u64;
ret = SR_OK;
break; break;
case SR_CONF_DATALOG: case SR_CONF_DATALOG:
return cem_dt_885x_recording_set(sdi, g_variant_get_boolean(data)); ret = cem_dt_885x_recording_set(sdi, g_variant_get_boolean(data));
break;
case SR_CONF_SPL_WEIGHT_FREQ: case SR_CONF_SPL_WEIGHT_FREQ:
if ((idx = std_str_idx(data, ARRAY_AND_SIZE(weight_freq))) < 0) 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
return SR_ERR_ARG; return SR_ERR_ARG;
return cem_dt_885x_weight_freq_set(sdi, (weight_freq[idx][0] == 'A') ? break;
SR_MQFLAG_SPL_FREQ_WEIGHT_A : SR_MQFLAG_SPL_FREQ_WEIGHT_C);
case SR_CONF_SPL_WEIGHT_TIME: case SR_CONF_SPL_WEIGHT_TIME:
if ((idx = std_str_idx(data, ARRAY_AND_SIZE(weight_time))) < 0) 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
return SR_ERR_ARG; return SR_ERR_ARG;
return cem_dt_885x_weight_time_set(sdi, (weight_time[idx][0] == 'F') ? break;
SR_MQFLAG_SPL_TIME_WEIGHT_F : SR_MQFLAG_SPL_TIME_WEIGHT_S);
case SR_CONF_HOLD_MAX: case SR_CONF_HOLD_MAX:
tmp = g_variant_get_boolean(data) ? SR_MQFLAG_MAX : 0; tmp = g_variant_get_boolean(data) ? SR_MQFLAG_MAX : 0;
return cem_dt_885x_holdmode_set(sdi, tmp); ret = cem_dt_885x_holdmode_set(sdi, tmp);
break;
case SR_CONF_HOLD_MIN: case SR_CONF_HOLD_MIN:
tmp = g_variant_get_boolean(data) ? SR_MQFLAG_MIN : 0; tmp = g_variant_get_boolean(data) ? SR_MQFLAG_MIN : 0;
return cem_dt_885x_holdmode_set(sdi, tmp); ret = cem_dt_885x_holdmode_set(sdi, tmp);
break;
case SR_CONF_SPL_MEASUREMENT_RANGE: case SR_CONF_SPL_MEASUREMENT_RANGE:
if ((idx = std_u64_tuple_idx(data, ARRAY_AND_SIZE(meas_ranges))) < 0) g_variant_get(data, "(tt)", &low, &high);
return SR_ERR_ARG; ret = SR_ERR_ARG;
return cem_dt_885x_meas_range_set(sdi, meas_ranges[idx][0], meas_ranges[idx][1]); 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;
case SR_CONF_POWER_OFF: case SR_CONF_POWER_OFF:
if (g_variant_get_boolean(data)) if (g_variant_get_boolean(data))
return cem_dt_885x_power_off(sdi); ret = cem_dt_885x_power_off(sdi);
break; break;
case SR_CONF_DATA_SOURCE: case SR_CONF_DATA_SOURCE:
if ((idx = std_str_idx(data, ARRAY_AND_SIZE(data_sources))) < 0) tmp_str = g_variant_get_string(data, NULL);
return SR_ERR_ARG; if (!strcmp(tmp_str, "Live"))
devc->cur_data_source = idx; devc->cur_data_source = DATA_SOURCE_LIVE;
devc->enable_data_source_memory = (idx == DATA_SOURCE_MEMORY); 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;
break; break;
default: default:
return SR_ERR_NA; ret = SR_ERR_NA;
} }
return SR_OK; return ret;
} }
static int config_list(uint32_t key, GVariant **data, static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) const struct sr_channel_group *cg)
{ {
GVariant *tuple, *range[2];
GVariantBuilder gvb;
unsigned int i;
int ret;
(void)cg;
ret = SR_OK;
if (!sdi) {
switch (key) { switch (key) {
case SR_CONF_SCAN_OPTIONS: case SR_CONF_SCAN_OPTIONS:
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
break;
case SR_CONF_DEVICE_OPTIONS: case SR_CONF_DEVICE_OPTIONS:
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts); *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
case SR_CONF_SPL_WEIGHT_FREQ: drvopts, ARRAY_SIZE(drvopts), sizeof(uint32_t));
*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; break;
default: default:
return SR_ERR_NA; 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;
}
}
return SR_OK; return ret;
} }
static int dev_acquisition_start(const struct sr_dev_inst *sdi) static int dev_acquisition_start(const struct sr_dev_inst *sdi)
@ -279,6 +346,9 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
struct dev_context *devc; struct dev_context *devc;
struct sr_serial_dev_inst *serial; struct sr_serial_dev_inst *serial;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv; devc = sdi->priv;
devc->state = ST_INIT; devc->state = ST_INIT;
devc->num_samples = 0; devc->num_samples = 0;
@ -286,6 +356,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
std_session_send_df_header(sdi); std_session_send_df_header(sdi);
/* Poll every 100ms, or whenever some data comes in. */
serial = sdi->conn; serial = sdi->conn;
serial_source_add(sdi->session, serial, G_IO_IN, 150, serial_source_add(sdi->session, serial, G_IO_IN, 150,
cem_dt_885x_receive_data, (void *)sdi); cem_dt_885x_receive_data, (void *)sdi);
@ -301,7 +372,7 @@ static struct sr_dev_driver cem_dt_885x_driver_info = {
.cleanup = std_cleanup, .cleanup = std_cleanup,
.scan = scan, .scan = scan,
.dev_list = std_dev_list, .dev_list = std_dev_list,
.dev_clear = std_dev_clear, .dev_clear = NULL,
.config_get = config_get, .config_get = config_get,
.config_set = config_set, .config_set = config_set,
.config_list = config_list, .config_list = config_list,

View File

@ -147,7 +147,7 @@ static void process_mset(const struct sr_dev_inst *sdi)
devc->num_samples++; devc->num_samples++;
if (devc->limit_samples && devc->num_samples >= devc->limit_samples) if (devc->limit_samples && devc->num_samples >= devc->limit_samples)
sr_dev_acquisition_stop((struct sr_dev_inst *)sdi); sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi);
break; break;
case TOKEN_RECORDING_ON: case TOKEN_RECORDING_ON:
devc->recording = TRUE; devc->recording = TRUE;
@ -208,7 +208,7 @@ static void send_data(const struct sr_dev_inst *sdi, unsigned char *data,
devc->num_samples += analog.num_samples; devc->num_samples += analog.num_samples;
if (devc->limit_samples && devc->num_samples >= devc->limit_samples) if (devc->limit_samples && devc->num_samples >= devc->limit_samples)
sr_dev_acquisition_stop((struct sr_dev_inst *)sdi); sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi);
return; return;
} }
@ -321,7 +321,7 @@ static void process_byte(const struct sr_dev_inst *sdi, const unsigned char c,
* records. Otherwise the frontend would have no * records. Otherwise the frontend would have no
* way to tell where stored data ends and live * way to tell where stored data ends and live
* measurements begin. */ * measurements begin. */
sr_dev_acquisition_stop((struct sr_dev_inst *)sdi); sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi);
} else if (c == RECORD_DATA) { } else if (c == RECORD_DATA) {
devc->buf_len = 0; devc->buf_len = 0;
devc->state = ST_GET_LOG_RECORD_DATA; devc->state = ST_GET_LOG_RECORD_DATA;
@ -346,8 +346,7 @@ static void process_byte(const struct sr_dev_inst *sdi, const unsigned char c,
g_variant_new_uint64(devc->buf[7] * 1000)); g_variant_new_uint64(devc->buf[7] * 1000));
meta.config = g_slist_append(NULL, src); meta.config = g_slist_append(NULL, src);
sr_session_send(sdi, &packet); sr_session_send(sdi, &packet);
g_slist_free(meta.config); g_free(src);
sr_config_free(src);
devc->buf_len = 0; devc->buf_len = 0;
} }
} else if (devc->state == ST_GET_LOG_RECORD_DATA) { } else if (devc->state == ST_GET_LOG_RECORD_DATA) {
@ -401,7 +400,7 @@ SR_PRIV int cem_dt_885x_receive_data(int fd, int revents, void *cb_data)
} else { } else {
/* Tell device to start transferring from memory. */ /* Tell device to start transferring from memory. */
cmd = CMD_TRANSFER_MEMORY; cmd = CMD_TRANSFER_MEMORY;
serial_write_blocking(serial, &cmd, 1, 0); serial_write_nonblocking(serial, &cmd, 1);
} }
} }
} }
@ -457,7 +456,7 @@ static int cem_dt_885x_toggle(const struct sr_dev_inst *sdi, uint8_t cmd,
* only thing to do is wait for the token that will confirm * only thing to do is wait for the token that will confirm
* whether the command worked or not, and resend if needed. */ * whether the command worked or not, and resend if needed. */
while (TRUE) { while (TRUE) {
if (serial_write_blocking(serial, (const void *)&cmd, 1, 0) < 0) if (serial_write_nonblocking(serial, (const void *)&cmd, 1) != 1)
return SR_ERR; return SR_ERR;
if (wait_for_token(sdi, tokens, timeout) == SR_ERR) if (wait_for_token(sdi, tokens, timeout) == SR_ERR)
return SR_ERR; return SR_ERR;
@ -818,7 +817,7 @@ SR_PRIV int cem_dt_885x_power_off(const struct sr_dev_inst *sdi)
cmd = CMD_TOGGLE_POWER_OFF; cmd = CMD_TOGGLE_POWER_OFF;
while (TRUE) { while (TRUE) {
serial_flush(serial); serial_flush(serial);
if (serial_write_blocking(serial, (const void *)&cmd, 1, 0) < 0) if (serial_write_nonblocking(serial, (const void *)&cmd, 1) != 1)
return SR_ERR; return SR_ERR;
/* It never takes more than 23ms for the next token to arrive. */ /* It never takes more than 23ms for the next token to arrive. */
g_usleep(25 * 1000); g_usleep(25 * 1000);

View File

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

View File

@ -67,6 +67,8 @@ static GSList *center_scan(const char *conn, const char *serialcomm, int idx)
if (serial_open(serial, SERIAL_RDWR) != SR_OK) if (serial_open(serial, SERIAL_RDWR) != SR_OK)
return NULL; return NULL;
serial_flush(serial);
sr_info("Found device on port %s.", conn); sr_info("Found device on port %s.", conn);
sdi = g_malloc0(sizeof(struct sr_dev_inst)); sdi = g_malloc0(sizeof(struct sr_dev_inst));
@ -107,30 +109,55 @@ static GSList *scan(GSList *options, int idx)
if (!conn) if (!conn)
return NULL; return NULL;
if (serialcomm) if (serialcomm) {
/* Use the provided comm specs. */
devices = center_scan(conn, serialcomm, idx); devices = center_scan(conn, serialcomm, idx);
else } else {
/* Try the default. */
devices = center_scan(conn, center_devs[idx].conn, idx); devices = center_scan(conn, center_devs[idx].conn, idx);
}
return std_scan_complete(center_devs[idx].di, devices); return std_scan_complete(center_devs[idx].di, devices);
} }
static int config_set(uint32_t key, GVariant *data, static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) const struct sr_channel_group *cg)
{ {
struct dev_context *devc; struct dev_context *devc;
(void)cg; (void)cg;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv; devc = sdi->priv;
return sr_sw_limits_config_set(&devc->sw_limits, key, data); return sr_sw_limits_config_set(&devc->sw_limits, key, data);
} }
static int config_list(uint32_t key, GVariant **data, static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) const struct sr_channel_group *cg)
{ {
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts); (void)cg;
switch (key) {
case SR_CONF_SCAN_OPTIONS:
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
break;
case SR_CONF_DEVICE_OPTIONS:
if (!sdi)
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
drvopts, ARRAY_SIZE(drvopts), sizeof(uint32_t));
else
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
break;
default:
return SR_ERR_NA;
}
return SR_OK;
} }
static int dev_acquisition_start(const struct sr_dev_inst *sdi, int idx) static int dev_acquisition_start(const struct sr_dev_inst *sdi, int idx)
@ -138,12 +165,16 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi, int idx)
struct dev_context *devc; struct dev_context *devc;
struct sr_serial_dev_inst *serial; struct sr_serial_dev_inst *serial;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv; devc = sdi->priv;
sr_sw_limits_acquisition_start(&devc->sw_limits); sr_sw_limits_acquisition_start(&devc->sw_limits);
std_session_send_df_header(sdi); std_session_send_df_header(sdi);
/* Poll every 500ms, or whenever some data comes in. */
serial = sdi->conn; serial = sdi->conn;
serial_source_add(sdi->session, serial, G_IO_IN, 500, serial_source_add(sdi->session, serial, G_IO_IN, 500,
center_devs[idx].receive_data, (void *)sdi); center_devs[idx].receive_data, (void *)sdi);
@ -171,7 +202,6 @@ static struct sr_dev_driver ID##_driver_info = { \
.cleanup = std_cleanup, \ .cleanup = std_cleanup, \
.scan = scan_##ID_UPPER, \ .scan = scan_##ID_UPPER, \
.dev_list = std_dev_list, \ .dev_list = std_dev_list, \
.dev_clear = std_dev_clear, \
.config_get = NULL, \ .config_get = NULL, \
.config_set = config_set, \ .config_set = config_set, \
.config_list = config_list, \ .config_list = config_list, \

View File

@ -64,7 +64,7 @@ static void log_packet(const uint8_t *buf, int idx)
static int packet_parse(const uint8_t *buf, int idx, struct center_info *info) static int packet_parse(const uint8_t *buf, int idx, struct center_info *info)
{ {
int i; int i;
int16_t temp_i16; uint16_t temp_u16;
log_packet(buf, idx); log_packet(buf, idx);
@ -89,8 +89,9 @@ static int packet_parse(const uint8_t *buf, int idx, struct center_info *info)
/* Byte 7+8/9+10/11+12/13+14: channel T1/T2/T3/T4 temperature. */ /* Byte 7+8/9+10/11+12/13+14: channel T1/T2/T3/T4 temperature. */
for (i = 0; i < NUM_CHANNELS; i++) { for (i = 0; i < NUM_CHANNELS; i++) {
temp_i16 = RB16S(&buf[7 + 2 * i]); temp_u16 = buf[8 + (i * 2)];
info->temp[i] = (float)temp_i16; temp_u16 |= ((uint16_t)buf[7 + (i * 2)] << 8);
info->temp[i] = (float)temp_u16;
} }
/* Byte 43: Specifies whether we need to divide the value(s) by 10. */ /* Byte 43: Specifies whether we need to divide the value(s) by 10. */
@ -176,7 +177,7 @@ static gboolean handle_new_data(struct sr_dev_inst *sdi, int idx)
{ {
struct dev_context *devc; struct dev_context *devc;
struct sr_serial_dev_inst *serial; struct sr_serial_dev_inst *serial;
int len, offset, ret = FALSE; int len, i, offset = 0, ret = FALSE;
devc = sdi->priv; devc = sdi->priv;
serial = sdi->conn; serial = sdi->conn;
@ -192,7 +193,6 @@ static gboolean handle_new_data(struct sr_dev_inst *sdi, int idx)
devc->buflen += len; devc->buflen += len;
/* Now look for packets in that data. */ /* Now look for packets in that data. */
offset = 0;
while ((devc->buflen - offset) >= center_devs[idx].packet_size) { while ((devc->buflen - offset) >= center_devs[idx].packet_size) {
if (center_devs[idx].packet_valid(devc->buf + offset)) { if (center_devs[idx].packet_valid(devc->buf + offset)) {
handle_packet(devc->buf + offset, sdi, idx); handle_packet(devc->buf + offset, sdi, idx);
@ -204,8 +204,8 @@ static gboolean handle_new_data(struct sr_dev_inst *sdi, int idx)
} }
/* If we have any data left, move it to the beginning of our buffer. */ /* If we have any data left, move it to the beginning of our buffer. */
if (offset < devc->buflen) for (i = 0; i < devc->buflen - offset; i++)
memmove(devc->buf, devc->buf + offset, devc->buflen - offset); devc->buf[i] = devc->buf[offset + i];
devc->buflen -= offset; devc->buflen -= offset;
return ret; return ret;
@ -243,7 +243,7 @@ static int receive_data(int fd, int revents, int idx, void *cb_data)
} }
if (sr_sw_limits_check(&devc->sw_limits)) if (sr_sw_limits_check(&devc->sw_limits))
sr_dev_acquisition_stop(sdi); sdi->driver->dev_acquisition_stop(sdi);
return TRUE; return TRUE;
} }

View File

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

View File

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

View File

@ -202,7 +202,7 @@ static int close_usb_reset_sequencer(struct dev_context *devc)
sr_dbg("Purging buffers, resetting+closing FTDI device."); sr_dbg("Purging buffers, resetting+closing FTDI device.");
/* Log errors, but ignore them (i.e., don't abort). */ /* Log errors, but ignore them (i.e., don't abort). */
if ((ret = ftdi_tcioflush(devc->ftdic)) < 0) if ((ret = ftdi_usb_purge_buffers(devc->ftdic)) < 0)
sr_err("Failed to purge FTDI buffers (%d): %s.", sr_err("Failed to purge FTDI buffers (%d): %s.",
ret, ftdi_get_error_string(devc->ftdic)); ret, ftdi_get_error_string(devc->ftdic));
if ((ret = ftdi_usb_reset(devc->ftdic)) < 0) if ((ret = ftdi_usb_reset(devc->ftdic)) < 0)
@ -300,11 +300,6 @@ SR_PRIV int cv_convert_trigger(const struct sr_dev_inst *sdi)
|| match->match == SR_TRIGGER_RISING) || match->match == SR_TRIGGER_RISING)
devc->trigger_pattern |= channel_bit; 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. */ /* LA16 (but not LA8) supports edge triggering. */
if ((devc->prof->model == CHRONOVU_LA16)) { if ((devc->prof->model == CHRONOVU_LA16)) {
if (match->match == SR_TRIGGER_RISING if (match->match == SR_TRIGGER_RISING
@ -494,7 +489,9 @@ SR_PRIV void cv_send_block_to_session_bus(const struct sr_dev_inst *sdi, int blo
/* Send the SR_DF_TRIGGER packet to the session bus. */ /* Send the SR_DF_TRIGGER packet to the session bus. */
sr_spew("Sending SR_DF_TRIGGER packet, sample = %d.", sr_spew("Sending SR_DF_TRIGGER packet, sample = %d.",
(block * BS) + trigger_point); (block * BS) + trigger_point);
std_session_send_df_trigger(sdi); packet.type = SR_DF_TRIGGER;
packet.payload = NULL;
sr_session_send(sdi, &packet);
/* If at least one sample is located after the trigger... */ /* If at least one sample is located after the trigger... */
if (trigger_point < (BS - 1)) { if (trigger_point < (BS - 1)) {

View File

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

View File

@ -35,11 +35,8 @@ static const uint32_t scanopts[] = {
SR_CONF_SERIALCOMM, SR_CONF_SERIALCOMM,
}; };
static const uint32_t drvopts[] = {
SR_CONF_SOUNDLEVELMETER,
};
static const uint32_t devopts[] = { static const uint32_t devopts[] = {
SR_CONF_SOUNDLEVELMETER,
SR_CONF_CONTINUOUS, SR_CONF_CONTINUOUS,
SR_CONF_LIMIT_SAMPLES | SR_CONF_SET, SR_CONF_LIMIT_SAMPLES | SR_CONF_SET,
SR_CONF_LIMIT_MSEC | SR_CONF_SET, SR_CONF_LIMIT_MSEC | SR_CONF_SET,
@ -84,22 +81,41 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
return std_scan_complete(di, g_slist_append(NULL, sdi)); return std_scan_complete(di, g_slist_append(NULL, sdi));
} }
static int config_set(uint32_t key, GVariant *data, static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) const struct sr_channel_group *cg)
{ {
struct dev_context *devc; struct dev_context *devc;
(void)cg; (void)cg;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv; devc = sdi->priv;
return sr_sw_limits_config_set(&devc->limits, key, data); return sr_sw_limits_config_set(&devc->limits, key, data);
} }
static int config_list(uint32_t key, GVariant **data, static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) const struct sr_channel_group *cg)
{ {
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts); (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) static int dev_acquisition_start(const struct sr_dev_inst *sdi)
@ -107,9 +123,13 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
struct dev_context *devc = sdi->priv; struct dev_context *devc = sdi->priv;
struct sr_serial_dev_inst *serial; struct sr_serial_dev_inst *serial;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
sr_sw_limits_acquisition_start(&devc->limits); sr_sw_limits_acquisition_start(&devc->limits);
std_session_send_df_header(sdi); std_session_send_df_header(sdi);
/* Poll every 150ms, or whenever some data comes in. */
serial = sdi->conn; serial = sdi->conn;
serial_source_add(sdi->session, serial, G_IO_IN, 150, serial_source_add(sdi->session, serial, G_IO_IN, 150,
colead_slm_receive_data, (void *)sdi); colead_slm_receive_data, (void *)sdi);
@ -125,7 +145,7 @@ static struct sr_dev_driver colead_slm_driver_info = {
.cleanup = std_cleanup, .cleanup = std_cleanup,
.scan = scan, .scan = scan,
.dev_list = std_dev_list, .dev_list = std_dev_list,
.dev_clear = std_dev_clear, .dev_clear = NULL,
.config_get = NULL, .config_get = NULL,
.config_set = config_set, .config_set = config_set,
.config_list = config_list, .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); sr_sw_limits_update_samples_read(&devc->limits, 1);
if (sr_sw_limits_check(&devc->limits)) if (sr_sw_limits_check(&devc->limits))
sr_dev_acquisition_stop((struct sr_dev_inst *)sdi); sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi);
} }
SR_PRIV int colead_slm_receive_data(int fd, int revents, void *cb_data) SR_PRIV int colead_slm_receive_data(int fd, int revents, void *cb_data)
@ -202,7 +202,7 @@ SR_PRIV int colead_slm_receive_data(int fd, int revents, void *cb_data)
serial = sdi->conn; serial = sdi->conn;
if (devc->state == IDLE) { if (devc->state == IDLE) {
if (serial_read_nonblocking(serial, buf, sizeof(buf)) != 1 || buf[0] != 0x10) if (serial_read_nonblocking(serial, buf, 128) != 1 || buf[0] != 0x10)
/* Nothing there, or caught the tail end of a previous packet, /* Nothing there, or caught the tail end of a previous packet,
* or some garbage. Unless it's a single "data ready" byte, * or some garbage. Unless it's a single "data ready" byte,
* we don't want it. */ * we don't want it. */

View File

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

View File

@ -17,6 +17,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/**
* @file
*
* <em>Conrad DIGI 35 CPU</em> power supply driver
*
* @internal
*/
#include <config.h> #include <config.h>
#include "protocol.h" #include "protocol.h"
@ -27,19 +35,15 @@ static const uint32_t scanopts[] = {
SR_CONF_SERIALCOMM, SR_CONF_SERIALCOMM,
}; };
static const uint32_t drvopts[] = {
SR_CONF_POWER_SUPPLY,
};
static const uint32_t devopts[] = { static const uint32_t devopts[] = {
SR_CONF_VOLTAGE_TARGET | SR_CONF_SET | SR_CONF_LIST, SR_CONF_POWER_SUPPLY,
SR_CONF_CURRENT_LIMIT | SR_CONF_SET | SR_CONF_LIST, SR_CONF_VOLTAGE | SR_CONF_SET,
SR_CONF_CURRENT | SR_CONF_SET,
SR_CONF_OVER_CURRENT_PROTECTION_ENABLED | SR_CONF_SET, SR_CONF_OVER_CURRENT_PROTECTION_ENABLED | SR_CONF_SET,
}; };
static GSList *scan(struct sr_dev_driver *di, GSList *options) static GSList *scan(struct sr_dev_driver *di, GSList *options)
{ {
struct dev_context *devc;
struct sr_dev_inst *sdi; struct sr_dev_inst *sdi;
struct sr_config *src; struct sr_config *src;
struct sr_serial_dev_inst *serial; struct sr_serial_dev_inst *serial;
@ -75,6 +79,7 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
if (serial_open(serial, SERIAL_RDWR) != SR_OK) if (serial_open(serial, SERIAL_RDWR) != SR_OK)
return NULL; return NULL;
serial_flush(serial);
serial_close(serial); serial_close(serial);
sr_spew("Conrad DIGI 35 CPU assumed at %s.", conn); sr_spew("Conrad DIGI 35 CPU assumed at %s.", conn);
@ -83,65 +88,91 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
sdi->status = SR_ST_INACTIVE; sdi->status = SR_ST_INACTIVE;
sdi->vendor = g_strdup("Conrad"); sdi->vendor = g_strdup("Conrad");
sdi->model = g_strdup("DIGI 35 CPU"); sdi->model = g_strdup("DIGI 35 CPU");
devc = g_malloc0(sizeof(struct dev_context));
sr_sw_limits_init(&devc->limits);
sdi->inst_type = SR_INST_SERIAL;
sdi->conn = serial; sdi->conn = serial;
sdi->priv = devc; sdi->priv = NULL;
sr_channel_new(sdi, 0, SR_CHANNEL_ANALOG, TRUE, "CH1");
return std_scan_complete(di, g_slist_append(NULL, sdi)); return std_scan_complete(di, g_slist_append(NULL, sdi));
} }
static int config_set(uint32_t key, GVariant *data, static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) const struct sr_channel_group *cg)
{ {
int ret;
double dblval; double dblval;
(void)cg; (void)cg;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
switch (key) { switch (key) {
case SR_CONF_VOLTAGE_TARGET: case SR_CONF_VOLTAGE:
dblval = g_variant_get_double(data); dblval = g_variant_get_double(data);
if ((dblval < 0.0) || (dblval > 35.0)) { if ((dblval < 0.0) || (dblval > 35.0)) {
sr_err("Voltage out of range (0 - 35.0)!"); sr_err("Voltage out of range (0 - 35.0)!");
return SR_ERR_ARG; return SR_ERR_ARG;
} }
return send_msg1(sdi, 'V', (int) (dblval * 10 + 0.5)); ret = send_msg1(sdi, 'V', (int) (dblval * 10 + 0.5));
case SR_CONF_CURRENT_LIMIT: break;
case SR_CONF_CURRENT:
dblval = g_variant_get_double(data); dblval = g_variant_get_double(data);
if ((dblval < 0.00) || (dblval > 2.55)) { if ((dblval < 0.01) || (dblval > 2.55)) {
sr_err("Current out of range (0 - 2.55)!"); sr_err("Current out of range (0 - 2.55)!");
return SR_ERR_ARG; return SR_ERR_ARG;
} }
return send_msg1(sdi, 'C', (int) (dblval * 100 + 0.5)); ret = send_msg1(sdi, 'C', (int) (dblval * 100 + 0.5));
break;
case SR_CONF_OVER_CURRENT_PROTECTION_ENABLED: case SR_CONF_OVER_CURRENT_PROTECTION_ENABLED:
if (g_variant_get_boolean(data)) if (g_variant_get_boolean(data))
return send_msg1(sdi, 'V', 900); ret = send_msg1(sdi, 'V', 900);
else /* Constant current mode */ else /* Constant current mode */
return send_msg1(sdi, 'V', 901); 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;
default: default:
return SR_ERR_NA; return SR_ERR_NA;
} }
return ret;
}
static int dev_acquisition_start(const struct sr_dev_inst *sdi)
{
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
return SR_OK; return SR_OK;
} }
static int config_list(uint32_t key, GVariant **data, static int dev_acquisition_stop(struct sr_dev_inst *sdi)
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{ {
switch (key) { if (sdi->status != SR_ST_ACTIVE)
case SR_CONF_SCAN_OPTIONS: return SR_ERR_DEV_CLOSED;
case SR_CONF_DEVICE_OPTIONS:
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
case SR_CONF_VOLTAGE_TARGET:
*data = std_gvar_min_max_step(0.0, 35.0, 0.1);
break;
case SR_CONF_CURRENT_LIMIT:
*data = std_gvar_min_max_step(0.0, 2.55, 0.01);
break;
default:
return SR_ERR_NA;
}
return SR_OK; return SR_OK;
} }
@ -154,14 +185,14 @@ static struct sr_dev_driver conrad_digi_35_cpu_driver_info = {
.cleanup = std_cleanup, .cleanup = std_cleanup,
.scan = scan, .scan = scan,
.dev_list = std_dev_list, .dev_list = std_dev_list,
.dev_clear = std_dev_clear, .dev_clear = NULL,
.config_get = NULL, .config_get = NULL,
.config_set = config_set, .config_set = config_set,
.config_list = config_list, .config_list = config_list,
.dev_open = std_serial_dev_open, .dev_open = std_serial_dev_open,
.dev_close = std_serial_dev_close, .dev_close = std_serial_dev_close,
.dev_acquisition_start = std_dummy_dev_acquisition_start, .dev_acquisition_start = dev_acquisition_start,
.dev_acquisition_stop = std_dummy_dev_acquisition_stop, .dev_acquisition_stop = dev_acquisition_stop,
.context = NULL, .context = NULL,
}; };
SR_REGISTER_DEV_DRIVER(conrad_digi_35_cpu_driver_info); SR_REGISTER_DEV_DRIVER(conrad_digi_35_cpu_driver_info);

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