]> sigrok.org Git - libsigrok.git/commitdiff
Reorganize project tree.
authorBert Vermeulen <redacted>
Mon, 21 Jul 2014 19:27:33 +0000 (21:27 +0200)
committerBert Vermeulen <redacted>
Tue, 22 Jul 2014 16:19:29 +0000 (18:19 +0200)
347 files changed:
Makefile.am
backend.c [deleted file]
device.c [deleted file]
drivers.c [deleted file]
error.c [deleted file]
hardware/agilent-dmm/agilent-dmm.h [deleted file]
hardware/agilent-dmm/api.c [deleted file]
hardware/agilent-dmm/sched.c [deleted file]
hardware/appa-55ii/api.c [deleted file]
hardware/appa-55ii/protocol.c [deleted file]
hardware/appa-55ii/protocol.h [deleted file]
hardware/asix-sigma/asix-sigma.c [deleted file]
hardware/asix-sigma/asix-sigma.h [deleted file]
hardware/atten-pps3xxx/api.c [deleted file]
hardware/atten-pps3xxx/protocol.c [deleted file]
hardware/atten-pps3xxx/protocol.h [deleted file]
hardware/beaglelogic/api.c [deleted file]
hardware/beaglelogic/beaglelogic.h [deleted file]
hardware/beaglelogic/protocol.c [deleted file]
hardware/beaglelogic/protocol.h [deleted file]
hardware/brymen-bm86x/api.c [deleted file]
hardware/brymen-bm86x/protocol.c [deleted file]
hardware/brymen-bm86x/protocol.h [deleted file]
hardware/brymen-dmm/api.c [deleted file]
hardware/brymen-dmm/parser.c [deleted file]
hardware/brymen-dmm/protocol.c [deleted file]
hardware/brymen-dmm/protocol.h [deleted file]
hardware/cem-dt-885x/api.c [deleted file]
hardware/cem-dt-885x/protocol.c [deleted file]
hardware/cem-dt-885x/protocol.h [deleted file]
hardware/center-3xx/api.c [deleted file]
hardware/center-3xx/protocol.c [deleted file]
hardware/center-3xx/protocol.h [deleted file]
hardware/chronovu-la/api.c [deleted file]
hardware/chronovu-la/protocol.c [deleted file]
hardware/chronovu-la/protocol.h [deleted file]
hardware/colead-slm/api.c [deleted file]
hardware/colead-slm/protocol.c [deleted file]
hardware/colead-slm/protocol.h [deleted file]
hardware/common/dmm/es519xx.c [deleted file]
hardware/common/dmm/fs9721.c [deleted file]
hardware/common/dmm/fs9922.c [deleted file]
hardware/common/dmm/m2110.c [deleted file]
hardware/common/dmm/metex14.c [deleted file]
hardware/common/dmm/rs9lcd.c [deleted file]
hardware/common/ezusb.c [deleted file]
hardware/common/scpi.c [deleted file]
hardware/common/scpi_serial.c [deleted file]
hardware/common/scpi_tcp.c [deleted file]
hardware/common/scpi_usbtmc_libusb.c [deleted file]
hardware/common/scpi_visa.c [deleted file]
hardware/common/scpi_vxi.c [deleted file]
hardware/common/serial.c [deleted file]
hardware/common/usb.c [deleted file]
hardware/common/vxi.h [deleted file]
hardware/common/vxi.x [deleted file]
hardware/common/vxi_clnt.c [deleted file]
hardware/common/vxi_xdr.c [deleted file]
hardware/conrad-digi-35-cpu/api.c [deleted file]
hardware/conrad-digi-35-cpu/protocol.c [deleted file]
hardware/conrad-digi-35-cpu/protocol.h [deleted file]
hardware/demo/demo.c [deleted file]
hardware/fluke-dmm/api.c [deleted file]
hardware/fluke-dmm/fluke-dmm.h [deleted file]
hardware/fluke-dmm/fluke.c [deleted file]
hardware/fx2lafw/api.c [deleted file]
hardware/fx2lafw/protocol.c [deleted file]
hardware/fx2lafw/protocol.h [deleted file]
hardware/gmc-mh-1x-2x/api.c [deleted file]
hardware/gmc-mh-1x-2x/protocol.c [deleted file]
hardware/gmc-mh-1x-2x/protocol.h [deleted file]
hardware/hameg-hmo/api.c [deleted file]
hardware/hameg-hmo/protocol.c [deleted file]
hardware/hameg-hmo/protocol.h [deleted file]
hardware/hantek-dso/api.c [deleted file]
hardware/hantek-dso/dso.c [deleted file]
hardware/hantek-dso/dso.h [deleted file]
hardware/ikalogic-scanalogic2/api.c [deleted file]
hardware/ikalogic-scanalogic2/protocol.c [deleted file]
hardware/ikalogic-scanalogic2/protocol.h [deleted file]
hardware/ikalogic-scanaplus/api.c [deleted file]
hardware/ikalogic-scanaplus/protocol.c [deleted file]
hardware/ikalogic-scanaplus/protocol.h [deleted file]
hardware/kecheng-kc-330b/api.c [deleted file]
hardware/kecheng-kc-330b/protocol.c [deleted file]
hardware/kecheng-kc-330b/protocol.h [deleted file]
hardware/lascar-el-usb/api.c [deleted file]
hardware/lascar-el-usb/protocol.c [deleted file]
hardware/lascar-el-usb/protocol.h [deleted file]
hardware/link-mso19/api.c [deleted file]
hardware/link-mso19/protocol.c [deleted file]
hardware/link-mso19/protocol.h [deleted file]
hardware/manson-hcs-3xxx/api.c [deleted file]
hardware/manson-hcs-3xxx/protocol.c [deleted file]
hardware/manson-hcs-3xxx/protocol.h [deleted file]
hardware/mic-985xx/api.c [deleted file]
hardware/mic-985xx/protocol.c [deleted file]
hardware/mic-985xx/protocol.h [deleted file]
hardware/motech-lps-30x/api.c [deleted file]
hardware/motech-lps-30x/protocol.c [deleted file]
hardware/motech-lps-30x/protocol.h [deleted file]
hardware/norma-dmm/api.c [deleted file]
hardware/norma-dmm/protocol.c [deleted file]
hardware/norma-dmm/protocol.h [deleted file]
hardware/openbench-logic-sniffer/api.c [deleted file]
hardware/openbench-logic-sniffer/protocol.c [deleted file]
hardware/openbench-logic-sniffer/protocol.h [deleted file]
hardware/rigol-ds/api.c [deleted file]
hardware/rigol-ds/protocol.c [deleted file]
hardware/rigol-ds/protocol.h [deleted file]
hardware/saleae-logic16/api.c [deleted file]
hardware/saleae-logic16/protocol.c [deleted file]
hardware/saleae-logic16/protocol.h [deleted file]
hardware/serial-dmm/api.c [deleted file]
hardware/serial-dmm/protocol.c [deleted file]
hardware/serial-dmm/protocol.h [deleted file]
hardware/sysclk-lwla/api.c [deleted file]
hardware/sysclk-lwla/lwla.c [deleted file]
hardware/sysclk-lwla/lwla.h [deleted file]
hardware/sysclk-lwla/protocol.c [deleted file]
hardware/sysclk-lwla/protocol.h [deleted file]
hardware/teleinfo/api.c [deleted file]
hardware/teleinfo/protocol.c [deleted file]
hardware/teleinfo/protocol.h [deleted file]
hardware/testo/api.c [deleted file]
hardware/testo/protocol.c [deleted file]
hardware/testo/protocol.h [deleted file]
hardware/tondaj-sl-814/api.c [deleted file]
hardware/tondaj-sl-814/protocol.c [deleted file]
hardware/tondaj-sl-814/protocol.h [deleted file]
hardware/uni-t-dmm/api.c [deleted file]
hardware/uni-t-dmm/protocol.c [deleted file]
hardware/uni-t-dmm/protocol.h [deleted file]
hardware/uni-t-ut32x/api.c [deleted file]
hardware/uni-t-ut32x/protocol.c [deleted file]
hardware/uni-t-ut32x/protocol.h [deleted file]
hardware/victor-dmm/api.c [deleted file]
hardware/victor-dmm/protocol.c [deleted file]
hardware/victor-dmm/protocol.h [deleted file]
hardware/zeroplus-logic-cube/analyzer.c [deleted file]
hardware/zeroplus-logic-cube/analyzer.h [deleted file]
hardware/zeroplus-logic-cube/api.c [deleted file]
hardware/zeroplus-logic-cube/gl_usb.c [deleted file]
hardware/zeroplus-logic-cube/gl_usb.h [deleted file]
hardware/zeroplus-logic-cube/protocol.c [deleted file]
hardware/zeroplus-logic-cube/protocol.h [deleted file]
hwdriver.c [deleted file]
input/binary.c [deleted file]
input/chronovu_la8.c [deleted file]
input/csv.c [deleted file]
input/input.c [deleted file]
input/vcd.c [deleted file]
input/wav.c [deleted file]
libsigrok-internal.h [deleted file]
log.c [deleted file]
output/analog.c [deleted file]
output/ascii.c [deleted file]
output/binary.c [deleted file]
output/bits.c [deleted file]
output/chronovu_la8.c [deleted file]
output/csv.c [deleted file]
output/gnuplot.c [deleted file]
output/hex.c [deleted file]
output/ols.c [deleted file]
output/output.c [deleted file]
output/vcd.c [deleted file]
session.c [deleted file]
session_driver.c [deleted file]
session_file.c [deleted file]
soft-trigger.c [deleted file]
src/backend.c [new file with mode: 0644]
src/device.c [new file with mode: 0644]
src/dmm/es519xx.c [new file with mode: 0644]
src/dmm/fs9721.c [new file with mode: 0644]
src/dmm/fs9922.c [new file with mode: 0644]
src/dmm/m2110.c [new file with mode: 0644]
src/dmm/metex14.c [new file with mode: 0644]
src/dmm/rs9lcd.c [new file with mode: 0644]
src/drivers.c [new file with mode: 0644]
src/error.c [new file with mode: 0644]
src/ezusb.c [new file with mode: 0644]
src/hardware/agilent-dmm/agilent-dmm.h [new file with mode: 0644]
src/hardware/agilent-dmm/api.c [new file with mode: 0644]
src/hardware/agilent-dmm/sched.c [new file with mode: 0644]
src/hardware/appa-55ii/api.c [new file with mode: 0644]
src/hardware/appa-55ii/protocol.c [new file with mode: 0644]
src/hardware/appa-55ii/protocol.h [new file with mode: 0644]
src/hardware/asix-sigma/asix-sigma.c [new file with mode: 0644]
src/hardware/asix-sigma/asix-sigma.h [new file with mode: 0644]
src/hardware/atten-pps3xxx/api.c [new file with mode: 0644]
src/hardware/atten-pps3xxx/protocol.c [new file with mode: 0644]
src/hardware/atten-pps3xxx/protocol.h [new file with mode: 0644]
src/hardware/beaglelogic/api.c [new file with mode: 0644]
src/hardware/beaglelogic/beaglelogic.h [new file with mode: 0644]
src/hardware/beaglelogic/protocol.c [new file with mode: 0644]
src/hardware/beaglelogic/protocol.h [new file with mode: 0644]
src/hardware/brymen-bm86x/api.c [new file with mode: 0644]
src/hardware/brymen-bm86x/protocol.c [new file with mode: 0644]
src/hardware/brymen-bm86x/protocol.h [new file with mode: 0644]
src/hardware/brymen-dmm/api.c [new file with mode: 0644]
src/hardware/brymen-dmm/parser.c [new file with mode: 0644]
src/hardware/brymen-dmm/protocol.c [new file with mode: 0644]
src/hardware/brymen-dmm/protocol.h [new file with mode: 0644]
src/hardware/cem-dt-885x/api.c [new file with mode: 0644]
src/hardware/cem-dt-885x/protocol.c [new file with mode: 0644]
src/hardware/cem-dt-885x/protocol.h [new file with mode: 0644]
src/hardware/center-3xx/api.c [new file with mode: 0644]
src/hardware/center-3xx/protocol.c [new file with mode: 0644]
src/hardware/center-3xx/protocol.h [new file with mode: 0644]
src/hardware/chronovu-la/api.c [new file with mode: 0644]
src/hardware/chronovu-la/protocol.c [new file with mode: 0644]
src/hardware/chronovu-la/protocol.h [new file with mode: 0644]
src/hardware/colead-slm/api.c [new file with mode: 0644]
src/hardware/colead-slm/protocol.c [new file with mode: 0644]
src/hardware/colead-slm/protocol.h [new file with mode: 0644]
src/hardware/conrad-digi-35-cpu/api.c [new file with mode: 0644]
src/hardware/conrad-digi-35-cpu/protocol.c [new file with mode: 0644]
src/hardware/conrad-digi-35-cpu/protocol.h [new file with mode: 0644]
src/hardware/demo/demo.c [new file with mode: 0644]
src/hardware/fluke-dmm/api.c [new file with mode: 0644]
src/hardware/fluke-dmm/fluke-dmm.h [new file with mode: 0644]
src/hardware/fluke-dmm/fluke.c [new file with mode: 0644]
src/hardware/fx2lafw/api.c [new file with mode: 0644]
src/hardware/fx2lafw/protocol.c [new file with mode: 0644]
src/hardware/fx2lafw/protocol.h [new file with mode: 0644]
src/hardware/gmc-mh-1x-2x/api.c [new file with mode: 0644]
src/hardware/gmc-mh-1x-2x/protocol.c [new file with mode: 0644]
src/hardware/gmc-mh-1x-2x/protocol.h [new file with mode: 0644]
src/hardware/hameg-hmo/api.c [new file with mode: 0644]
src/hardware/hameg-hmo/protocol.c [new file with mode: 0644]
src/hardware/hameg-hmo/protocol.h [new file with mode: 0644]
src/hardware/hantek-dso/api.c [new file with mode: 0644]
src/hardware/hantek-dso/dso.c [new file with mode: 0644]
src/hardware/hantek-dso/dso.h [new file with mode: 0644]
src/hardware/ikalogic-scanalogic2/api.c [new file with mode: 0644]
src/hardware/ikalogic-scanalogic2/protocol.c [new file with mode: 0644]
src/hardware/ikalogic-scanalogic2/protocol.h [new file with mode: 0644]
src/hardware/ikalogic-scanaplus/api.c [new file with mode: 0644]
src/hardware/ikalogic-scanaplus/protocol.c [new file with mode: 0644]
src/hardware/ikalogic-scanaplus/protocol.h [new file with mode: 0644]
src/hardware/kecheng-kc-330b/api.c [new file with mode: 0644]
src/hardware/kecheng-kc-330b/protocol.c [new file with mode: 0644]
src/hardware/kecheng-kc-330b/protocol.h [new file with mode: 0644]
src/hardware/lascar-el-usb/api.c [new file with mode: 0644]
src/hardware/lascar-el-usb/protocol.c [new file with mode: 0644]
src/hardware/lascar-el-usb/protocol.h [new file with mode: 0644]
src/hardware/link-mso19/api.c [new file with mode: 0644]
src/hardware/link-mso19/protocol.c [new file with mode: 0644]
src/hardware/link-mso19/protocol.h [new file with mode: 0644]
src/hardware/manson-hcs-3xxx/api.c [new file with mode: 0644]
src/hardware/manson-hcs-3xxx/protocol.c [new file with mode: 0644]
src/hardware/manson-hcs-3xxx/protocol.h [new file with mode: 0644]
src/hardware/mic-985xx/api.c [new file with mode: 0644]
src/hardware/mic-985xx/protocol.c [new file with mode: 0644]
src/hardware/mic-985xx/protocol.h [new file with mode: 0644]
src/hardware/motech-lps-30x/api.c [new file with mode: 0644]
src/hardware/motech-lps-30x/protocol.c [new file with mode: 0644]
src/hardware/motech-lps-30x/protocol.h [new file with mode: 0644]
src/hardware/norma-dmm/api.c [new file with mode: 0644]
src/hardware/norma-dmm/protocol.c [new file with mode: 0644]
src/hardware/norma-dmm/protocol.h [new file with mode: 0644]
src/hardware/openbench-logic-sniffer/api.c [new file with mode: 0644]
src/hardware/openbench-logic-sniffer/protocol.c [new file with mode: 0644]
src/hardware/openbench-logic-sniffer/protocol.h [new file with mode: 0644]
src/hardware/rigol-ds/api.c [new file with mode: 0644]
src/hardware/rigol-ds/protocol.c [new file with mode: 0644]
src/hardware/rigol-ds/protocol.h [new file with mode: 0644]
src/hardware/saleae-logic16/api.c [new file with mode: 0644]
src/hardware/saleae-logic16/protocol.c [new file with mode: 0644]
src/hardware/saleae-logic16/protocol.h [new file with mode: 0644]
src/hardware/serial-dmm/api.c [new file with mode: 0644]
src/hardware/serial-dmm/protocol.c [new file with mode: 0644]
src/hardware/serial-dmm/protocol.h [new file with mode: 0644]
src/hardware/sysclk-lwla/api.c [new file with mode: 0644]
src/hardware/sysclk-lwla/lwla.c [new file with mode: 0644]
src/hardware/sysclk-lwla/lwla.h [new file with mode: 0644]
src/hardware/sysclk-lwla/protocol.c [new file with mode: 0644]
src/hardware/sysclk-lwla/protocol.h [new file with mode: 0644]
src/hardware/teleinfo/api.c [new file with mode: 0644]
src/hardware/teleinfo/protocol.c [new file with mode: 0644]
src/hardware/teleinfo/protocol.h [new file with mode: 0644]
src/hardware/testo/api.c [new file with mode: 0644]
src/hardware/testo/protocol.c [new file with mode: 0644]
src/hardware/testo/protocol.h [new file with mode: 0644]
src/hardware/tondaj-sl-814/api.c [new file with mode: 0644]
src/hardware/tondaj-sl-814/protocol.c [new file with mode: 0644]
src/hardware/tondaj-sl-814/protocol.h [new file with mode: 0644]
src/hardware/uni-t-dmm/api.c [new file with mode: 0644]
src/hardware/uni-t-dmm/protocol.c [new file with mode: 0644]
src/hardware/uni-t-dmm/protocol.h [new file with mode: 0644]
src/hardware/uni-t-ut32x/api.c [new file with mode: 0644]
src/hardware/uni-t-ut32x/protocol.c [new file with mode: 0644]
src/hardware/uni-t-ut32x/protocol.h [new file with mode: 0644]
src/hardware/victor-dmm/api.c [new file with mode: 0644]
src/hardware/victor-dmm/protocol.c [new file with mode: 0644]
src/hardware/victor-dmm/protocol.h [new file with mode: 0644]
src/hardware/zeroplus-logic-cube/analyzer.c [new file with mode: 0644]
src/hardware/zeroplus-logic-cube/analyzer.h [new file with mode: 0644]
src/hardware/zeroplus-logic-cube/api.c [new file with mode: 0644]
src/hardware/zeroplus-logic-cube/gl_usb.c [new file with mode: 0644]
src/hardware/zeroplus-logic-cube/gl_usb.h [new file with mode: 0644]
src/hardware/zeroplus-logic-cube/protocol.c [new file with mode: 0644]
src/hardware/zeroplus-logic-cube/protocol.h [new file with mode: 0644]
src/hwdriver.c [new file with mode: 0644]
src/input/binary.c [new file with mode: 0644]
src/input/chronovu_la8.c [new file with mode: 0644]
src/input/csv.c [new file with mode: 0644]
src/input/input.c [new file with mode: 0644]
src/input/vcd.c [new file with mode: 0644]
src/input/wav.c [new file with mode: 0644]
src/libsigrok-internal.h [new file with mode: 0644]
src/log.c [new file with mode: 0644]
src/output/analog.c [new file with mode: 0644]
src/output/ascii.c [new file with mode: 0644]
src/output/binary.c [new file with mode: 0644]
src/output/bits.c [new file with mode: 0644]
src/output/chronovu_la8.c [new file with mode: 0644]
src/output/csv.c [new file with mode: 0644]
src/output/gnuplot.c [new file with mode: 0644]
src/output/hex.c [new file with mode: 0644]
src/output/ols.c [new file with mode: 0644]
src/output/output.c [new file with mode: 0644]
src/output/vcd.c [new file with mode: 0644]
src/scpi/scpi.c [new file with mode: 0644]
src/scpi/scpi_serial.c [new file with mode: 0644]
src/scpi/scpi_tcp.c [new file with mode: 0644]
src/scpi/scpi_usbtmc_libusb.c [new file with mode: 0644]
src/scpi/scpi_visa.c [new file with mode: 0644]
src/scpi/scpi_vxi.c [new file with mode: 0644]
src/scpi/vxi.h [new file with mode: 0644]
src/scpi/vxi.x [new file with mode: 0644]
src/scpi/vxi_clnt.c [new file with mode: 0644]
src/scpi/vxi_xdr.c [new file with mode: 0644]
src/serial.c [new file with mode: 0644]
src/session.c [new file with mode: 0644]
src/session_driver.c [new file with mode: 0644]
src/session_file.c [new file with mode: 0644]
src/soft-trigger.c [new file with mode: 0644]
src/std.c [new file with mode: 0644]
src/strutil.c [new file with mode: 0644]
src/trigger.c [new file with mode: 0644]
src/usb.c [new file with mode: 0644]
src/version.c [new file with mode: 0644]
std.c [deleted file]
strutil.c [deleted file]
trigger.c [deleted file]
version.c [deleted file]

index 72f97969b599c16dd7d086998f7522ae332c2f5f..3a485e0a84f010490508760796a71789b0873863 100644 (file)
 
 ACLOCAL_AMFLAGS = -I autostuff
 
-AM_CPPFLAGS = -DFIRMWARE_DIR='"$(FIRMWARE_DIR)"'
+AM_CPPFLAGS = -Isrc -DFIRMWARE_DIR='"$(FIRMWARE_DIR)"'
 
 lib_LTLIBRARIES = libsigrok.la
 
 # Backend files
 libsigrok_la_SOURCES = \
-       backend.c \
-       device.c \
-       session.c \
-       session_file.c \
-       session_driver.c \
-       drivers.c \
-       hwdriver.c \
-       trigger.c \
-       soft-trigger.c \
-       strutil.c \
-       log.c \
-       version.c \
-       error.c \
-       std.c
-
-# Input formats
-libsigrok_la_SOURCES += \
-       input/binary.c \
-       input/chronovu_la8.c \
-       input/csv.c \
-       input/input.c \
-       input/vcd.c \
-       input/wav.c
-
-# Output formats
-libsigrok_la_SOURCES += \
-       output/output.c \
-       output/analog.c \
-       output/ascii.c \
-       output/bits.c \
-       output/binary.c \
-       output/csv.c \
-       output/chronovu_la8.c \
-       output/gnuplot.c \
-       output/hex.c \
-       output/ols.c \
-       output/vcd.c
-
-# Hardware (common files)
-libsigrok_la_SOURCES += \
-       hardware/common/scpi.c \
-       hardware/common/scpi_tcp.c
+       src/backend.c \
+       src/device.c \
+       src/session.c \
+       src/session_file.c \
+       src/session_driver.c \
+       src/drivers.c \
+       src/hwdriver.c \
+       src/trigger.c \
+       src/soft-trigger.c \
+       src/strutil.c \
+       src/log.c \
+       src/version.c \
+       src/error.c \
+       src/std.c
+
+# Input modules
+libsigrok_la_SOURCES += \
+       src/input/binary.c \
+       src/input/chronovu_la8.c \
+       src/input/csv.c \
+       src/input/input.c \
+       src/input/vcd.c \
+       src/input/wav.c
+
+# Output modules
+libsigrok_la_SOURCES += \
+       src/output/output.c \
+       src/output/analog.c \
+       src/output/ascii.c \
+       src/output/bits.c \
+       src/output/binary.c \
+       src/output/csv.c \
+       src/output/chronovu_la8.c \
+       src/output/gnuplot.c \
+       src/output/hex.c \
+       src/output/ols.c \
+       src/output/vcd.c
+
+# SCPI support
+libsigrok_la_SOURCES += \
+       src/scpi/scpi.c \
+       src/scpi/scpi_tcp.c
 if NEED_RPC
 libsigrok_la_SOURCES += \
-       hardware/common/scpi_vxi.c \
-       hardware/common/vxi_clnt.c \
-       hardware/common/vxi_xdr.c \
-       hardware/common/vxi.h
+       src/scpi/scpi_vxi.c \
+       src/scpi/vxi_clnt.c \
+       src/scpi/vxi_xdr.c \
+       src/scpi/vxi.h
 endif
 if NEED_SERIAL
 libsigrok_la_SOURCES += \
-       hardware/common/serial.c \
-       hardware/common/scpi_serial.c
+       src/serial.c \
+       src/scpi/scpi_serial.c
 endif
 if NEED_USB
 libsigrok_la_SOURCES += \
-       hardware/common/ezusb.c \
-       hardware/common/usb.c \
-       hardware/common/scpi_usbtmc_libusb.c
+       src/ezusb.c \
+       src/usb.c \
+       src/scpi/scpi_usbtmc_libusb.c
 endif
 if NEED_VISA
 libsigrok_la_SOURCES += \
-       hardware/common/scpi_visa.c
+       src/scpi/scpi_visa.c
 endif
 
-# Hardware (DMM parsers)
+# Hardware (DMM chip parsers)
 libsigrok_la_SOURCES += \
-       hardware/common/dmm/es519xx.c \
-       hardware/common/dmm/fs9721.c \
-       hardware/common/dmm/fs9922.c \
-       hardware/common/dmm/m2110.c \
-       hardware/common/dmm/metex14.c \
-       hardware/common/dmm/rs9lcd.c
+       src/dmm/es519xx.c \
+       src/dmm/fs9721.c \
+       src/dmm/fs9922.c \
+       src/dmm/m2110.c \
+       src/dmm/metex14.c \
+       src/dmm/rs9lcd.c
 
 # Hardware drivers
 if HW_AGILENT_DMM
 libsigrok_la_SOURCES += \
-       hardware/agilent-dmm/api.c \
-       hardware/agilent-dmm/agilent-dmm.h \
-       hardware/agilent-dmm/sched.c
+       src/hardware/agilent-dmm/api.c \
+       src/hardware/agilent-dmm/agilent-dmm.h \
+       src/hardware/agilent-dmm/sched.c
 endif
 if HW_APPA_55II
 libsigrok_la_SOURCES += \
-       hardware/appa-55ii/protocol.h \
-       hardware/appa-55ii/protocol.c \
-       hardware/appa-55ii/api.c
+       src/hardware/appa-55ii/protocol.h \
+       src/hardware/appa-55ii/protocol.c \
+       src/hardware/appa-55ii/api.c
 endif
 if HW_ASIX_SIGMA
 libsigrok_la_SOURCES += \
-       hardware/asix-sigma/asix-sigma.h \
-       hardware/asix-sigma/asix-sigma.c
+       src/hardware/asix-sigma/asix-sigma.h \
+       src/hardware/asix-sigma/asix-sigma.c
 endif
 if HW_ATTEN_PPS3XXX
 libsigrok_la_SOURCES += \
-       hardware/atten-pps3xxx/protocol.h \
-       hardware/atten-pps3xxx/protocol.c \
-       hardware/atten-pps3xxx/api.c
+       src/hardware/atten-pps3xxx/protocol.h \
+       src/hardware/atten-pps3xxx/protocol.c \
+       src/hardware/atten-pps3xxx/api.c
 endif
 if HW_BEAGLELOGIC
 libsigrok_la_SOURCES += \
-       hardware/beaglelogic/protocol.h \
-       hardware/beaglelogic/protocol.c \
-       hardware/beaglelogic/api.c
+       src/hardware/beaglelogic/protocol.h \
+       src/hardware/beaglelogic/protocol.c \
+       src/hardware/beaglelogic/api.c
 endif
 if HW_BRYMEN_BM86X
 libsigrok_la_SOURCES += \
-       hardware/brymen-bm86x/protocol.h \
-       hardware/brymen-bm86x/protocol.c \
-       hardware/brymen-bm86x/api.c
+       src/hardware/brymen-bm86x/protocol.h \
+       src/hardware/brymen-bm86x/protocol.c \
+       src/hardware/brymen-bm86x/api.c
 endif
 if HW_BRYMEN_DMM
 libsigrok_la_SOURCES += \
-       hardware/brymen-dmm/parser.c \
-       hardware/brymen-dmm/protocol.h \
-       hardware/brymen-dmm/protocol.c \
-       hardware/brymen-dmm/api.c
+       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
 if HW_CEM_DT_885X
 libsigrok_la_SOURCES += \
-       hardware/cem-dt-885x/protocol.h \
-       hardware/cem-dt-885x/protocol.c \
-       hardware/cem-dt-885x/api.c
+       src/hardware/cem-dt-885x/protocol.h \
+       src/hardware/cem-dt-885x/protocol.c \
+       src/hardware/cem-dt-885x/api.c
 endif
 if HW_CENTER_3XX
 libsigrok_la_SOURCES += \
-       hardware/center-3xx/protocol.h \
-       hardware/center-3xx/protocol.c \
-       hardware/center-3xx/api.c
+       src/hardware/center-3xx/protocol.h \
+       src/hardware/center-3xx/protocol.c \
+       src/hardware/center-3xx/api.c
 endif
 if HW_CHRONOVU_LA
 libsigrok_la_SOURCES += \
-       hardware/chronovu-la/protocol.h \
-       hardware/chronovu-la/protocol.c \
-       hardware/chronovu-la/api.c
+       src/hardware/chronovu-la/protocol.h \
+       src/hardware/chronovu-la/protocol.c \
+       src/hardware/chronovu-la/api.c
 endif
 if HW_COLEAD_SLM
 libsigrok_la_SOURCES += \
-       hardware/colead-slm/protocol.h \
-       hardware/colead-slm/protocol.c \
-       hardware/colead-slm/api.c
+       src/hardware/colead-slm/protocol.h \
+       src/hardware/colead-slm/protocol.c \
+       src/hardware/colead-slm/api.c
 endif
 if HW_CONRAD_DIGI_35_CPU
 libsigrok_la_SOURCES += \
-       hardware/conrad-digi-35-cpu/protocol.h \
-       hardware/conrad-digi-35-cpu/protocol.c \
-       hardware/conrad-digi-35-cpu/api.c
+       src/hardware/conrad-digi-35-cpu/protocol.h \
+       src/hardware/conrad-digi-35-cpu/protocol.c \
+       src/hardware/conrad-digi-35-cpu/api.c
 endif
 if HW_DEMO
 libsigrok_la_SOURCES += \
-       hardware/demo/demo.c
+       src/hardware/demo/demo.c
 endif
 if HW_FLUKE_DMM
 libsigrok_la_SOURCES += \
-       hardware/fluke-dmm/fluke-dmm.h \
-       hardware/fluke-dmm/fluke.c \
-       hardware/fluke-dmm/api.c
+       src/hardware/fluke-dmm/fluke-dmm.h \
+       src/hardware/fluke-dmm/fluke.c \
+       src/hardware/fluke-dmm/api.c
 endif
 if HW_FX2LAFW
 libsigrok_la_SOURCES += \
-       hardware/fx2lafw/protocol.h \
-       hardware/fx2lafw/protocol.c \
-       hardware/fx2lafw/api.c
+       src/hardware/fx2lafw/protocol.h \
+       src/hardware/fx2lafw/protocol.c \
+       src/hardware/fx2lafw/api.c
 endif
 if HW_GMC_MH_1X_2X
 libsigrok_la_SOURCES += \
-       hardware/gmc-mh-1x-2x/protocol.h \
-       hardware/gmc-mh-1x-2x/protocol.c \
-       hardware/gmc-mh-1x-2x/api.c
+       src/hardware/gmc-mh-1x-2x/protocol.h \
+       src/hardware/gmc-mh-1x-2x/protocol.c \
+       src/hardware/gmc-mh-1x-2x/api.c
 endif
 if HW_HAMEG_HMO
 libsigrok_la_SOURCES += \
-       hardware/hameg-hmo/protocol.h \
-       hardware/hameg-hmo/protocol.c \
-       hardware/hameg-hmo/api.c
+       src/hardware/hameg-hmo/protocol.h \
+       src/hardware/hameg-hmo/protocol.c \
+       src/hardware/hameg-hmo/api.c
 endif
 if HW_HANTEK_DSO
 libsigrok_la_SOURCES += \
-       hardware/hantek-dso/dso.h \
-       hardware/hantek-dso/dso.c \
-       hardware/hantek-dso/api.c
+       src/hardware/hantek-dso/dso.h \
+       src/hardware/hantek-dso/dso.c \
+       src/hardware/hantek-dso/api.c
 endif
 if HW_IKALOGIC_SCANALOGIC2
 libsigrok_la_SOURCES += \
-       hardware/ikalogic-scanalogic2/protocol.h \
-       hardware/ikalogic-scanalogic2/protocol.c \
-       hardware/ikalogic-scanalogic2/api.c
+       src/hardware/ikalogic-scanalogic2/protocol.h \
+       src/hardware/ikalogic-scanalogic2/protocol.c \
+       src/hardware/ikalogic-scanalogic2/api.c
 endif
 if HW_IKALOGIC_SCANAPLUS
 libsigrok_la_SOURCES += \
-       hardware/ikalogic-scanaplus/protocol.h \
-       hardware/ikalogic-scanaplus/protocol.c \
-       hardware/ikalogic-scanaplus/api.c
+       src/hardware/ikalogic-scanaplus/protocol.h \
+       src/hardware/ikalogic-scanaplus/protocol.c \
+       src/hardware/ikalogic-scanaplus/api.c
 endif
 if HW_KECHENG_KC_330B
 libsigrok_la_SOURCES += \
-       hardware/kecheng-kc-330b/protocol.h \
-       hardware/kecheng-kc-330b/protocol.c \
-       hardware/kecheng-kc-330b/api.c
+       src/hardware/kecheng-kc-330b/protocol.h \
+       src/hardware/kecheng-kc-330b/protocol.c \
+       src/hardware/kecheng-kc-330b/api.c
 endif
 if HW_LASCAR_EL_USB
 libsigrok_la_SOURCES += \
-       hardware/lascar-el-usb/protocol.h \
-       hardware/lascar-el-usb/protocol.c \
-       hardware/lascar-el-usb/api.c
+       src/hardware/lascar-el-usb/protocol.h \
+       src/hardware/lascar-el-usb/protocol.c \
+       src/hardware/lascar-el-usb/api.c
 endif
 if HW_MANSON_HCS_3XXX
 libsigrok_la_SOURCES += \
-       hardware/manson-hcs-3xxx/protocol.h \
-       hardware/manson-hcs-3xxx/protocol.c \
-       hardware/manson-hcs-3xxx/api.c
+       src/hardware/manson-hcs-3xxx/protocol.h \
+       src/hardware/manson-hcs-3xxx/protocol.c \
+       src/hardware/manson-hcs-3xxx/api.c
 endif
 if HW_MIC_985XX
 libsigrok_la_SOURCES += \
-       hardware/mic-985xx/protocol.h \
-       hardware/mic-985xx/protocol.c \
-       hardware/mic-985xx/api.c
+       src/hardware/mic-985xx/protocol.h \
+       src/hardware/mic-985xx/protocol.c \
+       src/hardware/mic-985xx/api.c
 endif
 if HW_MOTECH_LPS_30X
 libsigrok_la_SOURCES += \
-       hardware/motech-lps-30x/protocol.h \
-       hardware/motech-lps-30x/protocol.c \
-       hardware/motech-lps-30x/api.c
+       src/hardware/motech-lps-30x/protocol.h \
+       src/hardware/motech-lps-30x/protocol.c \
+       src/hardware/motech-lps-30x/api.c
 endif
 if HW_NORMA_DMM
 libsigrok_la_SOURCES += \
-       hardware/norma-dmm/protocol.h \
-       hardware/norma-dmm/protocol.c \
-       hardware/norma-dmm/api.c
+       src/hardware/norma-dmm/protocol.h \
+       src/hardware/norma-dmm/protocol.c \
+       src/hardware/norma-dmm/api.c
 endif
 if HW_OPENBENCH_LOGIC_SNIFFER
 libsigrok_la_SOURCES += \
-       hardware/openbench-logic-sniffer/protocol.h \
-       hardware/openbench-logic-sniffer/protocol.c \
-       hardware/openbench-logic-sniffer/api.c
+       src/hardware/openbench-logic-sniffer/protocol.h \
+       src/hardware/openbench-logic-sniffer/protocol.c \
+       src/hardware/openbench-logic-sniffer/api.c
 endif
 if HW_RIGOL_DS
 libsigrok_la_SOURCES += \
-       hardware/rigol-ds/protocol.h \
-       hardware/rigol-ds/protocol.c \
-       hardware/rigol-ds/api.c
+       src/hardware/rigol-ds/protocol.h \
+       src/hardware/rigol-ds/protocol.c \
+       src/hardware/rigol-ds/api.c
 endif
 if HW_SALEAE_LOGIC16
 libsigrok_la_SOURCES += \
-       hardware/saleae-logic16/protocol.h \
-       hardware/saleae-logic16/protocol.c \
-       hardware/saleae-logic16/api.c
+       src/hardware/saleae-logic16/protocol.h \
+       src/hardware/saleae-logic16/protocol.c \
+       src/hardware/saleae-logic16/api.c
 endif
 if HW_SERIAL_DMM
 libsigrok_la_SOURCES += \
-       hardware/serial-dmm/protocol.h \
-       hardware/serial-dmm/protocol.c \
-       hardware/serial-dmm/api.c
+       src/hardware/serial-dmm/protocol.h \
+       src/hardware/serial-dmm/protocol.c \
+       src/hardware/serial-dmm/api.c
 endif
 if HW_SYSCLK_LWLA
 libsigrok_la_SOURCES += \
-       hardware/sysclk-lwla/lwla.h \
-       hardware/sysclk-lwla/lwla.c \
-       hardware/sysclk-lwla/protocol.h \
-       hardware/sysclk-lwla/protocol.c \
-       hardware/sysclk-lwla/api.c
+       src/hardware/sysclk-lwla/lwla.h \
+       src/hardware/sysclk-lwla/lwla.c \
+       src/hardware/sysclk-lwla/protocol.h \
+       src/hardware/sysclk-lwla/protocol.c \
+       src/hardware/sysclk-lwla/api.c
 endif
 if HW_TELEINFO
 libsigrok_la_SOURCES += \
-       hardware/teleinfo/protocol.h \
-       hardware/teleinfo/protocol.c \
-       hardware/teleinfo/api.c
+       src/hardware/teleinfo/protocol.h \
+       src/hardware/teleinfo/protocol.c \
+       src/hardware/teleinfo/api.c
 endif
 if HW_TESTO
 libsigrok_la_SOURCES += \
-       hardware/testo/protocol.h \
-       hardware/testo/protocol.c \
-       hardware/testo/api.c
+       src/hardware/testo/protocol.h \
+       src/hardware/testo/protocol.c \
+       src/hardware/testo/api.c
 endif
 if HW_TONDAJ_SL_814
 libsigrok_la_SOURCES += \
-       hardware/tondaj-sl-814/protocol.h \
-       hardware/tondaj-sl-814/protocol.c \
-       hardware/tondaj-sl-814/api.c
+       src/hardware/tondaj-sl-814/protocol.h \
+       src/hardware/tondaj-sl-814/protocol.c \
+       src/hardware/tondaj-sl-814/api.c
 endif
 if HW_UNI_T_DMM
 libsigrok_la_SOURCES += \
-       hardware/uni-t-dmm/protocol.h \
-       hardware/uni-t-dmm/protocol.c \
-       hardware/uni-t-dmm/api.c
+       src/hardware/uni-t-dmm/protocol.h \
+       src/hardware/uni-t-dmm/protocol.c \
+       src/hardware/uni-t-dmm/api.c
 endif
 if HW_UNI_T_UT32X
 libsigrok_la_SOURCES += \
-       hardware/uni-t-ut32x/protocol.h \
-       hardware/uni-t-ut32x/protocol.c \
-       hardware/uni-t-ut32x/api.c
+       src/hardware/uni-t-ut32x/protocol.h \
+       src/hardware/uni-t-ut32x/protocol.c \
+       src/hardware/uni-t-ut32x/api.c
 endif
 if HW_VICTOR_DMM
 libsigrok_la_SOURCES += \
-       hardware/victor-dmm/protocol.h \
-       hardware/victor-dmm/protocol.c \
-       hardware/victor-dmm/api.c
+       src/hardware/victor-dmm/protocol.h \
+       src/hardware/victor-dmm/protocol.c \
+       src/hardware/victor-dmm/api.c
 endif
 if HW_ZEROPLUS_LOGIC_CUBE
 libsigrok_la_SOURCES += \
-       hardware/zeroplus-logic-cube/analyzer.c \
-       hardware/zeroplus-logic-cube/analyzer.h \
-       hardware/zeroplus-logic-cube/gl_usb.h \
-       hardware/zeroplus-logic-cube/gl_usb.c \
-       hardware/zeroplus-logic-cube/protocol.h \
-       hardware/zeroplus-logic-cube/protocol.c \
-       hardware/zeroplus-logic-cube/api.c
+       src/hardware/zeroplus-logic-cube/analyzer.c \
+       src/hardware/zeroplus-logic-cube/analyzer.h \
+       src/hardware/zeroplus-logic-cube/gl_usb.h \
+       src/hardware/zeroplus-logic-cube/gl_usb.c \
+       src/hardware/zeroplus-logic-cube/protocol.h \
+       src/hardware/zeroplus-logic-cube/protocol.c \
+       src/hardware/zeroplus-logic-cube/api.c
 endif
 
 libsigrok_la_LIBADD = $(LIBOBJS)
@@ -343,7 +343,7 @@ library_include_HEADERS = \
        include/libsigrok/libsigrok.h \
        include/libsigrok/proto.h \
        include/libsigrok/version.h
-noinst_HEADERS = libsigrok-internal.h
+noinst_HEADERS = src/libsigrok-internal.h
 
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = libsigrok.pc
diff --git a/backend.c b/backend.c
deleted file mode 100644 (file)
index f650fe1..0000000
--- a/backend.c
+++ /dev/null
@@ -1,397 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com>
- * Copyright (C) 2012 Peter Stuge <peter@stuge.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 <glib.h>
-#include "config.h" /* Needed for HAVE_LIBUSB_1_0 and others. */
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-/** @cond PRIVATE */
-#define LOG_PREFIX "backend"
-/** @endcond */
-
-/**
- * @mainpage libsigrok API
- *
- * @section sec_intro Introduction
- *
- * The <a href="http://sigrok.org">sigrok</a> project aims at creating a
- * portable, cross-platform, Free/Libre/Open-Source signal analysis software
- * suite that supports various device types (such as logic analyzers,
- * oscilloscopes, multimeters, and more).
- *
- * <a href="http://sigrok.org/wiki/Libsigrok">libsigrok</a> is a shared
- * library written in C which provides the basic API for talking to
- * <a href="http://sigrok.org/wiki/Supported_hardware">supported hardware</a>
- * and reading/writing the acquired data into various
- * <a href="http://sigrok.org/wiki/Input_output_formats">input/output
- * file formats</a>.
- *
- * @section sec_api API reference
- *
- * See the "Modules" page for an introduction to various libsigrok
- * related topics and the detailed API documentation of the respective
- * functions.
- *
- * You can also browse the API documentation by file, or review all
- * data structures.
- *
- * @section sec_mailinglists Mailing lists
- *
- * There are two mailing lists for sigrok/libsigrok: <a href="https://lists.sourceforge.net/lists/listinfo/sigrok-devel">sigrok-devel</a> and <a href="https://lists.sourceforge.net/lists/listinfo/sigrok-commits">sigrok-commits</a>.
- *
- * @section sec_irc IRC
- *
- * You can find the sigrok developers in the
- * <a href="irc://chat.freenode.net/sigrok">\#sigrok</a>
- * IRC channel on Freenode.
- *
- * @section sec_website Website
- *
- * <a href="http://sigrok.org/wiki/Libsigrok">sigrok.org/wiki/Libsigrok</a>
- */
-
-/**
- * @file
- *
- * Initializing and shutting down libsigrok.
- */
-
-/**
- * @defgroup grp_init Initialization
- *
- * Initializing and shutting down libsigrok.
- *
- * Before using any of the libsigrok functionality (except
- * sr_log_loglevel_set() and sr_log_opts_set()), sr_init() must
- * be called to initialize the library, which will return a struct sr_context
- * when the initialization was successful.
- *
- * When libsigrok functionality is no longer needed, sr_exit() should be
- * called, which will (among other things) free the struct sr_context.
- *
- * Example for a minimal program using libsigrok:
- *
- * @code{.c}
- *   #include <stdio.h>
- *   #include <libsigrok/libsigrok.h>
- *
- *   int main(int argc, char **argv)
- *   {
- *     int ret;
- *     struct sr_context *sr_ctx;
- *
- *     if ((ret = sr_init(&sr_ctx)) != SR_OK) {
- *             printf("Error initializing libsigrok (%s): %s.\n",
- *                    sr_strerror_name(ret), sr_strerror(ret));
- *             return 1;
- *     }
- *
- *     // Use libsigrok functions here...
- *
- *     if ((ret = sr_exit(sr_ctx)) != SR_OK) {
- *             printf("Error shutting down libsigrok (%s): %s.\n",
- *                    sr_strerror_name(ret), sr_strerror(ret));
- *             return 1;
- *     }
- *
- *     return 0;
- *   }
- * @endcode
- *
- * @{
- */
-
-/**
- * Sanity-check all libsigrok drivers.
- *
- * @retval SR_OK All drivers are OK
- * @retval SR_ERR One or more drivers have issues.
- */
-static int sanity_check_all_drivers(void)
-{
-       int i, errors, ret = SR_OK;
-       struct sr_dev_driver **drivers;
-       const char *d;
-
-       sr_spew("Sanity-checking all drivers.");
-
-       drivers = sr_driver_list();
-       for (i = 0; drivers[i]; i++) {
-               errors = 0;
-
-               d = (drivers[i]->name) ? drivers[i]->name : "NULL";
-
-               if (!drivers[i]->name) {
-                       sr_err("No name in driver %d ('%s').", i, d);
-                       errors++;
-               }
-               if (!drivers[i]->longname) {
-                       sr_err("No longname in driver %d ('%s').", i, d);
-                       errors++;
-               }
-               if (drivers[i]->api_version < 1) {
-                       sr_err("API version in driver %d ('%s') < 1.", i, d);
-                       errors++;
-               }
-               if (!drivers[i]->init) {
-                       sr_err("No init in driver %d ('%s').", i, d);
-                       errors++;
-               }
-               if (!drivers[i]->cleanup) {
-                       sr_err("No cleanup in driver %d ('%s').", i, d);
-                       errors++;
-               }
-               if (!drivers[i]->scan) {
-                       sr_err("No scan in driver %d ('%s').", i, d);
-                       errors++;
-               }
-               if (!drivers[i]->dev_list) {
-                       sr_err("No dev_list in driver %d ('%s').", i, d);
-                       errors++;
-               }
-               /* Note: config_get() is optional. */
-               if (!drivers[i]->config_set) {
-                       sr_err("No config_set in driver %d ('%s').", i, d);
-                       errors++;
-               }
-               if (!drivers[i]->config_list) {
-                       sr_err("No config_list in driver %d ('%s').", i, d);
-                       errors++;
-               }
-               if (!drivers[i]->dev_open) {
-                       sr_err("No dev_open in driver %d ('%s').", i, d);
-                       errors++;
-               }
-               if (!drivers[i]->dev_close) {
-                       sr_err("No dev_close in driver %d ('%s').", i, d);
-                       errors++;
-               }
-               if (!drivers[i]->dev_acquisition_start) {
-                       sr_err("No dev_acquisition_start in driver %d ('%s').",
-                              i, d);
-                       errors++;
-               }
-               if (!drivers[i]->dev_acquisition_stop) {
-                       sr_err("No dev_acquisition_stop in driver %d ('%s').",
-                              i, d);
-                       errors++;
-               }
-
-               /* Note: 'priv' is allowed to be NULL. */
-
-               if (errors == 0)
-                       continue;
-
-               ret = SR_ERR;
-       }
-
-       return ret;
-}
-
-/**
- * Sanity-check all libsigrok input modules.
- *
- * @retval SR_OK All modules are OK
- * @retval SR_ERR One or more modules have issues.
- */
-static int sanity_check_all_input_modules(void)
-{
-       int i, errors, ret = SR_OK;
-       struct sr_input_format **inputs;
-       const char *d;
-
-       sr_spew("Sanity-checking all input modules.");
-
-       inputs = sr_input_list();
-       for (i = 0; inputs[i]; i++) {
-               errors = 0;
-
-               d = (inputs[i]->id) ? inputs[i]->id : "NULL";
-
-               if (!inputs[i]->id) {
-                       sr_err("No ID in module %d ('%s').", i, d);
-                       errors++;
-               }
-               if (!inputs[i]->description) {
-                       sr_err("No description in module %d ('%s').", i, d);
-                       errors++;
-               }
-               if (!inputs[i]->format_match) {
-                       sr_err("No format_match in module %d ('%s').", i, d);
-                       errors++;
-               }
-               if (!inputs[i]->init) {
-                       sr_err("No init in module %d ('%s').", i, d);
-                       errors++;
-               }
-               if (!inputs[i]->loadfile) {
-                       sr_err("No loadfile in module %d ('%s').", i, d);
-                       errors++;
-               }
-
-               if (errors == 0)
-                       continue;
-
-               ret = SR_ERR;
-       }
-
-       return ret;
-}
-
-/**
- * Sanity-check all libsigrok output modules.
- *
- * @retval SR_OK All modules are OK
- * @retval SR_ERR One or more modules have issues.
- */
-static int sanity_check_all_output_modules(void)
-{
-       int i, errors, ret = SR_OK;
-       struct sr_output_format **outputs;
-       const char *d;
-
-       sr_spew("Sanity-checking all output modules.");
-
-       outputs = sr_output_list();
-       for (i = 0; outputs[i]; i++) {
-               errors = 0;
-
-               d = (outputs[i]->id) ? outputs[i]->id : "NULL";
-
-               if (!outputs[i]->id) {
-                       sr_err("No ID in module %d ('%s').", i, d);
-                       errors++;
-               }
-               if (!outputs[i]->description) {
-                       sr_err("No description in module '%s'.", d);
-                       errors++;
-               }
-               if (!outputs[i]->receive) {
-                       sr_err("No receive in module '%s'.", d);
-                       errors++;
-               }
-
-               if (errors == 0)
-                       continue;
-
-               ret = SR_ERR;
-       }
-
-       return ret;
-}
-
-/**
- * Initialize libsigrok.
- *
- * This function must be called before any other libsigrok function.
- *
- * @param ctx Pointer to a libsigrok context struct pointer. Must not be NULL.
- *            This will be a pointer to a newly allocated libsigrok context
- *            object upon success, and is undefined upon errors.
- *
- * @return SR_OK upon success, a (negative) error code otherwise. Upon errors
- *         the 'ctx' pointer is undefined and should not be used. Upon success,
- *         the context will be free'd by sr_exit() as part of the libsigrok
- *         shutdown.
- *
- * @since 0.2.0
- */
-SR_API int sr_init(struct sr_context **ctx)
-{
-       int ret = SR_ERR;
-       struct sr_context *context;
-
-       if (!ctx) {
-               sr_err("%s(): libsigrok context was NULL.", __func__);
-               return SR_ERR;
-       }
-
-       if (sanity_check_all_drivers() < 0) {
-               sr_err("Internal driver error(s), aborting.");
-               return ret;
-       }
-
-       if (sanity_check_all_input_modules() < 0) {
-               sr_err("Internal input module error(s), aborting.");
-               return ret;
-       }
-
-       if (sanity_check_all_output_modules() < 0) {
-               sr_err("Internal output module error(s), aborting.");
-               return ret;
-       }
-
-       /* + 1 to handle when struct sr_context has no members. */
-       context = g_try_malloc0(sizeof(struct sr_context) + 1);
-
-       if (!context) {
-               ret = SR_ERR_MALLOC;
-               goto done;
-       }
-
-#ifdef HAVE_LIBUSB_1_0
-       ret = libusb_init(&context->libusb_ctx);
-       if (LIBUSB_SUCCESS != ret) {
-               sr_err("libusb_init() returned %s.", libusb_error_name(ret));
-               ret = SR_ERR;
-               goto done;
-       }
-#endif
-
-       *ctx = context;
-       context = NULL;
-       ret = SR_OK;
-
-done:
-       if (context)
-               g_free(context);
-       return ret;
-}
-
-/**
- * Shutdown libsigrok.
- *
- * @param ctx Pointer to a libsigrok context struct. Must not be NULL.
- *
- * @retval SR_OK Success
- * @retval other Error code SR_ERR, ...
- *
- * @since 0.2.0
- */
-SR_API int sr_exit(struct sr_context *ctx)
-{
-       if (!ctx) {
-               sr_err("%s(): libsigrok context was NULL.", __func__);
-               return SR_ERR;
-       }
-
-       sr_hw_cleanup_all();
-
-#ifdef HAVE_LIBUSB_1_0
-       libusb_exit(ctx->libusb_ctx);
-#endif
-
-       g_free(ctx);
-
-       return SR_OK;
-}
-
-/** @} */
diff --git a/device.c b/device.c
deleted file mode 100644 (file)
index 434d106..0000000
--- a/device.c
+++ /dev/null
@@ -1,474 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <glib.h>
-#include "config.h" /* Needed for HAVE_LIBUSB_1_0 and others. */
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-/** @cond PRIVATE */
-#define LOG_PREFIX "device"
-/** @endcond */
-
-/**
- * @file
- *
- * Device handling in libsigrok.
- */
-
-/**
- * @defgroup grp_devices Devices
- *
- * Device handling in libsigrok.
- *
- * @{
- */
-
-/** @private
- *  Allocate and initialize new struct sr_channel
- *  @param[in]  index @copydoc sr_channel::index
- *  @param[in]  type @copydoc sr_channel::type
- *  @param[in]  enabled @copydoc sr_channel::enabled
- *  @param[in]  name @copydoc sr_channel::name
- *
- *  @return NULL (failure) or new struct sr_channel*.
- */
-SR_PRIV struct sr_channel *sr_channel_new(int index, int type,
-               gboolean enabled, const char *name)
-{
-       struct sr_channel *ch;
-
-       if (!(ch = g_try_malloc0(sizeof(struct sr_channel)))) {
-               sr_err("Channel malloc failed.");
-               return NULL;
-       }
-
-       ch->index = index;
-       ch->type = type;
-       ch->enabled = enabled;
-       if (name)
-               ch->name = g_strdup(name);
-
-       return ch;
-}
-
-/**
- * Set the name of the specified channel in the specified device.
- *
- * If the channel already has a different name assigned to it, it will be
- * removed, and the new name will be saved instead.
- *
- * @param sdi The device instance the channel is connected to.
- * @param[in] channelnum The number of the channel whose name to set.
- *                 Note that the channel numbers start at 0.
- * @param[in] name The new name that the specified channel should get. A copy
- *             of the string is made.
- *
- * @return SR_OK on success, or SR_ERR_ARG on invalid arguments.
- *
- * @since 0.3.0
- */
-SR_API int sr_dev_channel_name_set(const struct sr_dev_inst *sdi,
-               int channelnum, const char *name)
-{
-       GSList *l;
-       struct sr_channel *ch;
-       int ret;
-
-       if (!sdi) {
-               sr_err("%s: sdi was NULL", __func__);
-               return SR_ERR_ARG;
-       }
-
-       ret = SR_ERR_ARG;
-       for (l = sdi->channels; l; l = l->next) {
-               ch = l->data;
-               if (ch->index == channelnum) {
-                       g_free(ch->name);
-                       ch->name = g_strdup(name);
-                       ret = SR_OK;
-                       break;
-               }
-       }
-
-       return ret;
-}
-
-/**
- * Enable or disable a channel on the specified device.
- *
- * @param sdi The device instance the channel is connected to.
- * @param channelnum The channel number, starting from 0.
- * @param state TRUE to enable the channel, FALSE to disable.
- *
- * @return SR_OK on success or SR_ERR on failure.  In case of invalid
- *         arguments, SR_ERR_ARG is returned and the channel enabled state
- *         remains unchanged.
- *
- * @since 0.3.0
- */
-SR_API int sr_dev_channel_enable(const struct sr_dev_inst *sdi, int channelnum,
-               gboolean state)
-{
-       GSList *l;
-       struct sr_channel *ch;
-       int ret;
-       gboolean was_enabled;
-
-       if (!sdi)
-               return SR_ERR_ARG;
-
-       ret = SR_ERR_ARG;
-       for (l = sdi->channels; l; l = l->next) {
-               ch = l->data;
-               if (ch->index == channelnum) {
-                       was_enabled = ch->enabled;
-                       ch->enabled = state;
-                       ret = SR_OK;
-                       if (!state != !was_enabled && sdi->driver
-                                       && sdi->driver->config_channel_set) {
-                               ret = sdi->driver->config_channel_set(
-                                       sdi, ch, SR_CHANNEL_SET_ENABLED);
-                               /* Roll back change if it wasn't applicable. */
-                               if (ret == SR_ERR_ARG)
-                                       ch->enabled = was_enabled;
-                       }
-                       break;
-               }
-       }
-
-       return ret;
-}
-
-/**
- * Determine whether the specified device instance has the specified
- * capability.
- *
- * @param sdi Pointer to the device instance to be checked. Must not be NULL.
- *            If the device's 'driver' field is NULL (virtual device), this
- *            function will always return FALSE (virtual devices don't have
- *            a hardware capabilities list).
- * @param[in] key The option that should be checked for is supported by the
- *            specified device.
- *
- * @retval TRUE Device has the specified option
- * @retval FALSE Device does not have the specified option, invalid input
- *         parameters or other error conditions.
- *
- * @since 0.2.0
- */
-SR_API gboolean sr_dev_has_option(const struct sr_dev_inst *sdi, int key)
-{
-       GVariant *gvar;
-       const int *devopts;
-       gsize num_opts, i;
-       int ret;
-
-       if (!sdi || !sdi->driver || !sdi->driver->config_list)
-               return FALSE;
-
-       if (sdi->driver->config_list(SR_CONF_DEVICE_OPTIONS,
-                               &gvar, sdi, NULL) != SR_OK)
-               return FALSE;
-
-       ret = FALSE;
-       devopts = g_variant_get_fixed_array(gvar, &num_opts, sizeof(int32_t));
-       for (i = 0; i < num_opts; i++) {
-               if (devopts[i] == key) {
-                       ret = TRUE;
-                       break;
-               }
-       }
-       g_variant_unref(gvar);
-
-       return ret;
-}
-
-/** @private
- *  Allocate and init new device instance struct.
- *  @param[in]  index   @copydoc sr_dev_inst::index
- *  @param[in]  status  @copydoc sr_dev_inst::status
- *  @param[in]  vendor  @copydoc sr_dev_inst::vendor
- *  @param[in]  model   @copydoc sr_dev_inst::model
- *  @param[in]  version @copydoc sr_dev_inst::version
- *
- *  @retval NULL Error
- *  @retval struct sr_dev_inst *. Dynamically allocated, free using
- *              sr_dev_inst_free().
- */
-SR_PRIV struct sr_dev_inst *sr_dev_inst_new(int index, int status,
-               const char *vendor, const char *model, const char *version)
-{
-       struct sr_dev_inst *sdi;
-
-       if (!(sdi = g_try_malloc(sizeof(struct sr_dev_inst)))) {
-               sr_err("Device instance malloc failed.");
-               return NULL;
-       }
-
-       sdi->driver = NULL;
-       sdi->index = index;
-       sdi->status = status;
-       sdi->inst_type = -1;
-       sdi->vendor = vendor ? g_strdup(vendor) : NULL;
-       sdi->model = model ? g_strdup(model) : NULL;
-       sdi->version = version ? g_strdup(version) : NULL;
-       sdi->channels = NULL;
-       sdi->channel_groups = NULL;
-       sdi->session = NULL;
-       sdi->conn = NULL;
-       sdi->priv = NULL;
-
-       return sdi;
-}
-
-/** @private
- *  Free device instance struct created by sr_dev_inst().
- *  @param sdi  struct* to free.
- */
-SR_PRIV void sr_dev_inst_free(struct sr_dev_inst *sdi)
-{
-       struct sr_channel *ch;
-       GSList *l;
-
-       for (l = sdi->channels; l; l = l->next) {
-               ch = l->data;
-               g_free(ch->name);
-               g_free(ch);
-       }
-       g_slist_free(sdi->channels);
-
-       if (sdi->channel_groups)
-               g_slist_free(sdi->channel_groups);
-
-       g_free(sdi->vendor);
-       g_free(sdi->model);
-       g_free(sdi->version);
-       g_free(sdi);
-}
-
-#ifdef HAVE_LIBUSB_1_0
-
-/** @private
- *  Allocate and init struct for USB device instance.
- *  @param[in]  bus @copydoc sr_usb_dev_inst::bus
- *  @param[in]  address @copydoc sr_usb_dev_inst::address
- *  @param[in]  hdl @copydoc sr_usb_dev_inst::devhdl
- *
- *  @retval NULL Error
- *  @retval other struct sr_usb_dev_inst * for USB device instance.
- */
-SR_PRIV struct sr_usb_dev_inst *sr_usb_dev_inst_new(uint8_t bus,
-                       uint8_t address, struct libusb_device_handle *hdl)
-{
-       struct sr_usb_dev_inst *udi;
-
-       if (!(udi = g_try_malloc(sizeof(struct sr_usb_dev_inst)))) {
-               sr_err("USB device instance malloc failed.");
-               return NULL;
-       }
-
-       udi->bus = bus;
-       udi->address = address;
-       udi->devhdl = hdl;
-
-       return udi;
-}
-
-/** @private
- *  Free struct * allocated by sr_usb_dev_inst().
- *  @param usb  struct* to free. Must not be NULL.
- */
-SR_PRIV void sr_usb_dev_inst_free(struct sr_usb_dev_inst *usb)
-{
-       g_free(usb);
-}
-
-#endif
-
-#ifdef HAVE_LIBSERIALPORT
-
-/**
- * @private
- *
- * Both parameters are copied to newly allocated strings, and freed
- * automatically by sr_serial_dev_inst_free().
- *
- * @param[in] port OS-specific serial port specification. Examples:
- *                 "/dev/ttyUSB0", "/dev/ttyACM1", "/dev/tty.Modem-0", "COM1".
- * @param[in] serialcomm A serial communication parameters string, in the form
- *              of \<speed\>/\<data bits\>\<parity\>\<stopbits\>, for example
- *              "9600/8n1" or "600/7o2". This is an optional parameter;
- *              it may be filled in later.
- *
- * @return A pointer to a newly initialized struct sr_serial_dev_inst,
- *         or NULL on error.
- */
-SR_PRIV struct sr_serial_dev_inst *sr_serial_dev_inst_new(const char *port,
-               const char *serialcomm)
-{
-       struct sr_serial_dev_inst *serial;
-
-       if (!port) {
-               sr_err("Serial port required.");
-               return NULL;
-       }
-
-       if (!(serial = g_try_malloc0(sizeof(struct sr_serial_dev_inst)))) {
-               sr_err("Serial device instance malloc failed.");
-               return NULL;
-       }
-
-       serial->port = g_strdup(port);
-       if (serialcomm)
-               serial->serialcomm = g_strdup(serialcomm);
-
-       return serial;
-}
-
-/** @private
- *  Free struct sr_serial_dev_inst * allocated by sr_serial_dev_inst().
- *  @param serial   struct sr_serial_dev_inst * to free. Must not be NULL.
- */
-SR_PRIV void sr_serial_dev_inst_free(struct sr_serial_dev_inst *serial)
-{
-       g_free(serial->port);
-       g_free(serial->serialcomm);
-       g_free(serial);
-}
-#endif
-
-/** @private */
-SR_PRIV struct sr_usbtmc_dev_inst *sr_usbtmc_dev_inst_new(const char *device)
-{
-       struct sr_usbtmc_dev_inst *usbtmc;
-
-       if (!device) {
-               sr_err("Device name required.");
-               return NULL;
-       }
-
-       if (!(usbtmc = g_try_malloc0(sizeof(struct sr_usbtmc_dev_inst)))) {
-               sr_err("USBTMC device instance malloc failed.");
-               return NULL;
-       }
-
-       usbtmc->device = g_strdup(device);
-       usbtmc->fd = -1;
-
-       return usbtmc;
-}
-
-/** @private */
-SR_PRIV void sr_usbtmc_dev_inst_free(struct sr_usbtmc_dev_inst *usbtmc)
-{
-       g_free(usbtmc->device);
-       g_free(usbtmc);
-}
-
-/**
- * Get the list of devices/instances of the specified driver.
- *
- * @param driver The driver to use. Must not be NULL.
- *
- * @return The list of devices/instances of this driver, or NULL upon errors
- *         or if the list is empty.
- *
- * @since 0.2.0
- */
-SR_API GSList *sr_dev_list(const struct sr_dev_driver *driver)
-{
-       if (driver && driver->dev_list)
-               return driver->dev_list();
-       else
-               return NULL;
-}
-
-/**
- * Clear the list of device instances a driver knows about.
- *
- * @param driver The driver to use. This must be a pointer to one of
- *               the entries returned by sr_driver_list(). Must not be NULL.
- *
- * @retval SR_OK Success
- * @retval SR_ERR_ARG Invalid driver
- *
- * @since 0.2.0
- */
-SR_API int sr_dev_clear(const struct sr_dev_driver *driver)
-{
-       int ret;
-
-       if (!driver) {
-               sr_err("Invalid driver.");
-               return SR_ERR_ARG;
-       }
-
-       if (driver->dev_clear)
-               ret = driver->dev_clear();
-       else
-               ret = std_dev_clear(driver, NULL);
-
-       return ret;
-}
-
-/**
- * Open the specified device.
- *
- * @param sdi Device instance to use. Must not be NULL.
- *
- * @return SR_OK upon success, a negative error code upon errors.
- *
- * @since 0.2.0
- */
-SR_API int sr_dev_open(struct sr_dev_inst *sdi)
-{
-       int ret;
-
-       if (!sdi || !sdi->driver || !sdi->driver->dev_open)
-               return SR_ERR;
-
-       ret = sdi->driver->dev_open(sdi);
-
-       return ret;
-}
-
-/**
- * Close the specified device.
- *
- * @param sdi Device instance to use. Must not be NULL.
- *
- * @return SR_OK upon success, a negative error code upon errors.
- *
- * @since 0.2.0
- */
-SR_API int sr_dev_close(struct sr_dev_inst *sdi)
-{
-       int ret;
-
-       if (!sdi || !sdi->driver || !sdi->driver->dev_close)
-               return SR_ERR;
-
-       ret = sdi->driver->dev_close(sdi);
-
-       return ret;
-}
-
-/** @} */
diff --git a/drivers.c b/drivers.c
deleted file mode 100644 (file)
index f93214d..0000000
--- a/drivers.c
+++ /dev/null
@@ -1,359 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2014 Bert Vermeulen <bert@biot.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 "libsigrok.h"
-#include "libsigrok-internal.h"
-
-/** @cond PRIVATE */
-#ifdef HAVE_HW_AGILENT_DMM
-extern SR_PRIV struct sr_dev_driver agdmm_driver_info;
-#endif
-#ifdef HAVE_HW_APPA_55II
-extern SR_PRIV struct sr_dev_driver appa_55ii_driver_info;
-#endif
-#ifdef HAVE_HW_ASIX_SIGMA
-extern SR_PRIV struct sr_dev_driver asix_sigma_driver_info;
-#endif
-#ifdef HAVE_HW_ATTEN_PPS3XXX
-extern SR_PRIV struct sr_dev_driver atten_pps3203_driver_info;
-#endif
-#ifdef HAVE_HW_BEAGLELOGIC
-extern SR_PRIV struct sr_dev_driver beaglelogic_driver_info;
-#endif
-#ifdef HAVE_HW_BRYMEN_BM86X
-extern SR_PRIV struct sr_dev_driver brymen_bm86x_driver_info;
-#endif
-#ifdef HAVE_HW_BRYMEN_DMM
-extern SR_PRIV struct sr_dev_driver brymen_bm857_driver_info;
-#endif
-#ifdef HAVE_HW_CEM_DT_885X
-extern SR_PRIV struct sr_dev_driver cem_dt_885x_driver_info;
-#endif
-#ifdef HAVE_HW_CENTER_3XX
-extern SR_PRIV struct sr_dev_driver center_309_driver_info;
-extern SR_PRIV struct sr_dev_driver voltcraft_k204_driver_info;
-#endif
-#ifdef HAVE_HW_CHRONOVU_LA
-extern SR_PRIV struct sr_dev_driver chronovu_la_driver_info;
-#endif
-#ifdef HAVE_HW_COLEAD_SLM
-extern SR_PRIV struct sr_dev_driver colead_slm_driver_info;
-#endif
-#ifdef HAVE_HW_CONRAD_DIGI_35_CPU
-extern SR_PRIV struct sr_dev_driver conrad_digi_35_cpu_driver_info;
-#endif
-#ifdef HAVE_HW_DEMO
-extern SR_PRIV struct sr_dev_driver demo_driver_info;
-#endif
-#ifdef HAVE_HW_FLUKE_DMM
-extern SR_PRIV struct sr_dev_driver flukedmm_driver_info;
-#endif
-#ifdef HAVE_HW_FX2LAFW
-extern SR_PRIV struct sr_dev_driver fx2lafw_driver_info;
-#endif
-#ifdef HAVE_HW_GMC_MH_1X_2X
-extern SR_PRIV struct sr_dev_driver gmc_mh_1x_2x_rs232_driver_info;
-extern SR_PRIV struct sr_dev_driver gmc_mh_2x_bd232_driver_info;
-#endif
-#ifdef HAVE_HW_HAMEG_HMO
-extern SR_PRIV struct sr_dev_driver hameg_hmo_driver_info;
-#endif
-#ifdef HAVE_HW_HANTEK_DSO
-extern SR_PRIV struct sr_dev_driver hantek_dso_driver_info;
-#endif
-#ifdef HAVE_HW_IKALOGIC_SCANALOGIC2
-extern SR_PRIV struct sr_dev_driver ikalogic_scanalogic2_driver_info;
-#endif
-#ifdef HAVE_HW_IKALOGIC_SCANAPLUS
-extern SR_PRIV struct sr_dev_driver ikalogic_scanaplus_driver_info;
-#endif
-#ifdef HAVE_HW_KECHENG_KC_330B
-extern SR_PRIV struct sr_dev_driver kecheng_kc_330b_driver_info;
-#endif
-#ifdef HAVE_HW_LASCAR_EL_USB
-extern SR_PRIV struct sr_dev_driver lascar_el_usb_driver_info;
-#endif
-#ifdef HAVE_HW_LINK_MSO19
-extern SR_PRIV struct sr_dev_driver link_mso19_driver_info;
-#endif
-#ifdef HAVE_HW_MANSON_HCS_3XXX
-extern SR_PRIV struct sr_dev_driver manson_hcs_3xxx_driver_info;
-#endif
-#ifdef HAVE_HW_MIC_985XX
-extern SR_PRIV struct sr_dev_driver mic_98581_driver_info;
-extern SR_PRIV struct sr_dev_driver mic_98583_driver_info;
-#endif
-#ifdef HAVE_HW_MOTECH_LPS_30X
-extern SR_PRIV struct sr_dev_driver motech_lps_301_driver_info;
-#endif
-#ifdef HAVE_HW_NORMA_DMM
-extern SR_PRIV struct sr_dev_driver norma_dmm_driver_info;
-extern SR_PRIV struct sr_dev_driver siemens_b102x_driver_info;
-#endif
-#ifdef HAVE_HW_OPENBENCH_LOGIC_SNIFFER
-extern SR_PRIV struct sr_dev_driver ols_driver_info;
-#endif
-#ifdef HAVE_HW_RIGOL_DS
-extern SR_PRIV struct sr_dev_driver rigol_ds_driver_info;
-#endif
-#ifdef HAVE_HW_SALEAE_LOGIC16
-extern SR_PRIV struct sr_dev_driver saleae_logic16_driver_info;
-#endif
-#ifdef HAVE_HW_SERIAL_DMM
-extern SR_PRIV struct sr_dev_driver bbcgm_m2110_driver_info;
-extern SR_PRIV struct sr_dev_driver digitek_dt4000zc_driver_info;
-extern SR_PRIV struct sr_dev_driver tekpower_tp4000zc_driver_info;
-extern SR_PRIV struct sr_dev_driver metex_me31_driver_info;
-extern SR_PRIV struct sr_dev_driver peaktech_3410_driver_info;
-extern SR_PRIV struct sr_dev_driver mastech_mas345_driver_info;
-extern SR_PRIV struct sr_dev_driver va_va18b_driver_info;
-extern SR_PRIV struct sr_dev_driver va_va40b_driver_info;
-extern SR_PRIV struct sr_dev_driver metex_m3640d_driver_info;
-extern SR_PRIV struct sr_dev_driver metex_m4650cr_driver_info;
-extern SR_PRIV struct sr_dev_driver peaktech_4370_driver_info;
-extern SR_PRIV struct sr_dev_driver pce_pce_dm32_driver_info;
-extern SR_PRIV struct sr_dev_driver radioshack_22_168_driver_info;
-extern SR_PRIV struct sr_dev_driver radioshack_22_805_driver_info;
-extern SR_PRIV struct sr_dev_driver radioshack_22_812_driver_info;
-extern SR_PRIV struct sr_dev_driver tecpel_dmm_8061_ser_driver_info;
-extern SR_PRIV struct sr_dev_driver voltcraft_m3650cr_driver_info;
-extern SR_PRIV struct sr_dev_driver voltcraft_m3650d_driver_info;
-extern SR_PRIV struct sr_dev_driver voltcraft_m4650cr_driver_info;
-extern SR_PRIV struct sr_dev_driver voltcraft_me42_driver_info;
-extern SR_PRIV struct sr_dev_driver voltcraft_vc820_ser_driver_info;
-extern SR_PRIV struct sr_dev_driver voltcraft_vc830_ser_driver_info;
-extern SR_PRIV struct sr_dev_driver voltcraft_vc840_ser_driver_info;
-extern SR_PRIV struct sr_dev_driver uni_t_ut60a_ser_driver_info;
-extern SR_PRIV struct sr_dev_driver uni_t_ut60e_ser_driver_info;
-extern SR_PRIV struct sr_dev_driver uni_t_ut60g_ser_driver_info;
-extern SR_PRIV struct sr_dev_driver uni_t_ut61b_ser_driver_info;
-extern SR_PRIV struct sr_dev_driver uni_t_ut61c_ser_driver_info;
-extern SR_PRIV struct sr_dev_driver uni_t_ut61d_ser_driver_info;
-extern SR_PRIV struct sr_dev_driver uni_t_ut61e_ser_driver_info;
-extern SR_PRIV struct sr_dev_driver iso_tech_idm103n_driver_info;
-extern SR_PRIV struct sr_dev_driver tenma_72_7745_ser_driver_info;
-extern SR_PRIV struct sr_dev_driver tenma_72_7750_ser_driver_info;
-#endif
-#ifdef HAVE_HW_SYSCLK_LWLA
-extern SR_PRIV struct sr_dev_driver sysclk_lwla_driver_info;
-#endif
-#ifdef HAVE_HW_TELEINFO
-extern SR_PRIV struct sr_dev_driver teleinfo_driver_info;
-#endif
-#ifdef HAVE_HW_TESTO
-extern SR_PRIV struct sr_dev_driver testo_driver_info;
-#endif
-#ifdef HAVE_HW_TONDAJ_SL_814
-extern SR_PRIV struct sr_dev_driver tondaj_sl_814_driver_info;
-#endif
-#ifdef HAVE_HW_UNI_T_DMM
-extern SR_PRIV struct sr_dev_driver tecpel_dmm_8061_driver_info;
-extern SR_PRIV struct sr_dev_driver uni_t_ut60a_driver_info;
-extern SR_PRIV struct sr_dev_driver uni_t_ut60e_driver_info;
-extern SR_PRIV struct sr_dev_driver uni_t_ut60g_driver_info;
-extern SR_PRIV struct sr_dev_driver uni_t_ut61b_driver_info;
-extern SR_PRIV struct sr_dev_driver uni_t_ut61c_driver_info;
-extern SR_PRIV struct sr_dev_driver uni_t_ut61d_driver_info;
-extern SR_PRIV struct sr_dev_driver uni_t_ut61e_driver_info;
-extern SR_PRIV struct sr_dev_driver voltcraft_vc820_driver_info;
-extern SR_PRIV struct sr_dev_driver voltcraft_vc830_driver_info;
-extern SR_PRIV struct sr_dev_driver voltcraft_vc840_driver_info;
-extern SR_PRIV struct sr_dev_driver tenma_72_7745_driver_info;
-extern SR_PRIV struct sr_dev_driver tenma_72_7750_driver_info;
-#endif
-#ifdef HAVE_HW_UNI_T_UT32X
-extern SR_PRIV struct sr_dev_driver uni_t_ut32x_driver_info;
-#endif
-#ifdef HAVE_HW_VICTOR_DMM
-extern SR_PRIV struct sr_dev_driver victor_dmm_driver_info;
-#endif
-#ifdef HAVE_HW_ZEROPLUS_LOGIC_CUBE
-extern SR_PRIV struct sr_dev_driver zeroplus_logic_cube_driver_info;
-#endif
-
-SR_PRIV struct sr_dev_driver *drivers_list[] = {
-#ifdef HAVE_HW_AGILENT_DMM
-       &agdmm_driver_info,
-#endif
-#ifdef HAVE_HW_APPA_55II
-       &appa_55ii_driver_info,
-#endif
-#ifdef HAVE_HW_ASIX_SIGMA
-       &asix_sigma_driver_info,
-#endif
-#ifdef HAVE_HW_ATTEN_PPS3XXX
-       &atten_pps3203_driver_info,
-#endif
-#ifdef HAVE_HW_BEAGLELOGIC
-       &beaglelogic_driver_info,
-#endif
-#ifdef HAVE_HW_BRYMEN_BM86X
-       &brymen_bm86x_driver_info,
-#endif
-#ifdef HAVE_HW_BRYMEN_DMM
-       &brymen_bm857_driver_info,
-#endif
-#ifdef HAVE_HW_CEM_DT_885X
-       &cem_dt_885x_driver_info,
-#endif
-#ifdef HAVE_HW_CENTER_3XX
-       &center_309_driver_info,
-       &voltcraft_k204_driver_info,
-#endif
-#ifdef HAVE_HW_CHRONOVU_LA
-       &chronovu_la_driver_info,
-#endif
-#ifdef HAVE_HW_COLEAD_SLM
-       &colead_slm_driver_info,
-#endif
-#ifdef HAVE_HW_CONRAD_DIGI_35_CPU
-       &conrad_digi_35_cpu_driver_info,
-#endif
-#ifdef HAVE_HW_DEMO
-       &demo_driver_info,
-#endif
-#ifdef HAVE_HW_FLUKE_DMM
-       &flukedmm_driver_info,
-#endif
-#ifdef HAVE_HW_FX2LAFW
-       &fx2lafw_driver_info,
-#endif
-#ifdef HAVE_HW_GMC_MH_1X_2X
-       &gmc_mh_1x_2x_rs232_driver_info,
-       &gmc_mh_2x_bd232_driver_info,
-#endif
-#ifdef HAVE_HW_HAMEG_HMO
-       &hameg_hmo_driver_info,
-#endif
-#ifdef HAVE_HW_HANTEK_DSO
-       &hantek_dso_driver_info,
-#endif
-#ifdef HAVE_HW_IKALOGIC_SCANALOGIC2
-       &ikalogic_scanalogic2_driver_info,
-#endif
-#ifdef HAVE_HW_IKALOGIC_SCANAPLUS
-       &ikalogic_scanaplus_driver_info,
-#endif
-#ifdef HAVE_HW_KECHENG_KC_330B
-       &kecheng_kc_330b_driver_info,
-#endif
-#ifdef HAVE_HW_LASCAR_EL_USB
-       &lascar_el_usb_driver_info,
-#endif
-#ifdef HAVE_HW_LINK_MSO19
-       &link_mso19_driver_info,
-#endif
-#ifdef HAVE_HW_MANSON_HCS_3XXX
-       &manson_hcs_3xxx_driver_info,
-#endif
-#ifdef HAVE_HW_MIC_985XX
-       &mic_98581_driver_info,
-       &mic_98583_driver_info,
-#endif
-#ifdef HAVE_HW_MOTECH_LPS_30X
-       &motech_lps_301_driver_info,
-#endif
-#ifdef HAVE_HW_NORMA_DMM
-       &norma_dmm_driver_info,
-       &siemens_b102x_driver_info,
-#endif
-#ifdef HAVE_HW_OPENBENCH_LOGIC_SNIFFER
-       &ols_driver_info,
-#endif
-#ifdef HAVE_HW_RIGOL_DS
-       &rigol_ds_driver_info,
-#endif
-#ifdef HAVE_HW_SALEAE_LOGIC16
-       &saleae_logic16_driver_info,
-#endif
-#ifdef HAVE_HW_SERIAL_DMM
-       &bbcgm_m2110_driver_info,
-       &digitek_dt4000zc_driver_info,
-       &tekpower_tp4000zc_driver_info,
-       &metex_me31_driver_info,
-       &peaktech_3410_driver_info,
-       &mastech_mas345_driver_info,
-       &va_va18b_driver_info,
-       &va_va40b_driver_info,
-       &metex_m3640d_driver_info,
-       &metex_m4650cr_driver_info,
-       &peaktech_4370_driver_info,
-       &pce_pce_dm32_driver_info,
-       &radioshack_22_168_driver_info,
-       &radioshack_22_805_driver_info,
-       &radioshack_22_812_driver_info,
-       &tecpel_dmm_8061_ser_driver_info,
-       &voltcraft_m3650cr_driver_info,
-       &voltcraft_m3650d_driver_info,
-       &voltcraft_m4650cr_driver_info,
-       &voltcraft_me42_driver_info,
-       &voltcraft_vc820_ser_driver_info,
-       &voltcraft_vc830_ser_driver_info,
-       &voltcraft_vc840_ser_driver_info,
-       &uni_t_ut60a_ser_driver_info,
-       &uni_t_ut60e_ser_driver_info,
-       &uni_t_ut60g_ser_driver_info,
-       &uni_t_ut61b_ser_driver_info,
-       &uni_t_ut61c_ser_driver_info,
-       &uni_t_ut61d_ser_driver_info,
-       &uni_t_ut61e_ser_driver_info,
-       &iso_tech_idm103n_driver_info,
-       &tenma_72_7745_ser_driver_info,
-       &tenma_72_7750_ser_driver_info,
-#endif
-#ifdef HAVE_HW_SYSCLK_LWLA
-       &sysclk_lwla_driver_info,
-#endif
-#ifdef HAVE_HW_TELEINFO
-       &teleinfo_driver_info,
-#endif
-#ifdef HAVE_HW_TESTO
-       &testo_driver_info,
-#endif
-#ifdef HAVE_HW_TONDAJ_SL_814
-       &tondaj_sl_814_driver_info,
-#endif
-#ifdef HAVE_HW_UNI_T_DMM
-       &tecpel_dmm_8061_driver_info,
-       &uni_t_ut60a_driver_info,
-       &uni_t_ut60e_driver_info,
-       &uni_t_ut60g_driver_info,
-       &uni_t_ut61b_driver_info,
-       &uni_t_ut61c_driver_info,
-       &uni_t_ut61d_driver_info,
-       &uni_t_ut61e_driver_info,
-       &voltcraft_vc820_driver_info,
-       &voltcraft_vc830_driver_info,
-       &voltcraft_vc840_driver_info,
-       &tenma_72_7745_driver_info,
-       &tenma_72_7750_driver_info,
-#endif
-#ifdef HAVE_HW_UNI_T_UT32X
-       &uni_t_ut32x_driver_info,
-#endif
-#ifdef HAVE_HW_VICTOR_DMM
-       &victor_dmm_driver_info,
-#endif
-#ifdef HAVE_HW_ZEROPLUS_LOGIC_CUBE
-       &zeroplus_logic_cube_driver_info,
-#endif
-       NULL,
-};
-/** @endcond */
-
diff --git a/error.c b/error.c
deleted file mode 100644 (file)
index f877975..0000000
--- a/error.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include "libsigrok.h"
-
-/**
- * @file
- *
- * Error handling in libsigrok.
- */
-
-/**
- * @defgroup grp_error Error handling
- *
- * Error handling in libsigrok.
- *
- * libsigrok functions usually return @ref SR_OK upon success, or a negative
- * error code on failure.
- *
- * @{
- */
-
-/**
- * Return a human-readable error string for the given libsigrok error code.
- *
- * @param error_code A libsigrok error code number, such as SR_ERR_MALLOC.
- *
- * @return A const string containing a short, human-readable (English)
- *         description of the error, such as "memory allocation error".
- *         The string must NOT be free'd by the caller!
- *
- * @see sr_strerror_name
- *
- * @since 0.2.0
- */
-SR_API const char *sr_strerror(int error_code)
-{
-       /*
-        * Note: All defined SR_* error macros from libsigrok.h must have
-        * an entry in this function, as well as in sr_strerror_name().
-        */
-
-       switch (error_code) {
-       case SR_OK:
-               return "no error";
-       case SR_ERR:
-               return "generic/unspecified error";
-       case SR_ERR_MALLOC:
-               return "memory allocation error";
-       case SR_ERR_ARG:
-               return "invalid argument";
-       case SR_ERR_BUG:
-               return "internal error";
-       case SR_ERR_SAMPLERATE:
-               return "invalid samplerate";
-       case SR_ERR_NA:
-               return "not applicable";
-       case SR_ERR_DEV_CLOSED:
-               return "device closed but should be open";
-       case SR_ERR_TIMEOUT:
-               return "timeout occurred";
-       case SR_ERR_CHANNEL_GROUP:
-               return "no channel group specified";
-       default:
-               return "unknown error";
-       }
-}
-
-/**
- * Return the "name" string of the given libsigrok error code.
- *
- * For example, the "name" of the SR_ERR_MALLOC error code is "SR_ERR_MALLOC",
- * the name of the SR_OK code is "SR_OK", and so on.
- *
- * This function can be used for various purposes where the "name" string of
- * a libsigrok error code is useful.
- *
- * @param error_code A libsigrok error code number, such as SR_ERR_MALLOC.
- *
- * @return A const string containing the "name" of the error code as string.
- *         The string must NOT be free'd by the caller!
- *
- * @see sr_strerror
- *
- * @since 0.2.0
- */
-SR_API const char *sr_strerror_name(int error_code)
-{
-       /*
-        * Note: All defined SR_* error macros from libsigrok.h must have
-        * an entry in this function, as well as in sr_strerror().
-        */
-
-       switch (error_code) {
-       case SR_OK:
-               return "SR_OK";
-       case SR_ERR:
-               return "SR_ERR";
-       case SR_ERR_MALLOC:
-               return "SR_ERR_MALLOC";
-       case SR_ERR_ARG:
-               return "SR_ERR_ARG";
-       case SR_ERR_BUG:
-               return "SR_ERR_BUG";
-       case SR_ERR_SAMPLERATE:
-               return "SR_ERR_SAMPLERATE";
-       case SR_ERR_NA:
-               return "SR_ERR_NA";
-       case SR_ERR_DEV_CLOSED:
-               return "SR_ERR_DEV_CLOSED";
-       case SR_ERR_TIMEOUT:
-               return "SR_ERR_TIMEOUT";
-       case SR_ERR_CHANNEL_GROUP:
-               return "SR_ERR_CHANNEL_GROUP";
-       default:
-               return "unknown error code";
-       }
-}
-
-/** @} */
diff --git a/hardware/agilent-dmm/agilent-dmm.h b/hardware/agilent-dmm/agilent-dmm.h
deleted file mode 100644 (file)
index 2277111..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012 Bert Vermeulen <bert@biot.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_AGILENT_DMM_AGILENT_DMM_H
-#define LIBSIGROK_HARDWARE_AGILENT_DMM_AGILENT_DMM_H
-
-#define LOG_PREFIX "agilent-dmm"
-
-#define AGDMM_BUFSIZE  256
-
-/* Supported models */
-enum {
-       AGILENT_U1231A = 1,
-       AGILENT_U1232A,
-       AGILENT_U1233A,
-       AGILENT_U1251A,
-       AGILENT_U1252A,
-       AGILENT_U1253A,
-};
-
-/* Supported device profiles */
-struct agdmm_profile {
-       int model;
-       const char *modelname;
-       const struct agdmm_job *jobs;
-       const struct agdmm_recv *recvs;
-};
-
-/* Private, per-device-instance driver context. */
-struct dev_context {
-       const struct agdmm_profile *profile;
-       uint64_t limit_samples;
-       uint64_t limit_msec;
-
-       /* Opaque pointer passed in by the frontend. */
-       void *cb_data;
-
-       /* Runtime. */
-       uint64_t num_samples;
-       int64_t jobqueue[8];
-       unsigned char buf[AGDMM_BUFSIZE];
-       int buflen;
-       int cur_mq;
-       int cur_unit;
-       int cur_mqflags;
-       int cur_divider;
-       int cur_acdc;
-       int mode_tempaux;
-       int mode_continuity;
-};
-
-struct agdmm_job {
-       int interval;
-       int (*send) (const struct sr_dev_inst *sdi);
-};
-
-struct agdmm_recv {
-       const char *recv_regex;
-       int (*recv) (const struct sr_dev_inst *sdi, GMatchInfo *match);
-};
-
-SR_PRIV int agdmm_receive_data(int fd, int revents, void *cb_data);
-
-#endif
diff --git a/hardware/agilent-dmm/api.c b/hardware/agilent-dmm/api.c
deleted file mode 100644 (file)
index cb7baa6..0000000
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012 Bert Vermeulen <bert@biot.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 <glib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <string.h>
-#include <errno.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-#include "agilent-dmm.h"
-
-static const int32_t hwopts[] = {
-       SR_CONF_CONN,
-       SR_CONF_SERIALCOMM,
-};
-
-static const int32_t hwcaps[] = {
-       SR_CONF_MULTIMETER,
-       SR_CONF_LIMIT_SAMPLES,
-       SR_CONF_LIMIT_MSEC,
-       SR_CONF_CONTINUOUS,
-};
-
-extern const struct agdmm_job agdmm_jobs_u123x[];
-extern const struct agdmm_recv agdmm_recvs_u123x[];
-extern const struct agdmm_job agdmm_jobs_u125x[];
-extern const struct agdmm_recv agdmm_recvs_u125x[];
-
-/* This works on all the Agilent U12xxA series, although the
- * U127xA can apparently also run at 19200/8n1. */
-#define SERIALCOMM "9600/8n1"
-
-static const struct agdmm_profile supported_agdmm[] = {
-       { AGILENT_U1231A, "U1231A", agdmm_jobs_u123x, agdmm_recvs_u123x },
-       { AGILENT_U1232A, "U1232A", agdmm_jobs_u123x, agdmm_recvs_u123x },
-       { AGILENT_U1233A, "U1233A", agdmm_jobs_u123x, agdmm_recvs_u123x },
-       { AGILENT_U1251A, "U1251A", agdmm_jobs_u125x, agdmm_recvs_u125x },
-       { AGILENT_U1252A, "U1252A", agdmm_jobs_u125x, agdmm_recvs_u125x },
-       { AGILENT_U1253A, "U1253A", agdmm_jobs_u125x, agdmm_recvs_u125x },
-       { 0, NULL, NULL, NULL }
-};
-
-SR_PRIV struct sr_dev_driver agdmm_driver_info;
-static struct sr_dev_driver *di = &agdmm_driver_info;
-
-static int init(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, di, LOG_PREFIX);
-}
-
-static GSList *scan(GSList *options)
-{
-       struct sr_dev_inst *sdi;
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       struct sr_config *src;
-       struct sr_channel *ch;
-       struct sr_serial_dev_inst *serial;
-       GSList *l, *devices;
-       int len, i;
-       const char *conn, *serialcomm;
-       char *buf, **tokens;
-
-       drvc = di->priv;
-       drvc->instances = NULL;
-
-       devices = NULL;
-       conn = serialcomm = NULL;
-       for (l = options; l; l = l->next) {
-               src = l->data;
-               switch (src->key) {
-               case SR_CONF_CONN:
-                       conn = g_variant_get_string(src->data, NULL);
-                       break;
-               case SR_CONF_SERIALCOMM:
-                       serialcomm = g_variant_get_string(src->data, NULL);
-                       break;
-               }
-       }
-       if (!conn)
-               return NULL;
-       if (!serialcomm)
-               serialcomm = SERIALCOMM;
-
-       if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
-               return NULL;
-
-       if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
-               return NULL;
-
-       serial_flush(serial);
-       if (serial_write(serial, "*IDN?\r\n", 7) == -1) {
-               sr_err("Unable to send identification string: %s.",
-                      strerror(errno));
-               return NULL;
-       }
-
-       len = 128;
-       if (!(buf = g_try_malloc(len))) {
-               sr_err("Serial buffer malloc failed.");
-               return NULL;
-       }
-       serial_readline(serial, &buf, &len, 150);
-       if (!len)
-               return NULL;
-
-       tokens = g_strsplit(buf, ",", 4);
-       if (!strcmp("Agilent Technologies", tokens[0])
-                       && tokens[1] && tokens[2] && tokens[3]) {
-               for (i = 0; supported_agdmm[i].model; i++) {
-                       if (strcmp(supported_agdmm[i].modelname, tokens[1]))
-                               continue;
-                       if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "Agilent",
-                                       tokens[1], tokens[3])))
-                               return NULL;
-                       if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
-                               sr_err("Device context malloc failed.");
-                               return NULL;
-                       }
-                       devc->profile = &supported_agdmm[i];
-                       devc->cur_mq = -1;
-                       sdi->inst_type = SR_INST_SERIAL;
-                       sdi->conn = serial;
-                       sdi->priv = devc;
-                       sdi->driver = di;
-                       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1")))
-                               return NULL;
-                       sdi->channels = g_slist_append(sdi->channels, ch);
-                       drvc->instances = g_slist_append(drvc->instances, sdi);
-                       devices = g_slist_append(devices, sdi);
-                       break;
-               }
-       }
-       g_strfreev(tokens);
-       g_free(buf);
-
-       serial_close(serial);
-       if (!devices)
-               sr_serial_dev_inst_free(serial);
-
-       return devices;
-}
-
-static GSList *dev_list(void)
-{
-       return ((struct drv_context *)(di->priv))->instances;
-}
-
-static int cleanup(void)
-{
-       return std_dev_clear(di, NULL);
-}
-
-static int config_set(int id, 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;
-
-       if (!(devc = sdi->priv)) {
-               sr_err("sdi->priv was NULL.");
-               return SR_ERR_BUG;
-       }
-
-       switch (id) {
-       case SR_CONF_LIMIT_MSEC:
-               /* TODO: not yet implemented */
-               if (g_variant_get_uint64(data) == 0) {
-                       sr_err("LIMIT_MSEC can't be 0.");
-                       return SR_ERR;
-               }
-               devc->limit_msec = g_variant_get_uint64(data);
-               sr_dbg("Setting time limit to %" PRIu64 "ms.",
-                      devc->limit_msec);
-               break;
-       case SR_CONF_LIMIT_SAMPLES:
-               devc->limit_samples = g_variant_get_uint64(data);
-               sr_dbg("Setting sample limit to %" PRIu64 ".",
-                      devc->limit_samples);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_list(int 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_INT32,
-                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
-               break;
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       if (!(devc = sdi->priv)) {
-               sr_err("sdi->priv was NULL.");
-               return SR_ERR_BUG;
-       }
-
-       devc->cb_data = cb_data;
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(cb_data, LOG_PREFIX);
-
-       /* Poll every 100ms, or whenever some data comes in. */
-       serial = sdi->conn;
-       serial_source_add(sdi->session, serial, G_IO_IN, 100,
-                       agdmm_receive_data, (void *)sdi);
-
-       return SR_OK;
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       return std_serial_dev_acquisition_stop(sdi, cb_data, std_serial_dev_close,
-                       sdi->conn, LOG_PREFIX);
-}
-
-SR_PRIV struct sr_dev_driver agdmm_driver_info = {
-       .name = "agilent-dmm",
-       .longname = "Agilent U12xx series DMMs",
-       .api_version = 1,
-       .init = init,
-       .cleanup = cleanup,
-       .scan = scan,
-       .dev_list = 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 = dev_acquisition_stop,
-       .priv = NULL,
-};
diff --git a/hardware/agilent-dmm/sched.c b/hardware/agilent-dmm/sched.c
deleted file mode 100644 (file)
index bd9cb38..0000000
+++ /dev/null
@@ -1,474 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012 Bert Vermeulen <bert@biot.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 <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-#include "agilent-dmm.h"
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <math.h>
-
-static void dispatch(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       const struct agdmm_job *jobs;
-       int64_t now;
-       int i;
-
-       devc = sdi->priv;
-       jobs = devc->profile->jobs;
-       now = g_get_monotonic_time() / 1000;
-       for (i = 0; (&jobs[i])->interval; i++) {
-               if (now - devc->jobqueue[i] > (&jobs[i])->interval) {
-                       sr_spew("Running job %d.", i);
-                       (&jobs[i])->send(sdi);
-                       devc->jobqueue[i] = now;
-               }
-       }
-}
-
-static void receive_line(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       const struct agdmm_recv *recvs, *recv;
-       GRegex *reg;
-       GMatchInfo *match;
-       int i;
-
-       devc = sdi->priv;
-
-       /* Strip CRLF */
-       while (devc->buflen) {
-               if (*(devc->buf + devc->buflen - 1) == '\r'
-                               || *(devc->buf + devc->buflen - 1) == '\n')
-                       *(devc->buf + --devc->buflen) = '\0';
-               else
-                       break;
-       }
-       sr_spew("Received '%s'.", devc->buf);
-
-       recv = NULL;
-       recvs = devc->profile->recvs;
-       for (i = 0; (&recvs[i])->recv_regex; i++) {
-               reg = g_regex_new((&recvs[i])->recv_regex, 0, 0, NULL);
-               if (g_regex_match(reg, (char *)devc->buf, 0, &match)) {
-                       recv = &recvs[i];
-                       break;
-               }
-               g_match_info_unref(match);
-               g_regex_unref(reg);
-       }
-       if (recv) {
-               recv->recv(sdi, match);
-               g_match_info_unref(match);
-               g_regex_unref(reg);
-       } else
-               sr_dbg("Unknown line '%s'.", devc->buf);
-
-       /* Done with this. */
-       devc->buflen = 0;
-}
-
-SR_PRIV int agdmm_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 len;
-
-       (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. */
-               while(AGDMM_BUFSIZE - devc->buflen - 1 > 0) {
-                       len = serial_read(serial, devc->buf + devc->buflen, 1);
-                       if (len < 1)
-                               break;
-                       devc->buflen += len;
-                       *(devc->buf + devc->buflen) = '\0';
-                       if (*(devc->buf + devc->buflen - 1) == '\n') {
-                               /* End of line */
-                               receive_line(sdi);
-                               break;
-                       }
-               }
-       }
-
-       dispatch(sdi);
-
-       if (devc->limit_samples && devc->num_samples >= devc->limit_samples)
-               sdi->driver->dev_acquisition_stop(sdi, cb_data);
-
-       return TRUE;
-}
-
-static int agdmm_send(const struct sr_dev_inst *sdi, const char *cmd)
-{
-       struct sr_serial_dev_inst *serial;
-       char buf[32];
-
-       serial = sdi->conn;
-
-       sr_spew("Sending '%s'.", cmd);
-       strncpy(buf, cmd, 28);
-       if (!strncmp(buf, "*IDN?", 5))
-               strncat(buf, "\r\n", 32);
-       else
-               strncat(buf, "\n\r\n", 32);
-       if (serial_write(serial, buf, strlen(buf)) == -1) {
-               sr_err("Failed to send: %s.", strerror(errno));
-               return SR_ERR;
-       }
-
-       return SR_OK;
-}
-
-static int send_stat(const struct sr_dev_inst *sdi)
-{
-       return agdmm_send(sdi, "STAT?");
-}
-
-static int recv_stat_u123x(const struct sr_dev_inst *sdi, GMatchInfo *match)
-{
-       struct dev_context *devc;
-       char *s;
-
-       devc = sdi->priv;
-       s = g_match_info_fetch(match, 1);
-       sr_spew("STAT response '%s'.", s);
-
-       /* Max, Min or Avg mode -- no way to tell which, so we'll
-        * set both flags to denote it's not a normal measurement. */
-       if (s[0] == '1')
-               devc->cur_mqflags |= SR_MQFLAG_MAX | SR_MQFLAG_MIN;
-       else
-               devc->cur_mqflags &= ~(SR_MQFLAG_MAX | SR_MQFLAG_MIN);
-
-       if (s[1] == '1')
-               devc->cur_mqflags |= SR_MQFLAG_RELATIVE;
-       else
-               devc->cur_mqflags &= ~SR_MQFLAG_RELATIVE;
-
-       /* Triggered or auto hold modes. */
-       if (s[2] == '1' || s[3] == '1')
-               devc->cur_mqflags |= SR_MQFLAG_HOLD;
-       else
-               devc->cur_mqflags &= ~SR_MQFLAG_HOLD;
-
-       /* Temp/aux mode. */
-       if (s[7] == '1')
-               devc->mode_tempaux = TRUE;
-       else
-               devc->mode_tempaux = FALSE;
-
-       /* Continuity mode. */
-       if (s[16] == '1')
-               devc->mode_continuity = TRUE;
-       else
-               devc->mode_continuity = FALSE;
-
-       g_free(s);
-
-       return SR_OK;
-}
-
-static int recv_stat_u125x(const struct sr_dev_inst *sdi, GMatchInfo *match)
-{
-       struct dev_context *devc;
-       char *s;
-
-       devc = sdi->priv;
-       s = g_match_info_fetch(match, 1);
-       sr_spew("STAT response '%s'.", s);
-
-       /* Peak hold mode. */
-       if (s[4] == '1')
-               devc->cur_mqflags |= SR_MQFLAG_MAX;
-       else
-               devc->cur_mqflags &= ~SR_MQFLAG_MAX;
-
-       /* Triggered hold mode. */
-       if (s[7] == '1')
-               devc->cur_mqflags |= SR_MQFLAG_HOLD;
-       else
-               devc->cur_mqflags &= ~SR_MQFLAG_HOLD;
-
-       g_free(s);
-
-       return SR_OK;
-}
-
-static int send_fetc(const struct sr_dev_inst *sdi)
-{
-       return agdmm_send(sdi, "FETC?");
-}
-
-static int recv_fetc(const struct sr_dev_inst *sdi, GMatchInfo *match)
-{
-       struct dev_context *devc;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_analog analog;
-       float fvalue;
-       char *mstr;
-
-       sr_spew("FETC reply '%s'.", g_match_info_get_string(match));
-       devc = sdi->priv;
-
-       if (devc->cur_mq == -1)
-               /* Haven't seen configuration yet, so can't know what
-                * the fetched float means. Not really an error, we'll
-                * get metadata soon enough. */
-               return SR_OK;
-
-       if (!strcmp(g_match_info_get_string(match), "+9.90000000E+37")) {
-               /* An invalid measurement shows up on the display as "O.L", but
-                * comes through like this. Since comparing 38-digit floats
-                * is rather problematic, we'll cut through this here. */
-               fvalue = NAN;
-       } else {
-               mstr = g_match_info_fetch(match, 1);
-               if (sr_atof_ascii(mstr, &fvalue) != SR_OK || fvalue == 0.0) {
-                       g_free(mstr);
-                       sr_err("Invalid float.");
-                       return SR_ERR;
-               }
-               g_free(mstr);
-               if (devc->cur_divider > 0)
-                       fvalue /= devc->cur_divider;
-       }
-
-       memset(&analog, 0, sizeof(struct sr_datafeed_analog));
-       analog.mq = devc->cur_mq;
-       analog.unit = devc->cur_unit;
-       analog.mqflags = devc->cur_mqflags;
-       analog.channels = sdi->channels;
-       analog.num_samples = 1;
-       analog.data = &fvalue;
-       packet.type = SR_DF_ANALOG;
-       packet.payload = &analog;
-       sr_session_send(devc->cb_data, &packet);
-
-       devc->num_samples++;
-
-       return SR_OK;
-}
-
-static int send_conf(const struct sr_dev_inst *sdi)
-{
-       return agdmm_send(sdi, "CONF?");
-}
-
-static int recv_conf_u123x(const struct sr_dev_inst *sdi, GMatchInfo *match)
-{
-       struct dev_context *devc;
-       char *mstr;
-
-       sr_spew("CONF? response '%s'.", g_match_info_get_string(match));
-       devc = sdi->priv;
-       mstr = g_match_info_fetch(match, 1);
-       if (!strcmp(mstr, "V")) {
-               devc->cur_mq = SR_MQ_VOLTAGE;
-               devc->cur_unit = SR_UNIT_VOLT;
-               devc->cur_mqflags = 0;
-               devc->cur_divider = 0;
-       } else if(!strcmp(mstr, "MV")) {
-               if (devc->mode_tempaux) {
-                       devc->cur_mq = SR_MQ_TEMPERATURE;
-                       /* No way to detect whether Fahrenheit or Celcius
-                        * is used, so we'll just default to Celcius. */
-                       devc->cur_unit = SR_UNIT_CELSIUS;
-               devc->cur_mqflags = 0;
-               devc->cur_divider = 0;
-               } else {
-                       devc->cur_mq = SR_MQ_VOLTAGE;
-                       devc->cur_unit = SR_UNIT_VOLT;
-                       devc->cur_mqflags = 0;
-                       devc->cur_divider = 1000;
-               }
-       } else if(!strcmp(mstr, "A")) {
-               devc->cur_mq = SR_MQ_CURRENT;
-               devc->cur_unit = SR_UNIT_AMPERE;
-               devc->cur_mqflags = 0;
-               devc->cur_divider = 0;
-       } else if(!strcmp(mstr, "UA")) {
-               devc->cur_mq = SR_MQ_CURRENT;
-               devc->cur_unit = SR_UNIT_AMPERE;
-               devc->cur_mqflags = 0;
-               devc->cur_divider = 1000000;
-       } else if(!strcmp(mstr, "FREQ")) {
-               devc->cur_mq = SR_MQ_FREQUENCY;
-               devc->cur_unit = SR_UNIT_HERTZ;
-               devc->cur_mqflags = 0;
-               devc->cur_divider = 0;
-       } else if(!strcmp(mstr, "RES")) {
-               if (devc->mode_continuity) {
-                       devc->cur_mq = SR_MQ_CONTINUITY;
-                       devc->cur_unit = SR_UNIT_BOOLEAN;
-               } else {
-                       devc->cur_mq = SR_MQ_RESISTANCE;
-                       devc->cur_unit = SR_UNIT_OHM;
-               }
-               devc->cur_mqflags = 0;
-               devc->cur_divider = 0;
-       } else if(!strcmp(mstr, "CAP")) {
-               devc->cur_mq = SR_MQ_CAPACITANCE;
-               devc->cur_unit = SR_UNIT_FARAD;
-               devc->cur_mqflags = 0;
-               devc->cur_divider = 0;
-       } else
-               sr_dbg("Unknown first argument.");
-       g_free(mstr);
-
-       if (g_match_info_get_match_count(match) == 4) {
-               mstr = g_match_info_fetch(match, 3);
-               /* Third value, if present, is always AC or DC. */
-               if (!strcmp(mstr, "AC"))
-                       devc->cur_mqflags |= SR_MQFLAG_AC;
-               else if (!strcmp(mstr, "DC"))
-                       devc->cur_mqflags |= SR_MQFLAG_DC;
-               else
-                       sr_dbg("Unknown third argument.");
-               g_free(mstr);
-       } else
-               devc->cur_mqflags &= ~(SR_MQFLAG_AC | SR_MQFLAG_DC);
-
-       return SR_OK;
-}
-
-static int recv_conf_u125x(const struct sr_dev_inst *sdi, GMatchInfo *match)
-{
-       struct dev_context *devc;
-       char *mstr;
-
-       sr_spew("CONF? response '%s'.", g_match_info_get_string(match));
-       devc = sdi->priv;
-       mstr = g_match_info_fetch(match, 1);
-       if (!strncmp(mstr, "VOLT", 4)) {
-               devc->cur_mq = SR_MQ_VOLTAGE;
-               devc->cur_unit = SR_UNIT_VOLT;
-               devc->cur_mqflags = 0;
-               devc->cur_divider = 0;
-               if (mstr[4] == ':') {
-                       if (!strcmp(mstr + 4, "AC"))
-                               devc->cur_mqflags |= SR_MQFLAG_AC;
-                       else if (!strcmp(mstr + 4, "DC"))
-                               devc->cur_mqflags |= SR_MQFLAG_DC;
-                       else
-                               /* "ACDC" appears as well, no idea what it means. */
-                               devc->cur_mqflags &= ~(SR_MQFLAG_AC | SR_MQFLAG_DC);
-               } else
-                       devc->cur_mqflags &= ~(SR_MQFLAG_AC | SR_MQFLAG_DC);
-       } else if(!strcmp(mstr, "CURR")) {
-               devc->cur_mq = SR_MQ_CURRENT;
-               devc->cur_unit = SR_UNIT_AMPERE;
-               devc->cur_mqflags = 0;
-               devc->cur_divider = 0;
-       } else if(!strcmp(mstr, "RES")) {
-               if (devc->mode_continuity) {
-                       devc->cur_mq = SR_MQ_CONTINUITY;
-                       devc->cur_unit = SR_UNIT_BOOLEAN;
-               } else {
-                       devc->cur_mq = SR_MQ_RESISTANCE;
-                       devc->cur_unit = SR_UNIT_OHM;
-               }
-               devc->cur_mqflags = 0;
-               devc->cur_divider = 0;
-       } else
-               sr_dbg("Unknown first argument.");
-       g_free(mstr);
-
-       return SR_OK;
-}
-
-/* At least the 123x and 125x appear to have this. */
-static int recv_conf(const struct sr_dev_inst *sdi, GMatchInfo *match)
-{
-       struct dev_context *devc;
-       char *mstr;
-
-       sr_spew("CONF? response '%s'.", g_match_info_get_string(match));
-       devc = sdi->priv;
-       mstr = g_match_info_fetch(match, 1);
-       if(!strcmp(mstr, "DIOD")) {
-               devc->cur_mq = SR_MQ_VOLTAGE;
-               devc->cur_unit = SR_UNIT_VOLT;
-               devc->cur_mqflags = SR_MQFLAG_DIODE;
-               devc->cur_divider = 0;
-       } else
-               sr_dbg("Unknown single argument.");
-       g_free(mstr);
-
-       return SR_OK;
-}
-
-/* This comes in whenever the rotary switch is changed to a new position.
- * We could use it to determine the major measurement mode, but we already
- * have the output of CONF? for that, which is more detailed. However
- * we do need to catch this here, or it'll show up in some other output. */
-static int recv_switch(const struct sr_dev_inst *sdi, GMatchInfo *match)
-{
-       (void)sdi;
-
-       sr_spew("Switch '%s'.", g_match_info_get_string(match));
-
-       return SR_OK;
-}
-
-SR_PRIV const struct agdmm_job agdmm_jobs_u123x[] = {
-       { 143, send_stat },
-       { 1000, send_conf },
-       { 143, send_fetc },
-       { 0, NULL }
-};
-
-SR_PRIV const struct agdmm_recv agdmm_recvs_u123x[] = {
-       { "^\"(\\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|UA|FREQ),(\\d),(AC|DC)\"$", recv_conf_u123x },
-       { "^\"(RES|CAP),(\\d)\"$", recv_conf_u123x},
-       { "^\"(DIOD)\"$", recv_conf },
-       { NULL, NULL }
-};
-
-SR_PRIV const struct agdmm_job agdmm_jobs_u125x[] = {
-       { 143, send_stat },
-       { 1000, send_conf },
-       { 143, send_fetc },
-       { 0, NULL }
-};
-
-SR_PRIV const struct agdmm_recv agdmm_recvs_u125x[] = {
-       { "^\"(\\d\\d.{18}\\d)\"$", recv_stat_u125x },
-       { "^\\*([0-9])$", recv_switch },
-       { "^([-+][0-9]\\.[0-9]{8}E[-+][0-9]{2})$", recv_fetc },
-       { "^(VOLT|CURR|RES|CAP) ([-+][0-9\\.E\\-+]+),([-+][0-9\\.E\\-+]+)$", recv_conf_u125x },
-       { "^(VOLT:[ACD]+) ([-+][0-9\\.E\\-+]+),([-+][0-9\\.E\\-+]+)$", recv_conf_u125x },
-       { "^\"(DIOD)\"$", recv_conf },
-       { NULL, NULL }
-};
diff --git a/hardware/appa-55ii/api.c b/hardware/appa-55ii/api.c
deleted file mode 100644 (file)
index de71e33..0000000
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 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 <string.h>
-#include "protocol.h"
-
-static const int32_t hwopts[] = {
-       SR_CONF_CONN,
-       SR_CONF_SERIALCOMM,
-};
-
-static const int32_t hwcaps[] = {
-       SR_CONF_THERMOMETER,
-       SR_CONF_LIMIT_SAMPLES,
-       SR_CONF_LIMIT_MSEC,
-       SR_CONF_CONTINUOUS,
-       SR_CONF_DATA_SOURCE,
-};
-
-static const char *data_sources[] = {
-       "Live",
-       "Memory",
-};
-
-SR_PRIV struct sr_dev_driver appa_55ii_driver_info;
-static struct sr_dev_driver *di = &appa_55ii_driver_info;
-
-static int init(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, di, LOG_PREFIX);
-}
-
-static GSList *scan(GSList *options)
-{
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-       struct sr_dev_inst *sdi;
-       struct sr_channel *ch;
-       struct sr_config *src;
-       GSList *devices, *l;
-       const char *conn, *serialcomm;
-       uint8_t buf[50];
-       size_t len;
-
-       len = sizeof(buf);
-       devices = NULL;
-       conn = serialcomm = NULL;
-       for (l = options; l; l = l->next) {
-               src = l->data;
-               switch (src->key) {
-               case SR_CONF_CONN:
-                       conn = g_variant_get_string(src->data, NULL);
-                       break;
-               case SR_CONF_SERIALCOMM:
-                       serialcomm = g_variant_get_string(src->data, NULL);
-                       break;
-               }
-       }
-       if (!conn)
-               return NULL;
-       if (!serialcomm)
-               serialcomm = "9600/8n1";
-
-       if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
-               return NULL;
-       if (serial_open(serial, SERIAL_RDONLY | SERIAL_NONBLOCK) != SR_OK)
-               return NULL;
-
-       sr_info("Probing serial port %s.", conn);
-
-       drvc = di->priv;
-       drvc->instances = NULL;
-       serial_flush(serial);
-
-       /* Let's get a bit of data and see if we can find a packet. */
-       if (serial_stream_detect(serial, buf, &len, 25,
-                       appa_55ii_packet_valid, 500, 9600) != SR_OK)
-               goto scan_cleanup;
-
-       sr_info("Found device on port %s.", conn);
-
-       if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "APPA", "55II", NULL)))
-               goto scan_cleanup;
-
-       if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
-               sr_err("Device context malloc failed.");
-               goto scan_cleanup;
-       }
-
-       devc->data_source = DEFAULT_DATA_SOURCE;
-
-       sdi->inst_type = SR_INST_SERIAL;
-       sdi->conn = serial;
-       sdi->priv = devc;
-       sdi->driver = di;
-
-       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "T1")))
-               goto scan_cleanup;
-       sdi->channels = g_slist_append(sdi->channels, ch);
-       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "T2")))
-               goto scan_cleanup;
-       sdi->channels = g_slist_append(sdi->channels, ch);
-
-       drvc->instances = g_slist_append(drvc->instances, sdi);
-       devices = g_slist_append(devices, sdi);
-
-scan_cleanup:
-       serial_close(serial);
-
-       return devices;
-}
-
-static GSList *dev_list(void)
-{
-       return ((struct drv_context *)(di->priv))->instances;
-}
-
-static int cleanup(void)
-{
-       return std_dev_clear(di, NULL);
-}
-
-static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc = sdi->priv;
-
-       (void)cg;
-
-       switch (key) {
-       case SR_CONF_LIMIT_SAMPLES:
-               *data = g_variant_new_uint64(devc->limit_samples);
-               break;
-       case SR_CONF_LIMIT_MSEC:
-               *data = g_variant_new_uint64(devc->limit_msec);
-               break;
-       case SR_CONF_DATA_SOURCE:
-               *data = g_variant_new_string(data_sources[devc->data_source]);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       const char *tmp_str;
-       unsigned int i;
-
-       (void)cg;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       if (!(devc = sdi->priv)) {
-               sr_err("sdi->priv was NULL.");
-               return SR_ERR_BUG;
-       }
-
-       switch (key) {
-       case SR_CONF_LIMIT_SAMPLES:
-               devc->limit_samples = g_variant_get_uint64(data);
-               sr_dbg("Setting sample limit to %" PRIu64 ".", devc->limit_samples);
-               break;
-       case SR_CONF_LIMIT_MSEC:
-               devc->limit_msec = g_variant_get_uint64(data);
-               sr_dbg("Setting time limit to %" PRIu64 "ms.", devc->limit_msec);
-               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:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_list(int 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_INT32,
-                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
-               break;
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
-               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;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi,
-               void *cb_data)
-{
-       struct sr_serial_dev_inst *serial;
-       struct dev_context *devc;
-
-       serial = sdi->conn;
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       if (!(devc = sdi->priv)) {
-               sr_err("sdi->priv was NULL.");
-               return SR_ERR_BUG;
-       }
-
-       devc->session_cb_data = cb_data;
-
-       /*
-        * Reset the number of samples to take. If we've already collected our
-        * quota, but we start a new session, and don't reset this, we'll just
-        * quit without acquiring any new samples.
-        */
-       devc->num_samples = 0;
-       devc->start_time = g_get_monotonic_time();
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(cb_data, LOG_PREFIX);
-
-       /* Poll every 50ms, or whenever some data comes in. */
-       serial_source_add(sdi->session, serial, G_IO_IN, 50,
-                       appa_55ii_receive_data, (void *)sdi);
-
-       return SR_OK;
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       return std_serial_dev_acquisition_stop(sdi, cb_data,
-                       std_serial_dev_close, sdi->conn, LOG_PREFIX);
-}
-
-SR_PRIV struct sr_dev_driver appa_55ii_driver_info = {
-       .name = "appa-55ii",
-       .longname = "APPA 55II",
-       .api_version = 1,
-       .init = init,
-       .cleanup = cleanup,
-       .scan = scan,
-       .dev_list = dev_list,
-       .dev_clear = NULL,
-       .config_get = config_get,
-       .config_set = config_set,
-       .config_list = config_list,
-       .dev_open = std_serial_dev_open,
-       .dev_close = std_serial_dev_close,
-       .dev_acquisition_start = dev_acquisition_start,
-       .dev_acquisition_stop = dev_acquisition_stop,
-       .priv = NULL,
-};
diff --git a/hardware/appa-55ii/protocol.c b/hardware/appa-55ii/protocol.c
deleted file mode 100644 (file)
index 708262b..0000000
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 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 <string.h>
-#include <math.h>
-#include "protocol.h"
-
-typedef enum {
-    LIVE_DATA    = 0x00,
-    LOG_METADATA = 0x11,
-    LOG_DATA     = 0x14,
-    LOG_START    = 0x18,
-    LOG_END      = 0x19,
-} packet_type;
-
-static gboolean appa_55ii_checksum(const uint8_t *buf)
-{
-       int i, size, checksum;
-
-       size = buf[3] + 4;
-       checksum = 0;
-       for (i = 0; i < size; i++)
-               checksum += buf[i];
-
-       return buf[size] == (checksum & 0xFF);
-}
-
-SR_PRIV gboolean appa_55ii_packet_valid(const uint8_t *buf)
-{
-       if (buf[0] == 0x55 && buf[1] == 0x55 && buf[3] <= 32
-                       && appa_55ii_checksum(buf))
-               return TRUE;
-
-       return FALSE;
-}
-
-static uint64_t appa_55ii_flags(const uint8_t *buf)
-{
-       uint8_t disp_mode;
-       uint64_t flags;
-
-       disp_mode = buf[4 + 13];
-       flags = 0;
-       if ((disp_mode & 0xF0) == 0x20)
-               flags |= SR_MQFLAG_HOLD;
-       if ((disp_mode & 0x0C) == 0x04)
-               flags |= SR_MQFLAG_MAX;
-       if ((disp_mode & 0x0C) == 0x08)
-               flags |= SR_MQFLAG_MIN;
-       if ((disp_mode & 0x0C) == 0x0C)
-               flags |= SR_MQFLAG_AVG;
-
-       return flags;
-}
-
-static float appa_55ii_temp(const uint8_t *buf, int ch)
-{
-       const uint8_t *ptr;
-       int16_t temp;
-       uint8_t flags;
-
-       ptr = buf + 4 + 14 + 3 * ch;
-       temp = RL16(ptr);
-       flags = ptr[2];
-
-       if (flags & 0x60)
-               return INFINITY;
-       else if (flags & 1)
-               return (float)temp / 10;
-       else
-               return (float)temp;
-}
-
-static void appa_55ii_live_data(struct sr_dev_inst *sdi, const uint8_t *buf)
-{
-       struct dev_context *devc;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_analog analog;
-       struct sr_channel *ch;
-       float values[APPA_55II_NUM_CHANNELS], *val_ptr;
-       int i;
-
-       devc = sdi->priv;
-
-       if (devc->data_source != DATA_SOURCE_LIVE)
-               return;
-
-       val_ptr = values;
-       memset(&analog, 0, sizeof(analog));
-       analog.num_samples = 1;
-       analog.mq = SR_MQ_TEMPERATURE;
-       analog.unit = SR_UNIT_CELSIUS;
-       analog.mqflags = appa_55ii_flags(buf);
-       analog.data = values;
-
-       for (i = 0; i < APPA_55II_NUM_CHANNELS; i++) {
-               ch = g_slist_nth_data(sdi->channels, i);
-               if (!ch->enabled)
-                       continue;
-               analog.channels = g_slist_append(analog.channels, ch);
-               *val_ptr++ = appa_55ii_temp(buf, i);
-       }
-
-       packet.type = SR_DF_ANALOG;
-       packet.payload = &analog;
-       sr_session_send(devc->session_cb_data, &packet);
-       g_slist_free(analog.channels);
-
-       devc->num_samples++;
-}
-
-static void appa_55ii_log_metadata(struct sr_dev_inst *sdi, const uint8_t *buf)
-{
-       struct dev_context *devc;
-
-       devc = sdi->priv;
-       devc->num_log_records = (buf[5] << 8) + buf[4];
-}
-
-static void appa_55ii_log_data_parse(struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_analog analog;
-       struct sr_channel *ch;
-       float values[APPA_55II_NUM_CHANNELS], *val_ptr;
-       const uint8_t *buf;
-       int16_t temp;
-       int offset, i;
-
-       devc = sdi->priv;
-       offset = 0;
-
-       while (devc->log_buf_len >= 20 && devc->num_log_records > 0) {
-               buf = devc->log_buf + offset;
-               val_ptr = values;
-
-               /* FIXME: Timestamp should be sent in the packet. */
-               sr_dbg("Timestamp: %02d:%02d:%02d", buf[2], buf[3], buf[4]);
-
-               memset(&analog, 0, sizeof(analog));
-               analog.num_samples = 1;
-               analog.mq = SR_MQ_TEMPERATURE;
-               analog.unit = SR_UNIT_CELSIUS;
-               analog.data = values;
-
-               for (i = 0; i < APPA_55II_NUM_CHANNELS; i++) {
-                       temp = RL16(buf + 12 + 2 * i);
-                       ch = g_slist_nth_data(sdi->channels, i);
-                       if (!ch->enabled)
-                               continue;
-                       analog.channels = g_slist_append(analog.channels, ch);
-                       *val_ptr++ = temp == 0x7FFF ? INFINITY : (float)temp / 10;
-               }
-
-               packet.type = SR_DF_ANALOG;
-               packet.payload = &analog;
-               sr_session_send(devc->session_cb_data, &packet);
-               g_slist_free(analog.channels);
-
-               devc->num_samples++;
-               devc->log_buf_len -= 20;
-               offset += 20;
-               devc->num_log_records--;
-       }
-
-       memmove(devc->log_buf, devc->log_buf + offset, devc->log_buf_len);
-}
-
-static void appa_55ii_log_data(struct sr_dev_inst *sdi, const uint8_t *buf)
-{
-       struct dev_context *devc;
-       const uint8_t *ptr;
-       unsigned int size;
-       int s;
-
-       devc = sdi->priv;
-       if (devc->data_source != DATA_SOURCE_MEMORY)
-               return;
-
-       ptr = buf + 4;
-       size = buf[3];
-       while (size > 0) {
-               s = MIN(size, sizeof(devc->log_buf) - devc->log_buf_len);
-               memcpy(devc->log_buf + devc->log_buf_len, ptr, s);
-               devc->log_buf_len += s;
-               size -= s;
-               ptr += s;
-
-               appa_55ii_log_data_parse(sdi);
-       }
-}
-
-static void appa_55ii_log_end(struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-
-       devc = sdi->priv;
-       if (devc->data_source != DATA_SOURCE_MEMORY)
-               return;
-
-       sdi->driver->dev_acquisition_stop(sdi, devc->session_cb_data);
-}
-
-static const uint8_t *appa_55ii_parse_data(struct sr_dev_inst *sdi,
-               const uint8_t *buf, int len)
-{
-       if (len < 5)
-               /* Need more data. */
-               return NULL;
-
-       if (buf[0] != 0x55 || buf[1] != 0x55)
-               /* Try to re-synchronize on a packet start. */
-               return buf + 1;
-
-       if (len < 5 + buf[3])
-               /* Need more data. */
-               return NULL;
-
-       if (!appa_55ii_checksum(buf))
-               /* Skip broken packet. */
-               return buf + 4 + buf[3] + 1;
-
-       switch ((packet_type)buf[2]) {
-       case LIVE_DATA:
-               appa_55ii_live_data(sdi, buf);
-               break;
-       case LOG_METADATA:
-               appa_55ii_log_metadata(sdi, buf);
-               break;
-       case LOG_DATA:
-               appa_55ii_log_data(sdi, buf);
-               break;
-       case LOG_START:
-               break;
-       case LOG_END:
-               appa_55ii_log_end(sdi);
-               break;
-       default:
-               sr_warn("Invalid packet type: 0x%02x.", buf[2]);
-               break;
-       }
-
-       return buf + 4 + buf[3] + 1;
-}
-
-SR_PRIV int appa_55ii_receive_data(int fd, int revents, void *cb_data)
-{
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-       int64_t time;
-       const uint8_t *ptr, *next_ptr, *end_ptr;
-       int len;
-
-       (void)fd;
-
-       if (!(sdi = cb_data) || !(devc = sdi->priv) || revents != G_IO_IN)
-               return TRUE;
-       serial = sdi->conn;
-
-       /* Try to get as much data as the buffer can hold. */
-       len = sizeof(devc->buf) - devc->buf_len;
-       len = serial_read(serial, devc->buf + devc->buf_len, len);
-       if (len < 1) {
-               sr_err("Serial port read error: %d.", len);
-               return FALSE;
-       }
-       devc->buf_len += len;
-
-       /* Now look for packets in that data. */
-       ptr = devc->buf;
-       end_ptr = ptr + devc->buf_len;
-       while ((next_ptr = appa_55ii_parse_data(sdi, ptr, end_ptr - ptr)))
-               ptr = next_ptr;
-
-       /* If we have any data left, move it to the beginning of our buffer. */
-       memmove(devc->buf, ptr, end_ptr - ptr);
-       devc->buf_len -= ptr - devc->buf;
-
-       /* If buffer is full and no valid packet was found, wipe buffer. */
-       if (devc->buf_len >= sizeof(devc->buf)) {
-               devc->buf_len = 0;
-               return FALSE;
-       }
-
-       if (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
-               sr_info("Requested number of samples reached.");
-               sdi->driver->dev_acquisition_stop(sdi, devc->session_cb_data);
-               return TRUE;
-       }
-
-       if (devc->limit_msec) {
-               time = (g_get_monotonic_time() - devc->start_time) / 1000;
-               if (time > (int64_t)devc->limit_msec) {
-                       sr_info("Requested time limit reached.");
-                       sdi->driver->dev_acquisition_stop(sdi,
-                                       devc->session_cb_data);
-                       return TRUE;
-               }
-       }
-
-       return TRUE;
-}
diff --git a/hardware/appa-55ii/protocol.h b/hardware/appa-55ii/protocol.h
deleted file mode 100644 (file)
index fa3c247..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Aurelien Jacobs <aurel@gnuage.org>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef LIBSIGROK_HARDWARE_APPA_55II_PROTOCOL_H
-#define LIBSIGROK_HARDWARE_APPA_55II_PROTOCOL_H
-
-#include <stdint.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "appa-55ii"
-
-#define APPA_55II_NUM_CHANNELS  2
-#define APPA_55II_BUF_SIZE    (4 + 32 + 1)
-#define DEFAULT_DATA_SOURCE   DATA_SOURCE_LIVE
-
-enum {
-       DATA_SOURCE_LIVE,
-       DATA_SOURCE_MEMORY,
-};
-
-/** Private, per-device-instance driver context. */
-struct dev_context {
-       /* Acquisition settings */
-       uint64_t limit_samples;   /**< The sampling limit (in number of samples). */
-       uint64_t limit_msec;      /**< The time limit (in milliseconds). */
-       gboolean data_source;     /**< Whether to read live samples or memory */
-       void *session_cb_data;    /**< Opaque pointer passed in by the frontend. */
-
-       /* Operational state */
-       uint64_t num_samples;     /**< The number of already received samples. */
-       int64_t start_time;       /**< The time at which sampling started. */
-
-       /* Temporary state across callbacks */
-       uint8_t buf[APPA_55II_BUF_SIZE];
-       unsigned int buf_len;
-       uint8_t log_buf[64];
-       unsigned int log_buf_len;
-       unsigned int num_log_records;
-};
-
-SR_PRIV gboolean appa_55ii_packet_valid(const uint8_t *buf);
-SR_PRIV int appa_55ii_receive_data(int fd, int revents, void *cb_data);
-
-#endif
diff --git a/hardware/asix-sigma/asix-sigma.c b/hardware/asix-sigma/asix-sigma.c
deleted file mode 100644 (file)
index bfd6948..0000000
+++ /dev/null
@@ -1,1553 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2010-2012 HÃ¥vard Espeland <gus@ping.uio.no>,
- * Copyright (C) 2010 Martin StensgÃ¥rd <mastensg@ping.uio.no>
- * Copyright (C) 2010 Carl Henrik Lunde <chlunde@ping.uio.no>
- *
- * 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/>.
- */
-
-/*
- * ASIX SIGMA/SIGMA2 logic analyzer driver
- */
-
-#include <glib.h>
-#include <glib/gstdio.h>
-#include <ftdi.h>
-#include <string.h>
-#include <unistd.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-#include "asix-sigma.h"
-
-#define USB_VENDOR                     0xa600
-#define USB_PRODUCT                    0xa000
-#define USB_DESCRIPTION                        "ASIX SIGMA"
-#define USB_VENDOR_NAME                        "ASIX"
-#define USB_MODEL_NAME                 "SIGMA"
-
-SR_PRIV struct sr_dev_driver asix_sigma_driver_info;
-static struct sr_dev_driver *di = &asix_sigma_driver_info;
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data);
-
-/*
- * The ASIX Sigma supports arbitrary integer frequency divider in
- * the 50MHz mode. The divider is in range 1...256 , allowing for
- * very precise sampling rate selection. This driver supports only
- * a subset of the sampling rates.
- */
-static const uint64_t samplerates[] = {
-       SR_KHZ(200),    /* div=250 */
-       SR_KHZ(250),    /* div=200 */
-       SR_KHZ(500),    /* div=100 */
-       SR_MHZ(1),      /* div=50  */
-       SR_MHZ(5),      /* div=10  */
-       SR_MHZ(10),     /* div=5   */
-       SR_MHZ(25),     /* div=2   */
-       SR_MHZ(50),     /* div=1   */
-       SR_MHZ(100),    /* Special FW needed */
-       SR_MHZ(200),    /* Special FW needed */
-};
-
-/*
- * Channel numbers seem to go from 1-16, according to this image:
- * http://tools.asix.net/img/sigma_sigmacab_pins_720.jpg
- * (the cable has two additional GND pins, and a TI and TO pin)
- */
-static const char *channel_names[] = {
-       "1", "2", "3", "4", "5", "6", "7", "8",
-       "9", "10", "11", "12", "13", "14", "15", "16",
-};
-
-static const int32_t hwcaps[] = {
-       SR_CONF_LOGIC_ANALYZER,
-       SR_CONF_SAMPLERATE,
-       SR_CONF_TRIGGER_MATCH,
-       SR_CONF_CAPTURE_RATIO,
-       SR_CONF_LIMIT_MSEC,
-};
-
-static const int32_t trigger_matches[] = {
-       SR_TRIGGER_ZERO,
-       SR_TRIGGER_ONE,
-       SR_TRIGGER_RISING,
-       SR_TRIGGER_FALLING,
-};
-
-static const char *sigma_firmware_files[] = {
-       /* 50 MHz, supports 8 bit fractions */
-       FIRMWARE_DIR "/asix-sigma-50.fw",
-       /* 100 MHz */
-       FIRMWARE_DIR "/asix-sigma-100.fw",
-       /* 200 MHz */
-       FIRMWARE_DIR "/asix-sigma-200.fw",
-       /* Synchronous clock from pin */
-       FIRMWARE_DIR "/asix-sigma-50sync.fw",
-       /* Frequency counter */
-       FIRMWARE_DIR "/asix-sigma-phasor.fw",
-};
-
-static int sigma_read(void *buf, size_t size, struct dev_context *devc)
-{
-       int ret;
-
-       ret = ftdi_read_data(&devc->ftdic, (unsigned char *)buf, size);
-       if (ret < 0) {
-               sr_err("ftdi_read_data failed: %s",
-                      ftdi_get_error_string(&devc->ftdic));
-       }
-
-       return ret;
-}
-
-static int sigma_write(void *buf, size_t size, struct dev_context *devc)
-{
-       int ret;
-
-       ret = ftdi_write_data(&devc->ftdic, (unsigned char *)buf, size);
-       if (ret < 0) {
-               sr_err("ftdi_write_data failed: %s",
-                      ftdi_get_error_string(&devc->ftdic));
-       } else if ((size_t) ret != size) {
-               sr_err("ftdi_write_data did not complete write.");
-       }
-
-       return ret;
-}
-
-static int sigma_write_register(uint8_t reg, uint8_t *data, size_t len,
-                               struct dev_context *devc)
-{
-       size_t i;
-       uint8_t buf[len + 2];
-       int idx = 0;
-
-       buf[idx++] = REG_ADDR_LOW | (reg & 0xf);
-       buf[idx++] = REG_ADDR_HIGH | (reg >> 4);
-
-       for (i = 0; i < len; ++i) {
-               buf[idx++] = REG_DATA_LOW | (data[i] & 0xf);
-               buf[idx++] = REG_DATA_HIGH_WRITE | (data[i] >> 4);
-       }
-
-       return sigma_write(buf, idx, devc);
-}
-
-static int sigma_set_register(uint8_t reg, uint8_t value, struct dev_context *devc)
-{
-       return sigma_write_register(reg, &value, 1, devc);
-}
-
-static int sigma_read_register(uint8_t reg, uint8_t *data, size_t len,
-                              struct dev_context *devc)
-{
-       uint8_t buf[3];
-
-       buf[0] = REG_ADDR_LOW | (reg & 0xf);
-       buf[1] = REG_ADDR_HIGH | (reg >> 4);
-       buf[2] = REG_READ_ADDR;
-
-       sigma_write(buf, sizeof(buf), devc);
-
-       return sigma_read(data, len, devc);
-}
-
-static uint8_t sigma_get_register(uint8_t reg, struct dev_context *devc)
-{
-       uint8_t value;
-
-       if (1 != sigma_read_register(reg, &value, 1, devc)) {
-               sr_err("sigma_get_register: 1 byte expected");
-               return 0;
-       }
-
-       return value;
-}
-
-static int sigma_read_pos(uint32_t *stoppos, uint32_t *triggerpos,
-                         struct dev_context *devc)
-{
-       uint8_t buf[] = {
-               REG_ADDR_LOW | READ_TRIGGER_POS_LOW,
-
-               REG_READ_ADDR | NEXT_REG,
-               REG_READ_ADDR | NEXT_REG,
-               REG_READ_ADDR | NEXT_REG,
-               REG_READ_ADDR | NEXT_REG,
-               REG_READ_ADDR | NEXT_REG,
-               REG_READ_ADDR | NEXT_REG,
-       };
-       uint8_t result[6];
-
-       sigma_write(buf, sizeof(buf), devc);
-
-       sigma_read(result, sizeof(result), devc);
-
-       *triggerpos = result[0] | (result[1] << 8) | (result[2] << 16);
-       *stoppos = result[3] | (result[4] << 8) | (result[5] << 16);
-
-       /* Not really sure why this must be done, but according to spec. */
-       if ((--*stoppos & 0x1ff) == 0x1ff)
-               stoppos -= 64;
-
-       if ((*--triggerpos & 0x1ff) == 0x1ff)
-               triggerpos -= 64;
-
-       return 1;
-}
-
-static int sigma_read_dram(uint16_t startchunk, size_t numchunks,
-                          uint8_t *data, struct dev_context *devc)
-{
-       size_t i;
-       uint8_t buf[4096];
-       int idx = 0;
-
-       /* Send the startchunk. Index start with 1. */
-       buf[0] = startchunk >> 8;
-       buf[1] = startchunk & 0xff;
-       sigma_write_register(WRITE_MEMROW, buf, 2, devc);
-
-       /* Read the DRAM. */
-       buf[idx++] = REG_DRAM_BLOCK;
-       buf[idx++] = REG_DRAM_WAIT_ACK;
-
-       for (i = 0; i < numchunks; ++i) {
-               /* Alternate bit to copy from DRAM to cache. */
-               if (i != (numchunks - 1))
-                       buf[idx++] = REG_DRAM_BLOCK | (((i + 1) % 2) << 4);
-
-               buf[idx++] = REG_DRAM_BLOCK_DATA | ((i % 2) << 4);
-
-               if (i != (numchunks - 1))
-                       buf[idx++] = REG_DRAM_WAIT_ACK;
-       }
-
-       sigma_write(buf, idx, devc);
-
-       return sigma_read(data, numchunks * CHUNK_SIZE, devc);
-}
-
-/* Upload trigger look-up tables to Sigma. */
-static int sigma_write_trigger_lut(struct triggerlut *lut, struct dev_context *devc)
-{
-       int i;
-       uint8_t tmp[2];
-       uint16_t bit;
-
-       /* Transpose the table and send to Sigma. */
-       for (i = 0; i < 16; ++i) {
-               bit = 1 << i;
-
-               tmp[0] = tmp[1] = 0;
-
-               if (lut->m2d[0] & bit)
-                       tmp[0] |= 0x01;
-               if (lut->m2d[1] & bit)
-                       tmp[0] |= 0x02;
-               if (lut->m2d[2] & bit)
-                       tmp[0] |= 0x04;
-               if (lut->m2d[3] & bit)
-                       tmp[0] |= 0x08;
-
-               if (lut->m3 & bit)
-                       tmp[0] |= 0x10;
-               if (lut->m3s & bit)
-                       tmp[0] |= 0x20;
-               if (lut->m4 & bit)
-                       tmp[0] |= 0x40;
-
-               if (lut->m0d[0] & bit)
-                       tmp[1] |= 0x01;
-               if (lut->m0d[1] & bit)
-                       tmp[1] |= 0x02;
-               if (lut->m0d[2] & bit)
-                       tmp[1] |= 0x04;
-               if (lut->m0d[3] & bit)
-                       tmp[1] |= 0x08;
-
-               if (lut->m1d[0] & bit)
-                       tmp[1] |= 0x10;
-               if (lut->m1d[1] & bit)
-                       tmp[1] |= 0x20;
-               if (lut->m1d[2] & bit)
-                       tmp[1] |= 0x40;
-               if (lut->m1d[3] & bit)
-                       tmp[1] |= 0x80;
-
-               sigma_write_register(WRITE_TRIGGER_SELECT0, tmp, sizeof(tmp),
-                                    devc);
-               sigma_set_register(WRITE_TRIGGER_SELECT1, 0x30 | i, devc);
-       }
-
-       /* Send the parameters */
-       sigma_write_register(WRITE_TRIGGER_SELECT0, (uint8_t *) &lut->params,
-                            sizeof(lut->params), devc);
-
-       return SR_OK;
-}
-
-static void clear_helper(void *priv)
-{
-       struct dev_context *devc;
-
-       devc = priv;
-
-       ftdi_deinit(&devc->ftdic);
-}
-
-static int dev_clear(void)
-{
-       return std_dev_clear(di, clear_helper);
-}
-
-static int init(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, di, LOG_PREFIX);
-}
-
-static GSList *scan(GSList *options)
-{
-       struct sr_dev_inst *sdi;
-       struct sr_channel *ch;
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       GSList *devices;
-       struct ftdi_device_list *devlist;
-       char serial_txt[10];
-       uint32_t serial;
-       int ret;
-       unsigned int i;
-
-       (void)options;
-
-       drvc = di->priv;
-
-       devices = NULL;
-
-       if (!(devc = g_try_malloc(sizeof(struct dev_context)))) {
-               sr_err("%s: devc malloc failed", __func__);
-               return NULL;
-       }
-
-       ftdi_init(&devc->ftdic);
-
-       /* Look for SIGMAs. */
-
-       if ((ret = ftdi_usb_find_all(&devc->ftdic, &devlist,
-           USB_VENDOR, USB_PRODUCT)) <= 0) {
-               if (ret < 0)
-                       sr_err("ftdi_usb_find_all(): %d", ret);
-               goto free;
-       }
-
-       /* 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);
-
-       if (serial < 0xa6010000 || serial > 0xa602ffff) {
-               sr_err("Only SIGMA and SIGMA2 are supported "
-                      "in this version of libsigrok.");
-               goto free;
-       }
-
-       sr_info("Found ASIX SIGMA - Serial: %s", serial_txt);
-
-       devc->cur_samplerate = samplerates[0];
-       devc->period_ps = 0;
-       devc->limit_msec = 0;
-       devc->cur_firmware = -1;
-       devc->num_channels = 0;
-       devc->samples_per_event = 0;
-       devc->capture_ratio = 50;
-       devc->use_triggers = 0;
-
-       /* Register SIGMA device. */
-       if (!(sdi = sr_dev_inst_new(0, SR_ST_INITIALIZING, USB_VENDOR_NAME,
-                                   USB_MODEL_NAME, NULL))) {
-               sr_err("%s: sdi was NULL", __func__);
-               goto free;
-       }
-       sdi->driver = di;
-
-       for (i = 0; i < ARRAY_SIZE(channel_names); i++) {
-               ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE,
-                                   channel_names[i]);
-               if (!ch)
-                       return NULL;
-               sdi->channels = g_slist_append(sdi->channels, ch);
-       }
-
-       devices = g_slist_append(devices, sdi);
-       drvc->instances = g_slist_append(drvc->instances, sdi);
-       sdi->priv = devc;
-
-       /* We will open the device again when we need it. */
-       ftdi_list_free(&devlist);
-
-       return devices;
-
-free:
-       ftdi_deinit(&devc->ftdic);
-       g_free(devc);
-       return NULL;
-}
-
-static GSList *dev_list(void)
-{
-       return ((struct drv_context *)(di->priv))->instances;
-}
-
-/*
- * Configure the FPGA for bitbang mode.
- * This sequence is documented in section 2. of the ASIX Sigma programming
- * manual. This sequence is necessary to configure the FPGA in the Sigma
- * into Bitbang mode, in which it can be programmed with the firmware.
- */
-static int sigma_fpga_init_bitbang(struct dev_context *devc)
-{
-       uint8_t suicide[] = {
-               0x84, 0x84, 0x88, 0x84, 0x88, 0x84, 0x88, 0x84,
-       };
-       uint8_t init_array[] = {
-               0x01, 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01,
-               0x01, 0x01,
-       };
-       int i, ret, timeout = 10000;
-       uint8_t data;
-
-       /* Section 2. part 1), do the FPGA suicide. */
-       sigma_write(suicide, sizeof(suicide), devc);
-       sigma_write(suicide, sizeof(suicide), devc);
-       sigma_write(suicide, sizeof(suicide), devc);
-       sigma_write(suicide, sizeof(suicide), devc);
-
-       /* Section 2. part 2), do pulse on D1. */
-       sigma_write(init_array, sizeof(init_array), devc);
-       ftdi_usb_purge_buffers(&devc->ftdic);
-
-       /* Wait until the FPGA asserts D6/INIT_B. */
-       for (i = 0; i < timeout; i++) {
-               ret = sigma_read(&data, 1, devc);
-               if (ret < 0)
-                       return ret;
-               /* Test if pin D6 got asserted. */
-               if (data & (1 << 5))
-                       return 0;
-               /* The D6 was not asserted yet, wait a bit. */
-               usleep(10000);
-       }
-
-       return SR_ERR_TIMEOUT;
-}
-
-/*
- * Configure the FPGA for logic-analyzer mode.
- */
-static int sigma_fpga_init_la(struct dev_context *devc)
-{
-       /* Initialize the logic analyzer mode. */
-       uint8_t logic_mode_start[] = {
-               REG_ADDR_LOW  | (READ_ID & 0xf),
-               REG_ADDR_HIGH | (READ_ID >> 8),
-               REG_READ_ADDR,  /* Read ID register. */
-
-               REG_ADDR_LOW | (WRITE_TEST & 0xf),
-               REG_DATA_LOW | 0x5,
-               REG_DATA_HIGH_WRITE | 0x5,
-               REG_READ_ADDR,  /* Read scratch register. */
-
-               REG_DATA_LOW | 0xa,
-               REG_DATA_HIGH_WRITE | 0xa,
-               REG_READ_ADDR,  /* Read scratch register. */
-
-               REG_ADDR_LOW | (WRITE_MODE & 0xf),
-               REG_DATA_LOW | 0x0,
-               REG_DATA_HIGH_WRITE | 0x8,
-       };
-
-       uint8_t result[3];
-       int ret;
-
-       /* Initialize the logic analyzer mode. */
-       sigma_write(logic_mode_start, sizeof(logic_mode_start), devc);
-
-       /* Expect a 3 byte reply since we issued three READ requests. */
-       ret = sigma_read(result, 3, devc);
-       if (ret != 3)
-               goto err;
-
-       if (result[0] != 0xa6 || result[1] != 0x55 || result[2] != 0xaa)
-               goto err;
-
-       return SR_OK;
-err:
-       sr_err("Configuration failed. Invalid reply received.");
-       return SR_ERR;
-}
-
-/*
- * Read the firmware from a file and transform it into a series of bitbang
- * pulses used to program the FPGA. Note that the *bb_cmd must be free()'d
- * by the caller of this function.
- */
-static int sigma_fw_2_bitbang(const char *filename,
-                             uint8_t **bb_cmd, gsize *bb_cmd_size)
-{
-       GMappedFile *file;
-       GError *error;
-       gsize i, file_size, bb_size;
-       gchar *firmware;
-       uint8_t *bb_stream, *bbs;
-       uint32_t imm;
-       int bit, v;
-       int ret = SR_OK;
-
-       /*
-        * Map the file and make the mapped buffer writable.
-        * NOTE: Using writable=TRUE does _NOT_ mean that file that is mapped
-        *       will be modified. It will not be modified until someone uses
-        *       g_file_set_contents() on it.
-        */
-       error = NULL;
-       file = g_mapped_file_new(filename, TRUE, &error);
-       g_assert_no_error(error);
-
-       file_size = g_mapped_file_get_length(file);
-       firmware = g_mapped_file_get_contents(file);
-       g_assert(firmware);
-
-       /* Weird magic transformation below, I have no idea what it does. */
-       imm = 0x3f6df2ab;
-       for (i = 0; i < file_size; i++) {
-               imm = (imm + 0xa853753) % 177 + (imm * 0x8034052);
-               firmware[i] ^= imm & 0xff;
-       }
-
-       /*
-        * Now that the firmware is "transformed", we will transcribe the
-        * firmware blob into a sequence of toggles of the Dx wires. This
-        * sequence will be fed directly into the Sigma, which must be in
-        * the FPGA bitbang programming mode.
-        */
-
-       /* Each bit of firmware is transcribed as two toggles of Dx wires. */
-       bb_size = file_size * 8 * 2;
-       bb_stream = (uint8_t *)g_try_malloc(bb_size);
-       if (!bb_stream) {
-               sr_err("%s: Failed to allocate bitbang stream", __func__);
-               ret = SR_ERR_MALLOC;
-               goto exit;
-       }
-
-       bbs = bb_stream;
-       for (i = 0; i < file_size; i++) {
-               for (bit = 7; bit >= 0; bit--) {
-                       v = (firmware[i] & (1 << bit)) ? 0x40 : 0x00;
-                       *bbs++ = v | 0x01;
-                       *bbs++ = v;
-               }
-       }
-
-       /* The transformation completed successfully, return the result. */
-       *bb_cmd = bb_stream;
-       *bb_cmd_size = bb_size;
-
-exit:
-       g_mapped_file_unref(file);
-       return ret;
-}
-
-static int upload_firmware(int firmware_idx, struct dev_context *devc)
-{
-       int ret;
-       unsigned char *buf;
-       unsigned char pins;
-       size_t buf_size;
-       const char *firmware = sigma_firmware_files[firmware_idx];
-       struct ftdi_context *ftdic = &devc->ftdic;
-
-       /* Make sure it's an ASIX SIGMA. */
-       ret = ftdi_usb_open_desc(ftdic, USB_VENDOR, USB_PRODUCT,
-                                USB_DESCRIPTION, NULL);
-       if (ret < 0) {
-               sr_err("ftdi_usb_open failed: %s",
-                      ftdi_get_error_string(ftdic));
-               return 0;
-       }
-
-       ret = ftdi_set_bitmode(ftdic, 0xdf, BITMODE_BITBANG);
-       if (ret < 0) {
-               sr_err("ftdi_set_bitmode failed: %s",
-                      ftdi_get_error_string(ftdic));
-               return 0;
-       }
-
-       /* Four times the speed of sigmalogan - Works well. */
-       ret = ftdi_set_baudrate(ftdic, 750000);
-       if (ret < 0) {
-               sr_err("ftdi_set_baudrate failed: %s",
-                      ftdi_get_error_string(ftdic));
-               return 0;
-       }
-
-       /* Initialize the FPGA for firmware upload. */
-       ret = sigma_fpga_init_bitbang(devc);
-       if (ret)
-               return ret;
-
-       /* Prepare firmware. */
-       ret = sigma_fw_2_bitbang(firmware, &buf, &buf_size);
-       if (ret != SR_OK) {
-               sr_err("An error occured while reading the firmware: %s",
-                      firmware);
-               return ret;
-       }
-
-       /* Upload firmare. */
-       sr_info("Uploading firmware file '%s'.", firmware);
-       sigma_write(buf, buf_size, devc);
-
-       g_free(buf);
-
-       ret = ftdi_set_bitmode(ftdic, 0x00, BITMODE_RESET);
-       if (ret < 0) {
-               sr_err("ftdi_set_bitmode failed: %s",
-                      ftdi_get_error_string(ftdic));
-               return SR_ERR;
-       }
-
-       ftdi_usb_purge_buffers(ftdic);
-
-       /* Discard garbage. */
-       while (sigma_read(&pins, 1, devc) == 1)
-               ;
-
-       /* Initialize the FPGA for logic-analyzer mode. */
-       ret = sigma_fpga_init_la(devc);
-       if (ret != SR_OK)
-               return ret;
-
-       devc->cur_firmware = firmware_idx;
-
-       sr_info("Firmware uploaded.");
-
-       return SR_OK;
-}
-
-static int dev_open(struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       int ret;
-
-       devc = sdi->priv;
-
-       /* Make sure it's an ASIX SIGMA. */
-       if ((ret = ftdi_usb_open_desc(&devc->ftdic,
-               USB_VENDOR, USB_PRODUCT, USB_DESCRIPTION, NULL)) < 0) {
-
-               sr_err("ftdi_usb_open failed: %s",
-                      ftdi_get_error_string(&devc->ftdic));
-
-               return 0;
-       }
-
-       sdi->status = SR_ST_ACTIVE;
-
-       return SR_OK;
-}
-
-static int set_samplerate(const struct sr_dev_inst *sdi, uint64_t samplerate)
-{
-       struct dev_context *devc;
-       unsigned int i;
-       int ret;
-
-       devc = sdi->priv;
-       ret = SR_OK;
-
-       for (i = 0; i < ARRAY_SIZE(samplerates); i++) {
-               if (samplerates[i] == samplerate)
-                       break;
-       }
-       if (samplerates[i] == 0)
-               return SR_ERR_SAMPLERATE;
-
-       if (samplerate <= SR_MHZ(50)) {
-               ret = upload_firmware(0, devc);
-               devc->num_channels = 16;
-       } else if (samplerate == SR_MHZ(100)) {
-               ret = upload_firmware(1, devc);
-               devc->num_channels = 8;
-       } else if (samplerate == SR_MHZ(200)) {
-               ret = upload_firmware(2, devc);
-               devc->num_channels = 4;
-       }
-
-       if (ret == SR_OK) {
-               devc->cur_samplerate = samplerate;
-               devc->period_ps = 1000000000000ULL / samplerate;
-               devc->samples_per_event = 16 / devc->num_channels;
-               devc->state.state = SIGMA_IDLE;
-       }
-
-       return ret;
-}
-
-/*
- * In 100 and 200 MHz mode, only a single pin rising/falling can be
- * set as trigger. In other modes, two rising/falling triggers can be set,
- * in addition to value/mask trigger for any number of channels.
- *
- * The Sigma supports complex triggers using boolean expressions, but this
- * has not been implemented yet.
- */
-static int convert_trigger(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_trigger *trigger;
-       struct sr_trigger_stage *stage;
-       struct sr_trigger_match *match;
-       const GSList *l, *m;
-       int channelbit, trigger_set;
-
-       devc = sdi->priv;
-       memset(&devc->trigger, 0, sizeof(struct sigma_trigger));
-       if (!(trigger = sr_session_trigger_get(sdi->session)))
-               return SR_OK;
-
-       trigger_set = 0;
-       for (l = trigger->stages; l; l = l->next) {
-               stage = l->data;
-               for (m = stage->matches; m; m = m->next) {
-                       match = m->data;
-                       if (!match->channel->enabled)
-                               /* Ignore disabled channels with a trigger. */
-                               continue;
-                       channelbit = 1 << (match->channel->index);
-                       if (devc->cur_samplerate >= SR_MHZ(100)) {
-                               /* Fast trigger support. */
-                               if (trigger_set) {
-                                       sr_err("Only a single pin trigger is "
-                                                       "supported in 100 and 200MHz mode.");
-                                       return SR_ERR;
-                               }
-                               if (match->match == SR_TRIGGER_FALLING)
-                                       devc->trigger.fallingmask |= channelbit;
-                               else if (match->match == SR_TRIGGER_RISING)
-                                       devc->trigger.risingmask |= channelbit;
-                               else {
-                                       sr_err("Only rising/falling trigger is "
-                                                       "supported in 100 and 200MHz mode.");
-                                       return SR_ERR;
-                               }
-
-                               ++trigger_set;
-                       } else {
-                               /* Simple trigger support (event). */
-                               if (match->match == SR_TRIGGER_ONE) {
-                                       devc->trigger.simplevalue |= channelbit;
-                                       devc->trigger.simplemask |= channelbit;
-                               }
-                               else if (match->match == SR_TRIGGER_ZERO) {
-                                       devc->trigger.simplevalue &= ~channelbit;
-                                       devc->trigger.simplemask |= channelbit;
-                               }
-                               else if (match->match == SR_TRIGGER_FALLING) {
-                                       devc->trigger.fallingmask |= channelbit;
-                                       ++trigger_set;
-                               }
-                               else if (match->match == SR_TRIGGER_RISING) {
-                                       devc->trigger.risingmask |= channelbit;
-                                       ++trigger_set;
-                               }
-
-                               /*
-                                * Actually, Sigma supports 2 rising/falling triggers,
-                                * but they are ORed and the current trigger syntax
-                                * does not permit ORed triggers.
-                                */
-                               if (trigger_set > 1) {
-                                       sr_err("Only 1 rising/falling trigger "
-                                                  "is supported.");
-                                       return SR_ERR;
-                               }
-                       }
-               }
-       }
-
-
-       return SR_OK;
-}
-
-static int dev_close(struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-
-       devc = sdi->priv;
-
-       /* TODO */
-       if (sdi->status == SR_ST_ACTIVE)
-               ftdi_usb_close(&devc->ftdic);
-
-       sdi->status = SR_ST_INACTIVE;
-
-       return SR_OK;
-}
-
-static int cleanup(void)
-{
-       return dev_clear();
-}
-
-static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-
-       (void)cg;
-
-       if (!sdi)
-               return SR_ERR;
-       devc = sdi->priv;
-
-       switch (id) {
-       case SR_CONF_SAMPLERATE:
-               *data = g_variant_new_uint64(devc->cur_samplerate);
-               break;
-       case SR_CONF_LIMIT_MSEC:
-               *data = g_variant_new_uint64(devc->limit_msec);
-               break;
-       case SR_CONF_CAPTURE_RATIO:
-               *data = g_variant_new_uint64(devc->capture_ratio);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       uint64_t tmp;
-       int ret;
-
-       (void)cg;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       devc = sdi->priv;
-
-       ret = SR_OK;
-       switch (id) {
-       case SR_CONF_SAMPLERATE:
-               ret = set_samplerate(sdi, g_variant_get_uint64(data));
-               break;
-       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:
-               tmp = g_variant_get_uint64(data);
-               devc->limit_msec = tmp * 1000 / devc->cur_samplerate;
-               break;
-       case SR_CONF_CAPTURE_RATIO:
-               tmp = g_variant_get_uint64(data);
-               if (tmp <= 100)
-                       devc->capture_ratio = tmp;
-               else
-                       ret = SR_ERR;
-               break;
-       default:
-               ret = SR_ERR_NA;
-       }
-
-       return ret;
-}
-
-static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       GVariant *gvar;
-       GVariantBuilder gvb;
-
-       (void)sdi;
-       (void)cg;
-
-       switch (key) {
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
-               break;
-       case SR_CONF_SAMPLERATE:
-               g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
-               gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), samplerates,
-                               ARRAY_SIZE(samplerates), sizeof(uint64_t));
-               g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar);
-               *data = g_variant_builder_end(&gvb);
-               break;
-       case SR_CONF_TRIGGER_MATCH:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               trigger_matches, ARRAY_SIZE(trigger_matches),
-                               sizeof(int32_t));
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-/* Software trigger to determine exact trigger position. */
-static int get_trigger_offset(uint8_t *samples, uint16_t last_sample,
-                             struct sigma_trigger *t)
-{
-       int i;
-       uint16_t sample = 0;
-
-       for (i = 0; i < 8; ++i) {
-               if (i > 0)
-                       last_sample = sample;
-               sample = samples[2 * i] | (samples[2 * i + 1] << 8);
-
-               /* Simple triggers. */
-               if ((sample & t->simplemask) != t->simplevalue)
-                       continue;
-
-               /* Rising edge. */
-               if (((last_sample & t->risingmask) != 0) ||
-                   ((sample & t->risingmask) != t->risingmask))
-                       continue;
-
-               /* Falling edge. */
-               if ((last_sample & t->fallingmask) != t->fallingmask ||
-                   (sample & t->fallingmask) != 0)
-                       continue;
-
-               break;
-       }
-
-       /* If we did not match, return original trigger pos. */
-       return i & 0x7;
-}
-
-
-/*
- * Return the timestamp of "DRAM cluster".
- */
-static uint16_t sigma_dram_cluster_ts(struct sigma_dram_cluster *cluster)
-{
-       return (cluster->timestamp_hi << 8) | cluster->timestamp_lo;
-}
-
-static void sigma_decode_dram_cluster(struct sigma_dram_cluster *dram_cluster,
-                                     unsigned int events_in_cluster,
-                                     unsigned int triggered,
-                                     struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc = sdi->priv;
-       struct sigma_state *ss = &devc->state;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_logic logic;
-       uint16_t tsdiff, ts;
-       uint8_t samples[2048];
-       unsigned int i;
-
-       ts = sigma_dram_cluster_ts(dram_cluster);
-       tsdiff = ts - ss->lastts;
-       ss->lastts = ts;
-
-       packet.type = SR_DF_LOGIC;
-       packet.payload = &logic;
-       logic.unitsize = 2;
-       logic.data = samples;
-
-       /*
-        * First of all, send Sigrok a copy of the last sample from
-        * previous cluster as many times as needed to make up for
-        * the differential characteristics of data we get from the
-        * Sigma. Sigrok needs one sample of data per period.
-        *
-        * One DRAM cluster contains a timestamp and seven samples,
-        * the units of timestamp are "devc->period_ps" , the first
-        * sample in the cluster happens at the time of the timestamp
-        * and the remaining samples happen at timestamp +1...+6 .
-        */
-       for (ts = 0; ts < tsdiff - (EVENTS_PER_CLUSTER - 1); ts++) {
-               i = ts % 1024;
-               samples[2 * i + 0] = ss->lastsample & 0xff;
-               samples[2 * i + 1] = ss->lastsample >> 8;
-
-               /*
-                * If we have 1024 samples ready or we're at the
-                * end of submitting the padding samples, submit
-                * the packet to Sigrok.
-                */
-               if ((i == 1023) || (ts == (tsdiff - EVENTS_PER_CLUSTER))) {
-                       logic.length = (i + 1) * logic.unitsize;
-                       sr_session_send(sdi, &packet);
-               }
-       }
-
-       /*
-        * Parse the samples in current cluster and prepare them
-        * to be submitted to Sigrok.
-        */
-       for (i = 0; i < events_in_cluster; i++) {
-               samples[2 * i + 1] = dram_cluster->samples[i].sample_lo;
-               samples[2 * i + 0] = dram_cluster->samples[i].sample_hi;
-       }
-
-       /* Send data up to trigger point (if triggered). */
-       int trigger_offset = 0;
-       if (triggered) {
-               /*
-                * Trigger is not always accurate to sample because of
-                * pipeline delay. However, it always triggers before
-                * the actual event. We therefore look at the next
-                * samples to pinpoint the exact position of the trigger.
-                */
-               trigger_offset = get_trigger_offset(samples,
-                                       ss->lastsample, &devc->trigger);
-
-               if (trigger_offset > 0) {
-                       packet.type = SR_DF_LOGIC;
-                       logic.length = trigger_offset * logic.unitsize;
-                       sr_session_send(sdi, &packet);
-                       events_in_cluster -= trigger_offset;
-               }
-
-               /* Only send trigger if explicitly enabled. */
-               if (devc->use_triggers) {
-                       packet.type = SR_DF_TRIGGER;
-                       sr_session_send(sdi, &packet);
-               }
-       }
-
-       if (events_in_cluster > 0) {
-               packet.type = SR_DF_LOGIC;
-               logic.length = events_in_cluster * logic.unitsize;
-               logic.data = samples + (trigger_offset * logic.unitsize);
-               sr_session_send(sdi, &packet);
-       }
-
-       ss->lastsample =
-               samples[2 * (events_in_cluster - 1) + 0] |
-               (samples[2 * (events_in_cluster - 1) + 1] << 8);
-
-}
-
-/*
- * Decode chunk of 1024 bytes, 64 clusters, 7 events per cluster.
- * Each event is 20ns apart, and can contain multiple samples.
- *
- * For 200 MHz, events contain 4 samples for each channel, spread 5 ns apart.
- * For 100 MHz, events contain 2 samples for each channel, spread 10 ns apart.
- * For 50 MHz and below, events contain one sample for each channel,
- * spread 20 ns apart.
- */
-static int decode_chunk_ts(struct sigma_dram_line *dram_line,
-                          uint16_t events_in_line,
-                          uint32_t trigger_event,
-                          struct sr_dev_inst *sdi)
-{
-       struct sigma_dram_cluster *dram_cluster;
-       struct dev_context *devc = sdi->priv;
-       unsigned int clusters_in_line =
-               (events_in_line + (EVENTS_PER_CLUSTER - 1)) / EVENTS_PER_CLUSTER;
-       unsigned int events_in_cluster;
-       unsigned int i;
-       uint32_t trigger_cluster = ~0, triggered = 0;
-
-       /* Check if trigger is in this chunk. */
-       if (trigger_event < (64 * 7)) {
-               if (devc->cur_samplerate <= SR_MHZ(50)) {
-                       trigger_event -= MIN(EVENTS_PER_CLUSTER - 1,
-                                            trigger_event);
-               }
-
-               /* Find in which cluster the trigger occured. */
-               trigger_cluster = trigger_event / EVENTS_PER_CLUSTER;
-       }
-
-       /* For each full DRAM cluster. */
-       for (i = 0; i < clusters_in_line; i++) {
-               dram_cluster = &dram_line->cluster[i];
-
-               /* The last cluster might not be full. */
-               if ((i == clusters_in_line - 1) &&
-                   (events_in_line % EVENTS_PER_CLUSTER)) {
-                       events_in_cluster = events_in_line % EVENTS_PER_CLUSTER;
-               } else {
-                       events_in_cluster = EVENTS_PER_CLUSTER;
-               }
-
-               triggered = (i == trigger_cluster);
-               sigma_decode_dram_cluster(dram_cluster, events_in_cluster,
-                                         triggered, sdi);
-       }
-
-       return SR_OK;
-}
-
-static int download_capture(struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc = sdi->priv;
-       const uint32_t chunks_per_read = 32;
-       struct sigma_dram_line *dram_line;
-       int bufsz;
-       uint32_t stoppos, triggerpos;
-       struct sr_datafeed_packet packet;
-       uint8_t modestatus;
-
-       uint32_t i;
-       uint32_t dl_lines_total, dl_lines_curr, dl_lines_done;
-       uint32_t dl_events_in_line = 64 * 7;
-       uint32_t trg_line = ~0, trg_event = ~0;
-
-       dram_line = g_try_malloc0(chunks_per_read * sizeof(*dram_line));
-       if (!dram_line)
-               return FALSE;
-
-       sr_info("Downloading sample data.");
-
-       /* Stop acquisition. */
-       sigma_set_register(WRITE_MODE, 0x11, devc);
-
-       /* Set SDRAM Read Enable. */
-       sigma_set_register(WRITE_MODE, 0x02, devc);
-
-       /* Get the current position. */
-       sigma_read_pos(&stoppos, &triggerpos, devc);
-
-       /* Check if trigger has fired. */
-       modestatus = sigma_get_register(READ_MODE, devc);
-       if (modestatus & 0x20) {
-               trg_line = triggerpos >> 9;
-               trg_event = triggerpos & 0x1ff;
-       }
-
-       /*
-        * Determine how many 1024b "DRAM lines" do we need to read from the
-        * Sigma so we have a complete set of samples. Note that the last
-        * line can be only partial, containing less than 64 clusters.
-        */
-       dl_lines_total = (stoppos >> 9) + 1;
-
-       dl_lines_done = 0;
-
-       while (dl_lines_total > dl_lines_done) {
-               /* We can download only up-to 32 DRAM lines in one go! */
-               dl_lines_curr = MIN(chunks_per_read, dl_lines_total);
-
-               bufsz = sigma_read_dram(dl_lines_done, dl_lines_curr,
-                                       (uint8_t *)dram_line, devc);
-               /* TODO: Check bufsz. For now, just avoid compiler warnings. */
-               (void)bufsz;
-
-               /* This is the first DRAM line, so find the initial timestamp. */
-               if (dl_lines_done == 0) {
-                       devc->state.lastts =
-                               sigma_dram_cluster_ts(&dram_line[0].cluster[0]);
-                       devc->state.lastsample = 0;
-               }
-
-               for (i = 0; i < dl_lines_curr; i++) {
-                       uint32_t trigger_event = ~0;
-                       /* The last "DRAM line" can be only partially full. */
-                       if (dl_lines_done + i == dl_lines_total - 1)
-                               dl_events_in_line = stoppos & 0x1ff;
-
-                       /* Test if the trigger happened on this line. */
-                       if (dl_lines_done + i == trg_line)
-                               trigger_event = trg_event;
-
-                       decode_chunk_ts(dram_line + i, dl_events_in_line,
-                                       trigger_event, sdi);
-               }
-
-               dl_lines_done += dl_lines_curr;
-       }
-
-       /* All done. */
-       packet.type = SR_DF_END;
-       sr_session_send(sdi, &packet);
-
-       dev_acquisition_stop(sdi, sdi);
-
-       g_free(dram_line);
-
-       return TRUE;
-}
-
-/*
- * Handle the Sigma when in CAPTURE mode. This function checks:
- * - Sampling time ended
- * - DRAM capacity overflow
- * This function triggers download of the samples from Sigma
- * in case either of the above conditions is true.
- */
-static int sigma_capture_mode(struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc = sdi->priv;
-
-       uint64_t running_msec;
-       struct timeval tv;
-
-       uint32_t stoppos, triggerpos;
-
-       /* Check if the selected sampling duration passed. */
-       gettimeofday(&tv, 0);
-       running_msec = (tv.tv_sec - devc->start_tv.tv_sec) * 1000 +
-                      (tv.tv_usec - devc->start_tv.tv_usec) / 1000;
-       if (running_msec >= devc->limit_msec)
-               return download_capture(sdi);
-
-       /* Get the position in DRAM to which the FPGA is writing now. */
-       sigma_read_pos(&stoppos, &triggerpos, devc);
-       /* Test if DRAM is full and if so, download the data. */
-       if ((stoppos >> 9) == 32767)
-               return download_capture(sdi);
-
-       return TRUE;
-}
-
-static int receive_data(int fd, int revents, void *cb_data)
-{
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-
-       (void)fd;
-       (void)revents;
-
-       sdi = cb_data;
-       devc = sdi->priv;
-
-       if (devc->state.state == SIGMA_IDLE)
-               return TRUE;
-
-       if (devc->state.state == SIGMA_CAPTURE)
-               return sigma_capture_mode(sdi);
-
-       return TRUE;
-}
-
-/* Build a LUT entry used by the trigger functions. */
-static void build_lut_entry(uint16_t value, uint16_t mask, uint16_t *entry)
-{
-       int i, j, k, bit;
-
-       /* For each quad channel. */
-       for (i = 0; i < 4; ++i) {
-               entry[i] = 0xffff;
-
-               /* For each bit in LUT. */
-               for (j = 0; j < 16; ++j)
-
-                       /* For each channel in quad. */
-                       for (k = 0; k < 4; ++k) {
-                               bit = 1 << (i * 4 + k);
-
-                               /* Set bit in entry */
-                               if ((mask & bit) &&
-                                   ((!(value & bit)) !=
-                                   (!(j & (1 << k)))))
-                                       entry[i] &= ~(1 << j);
-                       }
-       }
-}
-
-/* Add a logical function to LUT mask. */
-static void add_trigger_function(enum triggerop oper, enum triggerfunc func,
-                                int index, int neg, uint16_t *mask)
-{
-       int i, j;
-       int x[2][2], tmp, a, b, aset, bset, rset;
-
-       memset(x, 0, 4 * sizeof(int));
-
-       /* Trigger detect condition. */
-       switch (oper) {
-       case OP_LEVEL:
-               x[0][1] = 1;
-               x[1][1] = 1;
-               break;
-       case OP_NOT:
-               x[0][0] = 1;
-               x[1][0] = 1;
-               break;
-       case OP_RISE:
-               x[0][1] = 1;
-               break;
-       case OP_FALL:
-               x[1][0] = 1;
-               break;
-       case OP_RISEFALL:
-               x[0][1] = 1;
-               x[1][0] = 1;
-               break;
-       case OP_NOTRISE:
-               x[1][1] = 1;
-               x[0][0] = 1;
-               x[1][0] = 1;
-               break;
-       case OP_NOTFALL:
-               x[1][1] = 1;
-               x[0][0] = 1;
-               x[0][1] = 1;
-               break;
-       case OP_NOTRISEFALL:
-               x[1][1] = 1;
-               x[0][0] = 1;
-               break;
-       }
-
-       /* Transpose if neg is set. */
-       if (neg) {
-               for (i = 0; i < 2; ++i) {
-                       for (j = 0; j < 2; ++j) {
-                               tmp = x[i][j];
-                               x[i][j] = x[1-i][1-j];
-                               x[1-i][1-j] = tmp;
-                       }
-               }
-       }
-
-       /* Update mask with function. */
-       for (i = 0; i < 16; ++i) {
-               a = (i >> (2 * index + 0)) & 1;
-               b = (i >> (2 * index + 1)) & 1;
-
-               aset = (*mask >> i) & 1;
-               bset = x[b][a];
-
-               if (func == FUNC_AND || func == FUNC_NAND)
-                       rset = aset & bset;
-               else if (func == FUNC_OR || func == FUNC_NOR)
-                       rset = aset | bset;
-               else if (func == FUNC_XOR || func == FUNC_NXOR)
-                       rset = aset ^ bset;
-
-               if (func == FUNC_NAND || func == FUNC_NOR || func == FUNC_NXOR)
-                       rset = !rset;
-
-               *mask &= ~(1 << i);
-
-               if (rset)
-                       *mask |= 1 << i;
-       }
-}
-
-/*
- * Build trigger LUTs used by 50 MHz and lower sample rates for supporting
- * simple pin change and state triggers. Only two transitions (rise/fall) can be
- * set at any time, but a full mask and value can be set (0/1).
- */
-static int build_basic_trigger(struct triggerlut *lut, struct dev_context *devc)
-{
-       int i,j;
-       uint16_t masks[2] = { 0, 0 };
-
-       memset(lut, 0, sizeof(struct triggerlut));
-
-       /* Contant for simple triggers. */
-       lut->m4 = 0xa000;
-
-       /* Value/mask trigger support. */
-       build_lut_entry(devc->trigger.simplevalue, devc->trigger.simplemask,
-                       lut->m2d);
-
-       /* Rise/fall trigger support. */
-       for (i = 0, j = 0; i < 16; ++i) {
-               if (devc->trigger.risingmask & (1 << i) ||
-                   devc->trigger.fallingmask & (1 << i))
-                       masks[j++] = 1 << i;
-       }
-
-       build_lut_entry(masks[0], masks[0], lut->m0d);
-       build_lut_entry(masks[1], masks[1], lut->m1d);
-
-       /* Add glue logic */
-       if (masks[0] || masks[1]) {
-               /* Transition trigger. */
-               if (masks[0] & devc->trigger.risingmask)
-                       add_trigger_function(OP_RISE, FUNC_OR, 0, 0, &lut->m3);
-               if (masks[0] & devc->trigger.fallingmask)
-                       add_trigger_function(OP_FALL, FUNC_OR, 0, 0, &lut->m3);
-               if (masks[1] & devc->trigger.risingmask)
-                       add_trigger_function(OP_RISE, FUNC_OR, 1, 0, &lut->m3);
-               if (masks[1] & devc->trigger.fallingmask)
-                       add_trigger_function(OP_FALL, FUNC_OR, 1, 0, &lut->m3);
-       } else {
-               /* Only value/mask trigger. */
-               lut->m3 = 0xffff;
-       }
-
-       /* Triggertype: event. */
-       lut->params.selres = 3;
-
-       return SR_OK;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct dev_context *devc;
-       struct clockselect_50 clockselect;
-       int frac, triggerpin, ret;
-       uint8_t triggerselect = 0;
-       struct triggerinout triggerinout_conf;
-       struct triggerlut lut;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       devc = sdi->priv;
-
-       if (convert_trigger(sdi) != SR_OK) {
-               sr_err("Failed to configure triggers.");
-               return SR_ERR;
-       }
-
-       /* If the samplerate has not been set, default to 200 kHz. */
-       if (devc->cur_firmware == -1) {
-               if ((ret = set_samplerate(sdi, SR_KHZ(200))) != SR_OK)
-                       return ret;
-       }
-
-       /* Enter trigger programming mode. */
-       sigma_set_register(WRITE_TRIGGER_SELECT1, 0x20, devc);
-
-       /* 100 and 200 MHz mode. */
-       if (devc->cur_samplerate >= SR_MHZ(100)) {
-               sigma_set_register(WRITE_TRIGGER_SELECT1, 0x81, devc);
-
-               /* Find which pin to trigger on from mask. */
-               for (triggerpin = 0; triggerpin < 8; ++triggerpin)
-                       if ((devc->trigger.risingmask | devc->trigger.fallingmask) &
-                           (1 << triggerpin))
-                               break;
-
-               /* Set trigger pin and light LED on trigger. */
-               triggerselect = (1 << LEDSEL1) | (triggerpin & 0x7);
-
-               /* Default rising edge. */
-               if (devc->trigger.fallingmask)
-                       triggerselect |= 1 << 3;
-
-       /* All other modes. */
-       } else if (devc->cur_samplerate <= SR_MHZ(50)) {
-               build_basic_trigger(&lut, devc);
-
-               sigma_write_trigger_lut(&lut, devc);
-
-               triggerselect = (1 << LEDSEL1) | (1 << LEDSEL0);
-       }
-
-       /* Setup trigger in and out pins to default values. */
-       memset(&triggerinout_conf, 0, sizeof(struct triggerinout));
-       triggerinout_conf.trgout_bytrigger = 1;
-       triggerinout_conf.trgout_enable = 1;
-
-       sigma_write_register(WRITE_TRIGGER_OPTION,
-                            (uint8_t *) &triggerinout_conf,
-                            sizeof(struct triggerinout), devc);
-
-       /* Go back to normal mode. */
-       sigma_set_register(WRITE_TRIGGER_SELECT1, triggerselect, devc);
-
-       /* Set clock select register. */
-       if (devc->cur_samplerate == SR_MHZ(200))
-               /* Enable 4 channels. */
-               sigma_set_register(WRITE_CLOCK_SELECT, 0xf0, devc);
-       else if (devc->cur_samplerate == SR_MHZ(100))
-               /* Enable 8 channels. */
-               sigma_set_register(WRITE_CLOCK_SELECT, 0x00, devc);
-       else {
-               /*
-                * 50 MHz mode (or fraction thereof). Any fraction down to
-                * 50 MHz / 256 can be used, but is not supported by sigrok API.
-                */
-               frac = SR_MHZ(50) / devc->cur_samplerate - 1;
-
-               clockselect.async = 0;
-               clockselect.fraction = frac;
-               clockselect.disabled_channels = 0;
-
-               sigma_write_register(WRITE_CLOCK_SELECT,
-                                    (uint8_t *) &clockselect,
-                                    sizeof(clockselect), devc);
-       }
-
-       /* Setup maximum post trigger time. */
-       sigma_set_register(WRITE_POST_TRIGGER,
-                          (devc->capture_ratio * 255) / 100, devc);
-
-       /* Start acqusition. */
-       gettimeofday(&devc->start_tv, 0);
-       sigma_set_register(WRITE_MODE, 0x0d, devc);
-
-       devc->cb_data = cb_data;
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(sdi, LOG_PREFIX);
-
-       /* Add capture source. */
-       sr_session_source_add(sdi->session, 0, G_IO_IN, 10, receive_data, (void *)sdi);
-
-       devc->state.state = SIGMA_CAPTURE;
-
-       return SR_OK;
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct dev_context *devc;
-
-       (void)cb_data;
-
-       devc = sdi->priv;
-       devc->state.state = SIGMA_IDLE;
-
-       sr_session_source_remove(sdi->session, 0);
-
-       return SR_OK;
-}
-
-SR_PRIV struct sr_dev_driver asix_sigma_driver_info = {
-       .name = "asix-sigma",
-       .longname = "ASIX SIGMA/SIGMA2",
-       .api_version = 1,
-       .init = init,
-       .cleanup = cleanup,
-       .scan = scan,
-       .dev_list = dev_list,
-       .dev_clear = dev_clear,
-       .config_get = config_get,
-       .config_set = config_set,
-       .config_list = config_list,
-       .dev_open = dev_open,
-       .dev_close = dev_close,
-       .dev_acquisition_start = dev_acquisition_start,
-       .dev_acquisition_stop = dev_acquisition_stop,
-       .priv = NULL,
-};
diff --git a/hardware/asix-sigma/asix-sigma.h b/hardware/asix-sigma/asix-sigma.h
deleted file mode 100644 (file)
index 4c9deff..0000000
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2010 HÃ¥vard Espeland <gus@ping.uio.no>,
- * Copyright (C) 2010 Martin StensgÃ¥rd <mastensg@ping.uio.no>
- * Copyright (C) 2010 Carl Henrik Lunde <chlunde@ping.uio.no>
- *
- * 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_ASIX_SIGMA_ASIX_SIGMA_H
-#define LIBSIGROK_HARDWARE_ASIX_SIGMA_ASIX_SIGMA_H
-
-#define LOG_PREFIX "asix-sigma"
-
-enum sigma_write_register {
-       WRITE_CLOCK_SELECT      = 0,
-       WRITE_TRIGGER_SELECT0   = 1,
-       WRITE_TRIGGER_SELECT1   = 2,
-       WRITE_MODE              = 3,
-       WRITE_MEMROW            = 4,
-       WRITE_POST_TRIGGER      = 5,
-       WRITE_TRIGGER_OPTION    = 6,
-       WRITE_PIN_VIEW          = 7,
-
-       WRITE_TEST              = 15,
-};
-
-enum sigma_read_register {
-       READ_ID                 = 0,
-       READ_TRIGGER_POS_LOW    = 1,
-       READ_TRIGGER_POS_HIGH   = 2,
-       READ_TRIGGER_POS_UP     = 3,
-       READ_STOP_POS_LOW       = 4,
-       READ_STOP_POS_HIGH      = 5,
-       READ_STOP_POS_UP        = 6,
-       READ_MODE               = 7,
-       READ_PIN_CHANGE_LOW     = 8,
-       READ_PIN_CHANGE_HIGH    = 9,
-       READ_BLOCK_LAST_TS_LOW  = 10,
-       READ_BLOCK_LAST_TS_HIGH = 11,
-       READ_PIN_VIEW           = 12,
-
-       READ_TEST               = 15,
-};
-
-#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_DRAM_WAIT_ACK      (0x5 << 4)
-
-/* Bit (1 << 4) can be low or high (double buffer / cache) */
-#define REG_DRAM_BLOCK         (0x6 << 4)
-#define REG_DRAM_BLOCK_BEGIN   (0x8 << 4)
-#define REG_DRAM_BLOCK_DATA    (0xa << 4)
-
-#define LEDSEL0                        6
-#define LEDSEL1                        7
-
-#define NEXT_REG               1
-
-#define EVENTS_PER_CLUSTER     7
-
-#define CHUNK_SIZE             1024
-
-/*
- * The entire ASIX Sigma DRAM is an array of struct sigma_dram_line[1024];
- */
-
-/* One "DRAM cluster" contains a timestamp and 7 samples, 16b total. */
-struct sigma_dram_cluster {
-       uint8_t         timestamp_lo;
-       uint8_t         timestamp_hi;
-       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. */
-struct triggerinout {
-       uint8_t trgout_resistor_enable : 1;
-       uint8_t trgout_resistor_pullup : 1;
-       uint8_t reserved1 : 1;
-       uint8_t trgout_bytrigger : 1;
-       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 {
-       /* The actual LUTs. */
-       uint16_t m0d[4], m1d[4], m2d[4];
-       uint16_t m3, m3s, m4;
-
-       /* Paramters should be sent as a single register write. */
-       struct {
-               uint8_t selc : 2;
-               uint8_t selpresc : 6;
-
-               uint8_t selinc : 2;
-               uint8_t selres : 2;
-               uint8_t sela : 2;
-               uint8_t selb : 2;
-
-               uint16_t cmpb;
-               uint16_t cmpa;
-       } params;
-};
-
-/* Trigger configuration */
-struct sigma_trigger {
-       /* Only two channels can be used in mask. */
-       uint16_t risingmask;
-       uint16_t fallingmask;
-
-       /* Simple trigger support (<= 50 MHz). */
-       uint16_t simplemask;
-       uint16_t simplevalue;
-
-       /* TODO: Advanced trigger support (boolean expressions). */
-};
-
-/* Events for trigger operation. */
-enum triggerop {
-       OP_LEVEL = 1,
-       OP_NOT,
-       OP_RISE,
-       OP_FALL,
-       OP_RISEFALL,
-       OP_NOTRISE,
-       OP_NOTFALL,
-       OP_NOTRISEFALL,
-};
-
-/* Logical functions for trigger operation. */
-enum triggerfunc {
-       FUNC_AND = 1,
-       FUNC_NAND,
-       FUNC_OR,
-       FUNC_NOR,
-       FUNC_XOR,
-       FUNC_NXOR,
-};
-
-struct sigma_state {
-       enum {
-               SIGMA_UNINITIALIZED = 0,
-               SIGMA_IDLE,
-               SIGMA_CAPTURE,
-               SIGMA_DOWNLOAD,
-       } state;
-
-       uint16_t lastts;
-       uint16_t lastsample;
-};
-
-/* Private, per-device-instance driver context. */
-struct dev_context {
-       struct ftdi_context ftdic;
-       uint64_t cur_samplerate;
-       uint64_t period_ps;
-       uint64_t limit_msec;
-       struct timeval start_tv;
-       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;
-       void *cb_data;
-};
-
-#endif
diff --git a/hardware/atten-pps3xxx/api.c b/hardware/atten-pps3xxx/api.c
deleted file mode 100644 (file)
index 5ca3dbe..0000000
+++ /dev/null
@@ -1,518 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2014 Bert Vermeulen <bert@biot.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 <string.h>
-#include <errno.h>
-#include "protocol.h"
-
-/*
- * The default serial communication settings on the device are 9600
- * baud, 9 data bits. The 9th bit isn't actually used, and the vendor
- * software uses Mark parity to absorb the extra bit.
- *
- * Since 9 data bits is not a standard available in POSIX, we use two
- * stop bits to skip over the extra bit instead.
- */
-#define SERIALCOMM "9600/8n2"
-
-static const int32_t scanopts[] = {
-       SR_CONF_CONN,
-       SR_CONF_SERIALCOMM,
-};
-
-static const int32_t devopts[] = {
-       SR_CONF_POWER_SUPPLY,
-       SR_CONF_CONTINUOUS,
-       SR_CONF_OUTPUT_CHANNEL,
-       SR_CONF_OVER_CURRENT_PROTECTION,
-};
-
-static const int32_t devopts_cg[] = {
-       SR_CONF_OUTPUT_VOLTAGE,
-       SR_CONF_OUTPUT_VOLTAGE_MAX,
-       SR_CONF_OUTPUT_CURRENT,
-       SR_CONF_OUTPUT_CURRENT_MAX,
-       SR_CONF_OUTPUT_ENABLED,
-};
-
-static const char *channel_modes[] = {
-       "Independent",
-       "Series",
-       "Parallel",
-};
-
-static struct pps_model models[] = {
-       { PPS_3203T_3S, "PPS3203T-3S",
-               CHANMODE_INDEPENDENT | CHANMODE_SERIES | CHANMODE_PARALLEL,
-               3,
-               {
-                       /* Channel 1 */
-                       { { 0, 32, 0.01 }, { 0, 3, 0.001 } },
-                       /* Channel 2 */
-                       { { 0, 32, 0.01 }, { 0, 3, 0.001 } },
-                       /* Channel 3 */
-                       { { 0, 6, 0.01 }, { 0, 3, 0.001 } },
-               },
-       },
-};
-
-
-SR_PRIV struct sr_dev_driver atten_pps3203_driver_info;
-static struct sr_dev_driver *di = &atten_pps3203_driver_info;
-
-static int init(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, di, LOG_PREFIX);
-}
-
-static GSList *scan(GSList *options, int modelid)
-{
-       struct sr_dev_inst *sdi;
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       struct sr_config *src;
-       struct sr_channel *ch;
-       struct sr_channel_group *cg;
-       struct sr_serial_dev_inst *serial;
-       GSList *l, *devices;
-       struct pps_model *model;
-       uint8_t packet[PACKET_SIZE];
-       unsigned int i;
-       int ret;
-       const char *conn, *serialcomm;
-       char channel[10];
-
-       devices = NULL;
-       drvc = di->priv;
-       drvc->instances = NULL;
-
-       conn = serialcomm = NULL;
-       for (l = options; l; l = l->next) {
-               src = l->data;
-               switch (src->key) {
-               case SR_CONF_CONN:
-                       conn = g_variant_get_string(src->data, NULL);
-                       break;
-               case SR_CONF_SERIALCOMM:
-                       serialcomm = g_variant_get_string(src->data, NULL);
-                       break;
-               }
-       }
-       if (!conn)
-               return NULL;
-       if (!serialcomm)
-               serialcomm = SERIALCOMM;
-
-       if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
-               return NULL;
-
-       if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
-               return NULL;
-       serial_flush(serial);
-
-       /* This is how the vendor software channels for hardware. */
-       memset(packet, 0, PACKET_SIZE);
-       packet[0] = 0xaa;
-       packet[1] = 0xaa;
-       if (serial_write(serial, packet, PACKET_SIZE) == -1) {
-               sr_err("Unable to write while probing for hardware: %s",
-                               strerror(errno));
-               return NULL;
-       }
-       /* The device responds with a 24-byte packet when it receives a packet.
-        * At 9600 baud, 300ms is long enough for it to have arrived. */
-       g_usleep(300 * 1000);
-       memset(packet, 0, PACKET_SIZE);
-       if ((ret = serial_read_nonblocking(serial, packet, PACKET_SIZE)) < 0) {
-               sr_err("Unable to read while probing for hardware: %s",
-                               strerror(errno));
-               return NULL;
-       }
-       if (ret != PACKET_SIZE || packet[0] != 0xaa || packet[1] != 0xaa) {
-               /* Doesn't look like an Atten PPS. */
-               return NULL;
-       }
-
-       model = NULL;
-       for (i = 0; i < ARRAY_SIZE(models); i++) {
-               if (models[i].modelid == modelid) {
-                       model = &models[i];
-                       break;
-               }
-       }
-       if (!model) {
-               sr_err("Unknown modelid %d", modelid);
-               return NULL;
-       }
-
-       sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "Atten", model->name, NULL);
-       sdi->driver = di;
-       sdi->inst_type = SR_INST_SERIAL;
-       sdi->conn = serial;
-       for (i = 0; i < MAX_CHANNELS; i++) {
-               snprintf(channel, 10, "CH%d", i + 1);
-               ch = sr_channel_new(i, SR_CHANNEL_ANALOG, TRUE, channel);
-               sdi->channels = g_slist_append(sdi->channels, ch);
-               cg = g_malloc(sizeof(struct sr_channel_group));
-               cg->name = g_strdup(channel);
-               cg->channels = g_slist_append(NULL, ch);
-               cg->priv = NULL;
-               sdi->channel_groups = g_slist_append(sdi->channel_groups, cg);
-       }
-
-       devc = g_malloc0(sizeof(struct dev_context));
-       devc->model = model;
-       devc->config = g_malloc0(sizeof(struct per_channel_config) * model->num_channels);
-       sdi->priv = devc;
-       drvc->instances = g_slist_append(drvc->instances, sdi);
-       devices = g_slist_append(devices, sdi);
-
-       serial_close(serial);
-       if (!devices)
-               sr_serial_dev_inst_free(serial);
-
-       return devices;
-}
-
-static GSList *scan_3203(GSList *options)
-{
-       return scan(options, PPS_3203T_3S);
-}
-
-static GSList *dev_list(void)
-{
-       return ((struct drv_context *)(di->priv))->instances;
-}
-
-static int cleanup(void)
-{
-       return std_dev_clear(di, NULL);
-}
-
-static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       struct sr_channel *ch;
-       int channel, ret;
-
-       if (!sdi)
-               return SR_ERR_ARG;
-
-       devc = sdi->priv;
-
-       ret = SR_OK;
-       if (!cg) {
-               /* No channel group: global options. */
-               switch (key) {
-               case SR_CONF_OUTPUT_CHANNEL:
-                       *data = g_variant_new_string(channel_modes[devc->channel_mode]);
-                       break;
-               case SR_CONF_OVER_CURRENT_PROTECTION:
-                       *data = g_variant_new_boolean(devc->over_current_protection);
-                       break;
-               default:
-                       return SR_ERR_NA;
-               }
-       } else {
-               /* We only ever have one channel per channel group in this driver. */
-               ch = cg->channels->data;
-               channel = ch->index;
-
-               switch (key) {
-               case SR_CONF_OUTPUT_VOLTAGE:
-                       *data = g_variant_new_double(devc->config[channel].output_voltage_last);
-                       break;
-               case SR_CONF_OUTPUT_VOLTAGE_MAX:
-                       *data = g_variant_new_double(devc->config[channel].output_voltage_max);
-                       break;
-               case SR_CONF_OUTPUT_CURRENT:
-                       *data = g_variant_new_double(devc->config[channel].output_current_last);
-                       break;
-               case SR_CONF_OUTPUT_CURRENT_MAX:
-                       *data = g_variant_new_double(devc->config[channel].output_current_max);
-                       break;
-               case SR_CONF_OUTPUT_ENABLED:
-                       *data = g_variant_new_boolean(devc->config[channel].output_enabled);
-                       break;
-               default:
-                       return SR_ERR_NA;
-               }
-       }
-
-       return ret;
-}
-
-static int find_str(const char *str, const char **strings, int array_size)
-{
-       int idx, i;
-
-       idx = -1;
-       for (i = 0; i < array_size; i++) {
-               if (!strcmp(str, strings[i])) {
-                       idx = i;
-                       break;
-               }
-       }
-
-       return idx;
-}
-
-static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       struct sr_channel *ch;
-       gdouble dval;
-       int channel, ret, ival;
-       const char *sval;
-       gboolean bval;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       ret = SR_OK;
-       devc = sdi->priv;
-       if (!cg) {
-               /* No channel group: global options. */
-               switch (key) {
-               case SR_CONF_OUTPUT_CHANNEL:
-                       sval = g_variant_get_string(data, NULL);
-                       if ((ival = find_str(sval, channel_modes,
-                                                       ARRAY_SIZE(channel_modes))) == -1) {
-                               ret = SR_ERR_ARG;
-                               break;
-                       }
-                       if (devc->model->channel_modes && (1 << ival) == 0) {
-                               /* Not supported on this model. */
-                               ret = SR_ERR_ARG;
-                       }
-                       if (ival == devc->channel_mode_set)
-                               /* Nothing to do. */
-                               break;
-                       devc->channel_mode_set = ival;
-                       devc->config_dirty = TRUE;
-                       break;
-               case SR_CONF_OVER_CURRENT_PROTECTION:
-                       bval = g_variant_get_boolean(data);
-                       if (bval == devc->over_current_protection_set)
-                               /* Nothing to do. */
-                               break;
-                       devc->over_current_protection_set = bval;
-                       devc->config_dirty = TRUE;
-                       break;
-               default:
-                       return SR_ERR_NA;
-               }
-       } else {
-               /* Channel group specified: per-channel options. */
-               /* We only ever have one channel per channel group in this driver. */
-               ch = cg->channels->data;
-               channel = ch->index;
-
-               switch (key) {
-               case SR_CONF_OUTPUT_VOLTAGE_MAX:
-                       dval = g_variant_get_double(data);
-                       if (dval < 0 || dval > devc->model->channels[channel].voltage[1])
-                               ret = SR_ERR_ARG;
-                       devc->config[channel].output_voltage_max = dval;
-                       devc->config_dirty = TRUE;
-                       break;
-               case SR_CONF_OUTPUT_CURRENT_MAX:
-                       dval = g_variant_get_double(data);
-                       if (dval < 0 || dval > devc->model->channels[channel].current[1])
-                               ret = SR_ERR_ARG;
-                       devc->config[channel].output_current_max = dval;
-                       devc->config_dirty = TRUE;
-                       break;
-               case SR_CONF_OUTPUT_ENABLED:
-                       bval = g_variant_get_boolean(data);
-                       if (bval == devc->config[channel].output_enabled_set)
-                               /* Nothing to do. */
-                               break;
-                       devc->config[channel].output_enabled_set = bval;
-                       devc->config_dirty = TRUE;
-                       break;
-               default:
-                       ret = SR_ERR_NA;
-               }
-       }
-
-
-       return ret;
-}
-
-static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       struct sr_channel *ch;
-       GVariant *gvar;
-       GVariantBuilder gvb;
-       int channel, ret, i;
-
-       /* Always available, even without sdi. */
-       if (key == SR_CONF_SCAN_OPTIONS) {
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               scanopts, ARRAY_SIZE(scanopts), sizeof(int32_t));
-               return SR_OK;
-       }
-
-       if (!sdi)
-               return SR_ERR_ARG;
-       devc = sdi->priv;
-
-       ret = SR_OK;
-       if (!cg) {
-               /* No channel group: global options. */
-               switch (key) {
-               case SR_CONF_DEVICE_OPTIONS:
-                       *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                                       devopts, ARRAY_SIZE(devopts), sizeof(int32_t));
-                       break;
-               case SR_CONF_OUTPUT_CHANNEL:
-                       if (devc->model->channel_modes == CHANMODE_INDEPENDENT) {
-                               /* The 1-channel models. */
-                               *data = g_variant_new_strv(channel_modes, 1);
-                       } else {
-                               /* The other models support all modes. */
-                               *data = g_variant_new_strv(channel_modes, ARRAY_SIZE(channel_modes));
-                       }
-                       break;
-               default:
-                       return SR_ERR_NA;
-               }
-       } else {
-               /* Channel group specified: per-channel options. */
-               if (!sdi)
-                       return SR_ERR_ARG;
-               /* We only ever have one channel per channel group in this driver. */
-               ch = cg->channels->data;
-               channel = ch->index;
-
-               switch (key) {
-               case SR_CONF_DEVICE_OPTIONS:
-                       *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                                       devopts_cg, ARRAY_SIZE(devopts_cg), sizeof(int32_t));
-                       break;
-               case SR_CONF_OUTPUT_VOLTAGE_MAX:
-                       g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
-                       /* Min, max, step. */
-                       for (i = 0; i < 3; i++) {
-                               gvar = g_variant_new_double(devc->model->channels[channel].voltage[i]);
-                               g_variant_builder_add_value(&gvb, gvar);
-                       }
-                       *data = g_variant_builder_end(&gvb);
-                       break;
-               case SR_CONF_OUTPUT_CURRENT_MAX:
-                       g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
-                       /* Min, max, step. */
-                       for (i = 0; i < 3; i++) {
-                               gvar = g_variant_new_double(devc->model->channels[channel].current[i]);
-                               g_variant_builder_add_value(&gvb, gvar);
-                       }
-                       *data = g_variant_builder_end(&gvb);
-                       break;
-               default:
-                       return SR_ERR_NA;
-               }
-       }
-
-       return ret;
-}
-
-static int dev_close(struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-
-       devc = sdi->priv;
-       if (devc->config_dirty)
-               /* Some configuration changes were queued up but didn't
-                * get sent to the device, likely because we were never
-                * in acquisition mode. Send them out now. */
-               send_config(sdi);
-
-       return std_serial_dev_close(sdi);
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi,
-               void *cb_data)
-{
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-       uint8_t packet[PACKET_SIZE];
-
-       (void)cb_data;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       devc = sdi->priv;
-       memset(devc->packet, 0x44, PACKET_SIZE);
-       devc->packet_size = 0;
-
-       devc->acquisition_running = TRUE;
-
-       serial = sdi->conn;
-       serial_source_add(sdi->session, serial, G_IO_IN, 50,
-                       atten_pps3xxx_receive_data, (void *)sdi);
-       std_session_send_df_header(cb_data, LOG_PREFIX);
-
-       /* Send a "channel" configuration packet now. */
-       memset(packet, 0, PACKET_SIZE);
-       packet[0] = 0xaa;
-       packet[1] = 0xaa;
-       send_packet(sdi, packet);
-
-       return SR_OK;
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct dev_context *devc;
-
-       (void)cb_data;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       devc = sdi->priv;
-       devc->acquisition_running = FALSE;
-
-       return SR_OK;
-}
-
-SR_PRIV struct sr_dev_driver atten_pps3203_driver_info = {
-       .name = "atten-pps3203",
-       .longname = "Atten PPS3203T-3S",
-       .api_version = 1,
-       .init = init,
-       .cleanup = cleanup,
-       .scan = scan_3203,
-       .dev_list = dev_list,
-       .dev_clear = NULL,
-       .config_get = config_get,
-       .config_set = config_set,
-       .config_list = config_list,
-       .dev_open = std_serial_dev_open,
-       .dev_close = dev_close,
-       .dev_acquisition_start = dev_acquisition_start,
-       .dev_acquisition_stop = dev_acquisition_stop,
-       .priv = NULL,
-};
diff --git a/hardware/atten-pps3xxx/protocol.c b/hardware/atten-pps3xxx/protocol.c
deleted file mode 100644 (file)
index ed4d550..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2014 Bert Vermeulen <bert@biot.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 <string.h>
-#include <errno.h>
-#include "protocol.h"
-
-static void dump_packet(char *msg, uint8_t *packet)
-{
-       int i;
-       char str[128];
-
-       str[0] = 0;
-       for (i = 0; i < PACKET_SIZE; i++)
-               sprintf(str + strlen(str), "%.2x ", packet[i]);
-       sr_dbg("%s: %s", msg, str);
-
-}
-
-static void handle_packet(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_analog analog;
-       float value, data[MAX_CHANNELS];
-       int offset, i;
-
-       devc = sdi->priv;
-       dump_packet("received", devc->packet);
-       packet.type = SR_DF_ANALOG;
-       packet.payload = &analog;
-       analog.channels = sdi->channels;
-       analog.num_samples = 1;
-
-       analog.mq = SR_MQ_VOLTAGE;
-       analog.unit = SR_UNIT_VOLT;
-       analog.mqflags = SR_MQFLAG_DC;
-       analog.data = data;
-       for (i = 0; i < devc->model->num_channels; i++) {
-               offset = 2 + i * 4;
-               value = ((devc->packet[offset] << 8) + devc->packet[offset + 1]) / 100.0;
-               analog.data[i] = value;
-               devc->config[i].output_voltage_last = value;
-       }
-       sr_session_send(sdi, &packet);
-
-       analog.mq = SR_MQ_CURRENT;
-       analog.unit = SR_UNIT_AMPERE;
-       analog.mqflags = 0;
-       analog.data = data;
-       for (i = 0; i < devc->model->num_channels; i++) {
-               offset = 4 + i * 4;
-               value = ((devc->packet[offset] << 8) + devc->packet[offset + 1]) / 1000.0;
-               analog.data[i] = value;
-               devc->config[i].output_current_last = value;
-       }
-       sr_session_send(sdi, &packet);
-
-       for (i = 0; i < devc->model->num_channels; i++)
-               devc->config[i].output_enabled = (devc->packet[15] & (1 << i)) ? TRUE : FALSE;
-
-       devc->over_current_protection = devc->packet[18] ? TRUE : FALSE;
-       if (devc->packet[19] < 3)
-               devc->channel_mode = devc->packet[19];
-
-}
-
-SR_PRIV void send_packet(const struct sr_dev_inst *sdi, uint8_t *packet)
-{
-       struct sr_serial_dev_inst *serial;
-
-       serial = sdi->conn;
-       if (serial_write(serial, packet, PACKET_SIZE) == -1)
-               sr_dbg("Failed to send packet: %s", strerror(errno));
-       dump_packet("sent", packet);
-}
-
-SR_PRIV void send_config(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       uint8_t packet[PACKET_SIZE];
-       int value, offset, i;
-
-       devc = sdi->priv;
-       memset(packet, 0, PACKET_SIZE);
-       packet[0] = 0xaa;
-       packet[1] = 0x20;
-       packet[14] = 0x01;
-       packet[16] = 0x01;
-       for (i = 0; i < devc->model->num_channels; i++) {
-               offset = 2 + i * 4;
-               value = devc->config[i].output_voltage_max * 100;
-               packet[offset] = (value >> 8) & 0xff;
-               packet[offset + 1] = value & 0xff;
-               value = devc->config[i].output_current_max * 1000;
-               packet[offset + 2] = (value >> 8) & 0xff;
-               packet[offset + 3] = value & 0xff;
-               if (devc->config[i].output_enabled_set)
-                       packet[15] |= 1 << i;
-       }
-       packet[18] = devc->over_current_protection_set ? 1 : 0;
-       packet[19] = devc->channel_mode_set;
-       /* Checksum. */
-       value = 0;
-       for (i = 0; i < PACKET_SIZE - 1; i++)
-               value += packet[i];
-       packet[i] = value & 0xff;
-       send_packet(sdi, packet);
-       devc->config_dirty = FALSE;
-
-}
-
-SR_PRIV int atten_pps3xxx_receive_data(int fd, int revents, void *cb_data)
-{
-       struct dev_context *devc;
-       const struct sr_dev_inst *sdi;
-       struct sr_serial_dev_inst *serial;
-       struct sr_datafeed_packet packet;
-       unsigned char c;
-
-       (void)fd;
-
-       if (!(sdi = cb_data))
-               return TRUE;
-
-       if (!(devc = sdi->priv))
-               return TRUE;
-
-       serial = sdi->conn;
-       if (revents == G_IO_IN) {
-               if (serial_read_nonblocking(serial, &c, 1) < 0)
-                       return TRUE;
-               devc->packet[devc->packet_size++] = c;
-               if (devc->packet_size == PACKET_SIZE) {
-                       handle_packet(sdi);
-                       devc->packet_size = 0;
-                       if (devc->acquisition_running)
-                               send_config(sdi);
-                       else {
-                               serial_source_remove(sdi->session, serial);
-                               packet.type = SR_DF_END;
-                               sr_session_send(sdi, &packet);
-                       }
-               }
-       }
-
-       return TRUE;
-}
-
diff --git a/hardware/atten-pps3xxx/protocol.h b/hardware/atten-pps3xxx/protocol.h
deleted file mode 100644 (file)
index 1441305..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2014 Bert Vermeulen <bert@biot.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_ATTEN_PPS3XXX_PROTOCOL_H
-#define LIBSIGROK_HARDWARE_ATTEN_PPS3XXX_PROTOCOL_H
-
-#include <stdint.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "atten-pps3xxx"
-
-/* Packets to/from the device. */
-#define PACKET_SIZE 24
-
-enum {
-       PPS_3203T_3S,
-       PPS_3203T_2S,
-       PPS_3205T_3S,
-       PPS_3205T_2S,
-       PPS_3003S,
-       PPS_3005S,
-};
-
-/* Maximum number of output channels handled by this driver. */
-#define MAX_CHANNELS 3
-
-#define CHANMODE_INDEPENDENT 1 << 0
-#define CHANMODE_SERIES      1 << 1
-#define CHANMODE_PARALLEL    1 << 2
-
-struct channel_spec {
-       /* Min, max, step. */
-       gdouble voltage[3];
-       gdouble current[3];
-};
-
-struct pps_model {
-       int modelid;
-       char *name;
-       int channel_modes;
-       int num_channels;
-       struct channel_spec channels[MAX_CHANNELS];
-};
-
-struct per_channel_config {
-       /* Received from device. */
-       gdouble output_voltage_last;
-       gdouble output_current_last;
-       gboolean output_enabled;
-       /* Set by frontend. */
-       gdouble output_voltage_max;
-       gdouble output_current_max;
-       gboolean output_enabled_set;
-};
-
-/** Private, per-device-instance driver context. */
-struct dev_context {
-       /* Model-specific information */
-       struct pps_model *model;
-
-       /* Acquisition state */
-       gboolean acquisition_running;
-
-       /* Operational state */
-       gboolean config_dirty;
-       struct per_channel_config *config;
-       /* Received from device. */
-       int channel_mode;
-       gboolean over_current_protection;
-       /* Set by frontend. */
-       int channel_mode_set;
-       gboolean over_current_protection_set;
-
-       /* Temporary state across callbacks */
-       uint8_t packet[PACKET_SIZE];
-       int packet_size;
-
-};
-
-SR_PRIV int atten_pps3xxx_receive_data(int fd, int revents, void *cb_data);
-SR_PRIV void send_packet(const struct sr_dev_inst *sdi, uint8_t *packet);
-SR_PRIV void send_config(const struct sr_dev_inst *sdi);
-
-#endif
diff --git a/hardware/beaglelogic/api.c b/hardware/beaglelogic/api.c
deleted file mode 100644 (file)
index c86925b..0000000
+++ /dev/null
@@ -1,413 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2014 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"
-
-SR_PRIV struct sr_dev_driver beaglelogic_driver_info;
-static struct sr_dev_driver *di = &beaglelogic_driver_info;
-
-/* Hardware capabiities */
-static const int32_t hwcaps[] = {
-       SR_CONF_LOGIC_ANALYZER,
-       SR_CONF_SAMPLERATE,
-       SR_CONF_TRIGGER_MATCH,
-
-       SR_CONF_LIMIT_SAMPLES,
-       SR_CONF_CONTINUOUS,
-
-       SR_CONF_NUM_LOGIC_CHANNELS,
-};
-
-/* Trigger matching capabilities */
-static const int32_t soft_trigger_matches[] = {
-       SR_TRIGGER_ZERO,
-       SR_TRIGGER_ONE,
-       SR_TRIGGER_RISING,
-       SR_TRIGGER_FALLING,
-       SR_TRIGGER_EDGE,
-};
-
-/* Channels are numbered 0-13 */
-SR_PRIV const char *beaglelogic_channel_names[NUM_CHANNELS + 1] = {
-       "P8_45", "P8_46", "P8_43", "P8_44", "P8_41", "P8_42", "P8_39", "P8_40",
-       "P8_27", "P8_29", "P8_28", "P8_30", "P8_21", "P8_20", NULL,
-};
-
-/* Possible sample rates : 10 Hz to 100 MHz = (100 / x) MHz */
-static const uint64_t samplerates[] = {
-               SR_HZ(10),
-               SR_MHZ(100),
-               SR_HZ(1),
-};
-
-static int init(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, di, LOG_PREFIX);
-}
-
-static struct dev_context * beaglelogic_devc_alloc(void)
-{
-       struct dev_context *devc;
-
-       /* Allocate zeroed structure */
-       devc = g_try_malloc0(sizeof(*devc));
-
-       /* Default non-zero values (if any) */
-       devc->fd = -1;
-       devc->limit_samples = (uint64_t)-1;
-
-       return devc;
-}
-
-static GSList *scan(GSList *options)
-{
-       struct drv_context *drvc;
-       GSList *devices, *l;
-       struct sr_config *src;
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-       struct sr_channel *ch;
-       int i, maxch;
-
-       devices = NULL;
-       drvc = di->priv;
-       drvc->instances = NULL;
-
-       /* Probe for /dev/beaglelogic */
-       if (!g_file_test(BEAGLELOGIC_DEV_NODE, G_FILE_TEST_EXISTS))
-               return NULL;
-
-       sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, NULL, "BeagleLogic", "1.0");
-       sdi->driver = di;
-
-       /* Unless explicitly specified, keep max channels to 8 only */
-       maxch = 8;
-       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);
-       }
-
-       /* 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 */
-       for (i = 0; i < maxch; i++) {
-               if (!(ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE,
-                               beaglelogic_channel_names[i])))
-                       return NULL;
-               sdi->channels = g_slist_append(sdi->channels, ch);
-       }
-
-       sdi->priv = devc;
-       drvc->instances = g_slist_append(drvc->instances, sdi);
-       devices = g_slist_append(devices, sdi);
-
-       return devices;
-}
-
-static GSList *dev_list(void)
-{
-       return ((struct drv_context *)(di->priv))->instances;
-}
-
-static int dev_clear(void)
-{
-       return std_dev_clear(di, NULL);
-}
-
-static int dev_open(struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc = sdi->priv;
-
-       /* Open BeagleLogic */
-       if (beaglelogic_open_nonblock(devc))
-               return SR_ERR;
-
-       /* Set fd and local attributes */
-       devc->pollfd.fd = devc->fd;
-       devc->pollfd.events = G_IO_IN;
-
-       /* Get the default attributes */
-       beaglelogic_get_samplerate(devc);
-       beaglelogic_get_sampleunit(devc);
-       beaglelogic_get_triggerflags(devc);
-       beaglelogic_get_buffersize(devc);
-       beaglelogic_get_bufunitsize(devc);
-
-       /* Map the kernel capture FIFO for reads, saves 1 level of memcpy */
-       if (beaglelogic_mmap(devc) != SR_OK) {
-               sr_err("Unable to map capture buffer");
-               beaglelogic_close(devc);
-               return SR_ERR;
-       }
-
-       /* We're good to go now */
-       sdi->status = SR_ST_ACTIVE;
-       return SR_OK;
-}
-
-static int dev_close(struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc = sdi->priv;
-
-       if (sdi->status == SR_ST_ACTIVE) {
-               /* Close the memory mapping and the file */
-               beaglelogic_munmap(devc);
-               beaglelogic_close(devc);
-       }
-       sdi->status = SR_ST_INACTIVE;
-       return SR_OK;
-}
-
-static int cleanup(void)
-{
-       struct drv_context *drvc;
-       struct sr_dev_inst *sdi;
-       GSList *l;
-
-       /* unused driver */
-       if (!(drvc = di->priv))
-               return SR_OK;
-
-       /* Clean up the instances */
-       for (l = drvc->instances; l; l = l->next) {
-               sdi = l->data;
-               di->dev_close(sdi);
-               g_free(sdi->priv);
-               sr_dev_inst_free(sdi);
-       }
-       g_slist_free(drvc->instances);
-       drvc->instances = NULL;
-
-       di->priv = NULL;
-
-       return SR_OK;
-}
-
-static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc = sdi->priv;
-       (void)cg;
-
-       switch (key) {
-       case SR_CONF_LIMIT_SAMPLES:
-               *data = g_variant_new_uint64(devc->limit_samples);
-               break;
-
-       case SR_CONF_SAMPLERATE:
-               *data = g_variant_new_uint64(devc->cur_samplerate);
-               break;
-
-       case SR_CONF_NUM_LOGIC_CHANNELS:
-               *data = g_variant_new_uint32(g_slist_length(sdi->channels));
-               break;
-
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc = sdi->priv;
-       uint64_t tmp_u64;
-       (void)cg;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       switch (key) {
-       case SR_CONF_SAMPLERATE:
-               devc->cur_samplerate = g_variant_get_uint64(data);
-               return beaglelogic_set_samplerate(devc);
-
-       case SR_CONF_LIMIT_SAMPLES:
-               tmp_u64 = g_variant_get_uint64(data);
-               devc->limit_samples = tmp_u64;
-               devc->triggerflags = BL_TRIGGERFLAGS_ONESHOT;
-
-               /* Check if we have sufficient buffer size */
-               tmp_u64 *= SAMPLEUNIT_TO_BYTES(devc->sampleunit);
-               if (tmp_u64 > devc->buffersize) {
-                       sr_warn("Insufficient buffer space has been allocated.");
-                       sr_warn("Please use \'echo <size in bytes> > "\
-                               BEAGLELOGIC_SYSFS_ATTR(memalloc) \
-                               "\' as root to increase the buffer size, this"\
-                               " capture is now truncated to %d Msamples",
-                               devc->buffersize /
-                               (SAMPLEUNIT_TO_BYTES(devc->sampleunit) * 1000000));
-               }
-               return beaglelogic_set_triggerflags(devc);
-
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       int ret;
-       GVariant *gvar;
-       GVariantBuilder gvb;
-
-       (void)sdi;
-       (void)data;
-       (void)cg;
-
-       ret = SR_OK;
-       switch (key) {
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
-               break;
-       case SR_CONF_SAMPLERATE:
-               g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
-               gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"),
-                       samplerates, ARRAY_SIZE(samplerates), sizeof(uint64_t));
-               g_variant_builder_add(&gvb, "{sv}", "samplerate-steps", gvar);
-               *data = g_variant_builder_end(&gvb);
-               break;
-       case SR_CONF_TRIGGER_MATCH:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               soft_trigger_matches, ARRAY_SIZE(soft_trigger_matches),
-                               sizeof(int32_t));
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return ret;
-}
-
-/* get a sane timeout for poll() */
-#define BUFUNIT_TIMEOUT_MS(devc)       (100 + ((devc->bufunitsize * 1000) / \
-                               (uint32_t)(devc->cur_samplerate)))
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi,
-                                   void *cb_data)
-{
-       (void)cb_data;
-       struct dev_context *devc = sdi->priv;
-       struct sr_trigger *trigger;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       /* Save user pointer */
-       devc->cb_data = cb_data;
-
-       /* Clear capture state */
-       devc->bytes_read = 0;
-       devc->offset = 0;
-
-       /* Configure channels */
-       devc->sampleunit = g_slist_length(sdi->channels) > 8 ?
-                       BL_SAMPLEUNIT_16_BITS : BL_SAMPLEUNIT_8_BITS;
-       beaglelogic_set_sampleunit(devc);
-
-       /* Configure triggers & send header packet */
-       if ((trigger = sr_session_trigger_get(sdi->session))) {
-               devc->stl = soft_trigger_logic_new(sdi, trigger);
-               devc->trigger_fired = FALSE;
-       } else
-               devc->trigger_fired = TRUE;
-       std_session_send_df_header(cb_data, LOG_PREFIX);
-
-       /* Trigger and add poll on file */
-       beaglelogic_start(devc);
-       sr_session_source_add_pollfd(sdi->session, &devc->pollfd,
-                       BUFUNIT_TIMEOUT_MS(devc), beaglelogic_receive_data,
-                       (void *)sdi);
-
-       return SR_OK;
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct dev_context *devc = sdi->priv;
-       struct sr_datafeed_packet pkt;
-
-       (void)cb_data;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       /* Execute a stop on BeagleLogic */
-       beaglelogic_stop(devc);
-
-       /* lseek to offset 0, flushes the cache */
-       lseek(devc->fd, 0, SEEK_SET);
-
-       /* Remove session source and send EOT packet */
-       sr_session_source_remove_pollfd(sdi->session, &devc->pollfd);
-       pkt.type = SR_DF_END;
-       pkt.payload = NULL;
-       sr_session_send(sdi, &pkt);
-
-       return SR_OK;
-}
-
-SR_PRIV struct sr_dev_driver beaglelogic_driver_info = {
-       .name = "beaglelogic",
-       .longname = "BeagleLogic",
-       .api_version = 1,
-       .init = init,
-       .cleanup = cleanup,
-       .scan = scan,
-       .dev_list = dev_list,
-       .dev_clear = dev_clear,
-       .config_get = config_get,
-       .config_set = config_set,
-       .config_list = config_list,
-       .dev_open = dev_open,
-       .dev_close = dev_close,
-       .dev_acquisition_start = dev_acquisition_start,
-       .dev_acquisition_stop = dev_acquisition_stop,
-       .priv = NULL,
-};
diff --git a/hardware/beaglelogic/beaglelogic.h b/hardware/beaglelogic/beaglelogic.h
deleted file mode 100644 (file)
index 12e2f48..0000000
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2014 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/>.
- */
-
-#ifndef BEAGLELOGIC_H_
-#define BEAGLELOGIC_H_
-
-#include <fcntl.h>
-
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <sys/errno.h>
-#include <sys/ioctl.h>
-
-#include <stdlib.h>
-
-#include <unistd.h>
-
-/* BeagleLogic device node name */
-#define BEAGLELOGIC_DEV_NODE        "/dev/beaglelogic"
-#define BEAGLELOGIC_SYSFS_ATTR(a)   "/sys/devices/virtual/misc/beaglelogic/"\
-                                       __STRING(a)
-
-/* Reproduced verbatim from beaglelogic.h in the kernel tree until the kernel
- * module hits the mainline. Contains the ABI, so DO NOT TOUCH this section */
-
-/* ioctl calls that can be issued on /dev/beaglelogic */
-#define IOCTL_BL_GET_VERSION        _IOR('k', 0x20, uint32_t)
-
-#define IOCTL_BL_GET_SAMPLE_RATE    _IOR('k', 0x21, uint32_t)
-#define IOCTL_BL_SET_SAMPLE_RATE    _IOW('k', 0x21, uint32_t)
-
-#define IOCTL_BL_GET_SAMPLE_UNIT    _IOR('k', 0x22, uint32_t)
-#define IOCTL_BL_SET_SAMPLE_UNIT    _IOW('k', 0x22, 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_CACHE_INVALIDATE    _IO('k', 0x25)
-
-#define IOCTL_BL_GET_BUFFER_SIZE    _IOR('k', 0x26, uint32_t)
-#define IOCTL_BL_SET_BUFFER_SIZE    _IOW('k', 0x26, uint32_t)
-
-#define IOCTL_BL_GET_BUFUNIT_SIZE   _IOR('k', 0x27, uint32_t)
-
-#define IOCTL_BL_FILL_TEST_PATTERN   _IO('k', 0x28)
-
-#define IOCTL_BL_START               _IO('k', 0x29)
-#define IOCTL_BL_STOP                _IO('k', 0x2A)
-
-/* Possible States of BeagleLogic */
-enum beaglelogic_states {
-       STATE_BL_DISABLED,      /* Powered off (at module start) */
-       STATE_BL_INITIALIZED,   /* Powered on */
-       STATE_BL_MEMALLOCD,     /* Buffers allocated */
-       STATE_BL_ARMED,         /* All Buffers DMA-mapped and configuration done */
-       STATE_BL_RUNNING,       /* Data being captured */
-       STATE_BL_REQUEST_STOP,  /* Stop requested */
-       STATE_BL_ERROR          /* Buffer overrun */
-};
-
-/* Setting attributes */
-enum beaglelogic_triggerflags {
-       BL_TRIGGERFLAGS_ONESHOT = 0,
-       BL_TRIGGERFLAGS_CONTINUOUS
-};
-
-/* Possible sample unit / formats */
-enum beaglelogic_sampleunit {
-       BL_SAMPLEUNIT_16_BITS = 0,
-       BL_SAMPLEUNIT_8_BITS
-};
-/* END beaglelogic.h */
-
-/* For all the functions below:
- * Parameters:
- *     devc : Device context structure to operate on
- * Returns:
- *     SR_OK or SR_ERR
- */
-
-SR_PRIV int beaglelogic_open_nonblock(struct dev_context *devc);
-SR_PRIV int beaglelogic_close(struct dev_context *devc);
-
-SR_PRIV int beaglelogic_get_buffersize(struct dev_context *devc);
-SR_PRIV int beaglelogic_set_buffersize(struct dev_context *devc);
-
-SR_PRIV int beaglelogic_get_samplerate(struct dev_context *devc);
-SR_PRIV int beaglelogic_set_samplerate(struct dev_context *devc);
-
-SR_PRIV int beaglelogic_get_sampleunit(struct dev_context *devc);
-SR_PRIV int beaglelogic_set_sampleunit(struct dev_context *devc);
-
-SR_PRIV int beaglelogic_get_triggerflags(struct dev_context *devc);
-SR_PRIV int beaglelogic_set_triggerflags(struct dev_context *devc);
-
-/* Start and stop the capture operation */
-SR_PRIV int beaglelogic_start(struct dev_context *devc);
-SR_PRIV int beaglelogic_stop(struct dev_context *devc);
-
-/* Get the last error size */
-SR_PRIV int beaglelogic_getlasterror(struct dev_context *devc);
-
-/* Gets the unit size of the capture buffer (usually 4 or 8 MB) */
-SR_PRIV int beaglelogic_get_bufunitsize(struct dev_context *devc);
-
-SR_PRIV int beaglelogic_mmap(struct dev_context *devc);
-SR_PRIV int beaglelogic_munmap(struct dev_context *devc);
-
-/* Sources */
-SR_PRIV inline int beaglelogic_open_nonblock(struct dev_context *devc) {
-       devc->fd = open(BEAGLELOGIC_DEV_NODE, O_RDONLY | O_NONBLOCK);
-       return (devc->fd == -1 ? SR_ERR : SR_OK);
-}
-
-SR_PRIV inline int beaglelogic_close(struct dev_context *devc) {
-       return close(devc->fd);
-}
-
-SR_PRIV inline int beaglelogic_get_buffersize(struct dev_context *devc) {
-       return ioctl(devc->fd, IOCTL_BL_GET_BUFFER_SIZE, &devc->buffersize);
-}
-
-SR_PRIV inline int beaglelogic_set_buffersize(struct dev_context *devc) {
-       return ioctl(devc->fd, IOCTL_BL_SET_BUFFER_SIZE, devc->buffersize);
-}
-
-/* This is treated differently as it gets a uint64_t while a uint32_t is read */
-SR_PRIV inline int beaglelogic_get_samplerate(struct dev_context *devc) {
-       uint32_t arg, err;
-       err = ioctl(devc->fd, IOCTL_BL_GET_SAMPLE_RATE, &arg);
-       devc->cur_samplerate = arg;
-       return err;
-}
-
-SR_PRIV inline int beaglelogic_set_samplerate(struct dev_context *devc) {
-       return ioctl(devc->fd, IOCTL_BL_SET_SAMPLE_RATE,
-                       (uint32_t)devc->cur_samplerate);
-}
-
-SR_PRIV inline int beaglelogic_get_sampleunit(struct dev_context *devc) {
-       return ioctl(devc->fd, IOCTL_BL_GET_SAMPLE_UNIT, &devc->sampleunit);
-}
-
-SR_PRIV inline int beaglelogic_set_sampleunit(struct dev_context *devc) {
-       return ioctl(devc->fd, IOCTL_BL_SET_SAMPLE_UNIT, devc->sampleunit);
-}
-
-SR_PRIV inline int beaglelogic_get_triggerflags(struct dev_context *devc) {
-       return ioctl(devc->fd, IOCTL_BL_GET_TRIGGER_FLAGS, &devc->triggerflags);
-}
-
-SR_PRIV inline int beaglelogic_set_triggerflags(struct dev_context *devc) {
-       return ioctl(devc->fd, IOCTL_BL_SET_TRIGGER_FLAGS, devc->triggerflags);
-}
-
-SR_PRIV int beaglelogic_getlasterror(struct dev_context *devc) {
-       int fd;
-       char buf[16];
-       int ret;
-
-       if ((fd = open(BEAGLELOGIC_SYSFS_ATTR(lasterror), O_RDONLY)) == -1)
-               return SR_ERR;
-
-       if ((ret = read(fd, buf, 16)) < 0)
-               return SR_ERR;
-
-       close(fd);
-       devc->last_error = strtoul(buf, NULL, 10);
-
-       return SR_OK;
-}
-
-SR_PRIV inline int beaglelogic_start(struct dev_context *devc) {
-       return ioctl(devc->fd, IOCTL_BL_START);
-}
-
-SR_PRIV inline int beaglelogic_stop(struct dev_context *devc) {
-       return ioctl(devc->fd, IOCTL_BL_STOP);
-}
-
-SR_PRIV int beaglelogic_get_bufunitsize(struct dev_context *devc) {
-       return ioctl(devc->fd, IOCTL_BL_GET_BUFUNIT_SIZE, &devc->bufunitsize);
-}
-
-SR_PRIV int beaglelogic_mmap(struct dev_context *devc) {
-       if (!devc->buffersize)
-               beaglelogic_get_buffersize(devc);
-       devc->sample_buf = mmap(NULL, devc->buffersize,
-                       PROT_READ, MAP_SHARED, devc->fd, 0);
-       return (devc->sample_buf == MAP_FAILED ? -1 : SR_OK);
-}
-
-SR_PRIV int beaglelogic_munmap(struct dev_context *devc) {
-       return munmap(devc->sample_buf, devc->buffersize);
-}
-
-#endif /* BEAGLELOGIC_H_ */
diff --git a/hardware/beaglelogic/protocol.c b/hardware/beaglelogic/protocol.c
deleted file mode 100644 (file)
index 1c01b64..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2014 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 <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-/* Define data packet size independent of packet (bufunitsize bytes) size
- * from the BeagleLogic kernel module */
-#define PACKET_SIZE    (512 * 1024)
-
-/* This implementation is zero copy from the libsigrok side.
- * It does not copy any data, just passes a pointer from the mmap'ed
- * kernel buffers appropriately. It is up to the application which is
- * using libsigrok to decide how to deal with the data.
- */
-SR_PRIV int beaglelogic_receive_data(int fd, int revents, void *cb_data)
-{
-       const struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_logic logic;
-
-       int trigger_offset;
-       uint32_t packetsize;
-       uint64_t bytes_remaining;
-
-       if (!(sdi = cb_data) || !(devc = sdi->priv))
-               return TRUE;
-
-       packetsize = PACKET_SIZE;
-       logic.unitsize = SAMPLEUNIT_TO_BYTES(devc->sampleunit);
-
-       if (revents == G_IO_IN) {
-               sr_info("In callback G_IO_IN, offset=%d", devc->offset);
-
-               bytes_remaining = (devc->limit_samples * logic.unitsize) -
-                               devc->bytes_read;
-
-               /* Configure data packet */
-               packet.type = SR_DF_LOGIC;
-               packet.payload = &logic;
-               logic.data = devc->sample_buf + devc->offset;
-               logic.length = MIN(packetsize, bytes_remaining);
-
-               if (devc->trigger_fired) {
-                       /* Send the incoming transfer to the session bus. */
-                       sr_session_send(devc->cb_data, &packet);
-               } else {
-                       /* Check for trigger */
-                       trigger_offset = soft_trigger_logic_check(devc->stl,
-                                               logic.data,
-                                               packetsize);
-
-                       if (trigger_offset > -1) {
-                               trigger_offset *= logic.unitsize;
-                               logic.length = MIN(packetsize - trigger_offset,
-                                               bytes_remaining);
-                               logic.data += trigger_offset;
-
-                               sr_session_send(devc->cb_data, &packet);
-
-                               devc->trigger_fired = TRUE;
-                       }
-               }
-
-               /* Move the read pointer forward */
-               lseek(fd, packetsize, SEEK_CUR);
-
-               /* 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)
-                               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 */
-               packet.type = SR_DF_END;
-               packet.payload = NULL;
-               sr_session_send(devc->cb_data, &packet);
-
-               sr_session_source_remove_pollfd(sdi->session, &devc->pollfd);
-       }
-
-       return TRUE;
-}
diff --git a/hardware/beaglelogic/protocol.h b/hardware/beaglelogic/protocol.h
deleted file mode 100644 (file)
index f2acfeb..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2014 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/>.
- */
-
-#ifndef LIBSIGROK_HARDWARE_BEAGLELOGIC_PROTOCOL_H
-#define LIBSIGROK_HARDWARE_BEAGLELOGIC_PROTOCOL_H
-
-#include <stdint.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "beaglelogic"
-
-/* Maximum possible input channels */
-#define NUM_CHANNELS            14
-
-#define SAMPLEUNIT_TO_BYTES(x) ((x) == 1 ? 1 : 2)
-
-/** Private, per-device-instance driver context. */
-struct dev_context {
-       /* Model-specific information */
-       int max_channels;
-       uint32_t fw_ver;
-
-       /* Acquisition settings: see beaglelogic.h */
-       uint64_t cur_samplerate;
-       uint64_t limit_samples;
-       uint32_t sampleunit;
-       uint32_t triggerflags;
-
-       /* Buffers: size of each buffer block and the total buffer area */
-       uint32_t bufunitsize;
-       uint32_t buffersize;
-
-       /* Operational state */
-       int fd;
-       GPollFD pollfd;
-       int last_error;
-
-       uint64_t bytes_read;
-       uint64_t sent_samples;
-       uint32_t offset;
-       uint8_t *sample_buf;    /* mmap'd kernel buffer here */
-
-       void *cb_data;
-
-       /* Trigger logic */
-       struct soft_trigger_logic *stl;
-       gboolean trigger_fired;
-};
-
-SR_PRIV int beaglelogic_receive_data(int fd, int revents, void *cb_data);
-
-#endif
diff --git a/hardware/brymen-bm86x/api.c b/hardware/brymen-bm86x/api.c
deleted file mode 100644 (file)
index be21583..0000000
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "protocol.h"
-
-#define BRYMEN_BC86X "0820.0001"
-
-static const int32_t hwopts[] = {
-       SR_CONF_CONN,
-};
-
-static const int32_t hwcaps[] = {
-       SR_CONF_MULTIMETER,
-       SR_CONF_LIMIT_SAMPLES,
-       SR_CONF_LIMIT_MSEC,
-       SR_CONF_CONTINUOUS,
-};
-
-SR_PRIV struct sr_dev_driver brymen_bm86x_driver_info;
-static struct sr_dev_driver *di = &brymen_bm86x_driver_info;
-
-static int init(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, di, LOG_PREFIX);
-}
-
-static GSList *scan(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;
-       struct sr_channel *ch;
-       const char *conn;
-
-       drvc = di->priv;
-       drvc->instances = NULL;
-
-       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;
-
-               if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE,
-                                           "Brymen", "BM869", NULL))) {
-                       sr_err("sr_dev_inst_new returned NULL.");
-                       return NULL;
-               }
-
-               if (!(devc = g_try_malloc0(sizeof(*devc)))) {
-                       sr_err("Device context malloc failed.");
-                       return NULL;
-               }
-
-               sdi->priv = devc;
-               sdi->driver = di;
-               if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1")))
-                       return NULL;
-               sdi->channels = g_slist_append(sdi->channels, ch);
-               if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P2")))
-                       return NULL;
-               sdi->channels = g_slist_append(sdi->channels, ch);
-
-               sdi->inst_type = SR_INST_USB;
-               sdi->conn = usb;
-
-               drvc->instances = g_slist_append(drvc->instances, sdi);
-               devices = g_slist_append(devices, sdi);
-       }
-
-       return devices;
-}
-
-static GSList *dev_list(void)
-{
-       return ((struct drv_context *)(di->priv))->instances;
-}
-
-static int dev_open(struct sr_dev_inst *sdi)
-{
-       struct drv_context *drvc = di->priv;
-       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;
-
-       /* 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;
-
-       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 cleanup(void)
-{
-       return std_dev_clear(di, NULL);
-}
-
-static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc = sdi->priv;
-
-       (void)cg;
-
-       switch (key) {
-       case SR_CONF_LIMIT_SAMPLES:
-               *data = g_variant_new_uint64(devc->limit_samples);
-               break;
-       case SR_CONF_LIMIT_MSEC:
-               *data = g_variant_new_uint64(devc->limit_msec);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_set(int 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;
-
-       if (!(devc = sdi->priv)) {
-               sr_err("sdi->priv was NULL.");
-               return SR_ERR_BUG;
-       }
-
-       switch (key) {
-       case SR_CONF_LIMIT_SAMPLES:
-               devc->limit_samples = g_variant_get_uint64(data);
-               sr_dbg("Setting sample limit to %" PRIu64 ".", devc->limit_samples);
-               break;
-       case SR_CONF_LIMIT_MSEC:
-               devc->limit_msec = g_variant_get_uint64(data);
-               sr_dbg("Setting time limit to %" PRIu64 "ms.", devc->limit_msec);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_list(int 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_INT32,
-                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
-               break;
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi,
-                                   void *cb_data)
-{
-       struct dev_context *devc;
-
-       (void)cb_data;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       devc = sdi->priv;
-       devc->start_time = g_get_monotonic_time();
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(sdi, LOG_PREFIX);
-
-       sr_session_source_add(sdi->session, 0, 0, 10,
-                       brymen_bm86x_receive_data, (void *)sdi);
-
-       return SR_OK;
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct sr_datafeed_packet packet;
-
-       (void)cb_data;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       /* Send end packet to the session bus. */
-       packet.type = SR_DF_END;
-       sr_session_send(sdi, &packet);
-
-       sr_session_source_remove(sdi->session, 0);
-
-       return SR_OK;
-}
-
-SR_PRIV struct sr_dev_driver brymen_bm86x_driver_info = {
-       .name = "brymen-bm86x",
-       .longname = "Brymen BM86X",
-       .api_version = 1,
-       .init = init,
-       .cleanup = cleanup,
-       .scan = scan,
-       .dev_list = 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,
-       .priv = NULL,
-};
diff --git a/hardware/brymen-bm86x/protocol.c b/hardware/brymen-bm86x/protocol.c
deleted file mode 100644 (file)
index b8e16a3..0000000
+++ /dev/null
@@ -1,343 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <string.h>
-#include <math.h>
-#include "protocol.h"
-
-#define USB_TIMEOUT 500
-
-static 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 flag)
-{
-       char c, *p = str;
-       int i, ret;
-
-       if (buf[0] & flag)
-               *p++ = '-';
-       for (i = 0; i < length; i++) {
-               if (i && i < 5 && buf[i+1] & 0x01)
-                       *p++ = '.';
-               c = char_map[buf[i+1] >> 1];
-               if (i == 5 && (c == 'C' || c == 'F'))
-                       *temp_unit = c;
-               else if (c)
-                       *p++ = c;
-       }
-       *p = 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, over_limit;
-
-       ret1 = brymen_bm86x_parse_digits(buf+2, 6, str, &floatval[0],
-                                        &temp_unit, 0x80);
-       over_limit = strstr(str, "0L") || strstr(str, "0.L");
-       ret2 = brymen_bm86x_parse_digits(buf+9, 4, str, &floatval[1],
-                                        &temp_unit, 0x10);
-
-       /* main display */
-       if (ret1 == SR_OK || over_limit) {
-               /* SI unit */
-               if (buf[8] & 0x01) {
-                       analog[0].mq = SR_MQ_VOLTAGE;
-                       analog[0].unit = SR_UNIT_VOLT;
-                       if (!strcmp(str, "diod"))
-                               analog[0].mqflags |= SR_MQFLAG_DIODE;
-               } else if (buf[14] & 0x80) {
-                       analog[0].mq = SR_MQ_CURRENT;
-                       analog[0].unit = SR_UNIT_AMPERE;
-               } else if (buf[14] & 0x20) {
-                       analog[0].mq = SR_MQ_CAPACITANCE;
-                       analog[0].unit = SR_UNIT_FARAD;
-               } else if (buf[14] & 0x10) {
-                       analog[0].mq = SR_MQ_CONDUCTANCE;
-                       analog[0].unit = SR_UNIT_SIEMENS;
-               } else if (buf[15] & 0x01) {
-                       analog[0].mq = SR_MQ_FREQUENCY;
-                       analog[0].unit = SR_UNIT_HERTZ;
-               } else if (buf[10] & 0x01) {
-                       analog[0].mq = SR_MQ_CONTINUITY;
-                       analog[0].unit = SR_UNIT_OHM;
-               } else if (buf[15] & 0x10) {
-                       analog[0].mq = SR_MQ_RESISTANCE;
-                       analog[0].unit = SR_UNIT_OHM;
-               } else if (buf[15] & 0x02) {
-                       analog[0].mq = SR_MQ_POWER;
-                       analog[0].unit = SR_UNIT_DECIBEL_MW;
-               } else if (buf[15] & 0x80) {
-                       analog[0].mq = SR_MQ_DUTY_CYCLE;
-                       analog[0].unit = SR_UNIT_PERCENTAGE;
-               } else if (buf[ 2] & 0x0A) {
-                       analog[0].mq = SR_MQ_TEMPERATURE;
-                       if (temp_unit == 'F')
-                               analog[0].unit = SR_UNIT_FAHRENHEIT;
-                       else
-                               analog[0].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].mqflags |= SR_MQFLAG_DC;
-               if (buf[2] & 0x01)  analog[0].mqflags |= SR_MQFLAG_AC;
-               if (buf[1] & 0x01)  analog[0].mqflags |= SR_MQFLAG_AUTORANGE;
-               if (buf[1] & 0x08)  analog[0].mqflags |= SR_MQFLAG_HOLD;
-               if (buf[1] & 0x20)  analog[0].mqflags |= SR_MQFLAG_MAX;
-               if (buf[1] & 0x40)  analog[0].mqflags |= SR_MQFLAG_MIN;
-               if (buf[1] & 0x80)  analog[0].mqflags |= SR_MQFLAG_AVG;
-               if (buf[3] & 0x01)  analog[0].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;  /* n */
-               if (buf[15] & 0x08)  floatval[0] *= 1e-6;  /* Âµ */
-               if (buf[15] & 0x04)  floatval[0] *= 1e-3;  /* m */
-               if (buf[15] & 0x40)  floatval[0] *= 1e3;   /* k */
-               if (buf[15] & 0x20)  floatval[0] *= 1e6;   /* M */
-
-               if (over_limit)      floatval[0] = INFINITY;
-       }
-
-       /* secondary display */
-       if (ret2 == SR_OK) {
-               /* SI unit */
-               if (buf[14] & 0x08) {
-                       analog[1].mq = SR_MQ_VOLTAGE;
-                       analog[1].unit = SR_UNIT_VOLT;
-               } else if (buf[9] & 0x04) {
-                       analog[1].mq = SR_MQ_CURRENT;
-                       analog[1].unit = SR_UNIT_AMPERE;
-               } else if (buf[14] & 0x04) {
-                       analog[1].mq = SR_MQ_FREQUENCY;
-                       analog[1].unit = SR_UNIT_HERTZ;
-               } else if (buf[9] & 0x40) {
-                       analog[1].mq = SR_MQ_TEMPERATURE;
-                       if (temp_unit == 'F')
-                               analog[1].unit = SR_UNIT_FAHRENHEIT;
-                       else
-                               analog[1].unit = SR_UNIT_CELSIUS;
-               }
-
-               /* AC flag */
-               if (buf[9] & 0x20)  analog[1].mqflags |= SR_MQFLAG_AC;
-
-               /* SI prefix */
-               if (buf[ 9] & 0x01)  floatval[1] *= 1e-6;  /* Âµ */
-               if (buf[ 9] & 0x02)  floatval[1] *= 1e-3;  /* m */
-               if (buf[14] & 0x02)  floatval[1] *= 1e3;   /* k */
-               if (buf[14] & 0x01)  floatval[1] *= 1e6;   /* M */
-       }
-
-       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];
-       float floatval[2];
-
-       devc = sdi->priv;
-
-       analog[0].mq = -1;
-       analog[0].mqflags = 0;
-
-       analog[1].mq = -1;
-       analog[1].mqflags = 0;
-
-       brymen_bm86x_parse(buf, floatval, analog);
-
-       if (analog[0].mq != -1) {
-               /* Got a measurement. */
-               analog[0].num_samples = 1;
-               analog[0].data = &floatval[0];
-               analog[0].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].channels);
-       }
-
-       if (analog[1].mq != -1) {
-               /* Got a measurement. */
-               analog[1].num_samples = 1;
-               analog[1].data = &floatval[1];
-               analog[1].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].channels);
-       }
-
-       if (analog[0].mq != -1 || analog[1].mq != -1)
-               devc->num_samples++;
-}
-
-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/%ld 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/%d 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;
-       int64_t time;
-
-       (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 (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
-               sr_info("Requested number of samples reached, stopping.");
-               sdi->driver->dev_acquisition_stop(sdi, cb_data);
-               return TRUE;
-       }
-
-       if (devc->limit_msec) {
-               time = (g_get_monotonic_time() - devc->start_time) / 1000;
-               if (time > (int64_t)devc->limit_msec) {
-                       sr_info("Requested time limit reached, stopping.");
-                       sdi->driver->dev_acquisition_stop(sdi, cb_data);
-                       return TRUE;
-               }
-       }
-
-       return TRUE;
-}
diff --git a/hardware/brymen-bm86x/protocol.h b/hardware/brymen-bm86x/protocol.h
deleted file mode 100644 (file)
index 57af155..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef LIBSIGROK_HARDWARE_BRYMEN_BM86X_PROTOCOL_H
-#define LIBSIGROK_HARDWARE_BRYMEN_BM86X_PROTOCOL_H
-
-#include <stdint.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "brymen-bm86x"
-
-/** Private, per-device-instance driver context. */
-struct dev_context {
-       /* Acquisition settings */
-       uint64_t limit_samples;    /**< The sampling limit (in number of samples).*/
-       uint64_t limit_msec;       /**< The time limit (in milliseconds). */
-
-       /* Operational state */
-       int detached_kernel_driver;/**< Whether kernel driver was detached or not */
-       uint64_t num_samples;      /**< The number of already received samples. */
-       int64_t start_time;        /**< The time at which sampling started. */
-
-       /* Temporary state across callbacks */
-       int interrupt_pending;
-};
-
-SR_PRIV int brymen_bm86x_receive_data(int fd, int revents, void *cb_data);
-
-#endif
diff --git a/hardware/brymen-dmm/api.c b/hardware/brymen-dmm/api.c
deleted file mode 100644 (file)
index 1ccd18a..0000000
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * 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 "protocol.h"
-
-static const int32_t hwopts[] = {
-       SR_CONF_CONN,
-       SR_CONF_SERIALCOMM,
-};
-
-static const int32_t hwcaps[] = {
-       SR_CONF_MULTIMETER,
-       SR_CONF_LIMIT_SAMPLES,
-       SR_CONF_CONTINUOUS,
-       SR_CONF_LIMIT_MSEC,
-};
-
-SR_PRIV struct sr_dev_driver brymen_bm857_driver_info;
-static struct sr_dev_driver *di = &brymen_bm857_driver_info;
-
-static int init(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, di, LOG_PREFIX);
-}
-
-static GSList *brymen_scan(const char *conn, const char *serialcomm)
-{
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-       struct drv_context *drvc;
-       struct sr_channel *ch;
-       struct sr_serial_dev_inst *serial;
-       GSList *devices;
-       int ret;
-       uint8_t buf[128];
-       size_t len;
-
-       if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
-               return NULL;
-
-       if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != 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);
-
-       if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "Brymen", "BM85x", NULL)))
-               goto scan_cleanup;
-
-       if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
-               sr_err("Device context malloc failed.");
-               goto scan_cleanup;
-       }
-
-       sdi->inst_type = SR_INST_SERIAL;
-       sdi->conn = serial;
-       drvc = di->priv;
-       sdi->priv = devc;
-       sdi->driver = di;
-
-       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1")))
-               goto scan_cleanup;
-
-       sdi->channels = g_slist_append(sdi->channels, ch);
-       drvc->instances = g_slist_append(drvc->instances, sdi);
-       devices = g_slist_append(devices, sdi);
-
-scan_cleanup:
-       serial_close(serial);
-
-       return devices;
-}
-
-static GSList *scan(GSList *options)
-{
-       struct drv_context *drvc;
-       struct sr_config *src;
-       GSList *devices, *l;
-       const char *conn, *serialcomm;
-
-       devices = NULL;
-       drvc = di->priv;
-       drvc->instances = 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(conn, serialcomm);
-       } else {
-               /* But 9600/8n1 should work all of the time. */
-               devices = brymen_scan(conn, "9600/8n1/dtr=1/rts=1");
-       }
-
-       return devices;
-}
-
-static GSList *dev_list(void)
-{
-       return ((struct drv_context *)(di->priv))->instances;
-}
-
-static int cleanup(void)
-{
-       return std_dev_clear(di, NULL);
-}
-
-static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       int ret;
-
-       (void)cg;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       if (!(devc = sdi->priv)) {
-               sr_err("sdi->priv was NULL.");
-               return SR_ERR_BUG;
-       }
-
-       ret = SR_OK;
-       switch (id) {
-       case SR_CONF_LIMIT_SAMPLES:
-               devc->limit_samples = g_variant_get_uint64(data);
-               break;
-       case SR_CONF_LIMIT_MSEC:
-               devc->limit_msec = g_variant_get_uint64(data);
-               break;
-       default:
-               ret = SR_ERR_NA;
-       }
-
-       return ret;
-}
-
-static int config_list(int 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_INT32,
-                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
-               break;
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       if (!(devc = sdi->priv)) {
-               sr_err("sdi->priv was NULL.");
-               return SR_ERR_BUG;
-       }
-
-       devc->cb_data = cb_data;
-
-       /*
-        * Reset the number of samples to take. If we've already collected our
-        * quota, but we start a new session, and don't reset this, we'll just
-        * quit without acquiring any new samples.
-        */
-       devc->num_samples = 0;
-       devc->starttime = g_get_monotonic_time();
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(cb_data, LOG_PREFIX);
-
-       /* 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 int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       return std_serial_dev_acquisition_stop(sdi, cb_data, std_serial_dev_close,
-                       sdi->conn, LOG_PREFIX);
-}
-
-SR_PRIV struct sr_dev_driver brymen_bm857_driver_info = {
-       .name = "brymen-bm857",
-       .longname = "Brymen BM857",
-       .api_version = 1,
-       .init = init,
-       .cleanup = cleanup,
-       .scan = scan,
-       .dev_list = 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 = dev_acquisition_stop,
-       .priv = NULL,
-};
diff --git a/hardware/brymen-dmm/parser.c b/hardware/brymen-dmm/parser.c
deleted file mode 100644 (file)
index e4b1227..0000000
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * 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 "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(serial, &cmdout, 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->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->mq = SR_MQ_VOLTAGE;
-               analog->unit = SR_UNIT_VOLT;
-       }
-       if (flags.is_amp) {
-               analog->mq = SR_MQ_CURRENT;
-               analog->unit = SR_UNIT_AMPERE;
-       }
-       if (flags.is_ohm) {
-               if (flags.is_beep)
-                       analog->mq = SR_MQ_CONTINUITY;
-               else
-                       analog->mq = SR_MQ_RESISTANCE;
-               analog->unit = SR_UNIT_OHM;
-       }
-       if (flags.is_hertz) {
-               analog->mq = SR_MQ_FREQUENCY;
-               analog->unit = SR_UNIT_HERTZ;
-       }
-       if (flags.is_duty_cycle) {
-               analog->mq = SR_MQ_DUTY_CYCLE;
-               analog->unit = SR_UNIT_PERCENTAGE;
-       }
-       if (flags.is_capacitance) {
-               analog->mq = SR_MQ_CAPACITANCE;
-               analog->unit = SR_UNIT_FARAD;
-       }
-       if (flags.is_fahrenheit) {
-               analog->mq = SR_MQ_TEMPERATURE;
-               analog->unit = SR_UNIT_FAHRENHEIT;
-       }
-       if (flags.is_celsius) {
-               analog->mq = SR_MQ_TEMPERATURE;
-               analog->unit = SR_UNIT_CELSIUS;
-       }
-       if (flags.is_capacitance) {
-               analog->mq = SR_MQ_CAPACITANCE;
-               analog->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->mq = SR_MQ_POWER;
-               analog->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->mqflags |= SR_MQFLAG_DIODE;
-       /* We can have both AC+DC in a single measurement. */
-       if (flags.is_ac)
-               analog->mqflags |= SR_MQFLAG_AC;
-       if (flags.is_dc)
-               analog->mqflags |= SR_MQFLAG_DC;
-
-       if (flags.is_low_batt)
-               sr_info("Low battery!");
-
-       return SR_OK;
-}
diff --git a/hardware/brymen-dmm/protocol.c b/hardware/brymen-dmm/protocol.c
deleted file mode 100644 (file)
index dff7b98..0000000
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * 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 "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;
-
-       devc = sdi->priv;
-
-       analog.num_samples = 1;
-       analog.mq = -1;
-
-       if (brymen_parse(buf, &floatval, &analog, NULL) != SR_OK)
-               return;
-       analog.data = &floatval;
-
-       analog.channels = sdi->channels;
-
-       if (analog.mq != -1) {
-               /* Got a measurement. */
-               packet.type = SR_DF_ANALOG;
-               packet.payload = &analog;
-               sr_session_send(devc->cb_data, &packet);
-               devc->num_samples++;
-       }
-}
-
-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(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;
-       int64_t time;
-
-       (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 (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
-               sr_info("Requested number of samples reached, stopping.");
-               sdi->driver->dev_acquisition_stop(sdi, cb_data);
-               return TRUE;
-       }
-
-       if (devc->limit_msec) {
-               time = (g_get_monotonic_time() - devc->starttime) / 1000;
-               if (time > (int64_t)devc->limit_msec) {
-                       sr_info("Requested time limit reached, stopping.");
-                       sdi->driver->dev_acquisition_stop(sdi, cb_data);
-                       return TRUE;
-               }
-       }
-
-       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;
-       int status, len, packet_len, stream_len;
-
-       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 * (1000000 / baudrate);
-       start = g_get_monotonic_time();
-
-       packet_len = i = ibuf = len = 0;
-       while (ibuf < maxlen) {
-               len = serial_read(serial, &buf[ibuf], maxlen - ibuf);
-               if (len > 0) {
-                       ibuf += len;
-                       sr_spew("Read %d 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 %dms.", time);
-                       break;
-               }
-               g_usleep(byte_delay_us);
-       }
-
-       *buflen = ibuf;
-       sr_err("Didn't find a valid packet (read %d bytes).", ibuf);
-
-       return SR_ERR;
-}
diff --git a/hardware/brymen-dmm/protocol.h b/hardware/brymen-dmm/protocol.h
deleted file mode 100644 (file)
index 7c9aaae..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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.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 {
-       /** The current sampling limit (in number of samples). */
-       uint64_t limit_samples;
-
-       /** The current sampling limit (in ms). */
-       uint64_t limit_msec;
-
-       /** Opaque pointer passed in by the frontend. */
-       void *cb_data;
-
-       /** The current number of already received samples. */
-       uint64_t num_samples;
-
-       /** Start time of acquisition session */
-       int64_t starttime;
-
-       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
diff --git a/hardware/cem-dt-885x/api.c b/hardware/cem-dt-885x/api.c
deleted file mode 100644 (file)
index 9aed547..0000000
+++ /dev/null
@@ -1,432 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Bert Vermeulen <bert@biot.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 <string.h>
-#include "protocol.h"
-
-#define SERIALCOMM "9600/8n1"
-/* 23ms is the longest interval between tokens. */
-#define MAX_SCAN_TIME 25 * 1000
-
-static const int32_t hwopts[] = {
-       SR_CONF_CONN,
-};
-
-static const int32_t hwcaps[] = {
-       SR_CONF_SOUNDLEVELMETER,
-       SR_CONF_LIMIT_SAMPLES,
-       SR_CONF_CONTINUOUS,
-       SR_CONF_SPL_WEIGHT_FREQ,
-       SR_CONF_SPL_WEIGHT_TIME,
-       SR_CONF_SPL_MEASUREMENT_RANGE,
-       SR_CONF_DATALOG,
-       SR_CONF_HOLD_MAX,
-       SR_CONF_HOLD_MIN,
-       SR_CONF_POWER_OFF,
-       SR_CONF_DATA_SOURCE,
-};
-
-static const char *weight_freq[] = {
-       "A",
-       "C",
-};
-
-static const char *weight_time[] = {
-       "F",
-       "S",
-};
-
-static const uint64_t meas_ranges[][2] = {
-       { 30, 130 },
-       { 30, 80 },
-       { 50, 100 },
-       { 80, 130 },
-};
-
-static const char *data_sources[] = {
-       "Live",
-       "Memory",
-};
-SR_PRIV struct sr_dev_driver cem_dt_885x_driver_info;
-static struct sr_dev_driver *di = &cem_dt_885x_driver_info;
-
-
-static int init(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, di, LOG_PREFIX);
-}
-
-static GSList *scan(GSList *options)
-{
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       struct sr_config *src;
-       struct sr_serial_dev_inst *serial;
-       struct sr_dev_inst *sdi;
-       struct sr_channel *ch;
-       GSList *l, *devices;
-       gint64 start;
-       const char *conn;
-       unsigned char c;
-
-       conn = NULL;
-       for (l = options; l; l = l->next) {
-               src = l->data;
-               if (src->key == SR_CONF_CONN)
-                       conn = g_variant_get_string(src->data, NULL);
-       }
-       if (!conn)
-               return NULL;
-
-       if (!(serial = sr_serial_dev_inst_new(conn, SERIALCOMM)))
-               return NULL;
-
-       if (serial_open(serial, SERIAL_RDONLY | SERIAL_NONBLOCK) != SR_OK)
-               return NULL;
-
-       devices = NULL;
-       drvc = di->priv;
-       start = g_get_monotonic_time();
-       while (g_get_monotonic_time() - start < MAX_SCAN_TIME) {
-               if (serial_read(serial, &c, 1) == 1 && c == 0xa5) {
-                       /* Found one. */
-                       if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "CEM",
-                                       "DT-885x", NULL)))
-                               return NULL;
-
-                       if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
-                               sr_dbg("Device context malloc failed.");
-                               return NULL;
-                       }
-                       devc->cur_mqflags = 0;
-                       devc->recording = -1;
-                       devc->cur_meas_range = 0;
-                       devc->cur_data_source = DATA_SOURCE_LIVE;
-                       devc->enable_data_source_memory = FALSE;
-
-                       if (!(sdi->conn = sr_serial_dev_inst_new(conn, SERIALCOMM)))
-                               return NULL;
-
-                       sdi->inst_type = SR_INST_SERIAL;
-                       sdi->priv = devc;
-                       sdi->driver = di;
-                       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "SPL")))
-                               return NULL;
-                       sdi->channels = g_slist_append(sdi->channels, ch);
-                       drvc->instances = g_slist_append(drvc->instances, sdi);
-                       devices = g_slist_append(devices, sdi);
-                       break;
-               }
-               /* It takes about 1ms for a byte to come in. */
-               g_usleep(1000);
-       }
-
-       serial_close(serial);
-
-       return devices;
-}
-
-static GSList *dev_list(void)
-{
-       return ((struct drv_context *)(di->priv))->instances;
-}
-
-static int dev_open(struct sr_dev_inst *sdi)
-{
-       struct sr_serial_dev_inst *serial;
-
-       serial = sdi->conn;
-       if (serial_open(serial, SERIAL_RDWR) != SR_OK)
-               return SR_ERR;
-
-       sdi->status = SR_ST_ACTIVE;
-
-       return SR_OK;
-}
-
-static int cleanup(void)
-{
-       return std_dev_clear(di, NULL);
-}
-
-static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       GVariant *range[2];
-       uint64_t low, high;
-       int tmp, ret;
-
-       (void)cg;
-
-       if (!sdi)
-               return SR_ERR_ARG;
-
-       devc = sdi->priv;
-       ret = SR_OK;
-       switch (key) {
-       case SR_CONF_LIMIT_SAMPLES:
-               *data = g_variant_new_uint64(devc->limit_samples);
-               break;
-       case SR_CONF_DATALOG:
-               if ((ret = cem_dt_885x_recording_get(sdi, &tmp)) == SR_OK)
-                       *data = g_variant_new_boolean(tmp);
-               break;
-       case SR_CONF_SPL_WEIGHT_FREQ:
-               tmp = cem_dt_885x_weight_freq_get(sdi);
-               if (tmp == SR_MQFLAG_SPL_FREQ_WEIGHT_A)
-                       *data = g_variant_new_string("A");
-               else if (tmp == SR_MQFLAG_SPL_FREQ_WEIGHT_C)
-                       *data = g_variant_new_string("C");
-               else
-                       return SR_ERR;
-               break;
-       case SR_CONF_SPL_WEIGHT_TIME:
-               tmp = cem_dt_885x_weight_time_get(sdi);
-               if (tmp == SR_MQFLAG_SPL_TIME_WEIGHT_F)
-                       *data = g_variant_new_string("F");
-               else if (tmp == SR_MQFLAG_SPL_TIME_WEIGHT_S)
-                       *data = g_variant_new_string("S");
-               else
-                       return SR_ERR;
-               break;
-       case SR_CONF_HOLD_MAX:
-               if ((ret = cem_dt_885x_holdmode_get(sdi, &tmp)) == SR_OK)
-                       *data = g_variant_new_boolean(tmp == SR_MQFLAG_MAX);
-               break;
-       case SR_CONF_HOLD_MIN:
-               if ((ret = cem_dt_885x_holdmode_get(sdi, &tmp)) == SR_OK)
-                       *data = g_variant_new_boolean(tmp == SR_MQFLAG_MIN);
-               break;
-       case SR_CONF_SPL_MEASUREMENT_RANGE:
-               if ((ret = cem_dt_885x_meas_range_get(sdi, &low, &high)) == SR_OK) {
-                       range[0] = g_variant_new_uint64(low);
-                       range[1] = g_variant_new_uint64(high);
-                       *data = g_variant_new_tuple(range, 2);
-               }
-               break;
-       case SR_CONF_POWER_OFF:
-               *data = g_variant_new_boolean(FALSE);
-               break;
-       case SR_CONF_DATA_SOURCE:
-               if (devc->cur_data_source == DATA_SOURCE_LIVE)
-                       *data = g_variant_new_string("Live");
-               else
-                       *data = g_variant_new_string("Memory");
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return ret;
-}
-
-static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       uint64_t tmp_u64, low, high;
-       unsigned int i;
-       int tmp, ret;
-       const char *tmp_str;
-
-       (void)cg;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       if (!(devc = sdi->priv)) {
-               sr_err("sdi->priv was NULL.");
-               return SR_ERR_BUG;
-       }
-
-       ret = SR_OK;
-       switch (key) {
-       case SR_CONF_LIMIT_SAMPLES:
-               tmp_u64 = g_variant_get_uint64(data);
-               devc->limit_samples = tmp_u64;
-               ret = SR_OK;
-               break;
-       case SR_CONF_DATALOG:
-               ret = cem_dt_885x_recording_set(sdi, g_variant_get_boolean(data));
-               break;
-       case SR_CONF_SPL_WEIGHT_FREQ:
-               tmp_str = g_variant_get_string(data, NULL);
-               if (!strcmp(tmp_str, "A"))
-                       ret = cem_dt_885x_weight_freq_set(sdi,
-                                       SR_MQFLAG_SPL_FREQ_WEIGHT_A);
-               else if (!strcmp(tmp_str, "C"))
-                       ret = cem_dt_885x_weight_freq_set(sdi,
-                                       SR_MQFLAG_SPL_FREQ_WEIGHT_C);
-               else
-                       return SR_ERR_ARG;
-               break;
-       case SR_CONF_SPL_WEIGHT_TIME:
-               tmp_str = g_variant_get_string(data, NULL);
-               if (!strcmp(tmp_str, "F"))
-                       ret = cem_dt_885x_weight_time_set(sdi,
-                                       SR_MQFLAG_SPL_TIME_WEIGHT_F);
-               else if (!strcmp(tmp_str, "S"))
-                       ret = cem_dt_885x_weight_time_set(sdi,
-                                       SR_MQFLAG_SPL_TIME_WEIGHT_S);
-               else
-                       return SR_ERR_ARG;
-               break;
-       case SR_CONF_HOLD_MAX:
-               tmp = g_variant_get_boolean(data) ? SR_MQFLAG_MAX : 0;
-               ret = cem_dt_885x_holdmode_set(sdi, tmp);
-               break;
-       case SR_CONF_HOLD_MIN:
-               tmp = g_variant_get_boolean(data) ? SR_MQFLAG_MIN : 0;
-               ret = cem_dt_885x_holdmode_set(sdi, tmp);
-               break;
-       case SR_CONF_SPL_MEASUREMENT_RANGE:
-               g_variant_get(data, "(tt)", &low, &high);
-               ret = SR_ERR_ARG;
-               for (i = 0; i < ARRAY_SIZE(meas_ranges); i++) {
-                       if (meas_ranges[i][0] == low && meas_ranges[i][1] == high) {
-                               ret = cem_dt_885x_meas_range_set(sdi, low, high);
-                               break;
-                       }
-               }
-               break;
-       case SR_CONF_POWER_OFF:
-               if (g_variant_get_boolean(data))
-                       ret = cem_dt_885x_power_off(sdi);
-               break;
-       case SR_CONF_DATA_SOURCE:
-               tmp_str = g_variant_get_string(data, NULL);
-               if (!strcmp(tmp_str, "Live"))
-                       devc->cur_data_source = DATA_SOURCE_LIVE;
-               else if (!strcmp(tmp_str, "Memory"))
-                       devc->cur_data_source = DATA_SOURCE_MEMORY;
-               else
-                       return SR_ERR;
-               devc->enable_data_source_memory = devc->cur_data_source == DATA_SOURCE_MEMORY;
-               break;
-       default:
-               ret = SR_ERR_NA;
-       }
-
-       return ret;
-}
-
-static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       GVariant *tuple, *range[2];
-       GVariantBuilder gvb;
-       unsigned int i;
-       int ret;
-
-       (void)sdi;
-       (void)cg;
-
-       ret = SR_OK;
-       switch (key) {
-       case SR_CONF_SCAN_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
-               break;
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_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 ret;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       if (!(devc = sdi->priv)) {
-               sr_err("sdi->priv was NULL.");
-               return SR_ERR_BUG;
-       }
-
-       devc->cb_data = cb_data;
-       devc->state = ST_INIT;
-       devc->num_samples = 0;
-       devc->buf_len = 0;
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(cb_data, LOG_PREFIX);
-
-       /* Poll every 100ms, or whenever some data comes in. */
-       serial = sdi->conn;
-       serial_source_add(sdi->session, serial, G_IO_IN, 150,
-                       cem_dt_885x_receive_data, (void *)sdi);
-
-       return SR_OK;
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       return std_serial_dev_acquisition_stop(sdi, cb_data, std_serial_dev_close,
-                       sdi->conn, LOG_PREFIX);
-}
-
-SR_PRIV struct sr_dev_driver cem_dt_885x_driver_info = {
-       .name = "cem-dt-885x",
-       .longname = "CEM DT-885x",
-       .api_version = 1,
-       .init = init,
-       .cleanup = cleanup,
-       .scan = scan,
-       .dev_list = dev_list,
-       .dev_clear = NULL,
-       .config_get = config_get,
-       .config_set = config_set,
-       .config_list = config_list,
-       .dev_open = dev_open,
-       .dev_close = std_serial_dev_close,
-       .dev_acquisition_start = dev_acquisition_start,
-       .dev_acquisition_stop = dev_acquisition_stop,
-       .priv = NULL,
-};
diff --git a/hardware/cem-dt-885x/protocol.c b/hardware/cem-dt-885x/protocol.c
deleted file mode 100644 (file)
index 19e0830..0000000
+++ /dev/null
@@ -1,838 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Bert Vermeulen <bert@biot.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 <string.h>
-#include "protocol.h"
-
-/* Length of expected payload for each token. */
-static int token_payloads[][2] = {
-       { TOKEN_WEIGHT_TIME_FAST, 0 },
-       { TOKEN_WEIGHT_TIME_SLOW, 0 },
-       { TOKEN_HOLD_MAX, 0 },
-       { TOKEN_HOLD_MIN, 0 },
-       { TOKEN_TIME, 3 },
-       { TOKEN_MEAS_RANGE_OVER, 0 },
-       { TOKEN_MEAS_RANGE_UNDER, 0 },
-       { TOKEN_STORE_FULL, 0 },
-       { TOKEN_RECORDING_ON, 0 },
-       { TOKEN_MEAS_WAS_READOUT, 1 },
-       { TOKEN_MEAS_WAS_BARGRAPH, 0 },
-       { TOKEN_MEASUREMENT, 2 },
-       { TOKEN_HOLD_NONE, 0 },
-       { TOKEN_BATTERY_LOW, 0 },
-       { TOKEN_MEAS_RANGE_OK, 0 },
-       { TOKEN_STORE_OK, 0 },
-       { TOKEN_RECORDING_OFF, 0 },
-       { TOKEN_WEIGHT_FREQ_A, 1 },
-       { TOKEN_WEIGHT_FREQ_C, 1 },
-       { TOKEN_BATTERY_OK, 0 },
-       { TOKEN_MEAS_RANGE_30_80, 0 },
-       { TOKEN_MEAS_RANGE_30_130, 0 },
-       { TOKEN_MEAS_RANGE_50_100, 0 },
-       { TOKEN_MEAS_RANGE_80_130, 0 },
-};
-
-static int find_token_payload_len(unsigned char c)
-{
-       unsigned int i;
-
-       for (i = 0; i < ARRAY_SIZE(token_payloads); i++) {
-               if (token_payloads[i][0] == c)
-                       return token_payloads[i][1];
-       }
-
-       return -1;
-}
-
-/* Process measurement or setting (0xa5 command). */
-static void process_mset(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_analog analog;
-       GString *dbg;
-       float fvalue;
-       int i;
-
-       devc = sdi->priv;
-       if (sr_log_loglevel_get() >= SR_LOG_SPEW) {
-               dbg = g_string_sized_new(128);
-               g_string_printf(dbg, "got command 0x%.2x token 0x%.2x",
-                               devc->cmd, devc->token);
-               if (devc->buf_len) {
-                       g_string_append_printf(dbg, " payload");
-                       for (i = 0; i < devc->buf_len; i++)
-                               g_string_append_printf(dbg, " %.2x", devc->buf[i]);
-               }
-               sr_spew("%s", dbg->str);
-               g_string_free(dbg, TRUE);
-       }
-
-       switch(devc->token) {
-       case TOKEN_WEIGHT_TIME_FAST:
-               devc->cur_mqflags |= SR_MQFLAG_SPL_TIME_WEIGHT_F;
-               devc->cur_mqflags &= ~SR_MQFLAG_SPL_TIME_WEIGHT_S;
-               break;
-       case TOKEN_WEIGHT_TIME_SLOW:
-               devc->cur_mqflags |= SR_MQFLAG_SPL_TIME_WEIGHT_S;
-               devc->cur_mqflags &= ~SR_MQFLAG_SPL_TIME_WEIGHT_F;
-               break;
-       case TOKEN_WEIGHT_FREQ_A:
-               devc->cur_mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_A;
-               devc->cur_mqflags &= ~SR_MQFLAG_SPL_FREQ_WEIGHT_C;
-               break;
-       case TOKEN_WEIGHT_FREQ_C:
-               devc->cur_mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_C;
-               devc->cur_mqflags &= ~SR_MQFLAG_SPL_FREQ_WEIGHT_A;
-               break;
-       case TOKEN_HOLD_MAX:
-               devc->cur_mqflags |= SR_MQFLAG_HOLD | SR_MQFLAG_MAX;
-               devc->cur_mqflags &= ~SR_MQFLAG_MIN;
-               break;
-       case TOKEN_HOLD_MIN:
-               devc->cur_mqflags |= SR_MQFLAG_HOLD | SR_MQFLAG_MIN;
-               devc->cur_mqflags &= ~SR_MQFLAG_MAX;
-               break;
-       case TOKEN_HOLD_NONE:
-               devc->cur_mqflags &= ~(SR_MQFLAG_MAX | SR_MQFLAG_MIN | SR_MQFLAG_HOLD);
-               break;
-       case TOKEN_MEASUREMENT:
-               fvalue = ((devc->buf[0] & 0xf0) >> 4) * 100;
-               fvalue += (devc->buf[0] & 0x0f) * 10;
-               fvalue += ((devc->buf[1] & 0xf0) >> 4);
-               fvalue += (devc->buf[1] & 0x0f) / 10.0;
-               devc->last_spl = fvalue;
-               break;
-       case TOKEN_MEAS_WAS_READOUT:
-       case TOKEN_MEAS_WAS_BARGRAPH:
-               if (devc->cur_mqflags & (SR_MQFLAG_MAX | SR_MQFLAG_MIN)) {
-                       if (devc->token == TOKEN_MEAS_WAS_BARGRAPH) {
-                               /* The device still sends bargraph measurements even
-                                * when in max/min hold mode. Suppress them here, unless
-                                * they're readout values. This duplicates the behavior
-                                * of the device display exactly. */
-                               break;
-                       }
-               }
-               memset(&analog, 0, sizeof(struct sr_datafeed_analog));
-               analog.mq = SR_MQ_SOUND_PRESSURE_LEVEL;
-               analog.mqflags = devc->cur_mqflags;
-               analog.unit = SR_UNIT_DECIBEL_SPL;
-               analog.channels = sdi->channels;
-               analog.num_samples = 1;
-               analog.data = &devc->last_spl;
-               packet.type = SR_DF_ANALOG;
-               packet.payload = &analog;
-               sr_session_send(devc->cb_data, &packet);
-
-               devc->num_samples++;
-               if (devc->limit_samples && devc->num_samples >= devc->limit_samples)
-                       sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi,
-                                       devc->cb_data);
-               break;
-       case TOKEN_RECORDING_ON:
-               devc->recording = TRUE;
-               break;
-       case TOKEN_RECORDING_OFF:
-               devc->recording = FALSE;
-               break;
-       case TOKEN_MEAS_RANGE_30_80:
-       case TOKEN_MEAS_RANGE_30_130:
-       case TOKEN_MEAS_RANGE_50_100:
-       case TOKEN_MEAS_RANGE_80_130:
-               devc->cur_meas_range = devc->token;
-               break;
-       case TOKEN_TIME:
-       case TOKEN_STORE_OK:
-       case TOKEN_STORE_FULL:
-       case TOKEN_BATTERY_OK:
-       case TOKEN_BATTERY_LOW:
-       case TOKEN_MEAS_RANGE_OK:
-       case TOKEN_MEAS_RANGE_OVER:
-       case TOKEN_MEAS_RANGE_UNDER:
-               /* Not useful, or not expressable in sigrok. */
-               break;
-       }
-
-}
-
-static void send_data(const struct sr_dev_inst *sdi, unsigned char *data,
-               uint64_t num_samples)
-{
-       struct dev_context *devc;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_analog analog;
-       float fbuf[SAMPLES_PER_PACKET];
-       unsigned int i;
-
-       devc = sdi->priv;
-
-       for (i = 0; i < num_samples; i ++) {
-               fbuf[i] = ((data[i * 2] & 0xf0) >> 4) * 100;
-               fbuf[i] += (data[i * 2] & 0x0f) * 10;
-               fbuf[i] += ((data[i * 2 + 1] & 0xf0) >> 4);
-               fbuf[i] += (data[i * 2 + 1] & 0x0f) / 10.0;
-       }
-       memset(&analog, 0, sizeof(struct sr_datafeed_analog));
-       analog.mq = SR_MQ_SOUND_PRESSURE_LEVEL;
-       analog.mqflags = devc->cur_mqflags;
-       analog.unit = SR_UNIT_DECIBEL_SPL;
-       analog.channels = sdi->channels;
-       analog.num_samples = num_samples;
-       analog.data = fbuf;
-       packet.type = SR_DF_ANALOG;
-       packet.payload = &analog;
-       sr_session_send(devc->cb_data, &packet);
-
-       devc->num_samples += analog.num_samples;
-       if (devc->limit_samples && devc->num_samples >= devc->limit_samples)
-               sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi,
-                               devc->cb_data);
-
-       return;
-}
-
-static void process_byte(const struct sr_dev_inst *sdi, const unsigned char c,
-               int handle_packets)
-{
-       struct dev_context *devc;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_meta meta;
-       struct sr_config *src;
-       gint64 cur_time;
-       int len;
-
-       if (!(devc = sdi->priv))
-               return;
-
-       if (c == 0xff) {
-               /* Device is in hold mode */
-               devc->cur_mqflags |= SR_MQFLAG_HOLD;
-
-               if (devc->hold_last_sent == 0) {
-                       /* First hold notification. */
-                       devc->hold_last_sent = g_get_monotonic_time();
-                       /* When the device leaves hold mode, it starts from scratch. */
-                       devc->state = ST_INIT;
-               } else {
-                       cur_time = g_get_monotonic_time();
-                       if (cur_time - devc->hold_last_sent > HOLD_REPEAT_INTERVAL) {
-                               /* Force the last measurement out again. */
-                               devc->cmd = 0xa5;
-                               devc->token = TOKEN_MEAS_WAS_READOUT;
-                               if (handle_packets)
-                                       process_mset(sdi);
-                               devc->hold_last_sent = cur_time;
-                       }
-               }
-
-               return;
-       }
-       devc->cur_mqflags &= ~SR_MQFLAG_HOLD;
-       devc->hold_last_sent = 0;
-
-       if (devc->state == ST_INIT) {
-               if (c == 0xa5) {
-                       devc->cmd = c;
-                       devc->token = 0x00;
-                       devc->state = ST_GET_TOKEN;
-               } else if (c == 0xbb) {
-                       devc->cmd = c;
-                       devc->buf_len = 0;
-                       devc->state = ST_GET_LOG_HEADER;
-                       sr_dbg("got command 0xbb");
-               }
-       } else if (devc->state == ST_GET_TOKEN) {
-               devc->token = c;
-               devc->buf_len = 0;
-               len = find_token_payload_len(devc->token);
-               if (len == -1 || len > 0) {
-                       devc->buf_len = 0;
-                       devc->state = ST_GET_DATA;
-               } else {
-                       if (handle_packets)
-                               process_mset(sdi);
-                       devc->state = ST_INIT;
-               }
-       } else if (devc->state == ST_GET_DATA) {
-               len = find_token_payload_len(devc->token);
-               if (len == -1) {
-                       /* We don't know this token. */
-                       sr_dbg("Unknown 0xa5 token 0x%.2x", devc->token);
-                       if (c == 0xa5 || c == 0xbb) {
-                               /* Looks like a new command however. */
-                               if (handle_packets)
-                                       process_mset(sdi);
-                               devc->state = ST_INIT;
-                       } else {
-                               devc->buf[devc->buf_len++] = c;
-                               if (devc->buf_len > BUF_SIZE) {
-                                       /* Shouldn't happen, ignore. */
-                                       devc->state = ST_INIT;
-                               }
-                       }
-               } else {
-                       devc->buf[devc->buf_len++] = c;
-                       if (devc->buf_len == len) {
-                               if (handle_packets)
-                                       process_mset(sdi);
-                               devc->state = ST_INIT;
-                       } else if (devc->buf_len > BUF_SIZE) {
-                               /* Shouldn't happen, ignore. */
-                               devc->state = ST_INIT;
-                       }
-               }
-       } else if (devc->state == ST_GET_LOG_HEADER) {
-               sr_dbg("log header: 0x%.2x", c);
-               if (devc->buf_len < 2)
-                       devc->buf[devc->buf_len++] = c;
-               if (devc->buf_len == 2) {
-                       sr_dbg("Device says it has %d bytes stored.",
-                                       ((devc->buf[0] << 8) + devc->buf[1]) - 100);
-                       devc->buf_len = 0;
-                       devc->state = ST_GET_LOG_RECORD_META;
-               }
-       } else if (devc->state == ST_GET_LOG_RECORD_META) {
-               sr_dbg("log meta: 0x%.2x", c);
-               if (c == RECORD_END) {
-                       devc->state = ST_INIT;
-                       /* Stop acquisition after transferring all stored
-                        * records. Otherwise the frontend would have no
-                        * way to tell where stored data ends and live
-                        * measurements begin. */
-                       sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi,
-                                       devc->cb_data);
-               } else if (c == RECORD_DATA) {
-                       devc->buf_len = 0;
-                       devc->state = ST_GET_LOG_RECORD_DATA;
-               } else {
-                       /* RECORD_DBA/RECORD_DBC + 7 bytes of metadata */
-                       devc->buf[devc->buf_len++] = c;
-                       if (devc->buf_len < 8)
-                               /* Keep filling up the record header. */
-                               return;
-                       if (devc->buf[0] == RECORD_DBA)
-                               devc->cur_mqflags = SR_MQFLAG_SPL_FREQ_WEIGHT_A;
-                       else if (devc->buf[0] == RECORD_DBC)
-                               devc->cur_mqflags = SR_MQFLAG_SPL_FREQ_WEIGHT_C;
-                       else {
-                               /* Shouldn't happen. */
-                               sr_dbg("Unknown record token 0x%.2x", c);
-                               return;
-                       }
-                       packet.type = SR_DF_META;
-                       packet.payload = &meta;
-                       src = sr_config_new(SR_CONF_SAMPLE_INTERVAL,
-                                       g_variant_new_uint64(devc->buf[7] * 1000));
-                       meta.config = g_slist_append(NULL, src);
-                       sr_session_send(devc->cb_data, &packet);
-                       g_free(src);
-                       devc->buf_len = 0;
-               }
-       } else if (devc->state == ST_GET_LOG_RECORD_DATA) {
-               sr_dbg("log data: 0x%.2x", c);
-               if (c == RECORD_DBA || c == RECORD_DBC || c == RECORD_DATA || c == RECORD_END) {
-                       /* Work around off-by-one bug in device firmware. This
-                        * happens only on the last record, i.e. before RECORD_END */
-                       if (devc->buf_len & 1)
-                               devc->buf_len--;
-                       /* Done with this set of samples */
-                       send_data(sdi, devc->buf, devc->buf_len / 2);
-                       devc->buf_len = 0;
-
-                       /* Process this meta marker in the right state. */
-                       devc->state = ST_GET_LOG_RECORD_META;
-                       process_byte(sdi, c, handle_packets);
-               } else {
-                       devc->buf[devc->buf_len++] = c;
-                       if (devc->buf_len == SAMPLES_PER_PACKET * 2) {
-                               send_data(sdi, devc->buf, devc->buf_len / 2);
-                               devc->buf_len = 0;
-                       }
-               }
-       }
-
-}
-
-SR_PRIV int cem_dt_885x_receive_data(int fd, int revents, void *cb_data)
-{
-       const struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-       unsigned char c, cmd;
-
-       (void)fd;
-
-       if (!(sdi = cb_data))
-               return TRUE;
-
-       devc = sdi->priv;
-       serial = sdi->conn;
-       if (revents == G_IO_IN) {
-               if (serial_read(serial, &c, 1) != 1)
-                       return TRUE;
-               process_byte(sdi, c, TRUE);
-
-               if (devc->enable_data_source_memory) {
-                       if (devc->state == ST_GET_LOG_HEADER) {
-                               /* Memory transfer started. */
-                               devc->enable_data_source_memory = FALSE;
-                       } else {
-                               /* Tell device to start transferring from memory. */
-                               cmd = CMD_TRANSFER_MEMORY;
-                               serial_write(serial, &cmd, 1);
-                       }
-               }
-       }
-
-       return TRUE;
-}
-
-
-static int wait_for_token(const struct sr_dev_inst *sdi, int8_t *tokens, int timeout)
-{
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-       gint64 start_time;
-       int i;
-       unsigned char c;
-
-       serial = sdi->conn;
-       devc = sdi->priv;
-       devc->state = ST_INIT;
-       start_time = g_get_monotonic_time() / 1000;
-       while (TRUE) {
-               if (serial_read(serial, &c, 1) != 1)
-                       /* Device might have gone away. */
-                       return SR_ERR;
-               process_byte(sdi, c, FALSE);
-               if (devc->state != ST_INIT)
-                       /* Wait for a whole packet to get processed. */
-                       continue;
-               for (i = 0; tokens[i] != -1; i++) {
-                       if (devc->token == tokens[i]) {
-                               sr_spew("wait_for_token: got token 0x%.2x", devc->token);
-                               return SR_OK;
-                       }
-               }
-               if (timeout && g_get_monotonic_time() / 1000 - start_time > timeout)
-                       return SR_ERR_TIMEOUT;
-       }
-
-       return SR_OK;
-}
-
-/* cmd is the command to send, tokens are the tokens that denote the state
- * which the command affects. The first token is the desired state. */
-static int cem_dt_885x_toggle(const struct sr_dev_inst *sdi, uint8_t cmd,
-               int8_t *tokens, int timeout)
-{
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-
-       serial = sdi->conn;
-       devc = sdi->priv;
-
-       /* The device doesn't respond to commands very well. The
-        * only thing to do is wait for the token that will confirm
-        * whether the command worked or not, and resend if needed. */
-       while (TRUE) {
-               if (serial_write(serial, (const void *)&cmd, 1) != 1)
-                       return SR_ERR;
-               if (wait_for_token(sdi, tokens, timeout) == SR_ERR)
-                       return SR_ERR;
-               if (devc->token == tokens[0])
-                       /* It worked. */
-                       break;
-       }
-
-       return SR_OK;
-}
-
-SR_PRIV gboolean cem_dt_885x_recording_get(const struct sr_dev_inst *sdi,
-               int *state)
-{
-       struct dev_context *devc;
-       int8_t tokens[5];
-
-       devc = sdi->priv;
-       if (devc->recording == -1) {
-               /* Didn't pick up device state yet. */
-               tokens[0] = TOKEN_RECORDING_ON;
-               tokens[1] = TOKEN_RECORDING_OFF;
-               tokens[2] = -1;
-               if (wait_for_token(sdi, tokens, 510) != SR_OK)
-                       return SR_ERR;
-       }
-       *state = devc->token == TOKEN_RECORDING_ON;
-
-       return SR_OK;
-}
-
-SR_PRIV int cem_dt_885x_recording_set(const struct sr_dev_inst *sdi,
-               gboolean state)
-{
-       struct dev_context *devc;
-       int ret;
-       int8_t tokens[5];
-
-       devc = sdi->priv;
-
-       /* The toggle below needs the desired state in first position. */
-       if (state) {
-               tokens[0] = TOKEN_RECORDING_ON;
-               tokens[1] = TOKEN_RECORDING_OFF;
-       } else {
-               tokens[0] = TOKEN_RECORDING_OFF;
-               tokens[1] = TOKEN_RECORDING_ON;
-       }
-       tokens[2] = -1;
-
-       if (devc->recording == -1) {
-               /* Didn't pick up device state yet. */
-               if (wait_for_token(sdi, tokens, 0) != SR_OK)
-                       return SR_ERR;
-               if (devc->token == tokens[0])
-                       /* Nothing to do. */
-                       return SR_OK;
-       } else if (devc->recording == state)
-               /* Nothing to do. */
-               return SR_OK;
-
-       /* Recording state notifications are sent at 2Hz, so allow just over
-        * that, 510ms, for the state to come in. */
-       ret = cem_dt_885x_toggle(sdi, CMD_TOGGLE_RECORDING, tokens, 510);
-
-       return ret;
-}
-
-SR_PRIV int cem_dt_885x_weight_freq_get(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       int cur_setting;
-       int8_t tokens[5];
-
-       devc = sdi->priv;
-
-       cur_setting = devc->cur_mqflags & (SR_MQFLAG_SPL_FREQ_WEIGHT_A | SR_MQFLAG_SPL_FREQ_WEIGHT_C);
-       if (cur_setting == 0) {
-               /* Didn't pick up device state yet. */
-               tokens[0] = TOKEN_WEIGHT_FREQ_A;
-               tokens[1] = TOKEN_WEIGHT_FREQ_C;
-               tokens[2] = -1;
-               if (wait_for_token(sdi, tokens, 0) != SR_OK)
-                       return SR_ERR;
-               if (devc->token == TOKEN_WEIGHT_FREQ_A)
-                       return SR_MQFLAG_SPL_FREQ_WEIGHT_A;
-               else
-                       return SR_MQFLAG_SPL_FREQ_WEIGHT_C;
-       } else
-               return cur_setting;
-}
-
-SR_PRIV int cem_dt_885x_weight_freq_set(const struct sr_dev_inst *sdi, int freqw)
-{
-       struct dev_context *devc;
-       int cur_setting, ret;
-       int8_t tokens[5];
-
-       devc = sdi->priv;
-
-       cur_setting = devc->cur_mqflags & (SR_MQFLAG_SPL_FREQ_WEIGHT_A | SR_MQFLAG_SPL_FREQ_WEIGHT_C);
-       if (cur_setting == freqw)
-               /* Already set to this frequency weighting. */
-               return SR_OK;
-
-       /* The toggle below needs the desired state in first position. */
-       if (freqw == SR_MQFLAG_SPL_FREQ_WEIGHT_A) {
-               tokens[0] = TOKEN_WEIGHT_FREQ_A;
-               tokens[1] = TOKEN_WEIGHT_FREQ_C;
-       } else {
-               tokens[0] = TOKEN_WEIGHT_FREQ_C;
-               tokens[1] = TOKEN_WEIGHT_FREQ_A;
-       }
-       tokens[2] = -1;
-
-       if (cur_setting == 0) {
-               /* Didn't pick up device state yet. */
-               if (wait_for_token(sdi, tokens, 0) != SR_OK)
-                       return SR_ERR;
-               if (devc->token == tokens[0])
-                       /* Nothing to do. */
-                       return SR_OK;
-       }
-
-       /* 10ms timeout seems to work best for this. */
-       ret = cem_dt_885x_toggle(sdi, CMD_TOGGLE_WEIGHT_FREQ, tokens, 10);
-
-       return ret;
-}
-
-SR_PRIV int cem_dt_885x_weight_time_get(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       int cur_setting;
-       int8_t tokens[5];
-
-       devc = sdi->priv;
-
-       cur_setting = devc->cur_mqflags & (SR_MQFLAG_SPL_TIME_WEIGHT_F | SR_MQFLAG_SPL_TIME_WEIGHT_S);
-       if (cur_setting == 0) {
-               /* Didn't pick up device state yet. */
-               tokens[0] = TOKEN_WEIGHT_TIME_FAST;
-               tokens[1] = TOKEN_WEIGHT_TIME_SLOW;
-               tokens[2] = -1;
-               if (wait_for_token(sdi, tokens, 0) != SR_OK)
-                       return SR_ERR;
-               if (devc->token == TOKEN_WEIGHT_TIME_FAST)
-                       return SR_MQFLAG_SPL_TIME_WEIGHT_F;
-               else
-                       return SR_MQFLAG_SPL_TIME_WEIGHT_S;
-       } else
-               return cur_setting;
-}
-
-SR_PRIV int cem_dt_885x_weight_time_set(const struct sr_dev_inst *sdi, int timew)
-{
-       struct dev_context *devc;
-       int cur_setting, ret;
-       int8_t tokens[5];
-
-       devc = sdi->priv;
-
-       cur_setting = devc->cur_mqflags & (SR_MQFLAG_SPL_TIME_WEIGHT_F | SR_MQFLAG_SPL_TIME_WEIGHT_S);
-       if (cur_setting == timew)
-               /* Already set to this time weighting. */
-               return SR_OK;
-
-       /* The toggle below needs the desired state in first position. */
-       if (timew == SR_MQFLAG_SPL_TIME_WEIGHT_F) {
-               tokens[0] = TOKEN_WEIGHT_TIME_FAST;
-               tokens[1] = TOKEN_WEIGHT_TIME_SLOW;
-       } else {
-               tokens[0] = TOKEN_WEIGHT_TIME_SLOW;
-               tokens[1] = TOKEN_WEIGHT_TIME_FAST;
-       }
-       tokens[2] = -1;
-
-       if (cur_setting == 0) {
-               /* Didn't pick up device state yet. */
-               if (wait_for_token(sdi, tokens, 0) != SR_OK)
-                       return SR_ERR;
-               if (devc->token == tokens[0])
-                       /* Nothing to do. */
-                       return SR_OK;
-       }
-
-       /* 51ms timeout seems to work best for this. */
-       ret = cem_dt_885x_toggle(sdi, CMD_TOGGLE_WEIGHT_TIME, tokens, 51);
-
-       return ret;
-}
-
-SR_PRIV int cem_dt_885x_holdmode_get(const struct sr_dev_inst *sdi,
-               gboolean *holdmode)
-{
-       struct dev_context *devc;
-       int8_t tokens[5];
-
-       devc = sdi->priv;
-
-       if (devc->cur_mqflags == 0) {
-               tokens[0] = TOKEN_HOLD_MAX;
-               tokens[1] = TOKEN_HOLD_MIN;
-               tokens[2] = TOKEN_HOLD_NONE;
-               tokens[3] = -1;
-               if (wait_for_token(sdi, tokens, 0) != SR_OK)
-                       return SR_ERR;
-               if (devc->token == TOKEN_HOLD_MAX)
-                       devc->cur_mqflags = SR_MQFLAG_MAX;
-               else if (devc->token == TOKEN_HOLD_MIN)
-                       devc->cur_mqflags = SR_MQFLAG_MIN;
-       }
-       *holdmode = devc->cur_mqflags & (SR_MQFLAG_MAX | SR_MQFLAG_MIN);
-
-       return SR_OK;
-}
-
-SR_PRIV int cem_dt_885x_holdmode_set(const struct sr_dev_inst *sdi, int holdmode)
-{
-       struct dev_context *devc;
-       int cur_setting, ret;
-       int8_t tokens[5];
-
-       devc = sdi->priv;
-
-       /* The toggle below needs the desired state in first position. */
-       if (holdmode == SR_MQFLAG_MAX) {
-               tokens[0] = TOKEN_HOLD_MAX;
-               tokens[1] = TOKEN_HOLD_MIN;
-               tokens[2] = TOKEN_HOLD_NONE;
-       } else if (holdmode == SR_MQFLAG_MIN) {
-               tokens[0] = TOKEN_HOLD_MIN;
-               tokens[1] = TOKEN_HOLD_MAX;
-               tokens[2] = TOKEN_HOLD_NONE;
-       } else {
-               tokens[0] = TOKEN_HOLD_NONE;
-               tokens[1] = TOKEN_HOLD_MAX;
-               tokens[2] = TOKEN_HOLD_MIN;
-       }
-       tokens[3] = -1;
-
-       if (devc->cur_mqflags == 0) {
-               /* Didn't pick up device state yet. */
-               if (wait_for_token(sdi, tokens, 0) != SR_OK)
-                       return SR_ERR;
-               if (devc->token == tokens[0])
-                       /* Nothing to do. */
-                       return SR_OK;
-       } else {
-               cur_setting = devc->cur_mqflags & (SR_MQFLAG_MAX | SR_MQFLAG_MIN);
-               if (cur_setting == holdmode)
-                       /* Already set correctly. */
-                       return SR_OK;
-       }
-
-       /* 51ms timeout seems to work best for this. */
-       ret = cem_dt_885x_toggle(sdi, CMD_TOGGLE_HOLD_MAX_MIN, tokens, 51);
-
-       return ret;
-}
-
-SR_PRIV int cem_dt_885x_meas_range_get(const struct sr_dev_inst *sdi,
-               uint64_t *low, uint64_t *high)
-{
-       struct dev_context *devc;
-       int8_t tokens[5];
-
-       devc = sdi->priv;
-       if (devc->cur_meas_range == 0) {
-               tokens[0] = TOKEN_MEAS_RANGE_30_130;
-               tokens[1] = TOKEN_MEAS_RANGE_30_80;
-               tokens[2] = TOKEN_MEAS_RANGE_50_100;
-               tokens[3] = TOKEN_MEAS_RANGE_80_130;
-               tokens[4] = -1;
-               if (wait_for_token(sdi, tokens, 0) != SR_OK)
-                       return SR_ERR;
-               devc->cur_meas_range = devc->token;
-       }
-
-       switch (devc->cur_meas_range) {
-       case TOKEN_MEAS_RANGE_30_130:
-               *low = 30;
-               *high = 130;
-               break;
-       case TOKEN_MEAS_RANGE_30_80:
-               *low = 30;
-               *high = 80;
-               break;
-       case TOKEN_MEAS_RANGE_50_100:
-               *low = 50;
-               *high = 100;
-               break;
-       case TOKEN_MEAS_RANGE_80_130:
-               *low = 80;
-               *high = 130;
-               break;
-       default:
-               return SR_ERR;
-       }
-
-       return SR_OK;
-}
-
-SR_PRIV int cem_dt_885x_meas_range_set(const struct sr_dev_inst *sdi,
-               uint64_t low, uint64_t high)
-{
-       struct dev_context *devc;
-       int ret;
-       int8_t token, tokens[6];
-
-       devc = sdi->priv;
-       if (low == 30 && high == 130)
-               token = TOKEN_MEAS_RANGE_30_130;
-       else if (low == 30 &&  high == 80)
-               token = TOKEN_MEAS_RANGE_30_80;
-       else if (low == 50 &&  high == 100)
-               token = TOKEN_MEAS_RANGE_50_100;
-       else if (low == 80 &&  high == 130)
-               token = TOKEN_MEAS_RANGE_80_130;
-       else
-               return SR_ERR;
-
-       sr_dbg("want 0x%.2x", token);
-       /* The toggle below needs the desired state in first position. */
-       tokens[0] = token;
-       tokens[1] = TOKEN_MEAS_RANGE_30_130;
-       tokens[2] = TOKEN_MEAS_RANGE_30_80;
-       tokens[3] = TOKEN_MEAS_RANGE_50_100;
-       tokens[4] = TOKEN_MEAS_RANGE_80_130;
-       tokens[5] = -1;
-
-       if (devc->cur_meas_range == 0) {
-               /* 110ms should be enough for two of these announcements */
-               if (wait_for_token(sdi, tokens, 110) != SR_OK)
-                       return SR_ERR;
-               devc->cur_meas_range = devc->token;
-       }
-
-       if (devc->cur_meas_range == token)
-               /* Already set to this range. */
-               return SR_OK;
-
-       /* For measurement range, it works best to ignore announcements of the
-        * current setting and keep resending the toggle quickly. */
-       tokens[1] = -1;
-       ret = cem_dt_885x_toggle(sdi, CMD_TOGGLE_MEAS_RANGE, tokens, 11);
-
-       return ret;
-}
-
-SR_PRIV int cem_dt_885x_power_off(const struct sr_dev_inst *sdi)
-{
-       struct sr_serial_dev_inst *serial;
-       char c, cmd;
-
-       serial = sdi->conn;
-
-       /* Reopen the port in non-blocking mode, so we can properly
-        * detect when the device stops communicating. */
-       serial_close(serial);
-       if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
-               return SR_ERR;
-
-       cmd = CMD_TOGGLE_POWER_OFF;
-       while (TRUE) {
-               serial_flush(serial);
-               if (serial_write(serial, (const void *)&cmd, 1) != 1)
-                       return SR_ERR;
-               /* It never takes more than 23ms for the next token to arrive. */
-               g_usleep(25 * 1000);
-               if (serial_read(serial, &c, 1) != 1)
-                       /* Device is no longer responding. Good! */
-                       break;
-       }
-
-       /* In case the user manually turns on the device again, reset
-        * the port back to blocking. */
-       serial_close(serial);
-       serial_open(serial, SERIAL_RDWR);
-
-       return SR_OK;
-}
diff --git a/hardware/cem-dt-885x/protocol.h b/hardware/cem-dt-885x/protocol.h
deleted file mode 100644 (file)
index 233ef86..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Bert Vermeulen <bert@biot.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_CEM_DT_885X_PROTOCOL_H
-#define LIBSIGROK_HARDWARE_CEM_DT_885X_PROTOCOL_H
-
-#include <stdint.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "cem-dt-885x"
-
-/* When retrieving samples from device memory, group this many
- * together into a sigrok packet. */
-#define SAMPLES_PER_PACKET 50
-
-/* Various temporary storage, at least 8 bytes. */
-#define BUF_SIZE SAMPLES_PER_PACKET * 2
-
-/* When in hold mode, force the last measurement out at this interval.
- * We're using 50ms, which duplicates the non-hold 20Hz update rate. */
-#define HOLD_REPEAT_INTERVAL 50 * 1000
-
-enum {
-       TOKEN_WEIGHT_TIME_FAST = 0x02,
-       TOKEN_WEIGHT_TIME_SLOW = 0x03,
-       TOKEN_HOLD_MAX = 0x04,
-       TOKEN_HOLD_MIN = 0x05,
-       TOKEN_TIME = 0x06,
-       TOKEN_MEAS_RANGE_OVER = 0x07,
-       TOKEN_MEAS_RANGE_UNDER = 0x08,
-       TOKEN_STORE_FULL = 0x09,
-       TOKEN_RECORDING_ON = 0x0a,
-       TOKEN_MEAS_WAS_READOUT = 0x0b,
-       TOKEN_MEAS_WAS_BARGRAPH = 0x0c,
-       TOKEN_MEASUREMENT = 0xd,
-       TOKEN_HOLD_NONE = 0x0e,
-       TOKEN_BATTERY_LOW = 0x0f,
-       TOKEN_MEAS_RANGE_OK = 0x11,
-       TOKEN_STORE_OK = 0x19,
-       TOKEN_RECORDING_OFF = 0x1a,
-       TOKEN_WEIGHT_FREQ_A = 0x1b,
-       TOKEN_WEIGHT_FREQ_C = 0x1c,
-       TOKEN_BATTERY_OK = 0x1f,
-       TOKEN_MEAS_RANGE_30_80 = 0x30,
-       TOKEN_MEAS_RANGE_30_130 = 0x40,
-       TOKEN_MEAS_RANGE_50_100 = 0x4b,
-       TOKEN_MEAS_RANGE_80_130 = 0x4c,
-};
-
-enum {
-       CMD_TOGGLE_RECORDING = 0x55,
-       CMD_TOGGLE_WEIGHT_FREQ = 0x99,
-       CMD_TOGGLE_WEIGHT_TIME = 0x77,
-       CMD_TOGGLE_HOLD_MAX_MIN = 0x11,
-       CMD_TOGGLE_MEAS_RANGE = 0x88,
-       CMD_TOGGLE_POWER_OFF = 0x33,
-       CMD_TRANSFER_MEMORY = 0xac,
-};
-
-enum {
-       RECORD_DBA = 0xaa,
-       RECORD_DBC = 0xcc,
-       RECORD_DATA = 0xac,
-       RECORD_END = 0xdd,
-};
-
-enum {
-       DATA_SOURCE_LIVE,
-       DATA_SOURCE_MEMORY,
-};
-
-/** Private, per-device-instance driver context. */
-struct dev_context {
-       /* Device state */
-       uint64_t cur_mqflags;
-       int recording;
-       int cur_meas_range;
-       int cur_data_source;
-
-       /* Acquisition settings */
-       uint64_t limit_samples;
-
-       /* Operational state */
-       int state;
-       uint64_t num_samples;
-       gboolean enable_data_source_memory;
-
-       /* Temporary state across callbacks */
-       void *cb_data;
-       unsigned char cmd;
-       unsigned char token;
-       int buf_len;
-       unsigned char buf[BUF_SIZE];
-       float last_spl;
-       gint64 hold_last_sent;
-};
-
-/* Parser state machine. */
-enum {
-       ST_INIT,
-       ST_GET_TOKEN,
-       ST_GET_DATA,
-       ST_GET_LOG_HEADER,
-       ST_GET_LOG_RECORD_META,
-       ST_GET_LOG_RECORD_DATA,
-};
-
-SR_PRIV int cem_dt_885x_receive_data(int fd, int revents, void *cb_data);
-SR_PRIV int cem_dt_885x_recording_set(const struct sr_dev_inst *sdi, gboolean start);
-SR_PRIV gboolean cem_dt_885x_recording_get(const struct sr_dev_inst *sdi,
-               int *state);
-SR_PRIV int cem_dt_885x_weight_freq_get(const struct sr_dev_inst *sdi);
-SR_PRIV int cem_dt_885x_weight_freq_set(const struct sr_dev_inst *sdi, int freqw);
-SR_PRIV int cem_dt_885x_weight_time_get(const struct sr_dev_inst *sdi);
-SR_PRIV int cem_dt_885x_weight_time_set(const struct sr_dev_inst *sdi, int timew);
-SR_PRIV int cem_dt_885x_holdmode_get(const struct sr_dev_inst *sdi,
-               gboolean *holdmode);
-SR_PRIV int cem_dt_885x_holdmode_set(const struct sr_dev_inst *sdi, int holdmode);
-SR_PRIV int cem_dt_885x_meas_range_get(const struct sr_dev_inst *sdi,
-               uint64_t *low, uint64_t *high);
-SR_PRIV int cem_dt_885x_meas_range_set(const struct sr_dev_inst *sdi,
-               uint64_t low, uint64_t high);
-SR_PRIV int cem_dt_885x_power_off(const struct sr_dev_inst *sdi);
-
-#endif
diff --git a/hardware/center-3xx/api.c b/hardware/center-3xx/api.c
deleted file mode 100644 (file)
index 3f39b19..0000000
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include "protocol.h"
-
-static const int32_t hwopts[] = {
-       SR_CONF_CONN,
-       SR_CONF_SERIALCOMM,
-};
-
-static const int32_t hwcaps[] = {
-       SR_CONF_THERMOMETER,
-       SR_CONF_LIMIT_SAMPLES,
-       SR_CONF_LIMIT_MSEC,
-       SR_CONF_CONTINUOUS,
-};
-
-static const char *channel_names[] = {
-       "T1", "T2", "T3", "T4",
-       NULL,
-};
-
-SR_PRIV struct sr_dev_driver center_309_driver_info;
-SR_PRIV struct sr_dev_driver voltcraft_k204_driver_info;
-
-SR_PRIV const struct center_dev_info center_devs[] = {
-       {
-               "Center", "309", "9600/8n1", 4, 32000, 45,
-               center_3xx_packet_valid,
-               &center_309_driver_info, receive_data_CENTER_309,
-       },
-       {
-               "Voltcraft", "K204", "9600/8n1", 4, 32000, 45,
-               center_3xx_packet_valid,
-               &voltcraft_k204_driver_info, receive_data_VOLTCRAFT_K204,
-       },
-};
-
-static int dev_clear(int idx)
-{
-       return std_dev_clear(center_devs[idx].di, NULL);
-}
-
-static int init(struct sr_context *sr_ctx, int idx)
-{
-       sr_dbg("Selected '%s' subdriver.", center_devs[idx].di->name);
-
-       return std_init(sr_ctx, center_devs[idx].di, LOG_PREFIX);
-}
-
-static GSList *center_scan(const char *conn, const char *serialcomm, int idx)
-{
-       int i;
-       struct sr_dev_inst *sdi;
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       struct sr_channel *ch;
-       struct sr_serial_dev_inst *serial;
-       GSList *devices;
-
-       if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
-               return NULL;
-
-       if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
-               return NULL;
-
-       drvc = center_devs[idx].di->priv;
-       devices = NULL;
-       serial_flush(serial);
-
-       sr_info("Found device on port %s.", conn);
-
-       if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, center_devs[idx].vendor,
-                                   center_devs[idx].device, NULL)))
-               goto scan_cleanup;
-
-       if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
-               sr_err("Device context malloc failed.");
-               goto scan_cleanup;
-       }
-
-       sdi->inst_type = SR_INST_SERIAL;
-       sdi->conn = serial;
-
-       sdi->priv = devc;
-       sdi->driver = center_devs[idx].di;
-
-       for (i = 0; i <  center_devs[idx].num_channels; i++) {
-               if (!(ch = sr_channel_new(i, SR_CHANNEL_ANALOG,
-                                          TRUE, channel_names[i])))
-                       goto scan_cleanup;
-               sdi->channels = g_slist_append(sdi->channels, ch);
-       }
-
-       drvc->instances = g_slist_append(drvc->instances, sdi);
-       devices = g_slist_append(devices, sdi);
-
-scan_cleanup:
-       serial_close(serial);
-
-       return devices;
-}
-
-static GSList *scan(GSList *options, int idx)
-{
-       struct sr_config *src;
-       GSList *l, *devices;
-       const char *conn, *serialcomm;
-
-       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 = center_scan(conn, serialcomm, idx);
-       } else {
-               /* Try the default. */
-               devices = center_scan(conn, center_devs[idx].conn, idx);
-       }
-
-       return devices;
-}
-
-static GSList *dev_list(int idx)
-{
-       return ((struct drv_context *)(center_devs[idx].di->priv))->instances;
-}
-
-static int cleanup(int idx)
-{
-       return dev_clear(idx);
-}
-
-static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-
-       (void)cg;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       devc = sdi->priv;
-
-       switch (id) {
-       case SR_CONF_LIMIT_SAMPLES:
-               if (g_variant_get_uint64(data) == 0)
-                       return SR_ERR_ARG;
-               devc->limit_samples = g_variant_get_uint64(data);
-               break;
-       case SR_CONF_LIMIT_MSEC:
-               if (g_variant_get_uint64(data) == 0)
-                       return SR_ERR_ARG;
-               devc->limit_msec = g_variant_get_uint64(data);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_list(int 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_INT32,
-                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
-               break;
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi,
-                                   void *cb_data, int idx)
-{
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       devc = sdi->priv;
-       devc->cb_data = cb_data;
-       devc->num_samples = 0;
-       devc->starttime = g_get_monotonic_time();
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(cb_data, LOG_PREFIX);
-
-       /* Poll every 500ms, or whenever some data comes in. */
-       serial = sdi->conn;
-       serial_source_add(sdi->session, serial, G_IO_IN, 500,
-                     center_devs[idx].receive_data, (void *)sdi);
-
-       return SR_OK;
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       return std_serial_dev_acquisition_stop(sdi, cb_data,
-                       std_serial_dev_close, sdi->conn, LOG_PREFIX);
-}
-
-/* Driver-specific API function wrappers */
-#define HW_INIT(X) \
-static int init_##X(struct sr_context *sr_ctx) { return init(sr_ctx, X); }
-#define HW_CLEANUP(X) \
-static int cleanup_##X(void) { return cleanup(X); }
-#define HW_SCAN(X) \
-static GSList *scan_##X(GSList *options) { return scan(options, X); }
-#define HW_DEV_LIST(X) \
-static GSList *dev_list_##X(void) { return dev_list(X); }
-#define HW_DEV_CLEAR(X) \
-static int dev_clear_##X(void) { return dev_clear(X); }
-#define HW_DEV_ACQUISITION_START(X) \
-static int dev_acquisition_start_##X(const struct sr_dev_inst *sdi, \
-void *cb_data) { return dev_acquisition_start(sdi, cb_data, X); }
-
-/* Driver structs and API function wrappers */
-#define DRV(ID, ID_UPPER, NAME, LONGNAME) \
-HW_INIT(ID_UPPER) \
-HW_CLEANUP(ID_UPPER) \
-HW_SCAN(ID_UPPER) \
-HW_DEV_LIST(ID_UPPER) \
-HW_DEV_CLEAR(ID_UPPER) \
-HW_DEV_ACQUISITION_START(ID_UPPER) \
-SR_PRIV struct sr_dev_driver ID##_driver_info = { \
-       .name = NAME, \
-       .longname = LONGNAME, \
-       .api_version = 1, \
-       .init = init_##ID_UPPER, \
-       .cleanup = cleanup_##ID_UPPER, \
-       .scan = scan_##ID_UPPER, \
-       .dev_list = dev_list_##ID_UPPER, \
-       .dev_clear = dev_clear_##ID_UPPER, \
-       .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_##ID_UPPER, \
-       .dev_acquisition_stop = dev_acquisition_stop, \
-       .priv = NULL, \
-};
-
-DRV(center_309, CENTER_309, "center-309", "Center 309")
-DRV(voltcraft_k204, VOLTCRAFT_K204, "voltcraft-k204", "Voltcraft K204")
diff --git a/hardware/center-3xx/protocol.c b/hardware/center-3xx/protocol.c
deleted file mode 100644 (file)
index ef8b9dc..0000000
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include "protocol.h"
-
-struct center_info {
-       float temp[4];
-       gboolean rec, std, max, min, maxmin, t1t2, rel, hold, lowbat, celsius;
-       gboolean memfull, autooff;
-       gboolean mode_std, mode_rel, mode_max, mode_min, mode_maxmin;
-};
-
-static int center_send(struct sr_serial_dev_inst *serial, const char *cmd)
-{
-       int ret;
-
-       if ((ret = serial_write(serial, cmd, strlen(cmd))) < 0) {
-               sr_err("Error sending '%s' command: %d.", cmd, ret);
-               return SR_ERR;
-       }
-
-       return SR_OK;
-}
-
-SR_PRIV gboolean center_3xx_packet_valid(const uint8_t *buf)
-{
-       return (buf[0] == 0x02 && buf[44] == 0x03);
-}
-
-static void log_packet(const uint8_t *buf, int idx)
-{
-       int i;
-       GString *s;
-
-       s = g_string_sized_new(100);
-       g_string_printf(s, "Packet: ");
-       for (i = 0; i < center_devs[idx].packet_size; i++)
-               g_string_append_printf(s, "%02x ", buf[i]);
-       sr_spew("%s", s->str);
-       g_string_free(s, TRUE);
-}
-
-static int packet_parse(const uint8_t *buf, int idx, struct center_info *info)
-{
-       int i;
-       uint16_t temp_u16;
-
-       log_packet(buf, idx);
-
-       /* Byte 0: Always 0x02. */
-
-       /* Byte 1: Various status bits. */
-       info->rec         = (buf[1] & (1 << 0)) != 0;
-       info->mode_std    = (((buf[1] >> 1) & 0x3) == 0);
-       info->mode_max    = (((buf[1] >> 1) & 0x3) == 1);
-       info->mode_min    = (((buf[1] >> 1) & 0x3) == 2);
-       info->mode_maxmin = (((buf[1] >> 1) & 0x3) == 3);
-       /* TODO: Rel. Not available on all models. */
-       info->t1t2        = (buf[1] & (1 << 3)) != 0;
-       info->rel         = (buf[1] & (1 << 4)) != 0;
-       info->hold        = (buf[1] & (1 << 5)) != 0;
-       info->lowbat      = (buf[1] & (1 << 6)) != 0;
-       info->celsius     = (buf[1] & (1 << 7)) != 0;
-
-       /* Byte 2: Further status bits. */
-       info->memfull     = (buf[2] & (1 << 0)) != 0;
-       info->autooff     = (buf[2] & (1 << 7)) != 0;
-
-       /* Byte 7+8/9+10/11+12/13+14: channel T1/T2/T3/T4 temperature. */
-       for (i = 0; i < 4; i++) {
-               temp_u16 = buf[8 + (i * 2)];
-               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. */
-       for (i = 0; i < 4; i++) {
-               /* Bit = 0: Divide by 10. Bit = 1: Don't divide by 10. */
-               if ((buf[43] & (1 << i)) == 0)
-                       info->temp[i] /= 10;
-       }
-
-       /* Bytes 39-42: Overflow/overlimit bits, depending on mode. */
-       for (i = 0; i < 4; i++) {
-               if (info->mode_std && ((buf[39] & (1 << i)) != 0))
-                       info->temp[i] = INFINITY;
-               /* TODO: Rel. Not available on all models. */
-               // if (info->mode_rel && ((buf[40] & (1 << i)) != 0))
-               //      info->temp[i] = INFINITY;
-               if (info->mode_max && ((buf[41] & (1 << i)) != 0))
-                       info->temp[i] = INFINITY;
-               if (info->mode_min && ((buf[42] & (1 << i)) != 0))
-                       info->temp[i] = INFINITY;
-               /* TODO: Minmax? */
-       }
-
-       /* Byte 44: Always 0x03. */
-
-       return SR_OK;
-}
-
-static int handle_packet(const uint8_t *buf, struct sr_dev_inst *sdi, int idx)
-{
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_analog analog;
-       struct dev_context *devc;
-       struct center_info info;
-       GSList *l;
-       int i, ret;
-
-       devc = sdi->priv;
-
-       memset(&analog, 0, sizeof(struct sr_datafeed_analog));
-       memset(&info, 0, sizeof(struct center_info));
-
-       ret = packet_parse(buf, idx, &info);
-       if (ret < 0) {
-               sr_err("Failed to parse packet.");
-               return SR_ERR;
-       }
-
-       /* Common values for all 4 channels. */
-       packet.type = SR_DF_ANALOG;
-       packet.payload = &analog;
-       analog.mq = SR_MQ_TEMPERATURE;
-       analog.unit = (info.celsius) ? SR_UNIT_CELSIUS : SR_UNIT_FAHRENHEIT;
-       analog.num_samples = 1;
-
-       /* Send the values for T1 - T4. */
-       for (i = 0; i < 4; i++) {
-               l = NULL;
-               l = g_slist_append(l, g_slist_nth_data(sdi->channels, i));
-               analog.channels = l;
-               analog.data = &(info.temp[i]);
-               sr_session_send(devc->cb_data, &packet);
-               g_slist_free(l);
-       }
-
-       devc->num_samples++;
-
-       return SR_OK;
-}
-
-/* Return TRUE if a full packet was parsed, FALSE otherwise. */
-static gboolean handle_new_data(struct sr_dev_inst *sdi, int idx)
-{
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-       int len, i, offset = 0, ret = FALSE;
-
-       devc = sdi->priv;
-       serial = sdi->conn;
-
-       /* Try to get as much data as the buffer can hold. */
-       len = SERIAL_BUFSIZE - devc->buflen;
-       len = serial_read(serial, devc->buf + devc->buflen, len);
-       if (len < 1) {
-               sr_err("Serial port read error: %d.", len);
-               return FALSE;
-       }
-
-       devc->buflen += len;
-
-       /* Now look for packets in that data. */
-       while ((devc->buflen - offset) >= center_devs[idx].packet_size) {
-               if (center_devs[idx].packet_valid(devc->buf + offset)) {
-                       handle_packet(devc->buf + offset, sdi, idx);
-                       offset += center_devs[idx].packet_size;
-                       ret = TRUE;
-               } else {
-                       offset++;
-               }
-       }
-
-       /* If we have any data left, move it to the beginning of our buffer. */
-       for (i = 0; i < devc->buflen - offset; i++)
-               devc->buf[i] = devc->buf[offset + i];
-       devc->buflen -= offset;
-
-       return ret;
-}
-
-static int receive_data(int fd, int revents, int idx, void *cb_data)
-{
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-       int64_t t;
-       static gboolean request_new_packet = TRUE;
-       struct sr_serial_dev_inst *serial;
-
-       (void)fd;
-
-       if (!(sdi = cb_data))
-               return TRUE;
-
-       if (!(devc = sdi->priv))
-               return TRUE;
-
-       serial = sdi->conn;
-
-       if (revents == G_IO_IN) {
-               /* New data arrived. */
-               request_new_packet = handle_new_data(sdi, idx);
-       } else {
-               /*
-                * Timeout. Send "A" to request a packet, but then don't send
-                * further "A" commands until we received a full packet first.
-                */
-               if (request_new_packet) {
-                       center_send(serial, "A");
-                       request_new_packet = FALSE;
-               }
-       }
-
-       if (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
-               sr_info("Requested number of samples reached.");
-               sdi->driver->dev_acquisition_stop(sdi, cb_data);
-               return TRUE;
-       }
-
-       if (devc->limit_msec) {
-               t = (g_get_monotonic_time() - devc->starttime) / 1000;
-               if (t > (int64_t)devc->limit_msec) {
-                       sr_info("Requested time limit reached.");
-                       sdi->driver->dev_acquisition_stop(sdi, cb_data);
-                       return TRUE;
-               }
-       }
-
-       return TRUE;
-}
-
-#define RECEIVE_DATA(ID_UPPER) \
-SR_PRIV int receive_data_##ID_UPPER(int fd, int revents, void *cb_data) { \
-       return receive_data(fd, revents, ID_UPPER, cb_data); }
-
-/* Driver-specific receive_data() wrappers */
-RECEIVE_DATA(CENTER_309)
-RECEIVE_DATA(VOLTCRAFT_K204)
diff --git a/hardware/center-3xx/protocol.h b/hardware/center-3xx/protocol.h
deleted file mode 100644 (file)
index 71e2630..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#ifndef LIBSIGROK_HARDWARE_CENTER_3XX_PROTOCOL_H
-#define LIBSIGROK_HARDWARE_CENTER_3XX_PROTOCOL_H
-
-#include <stdint.h>
-#include <string.h>
-#include <ctype.h>
-#include <math.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "center-3xx"
-
-/* Note: When adding entries here, don't forget to update CENTER_DEV_COUNT. */
-enum {
-       CENTER_309,
-       VOLTCRAFT_K204,
-};
-
-#define CENTER_DEV_COUNT 2
-
-struct center_dev_info {
-       char *vendor;
-       char *device;
-       char *conn;
-       int num_channels;
-       uint32_t max_sample_points;
-       uint8_t packet_size;
-       gboolean (*packet_valid)(const uint8_t *);
-       struct sr_dev_driver *di;
-       int (*receive_data)(int, int, void *);
-};
-
-extern SR_PRIV const struct center_dev_info center_devs[CENTER_DEV_COUNT];
-
-#define SERIAL_BUFSIZE 256
-
-/** Private, per-device-instance driver context. */
-struct dev_context {
-       /** The current sampling limit (in number of samples). */
-       uint64_t limit_samples;
-
-       /** The current sampling limit (in ms). */
-       uint64_t limit_msec;
-
-       /** Opaque pointer passed in by the frontend. */
-       void *cb_data;
-
-       /** The current number of already received samples. */
-       uint64_t num_samples;
-
-       int64_t starttime;
-
-       uint8_t buf[SERIAL_BUFSIZE];
-       int bufoffset;
-       int buflen;
-};
-
-SR_PRIV gboolean center_3xx_packet_valid(const uint8_t *buf);
-
-SR_PRIV int receive_data_CENTER_309(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_VOLTCRAFT_K204(int fd, int revents, void *cb_data);
-
-#endif
diff --git a/hardware/chronovu-la/api.c b/hardware/chronovu-la/api.c
deleted file mode 100644 (file)
index 5a8a3d3..0000000
+++ /dev/null
@@ -1,558 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2011-2014 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include "protocol.h"
-
-SR_PRIV struct sr_dev_driver chronovu_la_driver_info;
-static struct sr_dev_driver *di = &chronovu_la_driver_info;
-
-static const int32_t hwcaps[] = {
-       SR_CONF_LOGIC_ANALYZER,
-       SR_CONF_SAMPLERATE,
-       SR_CONF_TRIGGER_MATCH,
-       SR_CONF_LIMIT_MSEC, /* TODO: Not yet implemented. */
-       SR_CONF_LIMIT_SAMPLES, /* TODO: Not yet implemented. */
-};
-
-static const int32_t trigger_matches[] = {
-       SR_TRIGGER_ZERO,
-       SR_TRIGGER_ONE,
-       SR_TRIGGER_RISING,
-       SR_TRIGGER_FALLING,
-};
-
-/* The ChronoVu LA8/LA16 can have multiple VID/PID pairs. */
-static struct {
-       uint16_t vid;
-       uint16_t pid;
-       int model;
-       const char *iproduct;
-} vid_pid[] = {
-       { 0x0403, 0x6001, CHRONOVU_LA8,  "ChronoVu LA8"  },
-       { 0x0403, 0x8867, CHRONOVU_LA8,  "ChronoVu LA8"  },
-       { 0x0403, 0x6001, CHRONOVU_LA16, "ChronoVu LA16" },
-       { 0x0403, 0x8867, CHRONOVU_LA16, "ChronoVu LA16" },
-};
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data);
-
-static void clear_helper(void *priv)
-{
-       struct dev_context *devc;
-
-       devc = priv;
-
-       ftdi_free(devc->ftdic);
-       g_free(devc->final_buf);
-}
-
-static int dev_clear(void)
-{
-       return std_dev_clear(di, clear_helper);
-}
-
-static int init(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, di, LOG_PREFIX);
-}
-
-static int add_device(int idx, int model, GSList **devices)
-{
-       int ret;
-       unsigned int i;
-       struct sr_dev_inst *sdi;
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       struct sr_channel *ch;
-
-       ret = SR_OK;
-
-       drvc = di->priv;
-
-       /* Allocate memory for our private device context. */
-       devc = g_try_malloc(sizeof(struct dev_context));
-
-       /* Set some sane defaults. */
-       devc->prof = &cv_profiles[model];
-       devc->ftdic = NULL; /* Will be set in the open() API call. */
-       devc->cur_samplerate = 0; /* Set later (different for LA8/LA16). */
-       devc->limit_msec = 0;
-       devc->limit_samples = 0;
-       devc->cb_data = NULL;
-       memset(devc->mangled_buf, 0, BS);
-       devc->final_buf = NULL;
-       devc->trigger_pattern = 0x0000; /* Irrelevant, see trigger_mask. */
-       devc->trigger_mask = 0x0000; /* All channels: "don't care". */
-       devc->trigger_edgemask = 0x0000; /* All channels: "state triggered". */
-       devc->trigger_found = 0;
-       devc->done = 0;
-       devc->block_counter = 0;
-       devc->divcount = 0;
-       devc->usb_vid = vid_pid[idx].vid;
-       devc->usb_pid = vid_pid[idx].pid;
-       memset(devc->samplerates, 0, sizeof(uint64_t) * 255);
-
-       /* Allocate memory where we'll store the de-mangled data. */
-       if (!(devc->final_buf = g_try_malloc(SDRAM_SIZE))) {
-               sr_err("Failed to allocate memory for sample buffer.");
-               ret = SR_ERR_MALLOC;
-               goto err_free_devc;
-       }
-
-       /* We now know the device, set its max. samplerate as default. */
-       devc->cur_samplerate = devc->prof->max_samplerate;
-
-       /* Register the device with libsigrok. */
-       sdi = sr_dev_inst_new(0, SR_ST_INITIALIZING,
-                             "ChronoVu", devc->prof->modelname, NULL);
-       if (!sdi) {
-               sr_err("Failed to create device instance.");
-               ret = SR_ERR;
-               goto err_free_final_buf;
-       }
-       sdi->driver = di;
-       sdi->priv = devc;
-
-       for (i = 0; i < devc->prof->num_channels; i++) {
-               if (!(ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE,
-                                         cv_channel_names[i]))) {
-                       ret = SR_ERR;
-                       goto err_free_dev_inst;
-               }
-               sdi->channels = g_slist_append(sdi->channels, ch);
-       }
-
-       *devices = g_slist_append(*devices, sdi);
-       drvc->instances = g_slist_append(drvc->instances, sdi);
-
-       return SR_OK;
-
-err_free_dev_inst:
-       sr_dev_inst_free(sdi);
-err_free_final_buf:
-       g_free(devc->final_buf);
-err_free_devc:
-       g_free(devc);
-
-       return ret;
-}
-
-static GSList *scan(GSList *options)
-{
-       int ret;
-       unsigned int i;
-       GSList *devices;
-       struct ftdi_context *ftdic;
-
-       (void)options;
-
-       devices = NULL;
-
-       /* Allocate memory for the FTDI context and initialize it. */
-       if (!(ftdic = ftdi_new())) {
-               sr_err("Failed to initialize libftdi.");
-               return NULL;
-       }
-
-       /* Check for LA8 and/or LA16 devices with various VID/PIDs. */
-       for (i = 0; i < ARRAY_SIZE(vid_pid); i++) {
-               ret = ftdi_usb_open_desc(ftdic, vid_pid[i].vid,
-                       vid_pid[i].pid, vid_pid[i].iproduct, NULL);
-               /* Show errors other than "device not found". */
-               if (ret < 0 && ret != -3)
-                       sr_dbg("Error finding/opening device (%d): %s.",
-                              ret, ftdi_get_error_string(ftdic));
-               if (ret < 0)
-                       continue; /* No device found, or not usable. */
-
-               sr_dbg("Found %s device (%04x:%04x).",
-                      vid_pid[i].iproduct, vid_pid[i].vid, vid_pid[i].pid);
-
-               if ((ret = add_device(i, vid_pid[i].model, &devices)) < 0)
-                       sr_dbg("Failed to add device: %d.", ret);
-
-               if ((ret = ftdi_usb_close(ftdic)) < 0)
-                       sr_dbg("Failed to close FTDI device (%d): %s.",
-                              ret, ftdi_get_error_string(ftdic));
-       }
-
-       /* Close USB device, deinitialize and free the FTDI context. */
-       ftdi_free(ftdic);
-       ftdic = NULL;
-
-       return devices;
-}
-
-static GSList *dev_list(void)
-{
-       return ((struct drv_context *)(di->priv))->instances;
-}
-
-static int dev_open(struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       int ret;
-
-       ret = SR_ERR;
-
-       if (!(devc = sdi->priv))
-               return SR_ERR_BUG;
-
-       /* Allocate memory for the FTDI context and initialize it. */
-       if (!(devc->ftdic = ftdi_new())) {
-               sr_err("Failed to initialize libftdi.");
-               return SR_ERR;
-       }
-
-       sr_dbg("Opening %s device (%04x:%04x).", devc->prof->modelname,
-              devc->usb_vid, devc->usb_pid);
-
-       /* Open the device. */
-       if ((ret = ftdi_usb_open_desc(devc->ftdic, devc->usb_vid,
-                       devc->usb_pid, devc->prof->iproduct, NULL)) < 0) {
-               sr_err("Failed to open FTDI device (%d): %s.",
-                      ret, ftdi_get_error_string(devc->ftdic));
-               goto err_ftdi_free;
-       }
-       sr_dbg("Device opened successfully.");
-
-       /* Purge RX/TX buffers in the FTDI chip. */
-       if ((ret = ftdi_usb_purge_buffers(devc->ftdic)) < 0) {
-               sr_err("Failed to purge FTDI buffers (%d): %s.",
-                      ret, ftdi_get_error_string(devc->ftdic));
-               goto err_ftdi_free;
-       }
-       sr_dbg("FTDI buffers purged successfully.");
-
-       /* Enable flow control in the FTDI chip. */
-       if ((ret = ftdi_setflowctrl(devc->ftdic, SIO_RTS_CTS_HS)) < 0) {
-               sr_err("Failed to enable FTDI flow control (%d): %s.",
-                      ret, ftdi_get_error_string(devc->ftdic));
-               goto err_ftdi_free;
-       }
-       sr_dbg("FTDI flow control enabled successfully.");
-
-       /* Wait 100ms. */
-       g_usleep(100 * 1000);
-
-       sdi->status = SR_ST_ACTIVE;
-
-       return SR_OK;
-
-err_ftdi_free:
-       ftdi_free(devc->ftdic); /* Close device (if open), free FTDI context. */
-       devc->ftdic = NULL;
-       return ret;
-}
-
-static int dev_close(struct sr_dev_inst *sdi)
-{
-       int ret;
-       struct dev_context *devc;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_OK;
-
-       devc = sdi->priv;
-
-       if (devc->ftdic && (ret = ftdi_usb_close(devc->ftdic)) < 0)
-               sr_err("Failed to close FTDI device (%d): %s.",
-                      ret, ftdi_get_error_string(devc->ftdic));
-       sdi->status = SR_ST_INACTIVE;
-
-       return SR_OK;
-}
-
-static int cleanup(void)
-{
-       return dev_clear();
-}
-
-static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-
-       (void)cg;
-
-       switch (id) {
-       case SR_CONF_SAMPLERATE:
-               if (!sdi || !(devc = sdi->priv))
-                       return SR_ERR_BUG;
-               *data = g_variant_new_uint64(devc->cur_samplerate);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_set(int id, 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;
-
-       if (!(devc = sdi->priv))
-               return SR_ERR_BUG;
-
-       switch (id) {
-       case SR_CONF_SAMPLERATE:
-               if (cv_set_samplerate(sdi, g_variant_get_uint64(data)) < 0)
-                       return SR_ERR;
-               break;
-       case SR_CONF_LIMIT_MSEC:
-               if (g_variant_get_uint64(data) == 0)
-                       return SR_ERR_ARG;
-               devc->limit_msec = g_variant_get_uint64(data);
-               break;
-       case SR_CONF_LIMIT_SAMPLES:
-               if (g_variant_get_uint64(data) == 0)
-                       return SR_ERR_ARG;
-               devc->limit_samples = g_variant_get_uint64(data);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       GVariant *gvar, *grange[2];
-       GVariantBuilder gvb;
-       struct dev_context *devc;
-
-       (void)cg;
-
-       switch (key) {
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
-               break;
-       case SR_CONF_SAMPLERATE:
-               if (!sdi || !sdi->priv || !(devc = sdi->priv))
-                       return SR_ERR_BUG;
-               cv_fill_samplerates_if_needed(sdi);
-               g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
-               gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"),
-                               devc->samplerates,
-                               ARRAY_SIZE(devc->samplerates),
-                               sizeof(uint64_t));
-               g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar);
-               *data = g_variant_builder_end(&gvb);
-               break;
-       case SR_CONF_LIMIT_SAMPLES:
-               if (!sdi || !sdi->priv || !(devc = sdi->priv) || !devc->prof)
-                       return SR_ERR_BUG;
-               grange[0] = g_variant_new_uint64(0);
-               if (devc->prof->model == CHRONOVU_LA8)
-                       grange[1] = g_variant_new_uint64(MAX_NUM_SAMPLES);
-               else
-                       grange[1] = g_variant_new_uint64(MAX_NUM_SAMPLES / 2);
-               *data = g_variant_new_tuple(grange, 2);
-               break;
-       case SR_CONF_TRIGGER_MATCH:
-               if (!sdi || !sdi->priv || !(devc = sdi->priv) || !devc->prof)
-                       return SR_ERR_BUG;
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               trigger_matches, devc->prof->num_trigger_matches,
-                               sizeof(int32_t));
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int receive_data(int fd, int revents, void *cb_data)
-{
-       int i, ret;
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-
-       (void)fd;
-       (void)revents;
-
-       if (!(sdi = cb_data)) {
-               sr_err("cb_data was NULL.");
-               return FALSE;
-       }
-
-       if (!(devc = sdi->priv)) {
-               sr_err("sdi->priv was NULL.");
-               return FALSE;
-       }
-
-       if (!devc->ftdic) {
-               sr_err("devc->ftdic was NULL.");
-               return FALSE;
-       }
-
-       /* Get one block of data. */
-       if ((ret = cv_read_block(devc)) < 0) {
-               sr_err("Failed to read data block: %d.", ret);
-               dev_acquisition_stop(sdi, sdi);
-               return FALSE;
-       }
-
-       /* We need to get exactly NUM_BLOCKS blocks (i.e. 8MB) of data. */
-       if (devc->block_counter != (NUM_BLOCKS - 1)) {
-               devc->block_counter++;
-               return TRUE;
-       }
-
-       sr_dbg("Sampling finished, sending data to session bus now.");
-
-       /*
-        * All data was received and demangled, send it to the session bus.
-        *
-        * Note: Due to the method how data is spread across the 8MByte of
-        * SDRAM, we can _not_ send it to the session bus in a streaming
-        * manner while we receive it. We have to receive and de-mangle the
-        * full 8MByte first, only then the whole buffer contains valid data.
-        */
-       for (i = 0; i < NUM_BLOCKS; i++)
-               cv_send_block_to_session_bus(devc, i);
-
-       dev_acquisition_stop(sdi, sdi);
-
-       return TRUE;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct dev_context *devc;
-       uint8_t buf[8];
-       int bytes_to_write, bytes_written;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       if (!(devc = sdi->priv)) {
-               sr_err("sdi->priv was NULL.");
-               return SR_ERR_BUG;
-       }
-
-       if (!devc->ftdic) {
-               sr_err("devc->ftdic was NULL.");
-               return SR_ERR_BUG;
-       }
-
-       devc->divcount = cv_samplerate_to_divcount(sdi, devc->cur_samplerate);
-       if (devc->divcount == 0xff) {
-               sr_err("Invalid divcount/samplerate.");
-               return SR_ERR;
-       }
-
-       if (cv_convert_trigger(sdi) != SR_OK) {
-               sr_err("Failed to configure trigger.");
-               return SR_ERR;
-       }
-
-       /* Fill acquisition parameters into buf[]. */
-       if (devc->prof->model == CHRONOVU_LA8) {
-               buf[0] = devc->divcount;
-               buf[1] = 0xff; /* This byte must always be 0xff. */
-               buf[2] = devc->trigger_pattern & 0xff;
-               buf[3] = devc->trigger_mask & 0xff;
-               bytes_to_write = 4;
-       } else {
-               buf[0] = devc->divcount;
-               buf[1] = 0xff; /* This byte must always be 0xff. */
-               buf[2] = (devc->trigger_pattern & 0xff00) >> 8;  /* LSB */
-               buf[3] = (devc->trigger_pattern & 0x00ff) >> 0;  /* MSB */
-               buf[4] = (devc->trigger_mask & 0xff00) >> 8;     /* LSB */
-               buf[5] = (devc->trigger_mask & 0x00ff) >> 0;     /* MSB */
-               buf[6] = (devc->trigger_edgemask & 0xff00) >> 8; /* LSB */
-               buf[7] = (devc->trigger_edgemask & 0x00ff) >> 0; /* MSB */
-               bytes_to_write = 8;
-       }
-
-       /* Start acquisition. */
-       bytes_written = cv_write(devc, buf, bytes_to_write);
-
-       if (bytes_written < 0 || bytes_written != bytes_to_write) {
-               sr_err("Acquisition failed to start.");
-               return SR_ERR;
-       }
-
-       sr_dbg("Hardware acquisition started successfully.");
-
-       devc->cb_data = cb_data;
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(sdi, LOG_PREFIX);
-
-       /* Time when we should be done (for detecting trigger timeouts). */
-       devc->done = (devc->divcount + 1) * devc->prof->trigger_constant +
-                       g_get_monotonic_time() + (10 * G_TIME_SPAN_SECOND);
-       devc->block_counter = 0;
-       devc->trigger_found = 0;
-
-       /* Hook up a dummy handler to receive data from the device. */
-       sr_session_source_add(sdi->session, -1, G_IO_IN, 0, receive_data, (void *)sdi);
-
-       return SR_OK;
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct sr_datafeed_packet packet;
-
-       (void)cb_data;
-
-       sr_dbg("Stopping acquisition.");
-       sr_session_source_remove(sdi->session, -1);
-
-       /* Send end packet to the session bus. */
-       sr_dbg("Sending SR_DF_END.");
-       packet.type = SR_DF_END;
-       sr_session_send(sdi, &packet);
-
-       return SR_OK;
-}
-
-SR_PRIV struct sr_dev_driver chronovu_la_driver_info = {
-       .name = "chronovu-la",
-       .longname = "ChronoVu LA8/LA16",
-       .api_version = 1,
-       .init = init,
-       .cleanup = cleanup,
-       .scan = scan,
-       .dev_list = dev_list,
-       .dev_clear = dev_clear,
-       .config_get = config_get,
-       .config_set = config_set,
-       .config_list = config_list,
-       .dev_open = dev_open,
-       .dev_close = dev_close,
-       .dev_acquisition_start = dev_acquisition_start,
-       .dev_acquisition_stop = dev_acquisition_stop,
-       .priv = NULL,
-};
diff --git a/hardware/chronovu-la/protocol.c b/hardware/chronovu-la/protocol.c
deleted file mode 100644 (file)
index c2f31a2..0000000
+++ /dev/null
@@ -1,506 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2011-2014 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include "protocol.h"
-
-SR_PRIV const struct cv_profile cv_profiles[] = {
-       { CHRONOVU_LA8,  "LA8",  "ChronoVu LA8",  8,  SR_MHZ(100), 2, 0.8388608 },
-       { CHRONOVU_LA16, "LA16", "ChronoVu LA16", 16, SR_MHZ(200), 4, 0.042 },
-       { 0, NULL, NULL, 0, 0, 0, 0.0 },
-};
-
-/* LA8: channels are numbered 0-7. LA16: channels are numbered 0-15. */
-SR_PRIV const char *cv_channel_names[] = {
-       "0", "1", "2", "3", "4", "5", "6", "7",
-       "8", "9", "10", "11", "12", "13", "14", "15",
-};
-
-static int close_usb_reset_sequencer(struct dev_context *devc);
-
-SR_PRIV void cv_fill_samplerates_if_needed(const struct sr_dev_inst *sdi)
-{
-       int i;
-       struct dev_context *devc;
-
-       devc = sdi->priv;
-
-       if (devc->samplerates[0] != 0)
-               return;
-
-       for (i = 0; i < 255; i++)
-               devc->samplerates[254 - i] = devc->prof->max_samplerate / (i + 1);
-}
-
-/**
- * Check if the given samplerate is supported by the hardware.
- *
- * @param sdi Device instance.
- * @param samplerate The samplerate (in Hz) to check.
- *
- * @return 1 if the samplerate is supported/valid, 0 otherwise.
- */
-static int is_valid_samplerate(const struct sr_dev_inst *sdi,
-                              uint64_t samplerate)
-{
-       int i;
-       struct dev_context *devc;
-
-       devc = sdi->priv;
-
-       cv_fill_samplerates_if_needed(sdi);
-
-       for (i = 0; i < 255; i++) {
-               if (devc->samplerates[i] == samplerate)
-                       return 1;
-       }
-
-       sr_err("Invalid samplerate (%" PRIu64 "Hz).", samplerate);
-
-       return 0;
-}
-
-/**
- * Convert a samplerate (in Hz) to the 'divcount' value the device wants.
- *
- * The divcount value can be 0x00 - 0xfe (0xff is not valid).
- *
- * LA8:
- * sample period = (divcount + 1) * 10ns.
- * divcount = 0x00: 10ns period, 100MHz samplerate.
- * divcount = 0xfe: 2550ns period, 392.15kHz samplerate.
- *
- * LA16:
- * sample period = (divcount + 1) * 5ns.
- * divcount = 0x00: 5ns period, 200MHz samplerate.
- * divcount = 0xfe: 1275ns period, ~784.31kHz samplerate.
- *
- * @param sdi Device instance.
- * @param samplerate The samplerate in Hz.
- *
- * @return The divcount value as needed by the hardware, or 0xff upon errors.
- */
-SR_PRIV uint8_t cv_samplerate_to_divcount(const struct sr_dev_inst *sdi,
-                                         uint64_t samplerate)
-{
-       struct dev_context *devc;
-
-       devc = sdi->priv;
-
-       if (samplerate == 0) {
-               sr_err("Can't convert invalid samplerate of 0 Hz.");
-               return 0xff;
-       }
-
-       if (!is_valid_samplerate(sdi, samplerate)) {
-               sr_err("Can't get divcount, samplerate invalid.");
-               return 0xff;
-       }
-
-       return (devc->prof->max_samplerate / samplerate) - 1;
-}
-
-/**
- * Write data of a certain length to the FTDI device.
- *
- * @param devc The struct containing private per-device-instance data. Must not
- *             be NULL. devc->ftdic must not be NULL either.
- * @param buf The buffer containing the data to write. Must not be NULL.
- * @param size The number of bytes to write. Must be > 0.
- *
- * @return The number of bytes written, or a negative value upon errors.
- */
-SR_PRIV int cv_write(struct dev_context *devc, uint8_t *buf, int size)
-{
-       int bytes_written;
-
-       /* Note: Caller ensures devc/devc->ftdic/buf != NULL and size > 0. */
-
-       bytes_written = ftdi_write_data(devc->ftdic, buf, size);
-
-       if (bytes_written < 0) {
-               sr_err("Failed to write data (%d): %s.",
-                      bytes_written, ftdi_get_error_string(devc->ftdic));
-               (void) close_usb_reset_sequencer(devc); /* Ignore errors. */
-       } else if (bytes_written != size) {
-               sr_err("Failed to write data, only %d/%d bytes written.",
-                      size, bytes_written);
-               (void) close_usb_reset_sequencer(devc); /* Ignore errors. */
-       }
-
-       return bytes_written;
-}
-
-/**
- * Read a certain amount of bytes from the FTDI device.
- *
- * @param devc The struct containing private per-device-instance data. Must not
- *             be NULL. devc->ftdic must not be NULL either.
- * @param buf The buffer where the received data will be stored. Must not
- *            be NULL.
- * @param size The number of bytes to read. Must be >= 1.
- *
- * @return The number of bytes read, or a negative value upon errors.
- */
-static int cv_read(struct dev_context *devc, uint8_t *buf, int size)
-{
-       int bytes_read;
-
-       /* Note: Caller ensures devc/devc->ftdic/buf != NULL and size > 0. */
-
-       bytes_read = ftdi_read_data(devc->ftdic, buf, size);
-
-       if (bytes_read < 0) {
-               sr_err("Failed to read data (%d): %s.",
-                      bytes_read, ftdi_get_error_string(devc->ftdic));
-       } else if (bytes_read != size) {
-               // sr_err("Failed to read data, only %d/%d bytes read.",
-               //        bytes_read, size);
-       }
-
-       return bytes_read;
-}
-
-/**
- * Close the USB port and reset the sequencer logic.
- *
- * @param devc The struct containing private per-device-instance data.
- *
- * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments.
- */
-static int close_usb_reset_sequencer(struct dev_context *devc)
-{
-       /* Magic sequence of bytes for resetting the sequencer logic. */
-       uint8_t buf[8] = {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01};
-       int ret;
-
-       /* Note: Caller checked that devc and devc->ftdic != NULL. */
-
-       if (devc->ftdic->usb_dev) {
-               /* Reset the sequencer logic, then wait 100ms. */
-               sr_dbg("Resetting sequencer logic.");
-               (void) cv_write(devc, buf, 8); /* Ignore errors. */
-               g_usleep(100 * 1000);
-
-               /* Purge FTDI buffers, then reset and close the FTDI device. */
-               sr_dbg("Purging buffers, resetting+closing FTDI device.");
-
-               /* Log errors, but ignore them (i.e., don't abort). */
-               if ((ret = ftdi_usb_purge_buffers(devc->ftdic)) < 0)
-                       sr_err("Failed to purge FTDI buffers (%d): %s.",
-                              ret, ftdi_get_error_string(devc->ftdic));
-               if ((ret = ftdi_usb_reset(devc->ftdic)) < 0)
-                       sr_err("Failed to reset FTDI device (%d): %s.",
-                              ret, ftdi_get_error_string(devc->ftdic));
-               if ((ret = ftdi_usb_close(devc->ftdic)) < 0)
-                       sr_err("Failed to close FTDI device (%d): %s.",
-                              ret, ftdi_get_error_string(devc->ftdic));
-       }
-
-       /* Close USB device, deinitialize and free the FTDI context. */
-       ftdi_free(devc->ftdic);
-       devc->ftdic = NULL;
-
-       return SR_OK;
-}
-
-/**
- * Reset the ChronoVu device.
- *
- * A reset is required after a failed read/write operation or upon timeouts.
- *
- * @param devc The struct containing private per-device-instance data.
- *
- * @return SR_OK upon success, SR_ERR upon failure.
- */
-static int reset_device(struct dev_context *devc)
-{
-       uint8_t buf[BS];
-       gint64 done, now;
-       int bytes_read;
-
-       /* Note: Caller checked that devc and devc->ftdic != NULL. */
-
-       sr_dbg("Resetting the device.");
-
-       /*
-        * Purge pending read data from the FTDI hardware FIFO until
-        * no more data is left, or a timeout occurs (after 20s).
-        */
-       done = (20 * G_TIME_SPAN_SECOND) + g_get_monotonic_time();
-       do {
-               /* Try to read bytes until none are left (or errors occur). */
-               bytes_read = cv_read(devc, (uint8_t *)&buf, BS);
-               now = g_get_monotonic_time();
-       } while ((done > now) && (bytes_read > 0));
-
-       /* Reset the sequencer logic and close the USB port. */
-       (void) close_usb_reset_sequencer(devc); /* Ignore errors. */
-
-       sr_dbg("Device reset finished.");
-
-       return SR_OK;
-}
-
-SR_PRIV int cv_convert_trigger(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_trigger *trigger;
-       struct sr_trigger_stage *stage;
-       struct sr_trigger_match *match;
-       const GSList *l, *m;
-       uint16_t channel_bit;
-
-       devc = sdi->priv;
-       devc->trigger_pattern = 0x0000; /* Default to "low" trigger. */
-       devc->trigger_mask = 0x0000; /* Default to "don't care". */
-       devc->trigger_edgemask = 0x0000; /* Default to "state triggered". */
-
-       if (!(trigger = sr_session_trigger_get(sdi->session)))
-               return SR_OK;
-
-       if (g_slist_length(trigger->stages) > 1) {
-               sr_err("This device only supports 1 trigger stage.");
-               return SR_ERR;
-       }
-
-       for (l = trigger->stages; l; l = l->next) {
-               stage = l->data;
-               for (m = stage->matches; m; m = m->next) {
-                       match = m->data;
-                       if (!match->channel->enabled)
-                               /* Ignore disabled channels with a trigger. */
-                               continue;
-                       if (devc->prof->model == CHRONOVU_LA8 &&
-                                       (match->match == SR_TRIGGER_RISING
-                                       || match->match == SR_TRIGGER_FALLING)) {
-                               sr_err("This model supports only simple triggers.");
-                               return SR_ERR;
-                       }
-                       channel_bit = (1 << (match->channel->index));
-
-                       /* state: 1 == high, edge: 1 == rising edge. */
-                       if (match->match == SR_TRIGGER_ONE
-                                       || match->match == SR_TRIGGER_RISING)
-                               devc->trigger_pattern |= channel_bit;
-
-                       /* LA16 (but not LA8) supports edge triggering. */
-                       if ((devc->prof->model == CHRONOVU_LA16)) {
-                               if (match->match == SR_TRIGGER_RISING
-                                               || match->match == SR_TRIGGER_FALLING)
-                                               devc->trigger_edgemask |= channel_bit;
-                       }
-               }
-       }
-
-       sr_dbg("Trigger pattern/mask/edgemask = 0x%04x / 0x%04x / 0x%04x.",
-                       devc->trigger_pattern, devc->trigger_mask,
-                       devc->trigger_edgemask);
-
-       return SR_OK;
-}
-
-SR_PRIV int cv_set_samplerate(const struct sr_dev_inst *sdi, uint64_t samplerate)
-{
-       struct dev_context *devc;
-
-       /* Note: Caller checked that sdi and sdi->priv != NULL. */
-
-       devc = sdi->priv;
-
-       sr_spew("Trying to set samplerate to %" PRIu64 "Hz.", samplerate);
-
-       cv_fill_samplerates_if_needed(sdi);
-
-       /* Check if this is a samplerate supported by the hardware. */
-       if (!is_valid_samplerate(sdi, samplerate)) {
-               sr_dbg("Failed to set invalid samplerate (%" PRIu64 "Hz).",
-                      samplerate);
-               return SR_ERR;
-       }
-
-       devc->cur_samplerate = samplerate;
-
-       sr_dbg("Samplerate set to %" PRIu64 "Hz.", devc->cur_samplerate);
-
-       return SR_OK;
-}
-
-/**
- * Get a block of data from the device.
- *
- * @param devc The struct containing private per-device-instance data. Must not
- *             be NULL. devc->ftdic must not be NULL either.
- *
- * @return SR_OK upon success, or SR_ERR upon errors.
- */
-SR_PRIV int cv_read_block(struct dev_context *devc)
-{
-       int i, byte_offset, m, mi, p, q, index, bytes_read;
-       gint64 now;
-
-       /* Note: Caller checked that devc and devc->ftdic != NULL. */
-
-       sr_spew("Reading block %d.", devc->block_counter);
-
-       bytes_read = cv_read(devc, devc->mangled_buf, BS);
-
-       /* If first block read got 0 bytes, retry until success or timeout. */
-       if ((bytes_read == 0) && (devc->block_counter == 0)) {
-               do {
-                       sr_spew("Reading block 0 (again).");
-                       /* Note: If bytes_read < 0 cv_read() will log errors. */
-                       bytes_read = cv_read(devc, devc->mangled_buf, BS);
-                       now = g_get_monotonic_time();
-               } while ((devc->done > now) && (bytes_read == 0));
-       }
-
-       /* Check if block read was successful or a timeout occured. */
-       if (bytes_read != BS) {
-               sr_err("Trigger timed out. Bytes read: %d.", bytes_read);
-               (void) reset_device(devc); /* Ignore errors. */
-               return SR_ERR;
-       }
-
-       /* De-mangle the data. */
-       sr_spew("Demangling block %d.", devc->block_counter);
-       byte_offset = devc->block_counter * BS;
-       m = byte_offset / (1024 * 1024);
-       mi = m * (1024 * 1024);
-       for (i = 0; i < BS; i++) {
-               if (devc->prof->model == CHRONOVU_LA8) {
-                       p = i & (1 << 0);
-                       index = m * 2 + (((byte_offset + i) - mi) / 2) * 16;
-                       index += (devc->divcount == 0) ? p : (1 - p);
-               } else {
-                       p = i & (1 << 0);
-                       q = i & (1 << 1);
-                       index = m * 4 + (((byte_offset + i) - mi) / 4) * 32;
-                       index += q + (1 - p);
-               }
-               devc->final_buf[index] = devc->mangled_buf[i];
-       }
-
-       return SR_OK;
-}
-
-SR_PRIV void cv_send_block_to_session_bus(struct dev_context *devc, int block)
-{
-       int i, idx;
-       uint8_t sample, expected_sample, tmp8;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_logic logic;
-       int trigger_point; /* Relative trigger point (in this block). */
-
-       /* Note: Caller ensures devc/devc->ftdic != NULL and block > 0. */
-
-       /* TODO: Implement/test proper trigger support for the LA16. */
-
-       /* Check if we can find the trigger condition in this block. */
-       trigger_point = -1;
-       expected_sample = devc->trigger_pattern & devc->trigger_mask;
-       for (i = 0; i < BS; i++) {
-               /* Don't continue if the trigger was found previously. */
-               if (devc->trigger_found)
-                       break;
-
-               /*
-                * Also, don't continue if triggers are "don't care", i.e. if
-                * no trigger conditions were specified by the user. In that
-                * case we don't want to send an SR_DF_TRIGGER packet at all.
-                */
-               if (devc->trigger_mask == 0x0000)
-                       break;
-
-               sample = *(devc->final_buf + (block * BS) + i);
-
-               if ((sample & devc->trigger_mask) == expected_sample) {
-                       trigger_point = i;
-                       devc->trigger_found = 1;
-                       break;
-               }
-       }
-
-       /* Swap low and high bytes of the 16-bit LA16 samples. */
-       if (devc->prof->model == CHRONOVU_LA16) {
-               for (i = 0; i < BS; i += 2) {
-                       idx = (block * BS) + i;
-                       tmp8 = devc->final_buf[idx];
-                       devc->final_buf[idx] = devc->final_buf[idx + 1];
-                       devc->final_buf[idx + 1] = tmp8;
-               }
-       }
-
-       /* If no trigger was found, send one SR_DF_LOGIC packet. */
-       if (trigger_point == -1) {
-               /* Send an SR_DF_LOGIC packet to the session bus. */
-               sr_spew("Sending SR_DF_LOGIC packet (%d bytes) for "
-                       "block %d.", BS, block);
-               packet.type = SR_DF_LOGIC;
-               packet.payload = &logic;
-               logic.length = BS;
-               logic.unitsize = devc->prof->num_channels / 8;
-               logic.data = devc->final_buf + (block * BS);
-               sr_session_send(devc->cb_data, &packet);
-               return;
-       }
-
-       /*
-        * We found the trigger, so some special handling is needed. We have
-        * to send an SR_DF_LOGIC packet with the samples before the trigger
-        * (if any), then the SD_DF_TRIGGER packet itself, then another
-        * SR_DF_LOGIC packet with the samples after the trigger (if any).
-        */
-
-       /* TODO: Send SR_DF_TRIGGER packet before or after the actual sample? */
-
-       /* If at least one sample is located before the trigger... */
-       if (trigger_point > 0) {
-               /* Send pre-trigger SR_DF_LOGIC packet to the session bus. */
-               sr_spew("Sending pre-trigger SR_DF_LOGIC packet, "
-                       "start = %d, length = %d.", block * BS, trigger_point);
-               packet.type = SR_DF_LOGIC;
-               packet.payload = &logic;
-               logic.length = trigger_point;
-               logic.unitsize = devc->prof->num_channels / 8;
-               logic.data = devc->final_buf + (block * BS);
-               sr_session_send(devc->cb_data, &packet);
-       }
-
-       /* Send the SR_DF_TRIGGER packet to the session bus. */
-       sr_spew("Sending SR_DF_TRIGGER packet, sample = %d.",
-               (block * BS) + trigger_point);
-       packet.type = SR_DF_TRIGGER;
-       packet.payload = NULL;
-       sr_session_send(devc->cb_data, &packet);
-
-       /* If at least one sample is located after the trigger... */
-       if (trigger_point < (BS - 1)) {
-               /* Send post-trigger SR_DF_LOGIC packet to the session bus. */
-               sr_spew("Sending post-trigger SR_DF_LOGIC packet, "
-                       "start = %d, length = %d.",
-                       (block * BS) + trigger_point, BS - trigger_point);
-               packet.type = SR_DF_LOGIC;
-               packet.payload = &logic;
-               logic.length = BS - trigger_point;
-               logic.unitsize = devc->prof->num_channels / 8;
-               logic.data = devc->final_buf + (block * BS) + trigger_point;
-               sr_session_send(devc->cb_data, &packet);
-       }
-}
diff --git a/hardware/chronovu-la/protocol.h b/hardware/chronovu-la/protocol.h
deleted file mode 100644 (file)
index c74feaa..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2011-2014 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#ifndef LIBSIGROK_HARDWARE_CHRONOVU_LA_PROTOCOL_H
-#define LIBSIGROK_HARDWARE_CHRONOVU_LA_PROTOCOL_H
-
-#include <glib.h>
-#include <ftdi.h>
-#include <stdint.h>
-#include <string.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "la8/la16"
-
-#define SDRAM_SIZE                     (8 * 1024 * 1024)
-#define MAX_NUM_SAMPLES                        SDRAM_SIZE
-
-#define BS                             4096 /* Block size */
-#define NUM_BLOCKS                     2048 /* Number of blocks */
-
-enum {
-       CHRONOVU_LA8,
-       CHRONOVU_LA16,
-};
-
-struct cv_profile {
-       int model;
-       const char *modelname;
-       const char *iproduct; /* USB iProduct string */
-       unsigned int num_channels;
-       uint64_t max_samplerate;
-       const int num_trigger_matches;
-       float trigger_constant;
-};
-
-/* Private, per-device-instance driver context. */
-struct dev_context {
-       /** Device profile struct for this device. */
-       const struct cv_profile *prof;
-
-       /** FTDI device context (used by libftdi). */
-       struct ftdi_context *ftdic;
-
-       /** The currently configured samplerate of the device. */
-       uint64_t cur_samplerate;
-
-       /** The current sampling limit (in ms). */
-       uint64_t limit_msec;
-
-       /** The current sampling limit (in number of samples). */
-       uint64_t limit_samples;
-
-       void *cb_data;
-
-       /**
-        * A buffer containing some (mangled) samples from the device.
-        * Format: Pretty mangled-up (due to hardware reasons), see code.
-        */
-       uint8_t mangled_buf[BS];
-
-       /**
-        * An 8MB buffer where we'll store the de-mangled samples.
-        * LA8: Each sample is 1 byte, MSB is channel 7, LSB is channel 0.
-        * LA16: Each sample is 2 bytes, MSB is channel 15, LSB is channel 0.
-        */
-       uint8_t *final_buf;
-
-       /**
-        * Trigger pattern.
-        * A 1 bit matches a high signal, 0 matches a low signal on a channel.
-        *
-        * If the resp. 'trigger_edgemask' bit is set, 1 means "rising edge",
-        * and 0 means "falling edge".
-        */
-       uint16_t trigger_pattern;
-
-       /**
-        * Trigger mask.
-        * A 1 bit means "must match trigger_pattern", 0 means "don't care".
-        */
-       uint16_t trigger_mask;
-
-       /**
-        * Trigger edge mask.
-        * A 1 bit means "edge triggered", 0 means "state triggered".
-        *
-        * Edge triggering is only supported on LA16 (but not LA8).
-        */
-       uint16_t trigger_edgemask;
-
-       /** Tells us whether an SR_DF_TRIGGER packet was already sent. */
-       int trigger_found;
-
-       /** Used for keeping track how much time has passed. */
-       gint64 done;
-
-       /** Counter/index for the data block to be read. */
-       int block_counter;
-
-       /** The divcount value (determines the sample period). */
-       uint8_t divcount;
-
-       /** This ChronoVu device's USB VID/PID. */
-       uint16_t usb_vid;
-       uint16_t usb_pid;
-
-       /** Samplerates supported by this device. */
-       uint64_t samplerates[255];
-};
-
-/* protocol.c */
-extern SR_PRIV const char *cv_channel_names[];
-extern const struct cv_profile cv_profiles[];
-SR_PRIV void cv_fill_samplerates_if_needed(const struct sr_dev_inst *sdi);
-SR_PRIV uint8_t cv_samplerate_to_divcount(const struct sr_dev_inst *sdi,
-                                         uint64_t samplerate);
-SR_PRIV int cv_write(struct dev_context *devc, uint8_t *buf, int size);
-SR_PRIV int cv_convert_trigger(const struct sr_dev_inst *sdi);
-SR_PRIV int cv_set_samplerate(const struct sr_dev_inst *sdi, uint64_t samplerate);
-SR_PRIV int cv_read_block(struct dev_context *devc);
-SR_PRIV void cv_send_block_to_session_bus(struct dev_context *devc, int block);
-
-#endif
diff --git a/hardware/colead-slm/api.c b/hardware/colead-slm/api.c
deleted file mode 100644 (file)
index d5fc9ac..0000000
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012 Bert Vermeulen <bert@biot.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 <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-#include "protocol.h"
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <string.h>
-
-/* The Colead SL-5868P uses this. */
-#define SERIALCOMM "2400/8n1"
-
-static const int32_t hwopts[] = {
-       SR_CONF_CONN,
-       SR_CONF_SERIALCOMM,
-};
-
-static const int32_t hwcaps[] = {
-       SR_CONF_SOUNDLEVELMETER,
-       SR_CONF_LIMIT_SAMPLES,
-       SR_CONF_LIMIT_MSEC,
-       SR_CONF_CONTINUOUS,
-};
-
-SR_PRIV struct sr_dev_driver colead_slm_driver_info;
-static struct sr_dev_driver *di = &colead_slm_driver_info;
-
-static int init(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, di, LOG_PREFIX);
-}
-
-static GSList *scan(GSList *options)
-{
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       struct sr_dev_inst *sdi;
-       struct sr_config *src;
-       struct sr_channel *ch;
-       GSList *devices, *l;
-       const char *conn, *serialcomm;
-
-       drvc = di->priv;
-       drvc->instances = NULL;
-
-       devices = NULL;
-
-       conn = serialcomm = NULL;
-       for (l = options; l; l = l->next) {
-               src = l->data;
-               switch (src->key) {
-               case SR_CONF_CONN:
-                       conn = g_variant_get_string(src->data, NULL);
-                       break;
-               case SR_CONF_SERIALCOMM:
-                       serialcomm = g_variant_get_string(src->data, NULL);
-                       break;
-               }
-       }
-       if (!conn)
-               return NULL;
-       if (!serialcomm)
-               serialcomm = SERIALCOMM;
-
-       if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "Colead",
-                       "SL-5868P", NULL)))
-               return NULL;
-
-       if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
-               sr_dbg("Device context malloc failed.");
-               return NULL;
-       }
-
-       if (!(sdi->conn = sr_serial_dev_inst_new(conn, serialcomm)))
-               return NULL;
-
-       sdi->inst_type = SR_INST_SERIAL;
-       sdi->priv = devc;
-       sdi->driver = di;
-       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1")))
-               return NULL;
-       sdi->channels = g_slist_append(sdi->channels, ch);
-       drvc->instances = g_slist_append(drvc->instances, sdi);
-       devices = g_slist_append(devices, sdi);
-
-       return devices;
-}
-
-static GSList *dev_list(void)
-{
-       return ((struct drv_context *)(di->priv))->instances;
-}
-
-static int dev_open(struct sr_dev_inst *sdi)
-{
-       struct sr_serial_dev_inst *serial;
-
-       serial = sdi->conn;
-       if (serial_open(serial, SERIAL_RDWR) != SR_OK)
-               return SR_ERR;
-
-       sdi->status = SR_ST_ACTIVE;
-
-       return SR_OK;
-}
-
-static int cleanup(void)
-{
-       return std_dev_clear(di, NULL);
-}
-
-static int config_set(int id, 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;
-
-       if (!(devc = sdi->priv)) {
-               sr_err("sdi->priv was NULL.");
-               return SR_ERR_BUG;
-       }
-
-       switch (id) {
-       case SR_CONF_LIMIT_MSEC:
-               /* TODO: not yet implemented */
-               if (g_variant_get_uint64(data) == 0) {
-                       sr_err("LIMIT_MSEC can't be 0.");
-                       return SR_ERR;
-               }
-               devc->limit_msec = g_variant_get_uint64(data);;
-               sr_dbg("Setting time limit to %" PRIu64 "ms.",
-                      devc->limit_msec);
-               break;
-       case SR_CONF_LIMIT_SAMPLES:
-               devc->limit_samples = g_variant_get_uint64(data);
-               sr_dbg("Setting sample limit to %" PRIu64 ".",
-                      devc->limit_samples);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_list(int 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_INT32,
-                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
-               break;
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       if (!(devc = sdi->priv)) {
-               sr_err("sdi->priv was NULL.");
-               return SR_ERR_BUG;
-       }
-
-       devc->cb_data = cb_data;
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(cb_data, LOG_PREFIX);
-
-       /* Poll every 150ms, or whenever some data comes in. */
-       serial = sdi->conn;
-       serial_source_add(sdi->session, serial, G_IO_IN, 150,
-                       colead_slm_receive_data, (void *)sdi);
-
-       return SR_OK;
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       return std_serial_dev_acquisition_stop(sdi, cb_data, std_serial_dev_close,
-                       sdi->conn, LOG_PREFIX);
-}
-
-SR_PRIV struct sr_dev_driver colead_slm_driver_info = {
-       .name = "colead-slm",
-       .longname = "Colead SLM",
-       .api_version = 1,
-       .init = init,
-       .cleanup = cleanup,
-       .scan = scan,
-       .dev_list = dev_list,
-       .dev_clear = NULL,
-       .config_get = NULL,
-       .config_set = config_set,
-       .config_list = config_list,
-       .dev_open = dev_open,
-       .dev_close = std_serial_dev_close,
-       .dev_acquisition_start = dev_acquisition_start,
-       .dev_acquisition_stop = dev_acquisition_stop,
-       .priv = NULL,
-};
diff --git a/hardware/colead-slm/protocol.c b/hardware/colead-slm/protocol.c
deleted file mode 100644 (file)
index 4abcdd5..0000000
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012 Bert Vermeulen <bert@biot.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 <stdlib.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-#include "protocol.h"
-#include <errno.h>
-#include <string.h>
-
-static void process_packet(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_analog analog;
-       GString *dbg;
-       float fvalue;
-       int checksum, mode, i;
-
-       devc = sdi->priv;
-       if (sr_log_loglevel_get() >= SR_LOG_SPEW) {
-               dbg = g_string_sized_new(128);
-               g_string_printf(dbg, "received packet:");
-               for (i = 0; i < 10; i++)
-                       g_string_append_printf(dbg, " %.2x", (devc->buf)[i]);
-               sr_spew("%s", dbg->str);
-               g_string_free(dbg, TRUE);
-       }
-
-       if (devc->buf[0] != 0x08 || devc->buf[1] != 0x04) {
-               sr_dbg("invalid packet header.");
-               return;
-       }
-
-       if (devc->buf[8] != 0x01) {
-               sr_dbg("invalid measurement.");
-               return;
-       }
-
-       checksum = 0;
-       for (i = 0; i < 9; i++)
-               checksum += devc->buf[i];
-       if ((checksum & 0xff) != devc->buf[9]) {
-               sr_dbg("invalid packet checksum.");
-               return;
-       }
-
-       fvalue = 0.0;
-       for (i = 3; i < 8; i++) {
-               if (devc->buf[i] > 0x09)
-                       continue;
-               fvalue *= 10;
-               fvalue += devc->buf[i];
-       }
-       fvalue /= 10;
-
-       memset(&analog, 0, sizeof(struct sr_datafeed_analog));
-       analog.mq = SR_MQ_SOUND_PRESSURE_LEVEL;
-       analog.unit = SR_UNIT_DECIBEL_SPL;
-       analog.channels = sdi->channels;
-       analog.num_samples = 1;
-       analog.data = &fvalue;
-
-       /* High nibble should only have 0x01 or 0x02. */
-       mode = (devc->buf[2] >> 4) & 0x0f;
-       if (mode == 0x02)
-               analog.mqflags |= SR_MQFLAG_HOLD;
-       else if (mode != 0x01) {
-               sr_dbg("unknown measurement mode 0x%.2x", mode);
-               return;
-       }
-
-       /* Low nibble has 14 combinations of direct/long-term average,
-        * time scale of that average, frequency weighting, and time
-        * weighting. */
-       mode = devc->buf[2] & 0x0f;
-       switch (mode) {
-               case 0x0:
-                       analog.mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_A \
-                                       | SR_MQFLAG_SPL_TIME_WEIGHT_F;
-                       break;
-               case 0x1:
-                       analog.mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_A \
-                                       | SR_MQFLAG_SPL_TIME_WEIGHT_S;
-                       break;
-               case 0x2:
-                       analog.mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_C \
-                                       | SR_MQFLAG_SPL_TIME_WEIGHT_F;
-                       break;
-               case 0x3:
-                       analog.mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_C \
-                                       | SR_MQFLAG_SPL_TIME_WEIGHT_S;
-                       break;
-               case 0x4:
-                       analog.mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_FLAT \
-                                       | SR_MQFLAG_SPL_TIME_WEIGHT_F;
-                       break;
-               case 0x5:
-                       analog.mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_FLAT \
-                                       | SR_MQFLAG_SPL_TIME_WEIGHT_S;
-                       break;
-               case 0x6:
-                       analog.mqflags |= SR_MQFLAG_SPL_PCT_OVER_ALARM \
-                                       | SR_MQFLAG_SPL_FREQ_WEIGHT_A \
-                                       | SR_MQFLAG_SPL_TIME_WEIGHT_F;
-                       break;
-               case 0x7:
-                       analog.mqflags |= SR_MQFLAG_SPL_PCT_OVER_ALARM \
-                                       | SR_MQFLAG_SPL_FREQ_WEIGHT_A \
-                                       | SR_MQFLAG_SPL_TIME_WEIGHT_S;
-                       break;
-               case 0x8:
-                       /* 10-second mean, but we don't have MQ flags to express it. */
-                       analog.mqflags |= SR_MQFLAG_SPL_LAT \
-                                       | SR_MQFLAG_SPL_FREQ_WEIGHT_A \
-                                       | SR_MQFLAG_SPL_TIME_WEIGHT_F;
-                       break;
-               case 0x9:
-                       /* Mean over a time period between 11 seconds and 24 hours.
-                        * Which is so silly that there's no point in expressing
-                        * either this or the previous case.  */
-                       analog.mqflags |= SR_MQFLAG_SPL_LAT \
-                                       | SR_MQFLAG_SPL_FREQ_WEIGHT_A \
-                                       | SR_MQFLAG_SPL_TIME_WEIGHT_F;
-                       break;
-               case 0xa:
-                       /* 10-second mean. */
-                       analog.mqflags |= SR_MQFLAG_SPL_LAT \
-                                       | SR_MQFLAG_SPL_FREQ_WEIGHT_A \
-                                       | SR_MQFLAG_SPL_TIME_WEIGHT_S;
-                       break;
-               case 0xb:
-                       /* Mean over a time period between 11 seconds and 24 hours. */
-                       analog.mqflags |= SR_MQFLAG_SPL_LAT \
-                                       | SR_MQFLAG_SPL_FREQ_WEIGHT_A \
-                                       | SR_MQFLAG_SPL_TIME_WEIGHT_S;
-                       break;
-               case 0xc:
-                       /* Internal calibration on 1kHz sine at 94dB, not useful
-                        * to anything but the device. */
-                       analog.mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_FLAT;
-                       break;
-               case 0xd:
-                       /* Internal calibration on 1kHz sine at 94dB, not useful
-                        * to anything but the device. */
-                       analog.mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_FLAT;
-                       break;
-               default:
-                       sr_dbg("unknown configuration 0x%.2x", mode);
-                       return;
-                       break;
-       }
-
-       packet.type = SR_DF_ANALOG;
-       packet.payload = &analog;
-       sr_session_send(devc->cb_data, &packet);
-
-       devc->num_samples++;
-
-}
-
-SR_PRIV int colead_slm_receive_data(int fd, int revents, void *cb_data)
-{
-       const struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-       int len;
-       char buf[128];
-
-       (void)fd;
-
-       if (!(sdi = cb_data))
-               return TRUE;
-
-       if (!(devc = sdi->priv))
-               return TRUE;
-
-       if (revents != G_IO_IN)
-               /* Timeout event. */
-               return TRUE;
-
-       serial = sdi->conn;
-       if (devc->state == IDLE) {
-               if (serial_read(serial, buf, 128) != 1 || buf[0] != 0x10)
-                       /* Nothing there, or caught the tail end of a previous packet,
-                        * or some garbage. Unless it's a single "data ready" byte,
-                        * we don't want it. */
-                       return TRUE;
-               /* Got 0x10, "measurement ready". */
-               if (serial_write(serial, "\x20", 1) == -1)
-                       sr_err("unable to send command: %s", strerror(errno));
-               else {
-                       devc->state = COMMAND_SENT;
-                       devc->buflen = 0;
-               }
-       } else {
-               len = serial_read(serial, devc->buf + devc->buflen,
-                               10 - devc->buflen);
-               if (len < 1)
-                       return TRUE;
-               devc->buflen += len;
-               if (devc->buflen > 10) {
-                       sr_dbg("buffer overrun");
-                       devc->state = IDLE;
-                       return TRUE;
-               }
-               if (devc->buflen == 10) {
-                       /* If we got here, we're sure the device sent a "data ready"
-                        * notification, we asked for data, and got it. */
-                       process_packet(sdi);
-                       devc->state = IDLE;
-               }
-       }
-
-       return TRUE;
-}
diff --git a/hardware/colead-slm/protocol.h b/hardware/colead-slm/protocol.h
deleted file mode 100644 (file)
index 8942ac8..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012 Bert Vermeulen <bert@biot.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_COLEAD_SLM_PROTOCOL_H
-#define LIBSIGROK_HARDWARE_COLEAD_SLM_PROTOCOL_H
-
-#include <stdint.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "colead-slm"
-
-enum {
-       IDLE,
-       COMMAND_SENT,
-};
-
-/** Private, per-device-instance driver context. */
-struct dev_context {
-       /** The current sampling limit (in number of samples). */
-       uint64_t limit_samples;
-
-       /** The current sampling limit (in ms). */
-       uint64_t limit_msec;
-
-       /** Opaque pointer passed in by the frontend. */
-       void *cb_data;
-
-       /** The current number of already received samples. */
-       uint64_t num_samples;
-       int state;
-       char buf[10];
-       int buflen;
-};
-
-SR_PRIV int colead_slm_receive_data(int fd, int revents, void *cb_data);
-
-#endif
diff --git a/hardware/common/dmm/es519xx.c b/hardware/common/dmm/es519xx.c
deleted file mode 100644 (file)
index 075587c..0000000
+++ /dev/null
@@ -1,828 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012 Uwe Hermann <uwe@hermann-uwe.de>
- * Copyright (C) 2013 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 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-/*
- * Cyrustek ES519XX protocol parser.
- *
- * Communication parameters: Unidirectional, 2400/7o1 or 19230/7o1
- */
-
-#include <string.h>
-#include <ctype.h>
-#include <math.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "es519xx"
-
-/* Factors for the respective measurement mode (0 means "invalid"). */
-static const float factors_2400_11b[9][8] = {
-       {1e-4,  1e-3,  1e-2,  1e-1, 1,    0,    0,    0   }, /* V */
-       {1e-7,  1e-6,  0,     0,    0,    0,    0,    0   }, /* uA */
-       {1e-5,  1e-4,  0,     0,    0,    0,    0,    0   }, /* mA */
-       {1e-2,  0,     0,     0,    0,    0,    0,    0   }, /* A */
-       {1e1,   1e2,   1e3,   1e4,  1e5,  1e6,  0,    0   }, /* RPM */
-       {1e-1,  1,     1e1,   1e2,  1e3,  1e4,  0,    0   }, /* Resistance */
-       {1,     1e1,   1e2,   1e3,  1e4,  1e5,  0,    0   }, /* Frequency */
-       {1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5}, /* Capacitance */
-       {1e-3,  0,     0,     0,    0,    0,    0,    0   }, /* Diode */
-};
-static const float factors_19200_11b_5digits[9][8] = {
-       {1e-4,  1e-3,  1e-2,  1e-1, 1e-5, 0,    0,    0},    /* V */
-       {1e-8,  1e-7,  0,     0,    0,    0,    0,    0},    /* uA */
-       {1e-6,  1e-5,  0,     0,    0,    0,    0,    0},    /* mA */
-       {0,     1e-3,  0,     0,    0,    0,    0,    0},    /* A */
-       {1e-4,  1e-3,  1e-2,  1e-1, 1,    0,    0,    0},    /* Manual A */
-       {1e-2,  1e-1,  1,     1e1,  1e2,  1e3,  1e4,  0},    /* Resistance */
-       {1e-1,  0,     1,     1e1,  1e2,  1e3,  1e4,  0},    /* Frequency */
-       {1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5}, /* Capacitance */
-       {1e-4,  0,     0,     0,    0,    0,    0,    0   }, /* Diode */
-};
-static const float factors_19200_11b_clampmeter[9][8] = {
-       {1e-3,  1e-2,  1e-1,  1,    1e-4, 0,    0,    0},    /* V */
-       {1e-7,  1e-6,  0,     0,    0,    0,    0,    0},    /* uA */
-       {1e-5,  1e-4,  0,     0,    0,    0,    0,    0},    /* mA */
-       {1e-2,  0,     0,     0,    0,    0,    0,    0},    /* A */
-       {1e-3,  1e-2,  1e-1,  1,    0,    0,    0,    0},    /* Manual A */
-       {1e-1,  1,     1e1,   1e2,  1e3,  1e4,  0,    0},    /* Resistance */
-       {1e-1,  0,     1,     1e1,  1e2,  1e3,  1e4,  0},    /* Frequency */
-       {1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5}, /* Capacitance */
-       {1e-3,  0,     0,     0,    0,    0,    0,    0   }, /* Diode */
-};
-static const float factors_19200_11b[9][8] = {
-       {1e-3,  1e-2,  1e-1,  1,    1e-4, 0,    0,    0},    /* V */
-       {1e-7,  1e-6,  0,     0,    0,    0,    0,    0},    /* uA */
-       {1e-5,  1e-4,  0,     0,    0,    0,    0,    0},    /* mA */
-       {1e-3,  1e-2,  0,     0,    0,    0,    0,    0},    /* A */
-       {0,     0,     0,     0,    0,    0,    0,    0},    /* Manual A */
-       {1e-1,  1,     1e1,   1e2,  1e3,  1e4,  0,    0},    /* Resistance */
-       {1,     1e1,   1e2,   1e3,  1e4,  0,    0,    0},    /* Frequency */
-       {1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 0},    /* Capacitance */
-       {1e-3,  0,     0,     0,    0,    0,    0,    0},    /* Diode */
-};
-static const float factors_19200_14b[9][8] = {
-       {1e-4,  1e-3,  1e-2,  1e-1, 1e-5, 0,    0,    0},    /* V */
-       {1e-8,  1e-7,  0,     0,    0,    0,    0,    0},    /* uA */
-       {1e-6,  1e-5,  0,     0,    0,    0,    0,    0},    /* mA */
-       {1e-3,  0,     0,     0,    0,    0,    0,    0},    /* A */
-       {1e-4,  1e-3,  1e-2,  1e-1, 1,    0,    0,    0},    /* Manual A */
-       {1e-2,  1e-1,  1,     1e1,  1e2,  1e3,  1e4,  0},    /* Resistance */
-       {1e-2,  1e-1,  0,     1,    1e1,  1e2,  1e3,  1e4},  /* Frequency */
-       {1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5}, /* Capacitance */
-       {1e-4,  0,     0,     0,    0,    0,    0,    0   }, /* Diode */
-};
-
-static int parse_value(const uint8_t *buf, struct es519xx_info *info,
-                       float *result)
-{
-       int i, intval, num_digits;
-       float floatval;
-
-       num_digits = 4 + ((info->packet_size == 14) ? 1 : 0);
-
-       /* Bytes 1-4 (or 5): Value (4 or 5 decimal digits) */
-       if (info->is_ol) {
-               sr_spew("Over limit.");
-               *result = INFINITY;
-               return SR_OK;
-       } else if (info->is_ul) {
-               sr_spew("Under limit.");
-               *result = INFINITY;
-               return SR_OK;
-       } else if (!isdigit(buf[1]) || !isdigit(buf[2]) ||
-                  !isdigit(buf[3]) || !isdigit(buf[4]) ||
-                  (num_digits == 5 && !isdigit(buf[5]))) {
-               sr_dbg("Value contained invalid digits: %02x %02x %02x %02x "
-                      "(%c %c %c %c).", buf[1], buf[2], buf[3], buf[4],
-                      buf[1], buf[2], buf[3], buf[4]);
-               return SR_ERR;
-       }
-       intval = (info->is_digit4) ? 1 : 0;
-       for (i = 0; i < num_digits; i++)
-               intval = 10 * intval + (buf[i + 1] - '0');
-
-       /* Apply sign. */
-       intval *= info->is_sign ? -1 : 1;
-
-       floatval = (float)intval;
-
-       /* Note: The decimal point position will be parsed later. */
-
-       sr_spew("The display value is %f.", floatval);
-
-       *result = floatval;
-
-       return SR_OK;
-}
-
-static int parse_range(uint8_t b, float *floatval,
-                       const struct es519xx_info *info)
-{
-       int idx, mode;
-       float factor = 0;
-
-       idx = b - '0';
-
-       if (idx < 0 || idx > 7) {
-               sr_dbg("Invalid range byte / index: 0x%02x / 0x%02x.", b, idx);
-               return SR_ERR;
-       }
-
-       /* Parse range byte (depends on the measurement mode). */
-       if (info->is_voltage)
-               mode = 0; /* V */
-       else if (info->is_current && info->is_micro)
-               mode = 1; /* uA */
-       else if (info->is_current && info->is_milli)
-               mode = 2; /* mA */
-       else if (info->is_current && info->is_auto)
-               mode = 3; /* A */
-       else if (info->is_current && !info->is_auto)
-               mode = 4; /* Manual A */
-       else if (info->is_rpm)
-               /* Not a typo, it's really index 4 in factors_2400_11b[][]. */
-               mode = 4; /* RPM */
-       else if (info->is_resistance || info->is_continuity)
-               mode = 5; /* Resistance */
-       else if (info->is_frequency)
-               mode = 6; /* Frequency */
-       else if (info->is_capacitance)
-               mode = 7; /* Capacitance */
-       else if (info->is_diode)
-               mode = 8; /* Diode */
-       else if (info->is_duty_cycle)
-               mode = 0; /* Dummy, unused */
-       else {
-               sr_dbg("Invalid mode, range byte was: 0x%02x.", b);
-               return SR_ERR;
-       }
-
-       if (info->is_vbar) {
-               if (info->is_micro)
-                       factor = (const float[]){1e-1, 1}[idx];
-               else if (info->is_milli)
-                       factor = (const float[]){1e-2, 1e-1}[idx];
-       }
-       else if (info->is_duty_cycle)
-               factor = 1e-1;
-       else if (info->baudrate == 2400)
-               factor = factors_2400_11b[mode][idx];
-       else if (info->fivedigits)
-               factor = factors_19200_11b_5digits[mode][idx];
-       else if (info->clampmeter)
-               factor = factors_19200_11b_clampmeter[mode][idx];
-       else if (info->packet_size == 11)
-               factor = factors_19200_11b[mode][idx];
-       else if (info->packet_size == 14)
-               factor = factors_19200_14b[mode][idx];
-
-       if (factor == 0) {
-               sr_dbg("Invalid factor for range byte: 0x%02x.", b);
-               return SR_ERR;
-       }
-
-       /* Apply respective factor (mode-dependent) on the value. */
-       *floatval *= factor;
-       sr_dbg("Applying factor %f, new value is %f.", factor, *floatval);
-
-       return SR_OK;
-}
-
-static void parse_flags(const uint8_t *buf, struct es519xx_info *info)
-{
-       int function, status;
-
-       function = 5 + ((info->packet_size == 14) ? 1 : 0);
-       status = function + 1;
-
-       /* Status byte */
-       if (info->alt_functions) {
-               info->is_sign  = (buf[status] & (1 << 3)) != 0;
-               info->is_batt  = (buf[status] & (1 << 2)) != 0; /* Bat. low */
-               info->is_ol    = (buf[status] & (1 << 1)) != 0; /* Overflow */
-               info->is_ol   |= (buf[status] & (1 << 0)) != 0; /* Overflow */
-       } else {
-               info->is_judge = (buf[status] & (1 << 3)) != 0;
-               info->is_sign  = (buf[status] & (1 << 2)) != 0;
-               info->is_batt  = (buf[status] & (1 << 1)) != 0; /* Bat. low */
-               info->is_ol    = (buf[status] & (1 << 0)) != 0; /* Overflow */
-       }
-
-       if (info->packet_size == 14) {
-               /* Option 1 byte */
-               info->is_max  = (buf[8] & (1 << 3)) != 0;
-               info->is_min  = (buf[8] & (1 << 2)) != 0;
-               info->is_rel  = (buf[8] & (1 << 1)) != 0;
-               info->is_rmr  = (buf[8] & (1 << 0)) != 0;
-
-               /* Option 2 byte */
-               info->is_ul   = (buf[9] & (1 << 3)) != 0; /* Underflow */
-               info->is_pmax = (buf[9] & (1 << 2)) != 0; /* Max. peak value */
-               info->is_pmin = (buf[9] & (1 << 1)) != 0; /* Min. peak value */
-
-               /* Option 3 byte */
-               info->is_dc   = (buf[10] & (1 << 3)) != 0;
-               info->is_ac   = (buf[10] & (1 << 2)) != 0;
-               info->is_auto = (buf[10] & (1 << 1)) != 0;
-               info->is_vahz = (buf[10] & (1 << 0)) != 0;
-
-               /* LPF: Low-pass filter(s) */
-               if (info->selectable_lpf) {
-                       /* Option 4 byte */
-                       info->is_hold = (buf[11] & (1 << 3)) != 0;
-                       info->is_vbar = (buf[11] & (1 << 2)) != 0;
-                       info->is_lpf1 = (buf[11] & (1 << 1)) != 0;
-                       info->is_lpf0 = (buf[11] & (1 << 0)) != 0;
-               } else {
-                       /* Option 4 byte */
-                       info->is_vbar = (buf[11] & (1 << 2)) != 0;
-                       info->is_hold = (buf[11] & (1 << 1)) != 0;
-                       info->is_lpf1 = (buf[11] & (1 << 0)) != 0;
-               }
-       } else if (info->alt_functions) {
-               /* Option 2 byte */
-               info->is_dc   = (buf[8] & (1 << 3)) != 0;
-               info->is_auto = (buf[8] & (1 << 2)) != 0;
-               info->is_apo  = (buf[8] & (1 << 0)) != 0;
-               info->is_ac   = !info->is_dc;
-       } else {
-               /* Option 1 byte */
-               if (info->baudrate == 2400) {
-                       info->is_pmax   = (buf[7] & (1 << 3)) != 0;
-                       info->is_pmin   = (buf[7] & (1 << 2)) != 0;
-                       info->is_vahz   = (buf[7] & (1 << 0)) != 0;
-               } else if (info->fivedigits) {
-                       info->is_ul     = (buf[7] & (1 << 3)) != 0;
-                       info->is_pmax   = (buf[7] & (1 << 2)) != 0;
-                       info->is_pmin   = (buf[7] & (1 << 1)) != 0;
-                       info->is_digit4 = (buf[7] & (1 << 0)) != 0;
-               } else if (info->clampmeter) {
-                       info->is_ul     = (buf[7] & (1 << 3)) != 0;
-                       info->is_vasel  = (buf[7] & (1 << 2)) != 0;
-                       info->is_vbar   = (buf[7] & (1 << 1)) != 0;
-               } else {
-                       info->is_hold   = (buf[7] & (1 << 3)) != 0;
-                       info->is_max    = (buf[7] & (1 << 2)) != 0;
-                       info->is_min    = (buf[7] & (1 << 1)) != 0;
-               }
-
-               /* Option 2 byte */
-               info->is_dc   = (buf[8] & (1 << 3)) != 0;
-               info->is_ac   = (buf[8] & (1 << 2)) != 0;
-               info->is_auto = (buf[8] & (1 << 1)) != 0;
-               if (info->baudrate == 2400)
-                       info->is_apo  = (buf[8] & (1 << 0)) != 0;
-               else
-                       info->is_vahz = (buf[8] & (1 << 0)) != 0;
-       }
-
-       /* Function byte */
-       if (info->alt_functions) {
-               switch (buf[function]) {
-               case 0x3f: /* A */
-                       info->is_current = info->is_auto = TRUE;
-                       break;
-               case 0x3e: /* uA */
-                       info->is_current = info->is_micro = info->is_auto = TRUE;
-                       break;
-               case 0x3d: /* mA */
-                       info->is_current = info->is_milli = info->is_auto = TRUE;
-                       break;
-               case 0x3c: /* V */
-                       info->is_voltage = TRUE;
-                       break;
-               case 0x37: /* Resistance */
-                       info->is_resistance = TRUE;
-                       break;
-               case 0x36: /* Continuity */
-                       info->is_continuity = TRUE;
-                       break;
-               case 0x3b: /* Diode */
-                       info->is_diode = TRUE;
-                       break;
-               case 0x3a: /* Frequency */
-                       info->is_frequency = TRUE;
-                       break;
-               case 0x34: /* ADP0 */
-               case 0x35: /* ADP0 */
-                       info->is_adp0 = TRUE;
-                       break;
-               case 0x38: /* ADP1 */
-               case 0x39: /* ADP1 */
-                       info->is_adp1 = TRUE;
-                       break;
-               case 0x32: /* ADP2 */
-               case 0x33: /* ADP2 */
-                       info->is_adp2 = TRUE;
-                       break;
-               case 0x30: /* ADP3 */
-               case 0x31: /* ADP3 */
-                       info->is_adp3 = TRUE;
-                       break;
-               default:
-                       sr_dbg("Invalid function byte: 0x%02x.", buf[function]);
-                       break;
-               }
-       } else {
-               /* Note: Some of these mappings are fixed up later. */
-               switch (buf[function]) {
-               case 0x3b: /* V */
-                       info->is_voltage = TRUE;
-                       break;
-               case 0x3d: /* uA */
-                       info->is_current = info->is_micro = info->is_auto = TRUE;
-                       break;
-               case 0x3f: /* mA */
-                       info->is_current = info->is_milli = info->is_auto = TRUE;
-                       break;
-               case 0x30: /* A */
-                       info->is_current = info->is_auto = TRUE;
-                       break;
-               case 0x39: /* Manual A */
-                       info->is_current = TRUE;
-                       info->is_auto = FALSE; /* Manual mode */
-                       break;
-               case 0x33: /* Resistance */
-                       info->is_resistance = TRUE;
-                       break;
-               case 0x35: /* Continuity */
-                       info->is_continuity = TRUE;
-                       break;
-               case 0x31: /* Diode */
-                       info->is_diode = TRUE;
-                       break;
-               case 0x32: /* Frequency / RPM / duty cycle */
-                       if (info->packet_size == 14) {
-                               if (info->is_judge)
-                                       info->is_duty_cycle = TRUE;
-                               else
-                                       info->is_frequency = TRUE;
-                       } else {
-                               if (info->is_judge)
-                                       info->is_rpm = TRUE;
-                               else
-                                       info->is_frequency = TRUE;
-                       }
-                       break;
-               case 0x36: /* Capacitance */
-                       info->is_capacitance = TRUE;
-                       break;
-               case 0x34: /* Temperature */
-                       info->is_temperature = TRUE;
-                       if (info->is_judge)
-                               info->is_celsius = TRUE;
-                       else
-                               info->is_fahrenheit = TRUE;
-                       /* IMPORTANT: The digits always represent Celsius! */
-                       break;
-               case 0x3e: /* ADP0 */
-                       info->is_adp0 = TRUE;
-                       break;
-               case 0x3c: /* ADP1 */
-                       info->is_adp1 = TRUE;
-                       break;
-               case 0x38: /* ADP2 */
-                       info->is_adp2 = TRUE;
-                       break;
-               case 0x3a: /* ADP3 */
-                       info->is_adp3 = TRUE;
-                       break;
-               default:
-                       sr_dbg("Invalid function byte: 0x%02x.", buf[function]);
-                       break;
-               }
-       }
-
-       if (info->is_vahz && (info->is_voltage || info->is_current)) {
-               info->is_voltage = FALSE;
-               info->is_current = FALSE;
-               info->is_milli = info->is_micro = FALSE;
-               if (info->packet_size == 14) {
-                       if (info->is_judge)
-                               info->is_duty_cycle = TRUE;
-                       else
-                               info->is_frequency = TRUE;
-               } else {
-                       if (info->is_judge)
-                               info->is_rpm = TRUE;
-                       else
-                               info->is_frequency = TRUE;
-               }
-       }
-
-       if (info->is_current && (info->is_micro || info->is_milli) && info->is_vasel) {
-               info->is_current = info->is_auto = FALSE;
-               info->is_voltage = TRUE;
-       }
-
-       if (info->baudrate == 2400) {
-               /* Inverted mapping between mA and A, and no manual A. */
-               if (info->is_current && (info->is_milli || !info->is_auto)) {
-                       info->is_milli = !info->is_milli;
-                       info->is_auto = TRUE;
-               }
-       }
-}
-
-static void handle_flags(struct sr_datafeed_analog *analog,
-                        float *floatval, const struct es519xx_info *info)
-{
-       /*
-        * Note: is_micro etc. are not used directly to multiply/divide
-        * floatval, this is handled via parse_range() and factors[][].
-        */
-
-       /* Measurement modes */
-       if (info->is_voltage) {
-               analog->mq = SR_MQ_VOLTAGE;
-               analog->unit = SR_UNIT_VOLT;
-       }
-       if (info->is_current) {
-               analog->mq = SR_MQ_CURRENT;
-               analog->unit = SR_UNIT_AMPERE;
-       }
-       if (info->is_resistance) {
-               analog->mq = SR_MQ_RESISTANCE;
-               analog->unit = SR_UNIT_OHM;
-       }
-       if (info->is_frequency) {
-               analog->mq = SR_MQ_FREQUENCY;
-               analog->unit = SR_UNIT_HERTZ;
-       }
-       if (info->is_capacitance) {
-               analog->mq = SR_MQ_CAPACITANCE;
-               analog->unit = SR_UNIT_FARAD;
-       }
-       if (info->is_temperature && info->is_celsius) {
-               analog->mq = SR_MQ_TEMPERATURE;
-               analog->unit = SR_UNIT_CELSIUS;
-       }
-       if (info->is_temperature && info->is_fahrenheit) {
-               analog->mq = SR_MQ_TEMPERATURE;
-               analog->unit = SR_UNIT_FAHRENHEIT;
-       }
-       if (info->is_continuity) {
-               analog->mq = SR_MQ_CONTINUITY;
-               analog->unit = SR_UNIT_BOOLEAN;
-               *floatval = (*floatval < 0.0 || *floatval > 25.0) ? 0.0 : 1.0;
-       }
-       if (info->is_diode) {
-               analog->mq = SR_MQ_VOLTAGE;
-               analog->unit = SR_UNIT_VOLT;
-       }
-       if (info->is_rpm) {
-               analog->mq = SR_MQ_FREQUENCY;
-               analog->unit = SR_UNIT_REVOLUTIONS_PER_MINUTE;
-       }
-       if (info->is_duty_cycle) {
-               analog->mq = SR_MQ_DUTY_CYCLE;
-               analog->unit = SR_UNIT_PERCENTAGE;
-       }
-
-       /* Measurement related flags */
-       if (info->is_ac)
-               analog->mqflags |= SR_MQFLAG_AC;
-       if (info->is_dc)
-               analog->mqflags |= SR_MQFLAG_DC;
-       if (info->is_auto)
-               analog->mqflags |= SR_MQFLAG_AUTORANGE;
-       if (info->is_diode)
-               analog->mqflags |= SR_MQFLAG_DIODE;
-       if (info->is_hold)
-               /*
-               * Note: HOLD only affects the number displayed on the LCD,
-               * but not the value sent via the protocol! It also does not
-               * affect the bargraph on the LCD.
-               */
-               analog->mqflags |= SR_MQFLAG_HOLD;
-       if (info->is_max)
-               analog->mqflags |= SR_MQFLAG_MAX;
-       if (info->is_min)
-               analog->mqflags |= SR_MQFLAG_MIN;
-       if (info->is_rel)
-               analog->mqflags |= SR_MQFLAG_RELATIVE;
-
-       /* Other flags */
-       if (info->is_judge)
-               sr_spew("Judge bit is set.");
-       if (info->is_batt)
-               sr_spew("Battery is low.");
-       if (info->is_ol)
-               sr_spew("Input overflow.");
-       if (info->is_ul)
-               sr_spew("Input underflow.");
-       if (info->is_pmax)
-               sr_spew("pMAX active, LCD shows max. peak value.");
-       if (info->is_pmin)
-               sr_spew("pMIN active, LCD shows min. peak value.");
-       if (info->is_vahz)
-               sr_spew("VAHZ active.");
-       if (info->is_apo)
-               sr_spew("Auto-Power-Off enabled.");
-       if (info->is_vbar)
-               sr_spew("VBAR active.");
-       if ((!info->selectable_lpf && info->is_lpf1) ||
-           (info->selectable_lpf && (!info->is_lpf0 || !info->is_lpf1)))
-               sr_spew("Low-pass filter feature is active.");
-}
-
-static gboolean flags_valid(const struct es519xx_info *info)
-{
-       int count;
-
-       /* Does the packet have more than one multiplier? */
-       count  = (info->is_micro) ? 1 : 0;
-       count += (info->is_milli) ? 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  = (info->is_voltage) ? 1 : 0;
-       count += (info->is_current) ? 1 : 0;
-       count += (info->is_resistance) ? 1 : 0;
-       count += (info->is_frequency) ? 1 : 0;
-       count += (info->is_capacitance) ? 1 : 0;
-       count += (info->is_temperature) ? 1 : 0;
-       count += (info->is_continuity) ? 1 : 0;
-       count += (info->is_diode) ? 1 : 0;
-       count += (info->is_rpm) ? 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;
-}
-
-static gboolean sr_es519xx_packet_valid(const uint8_t *buf,
-                                        struct es519xx_info *info)
-{
-       int s;
-
-       s = info->packet_size;
-
-       if (s == 11 && memcmp(buf, buf + s, s))
-               return FALSE;
-
-       if (buf[s - 2] != '\r' || buf[s - 1] != '\n')
-               return FALSE;
-
-       parse_flags(buf, info);
-
-       if (!flags_valid(info))
-               return FALSE;
-
-       return TRUE;
-}
-
-static int sr_es519xx_parse(const uint8_t *buf, float *floatval,
-                            struct sr_datafeed_analog *analog,
-                            struct es519xx_info *info)
-{
-       int ret;
-
-       if (!sr_es519xx_packet_valid(buf, info))
-               return SR_ERR;
-
-       if ((ret = parse_value(buf, info, floatval)) != SR_OK) {
-               sr_dbg("Error parsing value: %d.", ret);
-               return ret;
-       }
-
-       if ((ret = parse_range(buf[0], floatval, info)) != SR_OK)
-               return ret;
-
-       handle_flags(analog, floatval, info);
-       return SR_OK;
-}
-
-/*
- * Functions for 2400 baud / 11 bytes protocols.
- * This includes ES51962, ES51971, ES51972, ES51978 and ES51989.
- */
-SR_PRIV gboolean sr_es519xx_2400_11b_packet_valid(const uint8_t *buf)
-{
-       struct es519xx_info info;
-
-       memset(&info, 0, sizeof(struct es519xx_info));
-       info.baudrate = 2400;
-       info.packet_size = 11;
-
-       return sr_es519xx_packet_valid(buf, &info);
-}
-
-SR_PRIV int sr_es519xx_2400_11b_parse(const uint8_t *buf, float *floatval,
-                               struct sr_datafeed_analog *analog, void *info)
-{
-       struct es519xx_info *info_local;
-
-       info_local = info;
-       memset(info_local, 0, sizeof(struct es519xx_info));
-       info_local->baudrate = 2400;
-       info_local->packet_size = 11;
-
-       return sr_es519xx_parse(buf, floatval, analog, info);
-}
-
-/*
- * Functions for 2400 baud / 11 byte protocols.
- * This includes ES51960, ES51977 and ES51988.
- */
-SR_PRIV gboolean sr_es519xx_2400_11b_altfn_packet_valid(const uint8_t *buf)
-{
-       struct es519xx_info info;
-
-       memset(&info, 0, sizeof(struct es519xx_info));
-       info.baudrate = 2400;
-       info.packet_size = 11;
-       info.alt_functions = TRUE;
-
-       return sr_es519xx_packet_valid(buf, &info);
-}
-
-SR_PRIV int sr_es519xx_2400_11b_altfn_parse(const uint8_t *buf,
-               float *floatval, struct sr_datafeed_analog *analog, void *info)
-{
-       struct es519xx_info *info_local;
-
-       info_local = info;
-       memset(info_local, 0, sizeof(struct es519xx_info));
-       info_local->baudrate = 2400;
-       info_local->packet_size = 11;
-       info_local->alt_functions = TRUE;
-
-       return sr_es519xx_parse(buf, floatval, analog, info);
-}
-
-/*
- * Functions for 19200 baud / 11 bytes protocols with 5 digits display.
- * This includes ES51911, ES51916 and ES51918.
- */
-SR_PRIV gboolean sr_es519xx_19200_11b_5digits_packet_valid(const uint8_t *buf)
-{
-       struct es519xx_info info;
-
-       memset(&info, 0, sizeof(struct es519xx_info));
-       info.baudrate = 19200;
-       info.packet_size = 11;
-       info.fivedigits = TRUE;
-
-       return sr_es519xx_packet_valid(buf, &info);
-}
-
-SR_PRIV int sr_es519xx_19200_11b_5digits_parse(const uint8_t *buf,
-               float *floatval, struct sr_datafeed_analog *analog, void *info)
-{
-       struct es519xx_info *info_local;
-
-       info_local = info;
-       memset(info_local, 0, sizeof(struct es519xx_info));
-       info_local->baudrate = 19200;
-       info_local->packet_size = 11;
-       info_local->fivedigits = TRUE;
-
-       return sr_es519xx_parse(buf, floatval, analog, info);
-}
-
-/*
- * Functions for 19200 baud / 11 bytes protocols with clamp meter support.
- * This includes ES51967 and ES51969.
- */
-SR_PRIV gboolean sr_es519xx_19200_11b_clamp_packet_valid(const uint8_t *buf)
-{
-       struct es519xx_info info;
-
-       memset(&info, 0, sizeof(struct es519xx_info));
-       info.baudrate = 19200;
-       info.packet_size = 11;
-       info.clampmeter = TRUE;
-
-       return sr_es519xx_packet_valid(buf, &info);
-}
-
-SR_PRIV int sr_es519xx_19200_11b_clamp_parse(const uint8_t *buf,
-               float *floatval, struct sr_datafeed_analog *analog, void *info)
-{
-       struct es519xx_info *info_local;
-
-       info_local = info;
-       memset(info_local, 0, sizeof(struct es519xx_info));
-       info_local->baudrate = 19200;
-       info_local->packet_size = 11;
-       info_local->clampmeter = TRUE;
-
-       return sr_es519xx_parse(buf, floatval, analog, info);
-}
-
-/*
- * Functions for 19200 baud / 11 bytes protocols.
- * This includes ES51981, ES51982, ES51983, ES51984 and ES51986.
- */
-SR_PRIV gboolean sr_es519xx_19200_11b_packet_valid(const uint8_t *buf)
-{
-       struct es519xx_info info;
-
-       memset(&info, 0, sizeof(struct es519xx_info));
-       info.baudrate = 19200;
-       info.packet_size = 11;
-
-       return sr_es519xx_packet_valid(buf, &info);
-}
-
-SR_PRIV int sr_es519xx_19200_11b_parse(const uint8_t *buf, float *floatval,
-                       struct sr_datafeed_analog *analog, void *info)
-{
-       struct es519xx_info *info_local;
-
-       info_local = info;
-       memset(info_local, 0, sizeof(struct es519xx_info));
-       info_local->baudrate = 19200;
-       info_local->packet_size = 11;
-
-       return sr_es519xx_parse(buf, floatval, analog, info);
-}
-
-/*
- * Functions for 19200 baud / 14 bytes protocols.
- * This includes ES51921 and ES51922.
- */
-SR_PRIV gboolean sr_es519xx_19200_14b_packet_valid(const uint8_t *buf)
-{
-       struct es519xx_info info;
-
-       memset(&info, 0, sizeof(struct es519xx_info));
-       info.baudrate = 19200;
-       info.packet_size = 14;
-
-       return sr_es519xx_packet_valid(buf, &info);
-}
-
-SR_PRIV int sr_es519xx_19200_14b_parse(const uint8_t *buf, float *floatval,
-                       struct sr_datafeed_analog *analog, void *info)
-{
-       struct es519xx_info *info_local;
-
-       info_local = info;
-       memset(info_local, 0, sizeof(struct es519xx_info));
-       info_local->baudrate = 19200;
-       info_local->packet_size = 14;
-
-       return sr_es519xx_parse(buf, floatval, analog, info);
-}
-
-/*
- * Functions for 19200 baud / 14 bytes protocols with selectable LPF.
- * This includes ES51931 and ES51932.
- */
-SR_PRIV gboolean sr_es519xx_19200_14b_sel_lpf_packet_valid(const uint8_t *buf)
-{
-       struct es519xx_info info;
-
-       memset(&info, 0, sizeof(struct es519xx_info));
-       info.baudrate = 19200;
-       info.packet_size = 14;
-       info.selectable_lpf = TRUE;
-
-       return sr_es519xx_packet_valid(buf, &info);
-}
-
-SR_PRIV int sr_es519xx_19200_14b_sel_lpf_parse(const uint8_t *buf,
-               float *floatval, struct sr_datafeed_analog *analog, void *info)
-{
-       struct es519xx_info *info_local;
-
-       info_local = info;
-       memset(info_local, 0, sizeof(struct es519xx_info));
-       info_local->baudrate = 19200;
-       info_local->packet_size = 14;
-       info_local->selectable_lpf = TRUE;
-
-       return sr_es519xx_parse(buf, floatval, analog, info);
-}
diff --git a/hardware/common/dmm/fs9721.c b/hardware/common/dmm/fs9721.c
deleted file mode 100644 (file)
index f3101f8..0000000
+++ /dev/null
@@ -1,445 +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>
- *
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-/*
- * Fortune Semiconductor FS9721_LP3/FS9721B protocol parser.
- *
- * FS9721_LP3: 4000 counts (3 3/4 digits)
- * FS9721B/Q100: 2400 counts (3 2/3 digits)
- *
- * Same for both chips:
- *  - Packages: Bare die (78 pins) or QFP-100
- *  - Communication parameters: Unidirectional, 2400/8n1
- *  - The protocol seems to be exactly the same.
- */
-
-#include <string.h>
-#include <ctype.h>
-#include <math.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "fs9721"
-
-static int parse_digit(uint8_t b)
-{
-       switch (b) {
-       case 0x7d:
-               return 0;
-       case 0x05:
-               return 1;
-       case 0x5b:
-               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 digit byte: 0x%02x.", b);
-               return -1;
-       }
-}
-
-static gboolean sync_nibbles_valid(const uint8_t *buf)
-{
-       int i;
-
-       /* Check the synchronization nibbles, and make sure they all match. */
-       for (i = 0; i < FS9721_PACKET_SIZE; i++) {
-               if (((buf[i] >> 4) & 0x0f) != (i + 1)) {
-                       sr_dbg("Sync nibble in byte %d (0x%02x) is invalid.",
-                              i, buf[i]);
-                       return FALSE;
-               }
-       }
-
-       return TRUE;
-}
-
-static gboolean flags_valid(const struct fs9721_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;
-       count += (info->is_percent) ? 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 not set? */
-       if (!info->is_rs232) {
-               sr_dbg("No RS232 flag detected in packet.");
-               return FALSE;
-       }
-
-       return TRUE;
-}
-
-static int parse_value(const uint8_t *buf, float *result)
-{
-       int i, sign, intval = 0, digits[4];
-       uint8_t digit_bytes[4];
-       float floatval;
-
-       /* Byte 1: LCD SEG2 */
-       sign = ((buf[1] & (1 << 3)) != 0) ? -1 : 1;
-
-       /*
-        * Bytes 1-8: Value (4 decimal digits, sign, decimal point)
-        *
-        * Over limit: "0L" (LCD), 0x00 0x7d 0x68 0x00 (digit bytes).
-        */
-
-       /* Merge the two nibbles for a digit into one byte. */
-       for (i = 0; i < 4; i++) {
-               digit_bytes[i] = ((buf[1 + (i * 2)] & 0x0f) << 4);
-               digit_bytes[i] |= (buf[1 + (i * 2) + 1] & 0x0f);
-
-               /* Bit 7 in the byte is not part of the digit. */
-               digit_bytes[i] &= ~(1 << 7);
-       }
-
-       /* Check for "OL". */
-       if (digit_bytes[0] == 0x00 && digit_bytes[1] == 0x7d &&
-           digit_bytes[2] == 0x68 && digit_bytes[3] == 0x00) {
-               sr_spew("Over limit.");
-               *result = INFINITY;
-               return SR_OK;
-       }
-
-       /* Parse the digits. */
-       for (i = 0; i < 4; i++)
-               digits[i] = parse_digit(digit_bytes[i]);
-       sr_spew("Digits: %02x %02x %02x %02x (%d%d%d%d).",
-               digit_bytes[0], digit_bytes[1], digit_bytes[2], digit_bytes[3],
-               digits[0], digits[1], digits[2], digits[3]);
-
-       /* Merge all digits into an integer value. */
-       for (i = 0; i < 4; i++) {
-               intval *= 10;
-               intval += digits[i];
-       }
-
-       floatval = (float)intval;
-
-       /* Decimal point position. */
-       if ((buf[3] & (1 << 3)) != 0) {
-               floatval /= 1000;
-               sr_spew("Decimal point after first digit.");
-       } else if ((buf[5] & (1 << 3)) != 0) {
-               floatval /= 100;
-               sr_spew("Decimal point after second digit.");
-       } else if ((buf[7] & (1 << 3)) != 0) {
-               floatval /= 10;
-               sr_spew("Decimal point after third digit.");
-       } else {
-               sr_spew("No decimal point in the number.");
-       }
-
-       /* Apply sign. */
-       floatval *= sign;
-
-       sr_spew("The display value is %f.", floatval);
-
-       *result = floatval;
-
-       return SR_OK;
-}
-
-static void parse_flags(const uint8_t *buf, struct fs9721_info *info)
-{
-       /* Byte 0: LCD SEG1 */
-       info->is_ac         = (buf[0] & (1 << 3)) != 0;
-       info->is_dc         = (buf[0] & (1 << 2)) != 0;
-       info->is_auto       = (buf[0] & (1 << 1)) != 0;
-       info->is_rs232      = (buf[0] & (1 << 0)) != 0;
-
-       /* Byte 1: LCD SEG2 */
-       info->is_sign       = (buf[1] & (1 << 3)) != 0;
-
-       /* Byte 9: LCD SEG10 */
-       info->is_micro      = (buf[9] & (1 << 3)) != 0;
-       info->is_nano       = (buf[9] & (1 << 2)) != 0;
-       info->is_kilo       = (buf[9] & (1 << 1)) != 0;
-       info->is_diode      = (buf[9] & (1 << 0)) != 0;
-
-       /* Byte 10: LCD SEG11 */
-       info->is_milli      = (buf[10] & (1 << 3)) != 0;
-       info->is_percent    = (buf[10] & (1 << 2)) != 0;
-       info->is_mega       = (buf[10] & (1 << 1)) != 0;
-       info->is_beep       = (buf[10] & (1 << 0)) != 0;
-
-       /* Byte 11: LCD SEG12 */
-       info->is_farad      = (buf[11] & (1 << 3)) != 0;
-       info->is_ohm        = (buf[11] & (1 << 2)) != 0;
-       info->is_rel        = (buf[11] & (1 << 1)) != 0;
-       info->is_hold       = (buf[11] & (1 << 0)) != 0;
-
-       /* Byte 12: LCD SEG13 */
-       info->is_ampere     = (buf[12] & (1 << 3)) != 0;
-       info->is_volt       = (buf[12] & (1 << 2)) != 0;
-       info->is_hz         = (buf[12] & (1 << 1)) != 0;
-       info->is_bat        = (buf[12] & (1 << 0)) != 0;
-
-       /* Byte 13: LCD SEG14 */
-       info->is_c2c1_11    = (buf[13] & (1 << 3)) != 0;
-       info->is_c2c1_10    = (buf[13] & (1 << 2)) != 0;
-       info->is_c2c1_01    = (buf[13] & (1 << 1)) != 0;
-       info->is_c2c1_00    = (buf[13] & (1 << 0)) != 0;
-}
-
-static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
-                        const struct fs9721_info *info)
-{
-       /* Factors */
-       if (info->is_nano)
-               *floatval /= 1000000000;
-       if (info->is_micro)
-               *floatval /= 1000000;
-       if (info->is_milli)
-               *floatval /= 1000;
-       if (info->is_kilo)
-               *floatval *= 1000;
-       if (info->is_mega)
-               *floatval *= 1000000;
-
-       /* Measurement modes */
-       if (info->is_volt) {
-               analog->mq = SR_MQ_VOLTAGE;
-               analog->unit = SR_UNIT_VOLT;
-       }
-       if (info->is_ampere) {
-               analog->mq = SR_MQ_CURRENT;
-               analog->unit = SR_UNIT_AMPERE;
-       }
-       if (info->is_ohm) {
-               analog->mq = SR_MQ_RESISTANCE;
-               analog->unit = SR_UNIT_OHM;
-       }
-       if (info->is_hz) {
-               analog->mq = SR_MQ_FREQUENCY;
-               analog->unit = SR_UNIT_HERTZ;
-       }
-       if (info->is_farad) {
-               analog->mq = SR_MQ_CAPACITANCE;
-               analog->unit = SR_UNIT_FARAD;
-       }
-       if (info->is_beep) {
-               analog->mq = SR_MQ_CONTINUITY;
-               analog->unit = SR_UNIT_BOOLEAN;
-               *floatval = (*floatval == INFINITY) ? 0.0 : 1.0;
-       }
-       if (info->is_diode) {
-               analog->mq = SR_MQ_VOLTAGE;
-               analog->unit = SR_UNIT_VOLT;
-       }
-       if (info->is_percent) {
-               analog->mq = SR_MQ_DUTY_CYCLE;
-               analog->unit = SR_UNIT_PERCENTAGE;
-       }
-
-       /* Measurement related flags */
-       if (info->is_ac)
-               analog->mqflags |= SR_MQFLAG_AC;
-       if (info->is_dc)
-               analog->mqflags |= SR_MQFLAG_DC;
-       if (info->is_auto)
-               analog->mqflags |= SR_MQFLAG_AUTORANGE;
-       if (info->is_diode)
-               analog->mqflags |= SR_MQFLAG_DIODE;
-       if (info->is_hold)
-               analog->mqflags |= SR_MQFLAG_HOLD;
-       if (info->is_rel)
-               analog->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_c2c1_00)
-               sr_spew("User-defined LCD symbol 0 is active.");
-       if (info->is_c2c1_01)
-               sr_spew("User-defined LCD symbol 1 is active.");
-       if (info->is_c2c1_10)
-               sr_spew("User-defined LCD symbol 2 is active.");
-       if (info->is_c2c1_11)
-               sr_spew("User-defined LCD symbol 3 is active.");
-}
-
-SR_PRIV gboolean sr_fs9721_packet_valid(const uint8_t *buf)
-{
-       struct fs9721_info info;
-
-       parse_flags(buf, &info);
-
-       return (sync_nibbles_valid(buf) && flags_valid(&info));
-}
-
-/**
- * Parse a protocol packet.
- *
- * @param buf Buffer containing the 14-byte protocol packet. Must not be NULL.
- * @param floatval Pointer to a float variable. That variable will contain the
- *                 result value upon parsing success. Mut 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 fs9721_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_fs9721_parse(const uint8_t *buf, float *floatval,
-                           struct sr_datafeed_analog *analog, void *info)
-{
-       int ret;
-       struct fs9721_info *info_local;
-
-       info_local = (struct fs9721_info *)info;
-
-       if ((ret = parse_value(buf, floatval)) != SR_OK) {
-               sr_dbg("Error parsing value: %d.", ret);
-               return ret;
-       }
-
-       parse_flags(buf, info_local);
-       handle_flags(analog, floatval, info_local);
-
-       return SR_OK;
-}
-
-SR_PRIV void sr_fs9721_00_temp_c(struct sr_datafeed_analog *analog, void *info)
-{
-       struct fs9721_info *info_local;
-
-       info_local = (struct fs9721_info *)info;
-
-       /* User-defined FS9721_LP3 flag 'c2c1_00' means temperature (C). */
-       if (info_local->is_c2c1_00) {
-               analog->mq = SR_MQ_TEMPERATURE;
-               analog->unit = SR_UNIT_CELSIUS;
-       }
-}
-
-SR_PRIV void sr_fs9721_01_temp_c(struct sr_datafeed_analog *analog, void *info)
-{
-       struct fs9721_info *info_local;
-
-       info_local = (struct fs9721_info *)info;
-
-       /* User-defined FS9721_LP3 flag 'c2c1_01' means temperature (C). */
-       if (info_local->is_c2c1_01) {
-               analog->mq = SR_MQ_TEMPERATURE;
-               analog->unit = SR_UNIT_CELSIUS;
-       }
-}
-
-SR_PRIV void sr_fs9721_10_temp_c(struct sr_datafeed_analog *analog, void *info)
-{
-       struct fs9721_info *info_local;
-
-       info_local = (struct fs9721_info *)info;
-
-       /* User-defined FS9721_LP3 flag 'c2c1_10' means temperature (C). */
-       if (info_local->is_c2c1_10) {
-               analog->mq = SR_MQ_TEMPERATURE;
-               analog->unit = SR_UNIT_CELSIUS;
-       }
-}
-
-SR_PRIV void sr_fs9721_01_10_temp_f_c(struct sr_datafeed_analog *analog, void *info)
-{
-       struct fs9721_info *info_local;
-
-       info_local = (struct fs9721_info *)info;
-
-       /* User-defined FS9721_LP3 flag 'c2c1_01' means temperature (F). */
-       if (info_local->is_c2c1_01) {
-               analog->mq = SR_MQ_TEMPERATURE;
-               analog->unit = SR_UNIT_FAHRENHEIT;
-       }
-
-       /* User-defined FS9721_LP3 flag 'c2c1_10' means temperature (C). */
-       if (info_local->is_c2c1_10) {
-               analog->mq = SR_MQ_TEMPERATURE;
-               analog->unit = SR_UNIT_CELSIUS;
-       }
-}
-
-SR_PRIV void sr_fs9721_max_c_min(struct sr_datafeed_analog *analog, void *info)
-{
-       struct fs9721_info *info_local;
-
-       info_local = (struct fs9721_info *)info;
-
-       /* User-defined FS9721_LP3 flag 'c2c1_00' means MAX. */
-       if (info_local->is_c2c1_00)
-               analog->mqflags |= SR_MQFLAG_MAX;
-
-       /* User-defined FS9721_LP3 flag 'c2c1_01' means temperature (C). */
-       if (info_local->is_c2c1_01) {
-               analog->mq = SR_MQ_TEMPERATURE;
-               analog->unit = SR_UNIT_CELSIUS;
-       }
-
-       /* User-defined FS9721_LP3 flag 'c2c1_11' means MIN. */
-       if (info_local->is_c2c1_11)
-               analog->mqflags |= SR_MQFLAG_MIN;
-
-}
diff --git a/hardware/common/dmm/fs9922.c b/hardware/common/dmm/fs9922.c
deleted file mode 100644 (file)
index caaa51c..0000000
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-/*
- * Fortune Semiconductor FS9922-DMM3/FS9922-DMM4 protocol parser.
- */
-
-#include <string.h>
-#include <ctype.h>
-#include <math.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "fs9922"
-
-static gboolean flags_valid(const struct fs9922_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?
-        *
-        * Note: In "diode mode", both is_diode and is_volt will be set.
-        * That is a valid use-case, so we don't want to error out below
-        * if it happens. Thus, we don't check for is_diode here.
-        */
-       count = 0;
-       // count += (info->is_diode) ? 1 : 0;
-       count += (info->is_percent) ? 1 : 0;
-       count += (info->is_volt) ? 1 : 0;
-       count += (info->is_ampere) ? 1 : 0;
-       count += (info->is_ohm) ? 1 : 0;
-       count += (info->is_hfe) ? 1 : 0;
-       count += (info->is_hertz) ? 1 : 0;
-       count += (info->is_farad) ? 1 : 0;
-       count += (info->is_celsius) ? 1 : 0;
-       count += (info->is_fahrenheit) ? 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;
-       }
-
-       /* Both Celsius and Fahrenheit set? */
-       if (info->is_celsius && info->is_fahrenheit) {
-               sr_dbg("Both Celsius and Fahrenheit flags detected in packet.");
-               return FALSE;
-       }
-
-       return TRUE;
-}
-
-static int parse_value(const uint8_t *buf, float *result)
-{
-       int sign, intval;
-       float floatval;
-
-       /* Byte 0: Sign ('+' or '-') */
-       if (buf[0] == '+') {
-               sign = 1;
-       } else if (buf[0] == '-') {
-               sign = -1;
-       } else {
-               sr_dbg("Invalid sign byte: 0x%02x.", buf[0]);
-               return SR_ERR;
-       }
-
-       /*
-        * Bytes 1-4: Value (4 decimal digits)
-        *
-        * Over limit: "0.L" on the display, "?0:?" as protocol "digits".
-        */
-       if (buf[1] == '?' && buf[2] == '0' && buf[3] == ':' && buf[4] == '?') {
-               sr_spew("Over limit.");
-               *result = INFINITY;
-               return SR_OK;
-       } else if (!isdigit(buf[1]) || !isdigit(buf[2]) ||
-                  !isdigit(buf[3]) || !isdigit(buf[4])) {
-               sr_dbg("Value contained invalid digits: %02x %02x %02x %02x ("
-                      "%c %c %c %c).", buf[1], buf[2], buf[3], buf[4]);
-               return SR_ERR;
-       }
-       intval = 0;
-       intval += (buf[1] - '0') * 1000;
-       intval += (buf[2] - '0') * 100;
-       intval += (buf[3] - '0') * 10;
-       intval += (buf[4] - '0') * 1;
-
-       floatval = (float)intval;
-
-       /* Byte 5: Always ' ' (space, 0x20) */
-
-       /*
-        * Byte 6: Decimal point position ('0', '1', '2', or '4')
-        *
-        * Note: The Fortune Semiconductor FS9922-DMM3/4 datasheets both have
-        * an error/typo here. They claim that the values '0'/'1'/'2'/'3' are
-        * used, but '0'/'1'/'2'/'4' is actually correct.
-        */
-       if (buf[6] != '0' && buf[6] != '1' && buf[6] != '2' && buf[6] != '4') {
-               sr_dbg("Invalid decimal point value: 0x%02x.", buf[6]);
-               return SR_ERR;
-       }
-       if (buf[6] == '0')
-               floatval /= 1;
-       else if (buf[6] == '1')
-               floatval /= 1000;
-       else if (buf[6] == '2')
-               floatval /= 100;
-       else if (buf[6] == '4')
-               floatval /= 10;
-
-       /* Apply sign. */
-       floatval *= sign;
-
-       sr_spew("The display value is %f.", floatval);
-
-       *result = floatval;
-
-       return SR_OK;
-}
-
-static void parse_flags(const uint8_t *buf, struct fs9922_info *info)
-{
-       /* Z1/Z2/Z3/Z4 are bits for user-defined LCD symbols (on/off). */
-
-       /* Byte 7 */
-       /* Bit 7: Always 0 */
-       /* Bit 6: Always 0 */
-       info->is_auto       = (buf[7] & (1 << 5)) != 0;
-       info->is_dc         = (buf[7] & (1 << 4)) != 0;
-       info->is_ac         = (buf[7] & (1 << 3)) != 0;
-       info->is_rel        = (buf[7] & (1 << 2)) != 0;
-       info->is_hold       = (buf[7] & (1 << 1)) != 0;
-       info->is_bpn        = (buf[7] & (1 << 0)) != 0; /* Bargraph shown */
-
-       /* Byte 8 */
-       info->is_z1         = (buf[8] & (1 << 7)) != 0; /* User symbol 1 */
-       info->is_z2         = (buf[8] & (1 << 6)) != 0; /* User symbol 2 */
-       info->is_max        = (buf[8] & (1 << 5)) != 0;
-       info->is_min        = (buf[8] & (1 << 4)) != 0;
-       info->is_apo        = (buf[8] & (1 << 3)) != 0; /* Auto-poweroff on */
-       info->is_bat        = (buf[8] & (1 << 2)) != 0; /* Battery low */
-       info->is_nano       = (buf[8] & (1 << 1)) != 0;
-       info->is_z3         = (buf[8] & (1 << 0)) != 0; /* User symbol 3 */
-
-       /* Byte 9 */
-       info->is_micro      = (buf[9] & (1 << 7)) != 0;
-       info->is_milli      = (buf[9] & (1 << 6)) != 0;
-       info->is_kilo       = (buf[9] & (1 << 5)) != 0;
-       info->is_mega       = (buf[9] & (1 << 4)) != 0;
-       info->is_beep       = (buf[9] & (1 << 3)) != 0;
-       info->is_diode      = (buf[9] & (1 << 2)) != 0;
-       info->is_percent    = (buf[9] & (1 << 1)) != 0;
-       info->is_z4         = (buf[9] & (1 << 0)) != 0; /* User symbol 4 */
-
-       /* Byte 10 */
-       info->is_volt       = (buf[10] & (1 << 7)) != 0;
-       info->is_ampere     = (buf[10] & (1 << 6)) != 0;
-       info->is_ohm        = (buf[10] & (1 << 5)) != 0;
-       info->is_hfe        = (buf[10] & (1 << 4)) != 0;
-       info->is_hertz      = (buf[10] & (1 << 3)) != 0;
-       info->is_farad      = (buf[10] & (1 << 2)) != 0;
-       info->is_celsius    = (buf[10] & (1 << 1)) != 0; /* Only FS9922-DMM4 */
-       info->is_fahrenheit = (buf[10] & (1 << 0)) != 0; /* Only FS9922-DMM4 */
-
-       /*
-        * Byte 11: Bar graph
-        *
-        * Bit 7 contains the sign of the bargraph number (if the bit is set,
-        * the number is negative), bits 6..0 contain the actual number.
-        * Valid range: 0-40 (FS9922-DMM3), 0-60 (FS9922-DMM4).
-        *
-        * Upon "over limit" the bargraph value is 1 count above the highest
-        * valid number (i.e. 41 or 61, depending on chip).
-        */
-       if (info->is_bpn) {
-               info->bargraph_sign = ((buf[11] & (1 << 7)) != 0) ? -1 : 1;
-               info->bargraph_value = (buf[11] & 0x7f);
-               info->bargraph_value *= info->bargraph_sign;
-       }
-
-       /* Byte 12: Always '\r' (carriage return, 0x0d, 13) */
-
-       /* Byte 13: Always '\n' (newline, 0x0a, 10) */
-}
-
-static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
-                        const struct fs9922_info *info)
-{
-       /* Factors */
-       if (info->is_nano)
-               *floatval /= 1000000000;
-       if (info->is_micro)
-               *floatval /= 1000000;
-       if (info->is_milli)
-               *floatval /= 1000;
-       if (info->is_kilo)
-               *floatval *= 1000;
-       if (info->is_mega)
-               *floatval *= 1000000;
-
-       /* Measurement modes */
-       if (info->is_volt || info->is_diode) {
-               /* Note: In "diode mode" both is_diode and is_volt are set. */
-               analog->mq = SR_MQ_VOLTAGE;
-               analog->unit = SR_UNIT_VOLT;
-       }
-       if (info->is_ampere) {
-               analog->mq = SR_MQ_CURRENT;
-               analog->unit = SR_UNIT_AMPERE;
-       }
-       if (info->is_ohm) {
-               analog->mq = SR_MQ_RESISTANCE;
-               analog->unit = SR_UNIT_OHM;
-       }
-       if (info->is_hfe) {
-               analog->mq = SR_MQ_GAIN;
-               analog->unit = SR_UNIT_UNITLESS;
-       }
-       if (info->is_hertz) {
-               analog->mq = SR_MQ_FREQUENCY;
-               analog->unit = SR_UNIT_HERTZ;
-       }
-       if (info->is_farad) {
-               analog->mq = SR_MQ_CAPACITANCE;
-               analog->unit = SR_UNIT_FARAD;
-       }
-       if (info->is_celsius) {
-               analog->mq = SR_MQ_TEMPERATURE;
-               analog->unit = SR_UNIT_CELSIUS;
-       }
-       if (info->is_fahrenheit) {
-               analog->mq = SR_MQ_TEMPERATURE;
-               analog->unit = SR_UNIT_FAHRENHEIT;
-       }
-       if (info->is_beep) {
-               analog->mq = SR_MQ_CONTINUITY;
-               analog->unit = SR_UNIT_BOOLEAN;
-               *floatval = (*floatval == INFINITY) ? 0.0 : 1.0;
-       }
-       if (info->is_percent) {
-               analog->mq = SR_MQ_DUTY_CYCLE;
-               analog->unit = SR_UNIT_PERCENTAGE;
-       }
-
-       /* Measurement related flags */
-       if (info->is_ac)
-               analog->mqflags |= SR_MQFLAG_AC;
-       if (info->is_dc)
-               analog->mqflags |= SR_MQFLAG_DC;
-       if (info->is_auto)
-               analog->mqflags |= SR_MQFLAG_AUTORANGE;
-       if (info->is_diode)
-               analog->mqflags |= SR_MQFLAG_DIODE;
-       if (info->is_hold)
-               analog->mqflags |= SR_MQFLAG_HOLD;
-       if (info->is_max)
-               analog->mqflags |= SR_MQFLAG_MAX;
-       if (info->is_min)
-               analog->mqflags |= SR_MQFLAG_MIN;
-       if (info->is_rel)
-               analog->mqflags |= SR_MQFLAG_RELATIVE;
-
-       /* Other flags */
-       if (info->is_apo)
-               sr_spew("Automatic power-off function is active.");
-       if (info->is_bat)
-               sr_spew("Battery is low.");
-       if (info->is_z1)
-               sr_spew("User-defined LCD symbol 1 is active.");
-       if (info->is_z2)
-               sr_spew("User-defined LCD symbol 2 is active.");
-       if (info->is_z3)
-               sr_spew("User-defined LCD symbol 3 is active.");
-       if (info->is_z4)
-               sr_spew("User-defined LCD symbol 4 is active.");
-       if (info->is_bpn)
-               sr_spew("The bargraph value is %d.", info->bargraph_value);
-       else
-               sr_spew("The bargraph is not active.");
-
-}
-
-SR_PRIV gboolean sr_fs9922_packet_valid(const uint8_t *buf)
-{
-       struct fs9922_info info;
-
-       /* Byte 0: Sign (must be '+' or '-') */
-       if (buf[0] != '+' && buf[0] != '-')
-               return FALSE;
-
-       /* Byte 12: Always '\r' (carriage return, 0x0d, 13) */
-       /* Byte 13: Always '\n' (newline, 0x0a, 10) */
-       if (buf[12] != '\r' || buf[13] != '\n')
-               return FALSE;
-
-       parse_flags(buf, &info);
-
-       return flags_valid(&info);
-}
-
-/**
- * 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 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 fs9922_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_fs9922_parse(const uint8_t *buf, float *floatval,
-                           struct sr_datafeed_analog *analog, void *info)
-{
-       int ret;
-       struct fs9922_info *info_local;
-
-       info_local = (struct fs9922_info *)info;
-
-       if ((ret = parse_value(buf, floatval)) != SR_OK) {
-               sr_dbg("Error parsing value: %d.", ret);
-               return ret;
-       }
-
-       parse_flags(buf, info_local);
-       handle_flags(analog, floatval, info_local);
-
-       return SR_OK;
-}
-
-SR_PRIV void sr_fs9922_z1_diode(struct sr_datafeed_analog *analog, void *info)
-{
-       struct fs9922_info *info_local;
-
-       info_local = (struct fs9922_info *)info;
-
-       /* User-defined z1 flag means "diode mode". */
-       if (info_local->is_z1) {
-               analog->mq = SR_MQ_VOLTAGE;
-               analog->unit = SR_UNIT_VOLT;
-               analog->mqflags |= SR_MQFLAG_DIODE;
-       }
-}
diff --git a/hardware/common/dmm/m2110.c b/hardware/common/dmm/m2110.c
deleted file mode 100644 (file)
index 5863cef..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Matthias Heidbrink <m-sigrok@heidbrink.biz>
- *
- * 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
- *
- * BBC Goerz Metrawatt M2110 ASCII protocol parser.
- *
- * Most probably the simplest multimeter protocol ever ;-) .
- */
-
-#include <string.h>
-#include <math.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "m2110"
-
-SR_PRIV gboolean sr_m2110_packet_valid(const uint8_t *buf)
-{
-       float val;
-
-       if ((buf[7] != '\r') || (buf[8] != '\n'))
-               return FALSE;
-
-       if (!strncmp((const char *)buf, "OVERRNG", 7))
-               return TRUE;
-
-       if (sscanf((const char *)buf, "%f", &val) == 1)
-               return TRUE;
-       else
-               return FALSE;
-}
-
-SR_PRIV int sr_m2110_parse(const uint8_t *buf, float *floatval,
-                               struct sr_datafeed_analog *analog, void *info)
-{
-       float val;
-
-       (void)info;
-
-       /* We don't know the unit, so that's the best we can do. */
-       analog->mq = SR_MQ_GAIN;
-       analog->unit = SR_UNIT_UNITLESS;
-       analog->mqflags = 0;
-
-       if (!strncmp((const char *)buf, "OVERRNG", 7))
-               *floatval = INFINITY;
-       else if (sscanf((const char *)buf, "%f", &val) == 1)
-               *floatval = val;
-
-       return SR_OK;
-}
diff --git a/hardware/common/dmm/metex14.c b/hardware/common/dmm/metex14.c
deleted file mode 100644 (file)
index 8151aa9..0000000
+++ /dev/null
@@ -1,343 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012-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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-/**
- * @file
- *
- * Metex 14-bytes ASCII protocol parser.
- *
- * @internal
- * This should work for various multimeters which use this kind of protocol,
- * even though there is some variation in which modes each DMM supports.
- *
- * It does _not_ work for all Metex DMMs, some use a quite different protocol.
- */
-
-#include <string.h>
-#include <ctype.h>
-#include <math.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "metex14"
-
-/** Parse value from buf, byte 2-8. */
-static int parse_value(const uint8_t *buf, struct metex14_info *info,
-                       float *result)
-{
-       int i, is_ol, cnt;
-       char valstr[7 + 1];
-
-       /* Strip all spaces from bytes 2-8. */
-       memset(&valstr, 0, 7 + 1);
-       for (i = 0, cnt = 0; i < 7; i++) {
-               if (buf[2 + i] != ' ')
-                       valstr[cnt++] = buf[2 + i];
-       }
-
-       /* Bytes 5-7: Over limit (various forms) */
-       is_ol = 0;
-       is_ol += (!strcasecmp((const char *)&valstr, ".OL")) ? 1 : 0;
-       is_ol += (!strcasecmp((const char *)&valstr, "O.L")) ? 1 : 0;
-       is_ol += (!strcasecmp((const char *)&valstr, "OL.")) ? 1 : 0;
-       is_ol += (!strcasecmp((const char *)&valstr, "OL")) ? 1 : 0;
-       is_ol += (!strcasecmp((const char *)&valstr, "-.OL")) ? 1 : 0;
-       is_ol += (!strcasecmp((const char *)&valstr, "-O.L")) ? 1 : 0;
-       is_ol += (!strcasecmp((const char *)&valstr, "-OL.")) ? 1 : 0;
-       is_ol += (!strcasecmp((const char *)&valstr, "-OL")) ? 1 : 0;
-       if (is_ol != 0) {
-               sr_spew("Over limit.");
-               *result = INFINITY;
-               return SR_OK;
-       }
-
-       /* Logic functions */
-       if (!strcmp((const char *)&valstr, "READY") ||
-                       !strcmp((const char *)&valstr, "FLOAT")) {
-               *result = INFINITY;
-               info->is_logic = TRUE;
-       } else if (!strcmp((const char *)&valstr, "Hi")) {
-               *result = 1.0;
-               info->is_logic = TRUE;
-       } else if (!strcmp((const char *)&valstr, "Lo")) {
-               *result = 0.0;
-               info->is_logic = TRUE;
-       }
-       if (info->is_logic)
-               return SR_OK;
-
-       /* Bytes 2-8: Sign, value (up to 5 digits) and decimal point */
-       sscanf((const char *)&valstr, "%f", result);
-
-       sr_spew("The display value is %f.", *result);
-
-       return SR_OK;
-}
-
-static void parse_flags(const char *buf, struct metex14_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 2-8: See parse_value(). */
-
-       /* Strip all spaces from bytes 9-12. */
-       memset(&unit, 0, 4 + 1);
-       for (i = 0, cnt = 0; i < 4; i++) {
-               if (buf[9 + i] != ' ')
-                       unit[cnt++] = buf[9 + i];
-       }
-
-       /* Bytes 9-12: Unit */
-       u = (const char *)&unit;
-       if (!strcasecmp(u, "A"))
-               info->is_ampere = TRUE;
-       else if (!strcasecmp(u, "mA"))
-               info->is_milli = info->is_ampere = TRUE;
-       else if (!strcasecmp(u, "uA"))
-               info->is_micro = info->is_ampere = TRUE;
-       else if (!strcasecmp(u, "V"))
-               info->is_volt = TRUE;
-       else if (!strcasecmp(u, "mV"))
-               info->is_milli = info->is_volt = TRUE;
-       else if (!strcasecmp(u, "Ohm"))
-               info->is_ohm = TRUE;
-       else if (!strcasecmp(u, "KOhm"))
-               info->is_kilo = info->is_ohm = TRUE;
-       else if (!strcasecmp(u, "MOhm"))
-               info->is_mega = info->is_ohm = TRUE;
-       else if (!strcasecmp(u, "pF"))
-               info->is_pico = info->is_farad = TRUE;
-       else if (!strcasecmp(u, "nF"))
-               info->is_nano = info->is_farad = TRUE;
-       else if (!strcasecmp(u, "uF"))
-               info->is_micro = info->is_farad = TRUE;
-       else if (!strcasecmp(u, "KHz"))
-               info->is_kilo = info->is_hertz = TRUE;
-       else if (!strcasecmp(u, "C"))
-               info->is_celsius = TRUE;
-       else if (!strcasecmp(u, "DB"))
-               info->is_decibel = TRUE;
-       else if (!strcasecmp(u, ""))
-               info->is_unitless = TRUE;
-
-       /* Bytes 0-1: Measurement mode, except AC/DC */
-       info->is_resistance  = !strncmp(buf, "OH", 2) ||
-               (!strncmp(buf, "  ", 2) && info->is_ohm);
-       info->is_capacity    = !strncmp(buf, "CA", 2) ||
-               (!strncmp(buf, "  ", 2) && info->is_farad);
-       info->is_temperature = !strncmp(buf, "TE", 2);
-       info->is_diode       = !strncmp(buf, "DI", 2) ||
-               (!strncmp(buf, "  ", 2) && info->is_volt && info->is_milli);
-       info->is_frequency   = !strncmp(buf, "FR", 2) ||
-               (!strncmp(buf, "  ", 2) && info->is_hertz);
-       info->is_gain        = !strncmp(buf, "DB", 2);
-       info->is_hfe         = !strncmp(buf, "HF", 2) ||
-               (!strncmp(buf, "  ", 2) && !info->is_volt && !info->is_ohm &&
-                !info->is_logic && !info->is_farad && !info->is_hertz);
-       /*
-        * Note:
-        * - Protocol doesn't distinguish "resistance" from "beep" mode.
-        * - "DB" shows the logarithmic ratio of input voltage to a
-        *   pre-stored (user-changeable) value in the DMM.
-        */
-
-       /* Byte 13: Always '\r' (carriage return, 0x0d, 13) */
-}
-
-static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
-                        const struct metex14_info *info)
-{
-       /* Factors */
-       if (info->is_pico)
-               *floatval /= 1000000000000ULL;
-       if (info->is_nano)
-               *floatval /= 1000000000;
-       if (info->is_micro)
-               *floatval /= 1000000;
-       if (info->is_milli)
-               *floatval /= 1000;
-       if (info->is_kilo)
-               *floatval *= 1000;
-       if (info->is_mega)
-               *floatval *= 1000000;
-
-       /* Measurement modes */
-       if (info->is_volt) {
-               analog->mq = SR_MQ_VOLTAGE;
-               analog->unit = SR_UNIT_VOLT;
-       }
-       if (info->is_ampere) {
-               analog->mq = SR_MQ_CURRENT;
-               analog->unit = SR_UNIT_AMPERE;
-       }
-       if (info->is_ohm) {
-               analog->mq = SR_MQ_RESISTANCE;
-               analog->unit = SR_UNIT_OHM;
-       }
-       if (info->is_hertz) {
-               analog->mq = SR_MQ_FREQUENCY;
-               analog->unit = SR_UNIT_HERTZ;
-       }
-       if (info->is_farad) {
-               analog->mq = SR_MQ_CAPACITANCE;
-               analog->unit = SR_UNIT_FARAD;
-       }
-       if (info->is_celsius) {
-               analog->mq = SR_MQ_TEMPERATURE;
-               analog->unit = SR_UNIT_CELSIUS;
-       }
-       if (info->is_diode) {
-               analog->mq = SR_MQ_VOLTAGE;
-               analog->unit = SR_UNIT_VOLT;
-       }
-       if (info->is_gain) {
-               analog->mq = SR_MQ_GAIN;
-               analog->unit = SR_UNIT_DECIBEL_VOLT;
-       }
-       if (info->is_hfe) {
-               analog->mq = SR_MQ_GAIN;
-               analog->unit = SR_UNIT_UNITLESS;
-       }
-       if (info->is_logic) {
-               analog->mq = SR_MQ_GAIN;
-               analog->unit = SR_UNIT_UNITLESS;
-       }
-
-       /* Measurement related flags */
-       if (info->is_ac)
-               analog->mqflags |= SR_MQFLAG_AC;
-       if (info->is_dc)
-               analog->mqflags |= SR_MQFLAG_DC;
-       if (info->is_diode)
-               analog->mqflags |= SR_MQFLAG_DIODE;
-}
-
-static gboolean flags_valid(const struct metex14_info *info)
-{
-       int count;
-
-       /* Does the packet have more than one multiplier? */
-       count = 0;
-       count += (info->is_pico) ? 1 : 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_ac) ? 1 : 0;
-       count += (info->is_dc) ? 1 : 0;
-       count += (info->is_resistance) ? 1 : 0;
-       count += (info->is_capacity) ? 1 : 0;
-       count += (info->is_temperature) ? 1 : 0;
-       count += (info->is_diode) ? 1 : 0;
-       count += (info->is_frequency) ? 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;
-}
-
-#ifdef HAVE_LIBSERIALPORT
-SR_PRIV int sr_metex14_packet_request(struct sr_serial_dev_inst *serial)
-{
-       const uint8_t wbuf = 'D';
-
-       sr_spew("Requesting DMM packet.");
-
-       return (serial_write(serial, &wbuf, 1) == 1) ? SR_OK : SR_ERR;
-}
-#endif
-
-SR_PRIV gboolean sr_metex14_packet_valid(const uint8_t *buf)
-{
-       struct metex14_info info;
-
-       memset(&info, 0x00, sizeof(struct metex14_info));
-       parse_flags((const char *)buf, &info);
-
-       if (!flags_valid(&info))
-               return FALSE;
-
-       if (buf[13] != '\r')
-               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 metex14_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_metex14_parse(const uint8_t *buf, float *floatval,
-                            struct sr_datafeed_analog *analog, void *info)
-{
-       int ret;
-       struct metex14_info *info_local;
-
-       info_local = (struct metex14_info *)info;
-
-       /* Don't print byte 13. That one contains the carriage return. */
-       sr_dbg("DMM packet: \"%.13s\"", buf);
-
-       memset(info_local, 0x00, sizeof(struct metex14_info));
-
-       if ((ret = parse_value(buf, info_local, floatval)) != SR_OK) {
-               sr_dbg("Error parsing value: %d.", ret);
-               return ret;
-       }
-
-       parse_flags((const char *)buf, info_local);
-       handle_flags(analog, floatval, info_local);
-
-       return SR_OK;
-}
diff --git a/hardware/common/dmm/rs9lcd.c b/hardware/common/dmm/rs9lcd.c
deleted file mode 100644 (file)
index 539c233..0000000
+++ /dev/null
@@ -1,437 +0,0 @@
-/*
- * 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/>.
- */
-
-/*
- * RadioShack 22-812 protocol parser.
- *
- * This protocol is currently encountered on the RadioShack 22-812 DMM.
- * It is a 9-byte packet representing a 1:1 mapping of the LCD segments, hence
- * the name rs9lcd.
- *
- * The chip is a bare die covered by a plastic blob. It is unclear if this chip
- * and protocol is used on any other device.
- */
-
-#include <string.h>
-#include <ctype.h>
-#include <math.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "rs9lcd"
-
-/* Byte 1 of the packet, and the modes it represents */
-#define IND1_HZ                (1 << 7)
-#define IND1_OHM       (1 << 6)
-#define IND1_KILO      (1 << 5)
-#define IND1_MEGA      (1 << 4)
-#define IND1_FARAD     (1 << 3)
-#define IND1_AMP       (1 << 2)
-#define IND1_VOLT      (1 << 1)
-#define IND1_MILI      (1 << 0)
-/* Byte 2 of the packet, and the modes it represents */
-#define IND2_MICRO     (1 << 7)
-#define IND2_NANO      (1 << 6)
-#define IND2_DBM       (1 << 5)
-#define IND2_SEC       (1 << 4)
-#define IND2_DUTY      (1 << 3)
-#define IND2_HFE       (1 << 2)
-#define IND2_REL       (1 << 1)
-#define IND2_MIN       (1 << 0)
-/* Byte 7 of the packet, and the modes it represents */
-#define INFO_BEEP      (1 << 7)
-#define INFO_DIODE     (1 << 6)
-#define INFO_BAT       (1 << 5)
-#define INFO_HOLD      (1 << 4)
-#define INFO_NEG       (1 << 3)
-#define INFO_AC                (1 << 2)
-#define INFO_RS232     (1 << 1)
-#define INFO_AUTO      (1 << 0)
-/* Instead of a decimal point, digit 4 carries the MAX flag */
-#define DIG4_MAX       (1 << 3)
-/* Mask to remove the decimal point from a digit */
-#define DP_MASK                (1 << 3)
-
-/* What the LCD values represent */
-#define LCD_0          0xd7
-#define LCD_1          0x50
-#define LCD_2          0xb5
-#define LCD_3          0xf1
-#define LCD_4          0x72
-#define LCD_5          0xe3
-#define LCD_6          0xe7
-#define LCD_7          0x51
-#define LCD_8          0xf7
-#define LCD_9          0xf3
-
-#define LCD_C          0x87
-#define LCD_E
-#define LCD_F
-#define LCD_h          0x66
-#define LCD_H          0x76
-#define LCD_I
-#define LCD_n
-#define LCD_P          0x37
-#define LCD_r
-
-enum {
-       MODE_DC_V       = 0,
-       MODE_AC_V       = 1,
-       MODE_DC_UA      = 2,
-       MODE_DC_MA      = 3,
-       MODE_DC_A       = 4,
-       MODE_AC_UA      = 5,
-       MODE_AC_MA      = 6,
-       MODE_AC_A       = 7,
-       MODE_OHM        = 8,
-       MODE_FARAD      = 9,
-       MODE_HZ         = 10,
-       MODE_VOLT_HZ    = 11,   /* Dial set to V, Hz selected by Hz button */
-       MODE_AMP_HZ     = 12,   /* Dial set to A, Hz selected by Hz button */
-       MODE_DUTY       = 13,
-       MODE_VOLT_DUTY  = 14,   /* Dial set to V, duty cycle selected */
-       MODE_AMP_DUTY   = 15,   /* Dial set to A, duty cycle selected */
-       MODE_WIDTH      = 16,
-       MODE_VOLT_WIDTH = 17,   /* Dial set to V, pulse width selected */
-       MODE_AMP_WIDTH  = 18,   /* Dial set to A, pulse width selected */
-       MODE_DIODE      = 19,
-       MODE_CONT       = 20,
-       MODE_HFE        = 21,
-       MODE_LOGIC      = 22,
-       MODE_DBM        = 23,
-       /* MODE_EF      = 24, */ /* Not encountered on any DMM */
-       MODE_TEMP       = 25,
-       MODE_INVALID    = 26,
-};
-
-enum {
-       READ_ALL,
-       READ_TEMP,
-};
-
-struct rs9lcd_packet {
-       uint8_t mode;
-       uint8_t indicatrix1;
-       uint8_t indicatrix2;
-       uint8_t digit4;
-       uint8_t digit3;
-       uint8_t digit2;
-       uint8_t digit1;
-       uint8_t info;
-       uint8_t checksum;
-};
-
-static gboolean checksum_valid(const struct rs9lcd_packet *rs_packet)
-{
-       uint8_t *raw;
-       uint8_t sum = 0;
-       int i;
-
-       raw = (void *)rs_packet;
-
-       for (i = 0; i < RS9LCD_PACKET_SIZE - 1; i++)
-               sum += raw[i];
-
-       /* This is just a funky constant added to the checksum. */
-       sum += 57;
-       sum -= rs_packet->checksum;
-       return (sum == 0);
-}
-
-static gboolean selection_good(const struct rs9lcd_packet *rs_packet)
-{
-       int count;
-
-       /* Does the packet have more than one multiplier? */
-       count = 0;
-       count += (rs_packet->indicatrix1 & IND1_KILO)  ? 1 : 0;
-       count += (rs_packet->indicatrix1 & IND1_MEGA)  ? 1 : 0;
-       count += (rs_packet->indicatrix1 & IND1_MILI)  ? 1 : 0;
-       count += (rs_packet->indicatrix2 & IND2_MICRO) ? 1 : 0;
-       count += (rs_packet->indicatrix2 & IND2_NANO)  ? 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 += (rs_packet->indicatrix1 & IND1_HZ)    ? 1 : 0;
-       count += (rs_packet->indicatrix1 & IND1_OHM)   ? 1 : 0;
-       count += (rs_packet->indicatrix1 & IND1_FARAD) ? 1 : 0;
-       count += (rs_packet->indicatrix1 & IND1_AMP)   ? 1 : 0;
-       count += (rs_packet->indicatrix1 & IND1_VOLT)  ? 1 : 0;
-       count += (rs_packet->indicatrix2 & IND2_DBM)   ? 1 : 0;
-       count += (rs_packet->indicatrix2 & IND2_SEC)   ? 1 : 0;
-       count += (rs_packet->indicatrix2 & IND2_DUTY)  ? 1 : 0;
-       count += (rs_packet->indicatrix2 & IND2_HFE)   ? 1 : 0;
-       if (count > 1) {
-               sr_dbg("More than one measurement type detected in packet.");
-               return FALSE;
-       }
-
-       return TRUE;
-}
-
-/*
- * Since the 22-812 does not identify itself in any way, shape, or form,
- * we really don't know for sure who is sending the data. We must use every
- * possible check to filter out bad packets, especially since detection of the
- * 22-812 depends on how well we can filter the packets.
- */
-SR_PRIV gboolean sr_rs9lcd_packet_valid(const uint8_t *buf)
-{
-       const struct rs9lcd_packet *rs_packet = (void *)buf;
-
-       /*
-        * Check for valid mode first, before calculating the checksum. No
-        * point calculating the checksum, if we know we'll reject the packet.
-        */
-       if (!(rs_packet->mode < MODE_INVALID))
-               return FALSE;
-
-       if (!checksum_valid(rs_packet)) {
-               sr_spew("Packet with invalid checksum. Discarding.");
-               return FALSE;
-       }
-
-       if (!selection_good(rs_packet)) {
-               sr_spew("Packet with invalid selection bits. Discarding.");
-               return FALSE;
-       }
-
-       return TRUE;
-}
-
-static uint8_t decode_digit(uint8_t raw_digit)
-{
-       /* Take out the decimal point, so we can use a simple switch(). */
-       raw_digit &= ~DP_MASK;
-
-       switch (raw_digit) {
-       case 0x00:
-       case LCD_0:
-               return 0;
-       case LCD_1:
-               return 1;
-       case LCD_2:
-               return 2;
-       case LCD_3:
-               return 3;
-       case LCD_4:
-               return 4;
-       case LCD_5:
-               return 5;
-       case LCD_6:
-               return 6;
-       case LCD_7:
-               return 7;
-       case LCD_8:
-               return 8;
-       case LCD_9:
-               return 9;
-       default:
-               sr_dbg("Invalid digit byte: 0x%02x.", raw_digit);
-               return 0xff;
-       }
-}
-
-static double lcd_to_double(const struct rs9lcd_packet *rs_packet, int type)
-{
-       double rawval = 0, multiplier = 1;
-       uint8_t digit, raw_digit;
-       gboolean dp_reached = FALSE;
-       int i, end;
-
-       /* end = 1: Don't parse last digit. end = 0: Parse all digits. */
-       end = (type == READ_TEMP) ? 1 : 0;
-
-       /* We have 4 digits, and we start from the most significant. */
-       for (i = 3; i >= end; i--) {
-               raw_digit = *(&(rs_packet->digit4) + i);
-               digit = decode_digit(raw_digit);
-               if (digit == 0xff) {
-                       rawval = NAN;
-                       break;
-               }
-               /*
-                * Digit 1 does not have a decimal point. Instead, the decimal
-                * point is used to indicate MAX, so we must avoid testing it.
-                */
-               if ((i < 3) && (raw_digit & DP_MASK))
-                       dp_reached = TRUE;
-               if (dp_reached)
-                       multiplier /= 10;
-               rawval = rawval * 10 + digit;
-       }
-       rawval *= multiplier;
-       if (rs_packet->info & INFO_NEG)
-               rawval *= -1;
-
-       /* See if we need to multiply our raw value by anything. */
-       if (rs_packet->indicatrix1 & IND2_NANO)
-               rawval *= 1E-9;
-       else if (rs_packet->indicatrix2 & IND2_MICRO)
-               rawval *= 1E-6;
-       else if (rs_packet->indicatrix1 & IND1_MILI)
-               rawval *= 1E-3;
-       else if (rs_packet->indicatrix1 & IND1_KILO)
-               rawval *= 1E3;
-       else if (rs_packet->indicatrix1 & IND1_MEGA)
-               rawval *= 1E6;
-
-       return rawval;
-}
-
-static gboolean is_celsius(const struct rs9lcd_packet *rs_packet)
-{
-       return ((rs_packet->digit4 & ~DP_MASK) == LCD_C);
-}
-
-static gboolean is_shortcirc(const struct rs9lcd_packet *rs_packet)
-{
-       return ((rs_packet->digit2 & ~DP_MASK) == LCD_h);
-}
-
-static gboolean is_logic_high(const struct rs9lcd_packet *rs_packet)
-{
-       sr_spew("Digit 2: 0x%02x.", rs_packet->digit2 & ~DP_MASK);
-       return ((rs_packet->digit2 & ~DP_MASK) == LCD_H);
-}
-
-SR_PRIV int sr_rs9lcd_parse(const uint8_t *buf, float *floatval,
-                           struct sr_datafeed_analog *analog, void *info)
-{
-       const struct rs9lcd_packet *rs_packet = (void *)buf;
-       double rawval;
-
-       (void)info;
-
-       rawval = lcd_to_double(rs_packet, READ_ALL);
-
-       switch (rs_packet->mode) {
-       case MODE_DC_V:
-               analog->mq = SR_MQ_VOLTAGE;
-               analog->unit = SR_UNIT_VOLT;
-               analog->mqflags |= SR_MQFLAG_DC;
-               break;
-       case MODE_AC_V:
-               analog->mq = SR_MQ_VOLTAGE;
-               analog->unit = SR_UNIT_VOLT;
-               analog->mqflags |= SR_MQFLAG_AC;
-               break;
-       case MODE_DC_UA:        /* Fall through */
-       case MODE_DC_MA:        /* Fall through */
-       case MODE_DC_A:
-               analog->mq = SR_MQ_CURRENT;
-               analog->unit = SR_UNIT_AMPERE;
-               analog->mqflags |= SR_MQFLAG_DC;
-               break;
-       case MODE_AC_UA:        /* Fall through */
-       case MODE_AC_MA:        /* Fall through */
-       case MODE_AC_A:
-               analog->mq = SR_MQ_CURRENT;
-               analog->unit = SR_UNIT_AMPERE;
-               analog->mqflags |= SR_MQFLAG_AC;
-               break;
-       case MODE_OHM:
-               analog->mq = SR_MQ_RESISTANCE;
-               analog->unit = SR_UNIT_OHM;
-               break;
-       case MODE_FARAD:
-               analog->mq = SR_MQ_CAPACITANCE;
-               analog->unit = SR_UNIT_FARAD;
-               break;
-       case MODE_CONT:
-               analog->mq = SR_MQ_CONTINUITY;
-               analog->unit = SR_UNIT_BOOLEAN;
-               rawval = is_shortcirc(rs_packet);
-               break;
-       case MODE_DIODE:
-               analog->mq = SR_MQ_VOLTAGE;
-               analog->unit = SR_UNIT_VOLT;
-               analog->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
-               break;
-       case MODE_HZ:           /* Fall through */
-       case MODE_VOLT_HZ:      /* Fall through */
-       case MODE_AMP_HZ:
-               analog->mq = SR_MQ_FREQUENCY;
-               analog->unit = SR_UNIT_HERTZ;
-               break;
-       case MODE_LOGIC:
-               /*
-                * No matter whether or not we have an actual voltage reading,
-                * we are measuring voltage, so we set our MQ as VOLTAGE.
-                */
-               analog->mq = SR_MQ_VOLTAGE;
-               if (!isnan(rawval)) {
-                       /* We have an actual voltage. */
-                       analog->unit = SR_UNIT_VOLT;
-               } else {
-                       /* We have either HI or LOW. */
-                       analog->unit = SR_UNIT_BOOLEAN;
-                       rawval = is_logic_high(rs_packet);
-               }
-               break;
-       case MODE_HFE:
-               analog->mq = SR_MQ_GAIN;
-               analog->unit = SR_UNIT_UNITLESS;
-               break;
-       case MODE_DUTY:         /* Fall through */
-       case MODE_VOLT_DUTY:    /* Fall through */
-       case MODE_AMP_DUTY:
-               analog->mq = SR_MQ_DUTY_CYCLE;
-               analog->unit = SR_UNIT_PERCENTAGE;
-               break;
-       case MODE_WIDTH:        /* Fall through */
-       case MODE_VOLT_WIDTH:   /* Fall through */
-       case MODE_AMP_WIDTH:
-               analog->mq = SR_MQ_PULSE_WIDTH;
-               analog->unit = SR_UNIT_SECOND;
-               break;
-       case MODE_TEMP:
-               analog->mq = SR_MQ_TEMPERATURE;
-               /* We need to reparse. */
-               rawval = lcd_to_double(rs_packet, READ_TEMP);
-               analog->unit = is_celsius(rs_packet) ?
-                               SR_UNIT_CELSIUS : SR_UNIT_FAHRENHEIT;
-               break;
-       case MODE_DBM:
-               analog->mq = SR_MQ_POWER;
-               analog->unit = SR_UNIT_DECIBEL_MW;
-               analog->mqflags |= SR_MQFLAG_AC;
-               break;
-       default:
-               sr_dbg("Unknown mode: %d.", rs_packet->mode);
-               break;
-       }
-
-       if (rs_packet->info & INFO_HOLD)
-               analog->mqflags |= SR_MQFLAG_HOLD;
-       if (rs_packet->digit4 & DIG4_MAX)
-               analog->mqflags |= SR_MQFLAG_MAX;
-       if (rs_packet->indicatrix2 & IND2_MIN)
-               analog->mqflags |= SR_MQFLAG_MIN;
-       if (rs_packet->info & INFO_AUTO)
-               analog->mqflags |= SR_MQFLAG_AUTORANGE;
-
-       *floatval = rawval;
-       return SR_OK;
-}
diff --git a/hardware/common/ezusb.c b/hardware/common/ezusb.c
deleted file mode 100644 (file)
index 044b464..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.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/>.
- */
-
-/*
- * Helper functions for the Cypress EZ-USB / FX2 series chips.
- */
-
-#include <libusb.h>
-#include <glib.h>
-#include <glib/gstdio.h>
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "ezusb"
-
-SR_PRIV int ezusb_reset(struct libusb_device_handle *hdl, int set_clear)
-{
-       int ret;
-       unsigned char buf[1];
-
-       sr_info("setting CPU reset mode %s...",
-               set_clear ? "on" : "off");
-       buf[0] = set_clear ? 1 : 0;
-       ret = libusb_control_transfer(hdl, LIBUSB_REQUEST_TYPE_VENDOR, 0xa0,
-                                     0xe600, 0x0000, buf, 1, 100);
-       if (ret < 0)
-               sr_err("Unable to send control request: %s.",
-                               libusb_error_name(ret));
-
-       return ret;
-}
-
-SR_PRIV int ezusb_install_firmware(libusb_device_handle *hdl,
-                                  const char *filename)
-{
-       FILE *fw;
-       int offset, chunksize, ret, result;
-       unsigned char buf[4096];
-
-       sr_info("Uploading firmware at %s", filename);
-       if ((fw = g_fopen(filename, "rb")) == NULL) {
-               sr_err("Unable to open firmware file %s for reading: %s",
-                      filename, strerror(errno));
-               return SR_ERR;
-       }
-
-       result = SR_OK;
-       offset = 0;
-       while (1) {
-               chunksize = fread(buf, 1, 4096, fw);
-               if (chunksize == 0)
-                       break;
-               ret = libusb_control_transfer(hdl, LIBUSB_REQUEST_TYPE_VENDOR |
-                                             LIBUSB_ENDPOINT_OUT, 0xa0, offset,
-                                             0x0000, buf, chunksize, 100);
-               if (ret < 0) {
-                       sr_err("Unable to send firmware to device: %s.",
-                                       libusb_error_name(ret));
-                       result = SR_ERR;
-                       break;
-               }
-               sr_info("Uploaded %d bytes", chunksize);
-               offset += chunksize;
-       }
-       fclose(fw);
-       sr_info("Firmware upload done");
-
-       return result;
-}
-
-SR_PRIV int ezusb_upload_firmware(libusb_device *dev, int configuration,
-                                 const char *filename)
-{
-       struct libusb_device_handle *hdl;
-       int ret;
-
-       sr_info("uploading firmware to device on %d.%d",
-               libusb_get_bus_number(dev), libusb_get_device_address(dev));
-
-       if ((ret = libusb_open(dev, &hdl)) < 0) {
-               sr_err("failed to open device: %s.", libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-/*
- * The libusbx darwin backend is broken: it can report a kernel driver being
- * active, but detaching it always returns an error.
- */
-#if !defined(__APPLE__)
-       if (libusb_kernel_driver_active(hdl, 0) == 1) {
-               if ((ret = libusb_detach_kernel_driver(hdl, 0)) < 0) {
-                       sr_err("failed to detach kernel driver: %s",
-                                       libusb_error_name(ret));
-                       return SR_ERR;
-               }
-       }
-#endif
-
-       if ((ret = libusb_set_configuration(hdl, configuration)) < 0) {
-               sr_err("Unable to set configuration: %s",
-                               libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-       if ((ezusb_reset(hdl, 1)) < 0)
-               return SR_ERR;
-
-       if (ezusb_install_firmware(hdl, filename) < 0)
-               return SR_ERR;
-
-       if ((ezusb_reset(hdl, 0)) < 0)
-               return SR_ERR;
-
-       libusb_close(hdl);
-
-       return SR_OK;
-}
diff --git a/hardware/common/scpi.c b/hardware/common/scpi.c
deleted file mode 100644 (file)
index 829a4c8..0000000
+++ /dev/null
@@ -1,754 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * 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 "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#include <glib.h>
-#include <string.h>
-
-#define LOG_PREFIX "scpi"
-
-#define SCPI_READ_RETRIES 100
-#define SCPI_READ_RETRY_TIMEOUT 10000
-
-/**
- * Parse a string representation of a boolean-like value into a gboolean.
- * Similar to sr_parse_boolstring but rejects strings which do not represent
- * a boolean-like value.
- *
- * @param str String to convert.
- * @param ret Pointer to a gboolean where the result of the conversion will be
- * stored.
- *
- * @return SR_OK on success, SR_ERR on failure.
- */
-static int parse_strict_bool(const char *str, gboolean *ret)
-{
-       if (!str)
-               return SR_ERR_ARG;
-
-       if (!g_strcmp0(str, "1") ||
-           !g_ascii_strncasecmp(str, "y", 1) ||
-           !g_ascii_strncasecmp(str, "t", 1) ||
-           !g_ascii_strncasecmp(str, "yes", 3) ||
-           !g_ascii_strncasecmp(str, "true", 4) ||
-           !g_ascii_strncasecmp(str, "on", 2)) {
-               *ret = TRUE;
-               return SR_OK;
-       } else if (!g_strcmp0(str, "0") ||
-                  !g_ascii_strncasecmp(str, "n", 1) ||
-                  !g_ascii_strncasecmp(str, "f", 1) ||
-                  !g_ascii_strncasecmp(str, "no", 2) ||
-                  !g_ascii_strncasecmp(str, "false", 5) ||
-                  !g_ascii_strncasecmp(str, "off", 3)) {
-               *ret = FALSE;
-               return SR_OK;
-       }
-
-       return SR_ERR;
-}
-
-SR_PRIV extern const struct sr_scpi_dev_inst scpi_serial_dev;
-SR_PRIV extern const struct sr_scpi_dev_inst scpi_tcp_raw_dev;
-SR_PRIV extern const struct sr_scpi_dev_inst scpi_tcp_rigol_dev;
-SR_PRIV extern const struct sr_scpi_dev_inst scpi_usbtmc_libusb_dev;
-SR_PRIV extern const struct sr_scpi_dev_inst scpi_vxi_dev;
-SR_PRIV extern const struct sr_scpi_dev_inst scpi_visa_dev;
-
-static const struct sr_scpi_dev_inst *scpi_devs[] = {
-       &scpi_tcp_raw_dev,
-       &scpi_tcp_rigol_dev,
-#ifdef HAVE_LIBUSB_1_0
-       &scpi_usbtmc_libusb_dev,
-#endif
-#if HAVE_RPC
-       &scpi_vxi_dev,
-#endif
-#ifdef HAVE_LIBREVISA
-       &scpi_visa_dev,
-#endif
-#ifdef HAVE_LIBSERIALPORT
-       &scpi_serial_dev,  /* must be last as it matches any resource */
-#endif
-};
-
-static struct sr_dev_inst *sr_scpi_scan_resource(struct drv_context *drvc,
-               const char *resource, const char *serialcomm,
-               struct sr_dev_inst *(*probe_device)(struct sr_scpi_dev_inst *scpi))
-{
-       struct sr_scpi_dev_inst *scpi;
-       struct sr_dev_inst *sdi;
-
-       if (!(scpi = scpi_dev_inst_new(drvc, resource, serialcomm)))
-               return NULL;
-
-       if (sr_scpi_open(scpi) != SR_OK) {
-               sr_info("Couldn't open SCPI device.");
-               sr_scpi_free(scpi);
-               return NULL;
-       };
-
-       if ((sdi = probe_device(scpi)))
-               return sdi;
-
-       sr_scpi_close(scpi);
-       sr_scpi_free(scpi);
-       return NULL;
-}
-
-SR_PRIV GSList *sr_scpi_scan(struct drv_context *drvc, GSList *options,
-               struct sr_dev_inst *(*probe_device)(struct sr_scpi_dev_inst *scpi))
-{
-       GSList *resources, *l, *devices;
-       struct sr_dev_inst *sdi;
-       const char *resource = NULL;
-       const char *serialcomm = NULL;
-       gchar **res;
-       unsigned i;
-
-       for (l = options; l; l = l->next) {
-               struct sr_config *src = l->data;
-               switch (src->key) {
-               case SR_CONF_CONN:
-                       resource = g_variant_get_string(src->data, NULL);
-                       break;
-               case SR_CONF_SERIALCOMM:
-                       serialcomm = g_variant_get_string(src->data, NULL);
-                       break;
-               }
-       }
-
-       devices = NULL;
-       for (i = 0; i < ARRAY_SIZE(scpi_devs); i++) {
-               if ((resource && strcmp(resource, scpi_devs[i]->prefix))
-                   || !scpi_devs[i]->scan)
-                       continue;
-               resources = scpi_devs[i]->scan(drvc);
-               for (l = resources; l; l = l->next) {
-                       res = g_strsplit(l->data, ":", 2);
-                       if (res[0] && (sdi = sr_scpi_scan_resource(drvc, res[0],
-                                      serialcomm ? serialcomm : res[1], probe_device)))
-                               devices = g_slist_append(devices, sdi);
-                       g_strfreev(res);
-               }
-               g_slist_free_full(resources, g_free);
-       }
-
-       if (!devices && resource) {
-               sdi = sr_scpi_scan_resource(drvc, resource, serialcomm, probe_device);
-               devices = g_slist_append(NULL, sdi);
-       }
-
-       /* Tack a copy of the newly found devices onto the driver list. */
-       if (devices)
-               drvc->instances = g_slist_concat(drvc->instances, g_slist_copy(devices));
-
-       return devices;
-}
-
-SR_PRIV struct sr_scpi_dev_inst *scpi_dev_inst_new(struct drv_context *drvc,
-               const char *resource, const char *serialcomm)
-{
-       struct sr_scpi_dev_inst *scpi = NULL;
-       const struct sr_scpi_dev_inst *scpi_dev;
-       gchar **params;
-       unsigned i;
-
-       for (i = 0; i < ARRAY_SIZE(scpi_devs); i++) {
-               scpi_dev = scpi_devs[i];
-               if (!strncmp(resource, scpi_dev->prefix, strlen(scpi_dev->prefix))) {
-                       sr_dbg("Opening %s device %s.", scpi_dev->name, resource);
-                       scpi = g_malloc(sizeof(*scpi));
-                       *scpi = *scpi_dev;
-                       scpi->priv = g_malloc0(scpi->priv_size);
-                       params = g_strsplit(resource, "/", 0);
-                       if (scpi->dev_inst_new(scpi->priv, drvc, resource,
-                                              params, serialcomm) != SR_OK) {
-                               sr_scpi_free(scpi);
-                               scpi = NULL;
-                       }
-                       g_strfreev(params);
-                       break;
-               }
-       }
-
-       return scpi;
-}
-
-/**
- * Open SCPI device.
- *
- * @param scpi Previously initialized SCPI device structure.
- *
- * @return SR_OK on success, SR_ERR on failure.
- */
-SR_PRIV int sr_scpi_open(struct sr_scpi_dev_inst *scpi)
-{
-       return scpi->open(scpi->priv);
-}
-
-/**
- * Add an event source for an SCPI device.
- *
- * @param scpi Previously initialized SCPI device structure.
- * @param events Events to check for.
- * @param timeout Max time to wait before the callback is called, ignored if 0.
- * @param cb Callback function to add. Must not be NULL.
- * @param cb_data Data for the callback function. Can be NULL.
- *
- * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments, or
- *         SR_ERR_MALLOC upon memory allocation errors.
- */
-SR_PRIV int sr_scpi_source_add(struct sr_session *session,
-               struct sr_scpi_dev_inst *scpi, int events, int timeout,
-               sr_receive_data_callback cb, void *cb_data)
-{
-       return scpi->source_add(session, scpi->priv, events, timeout, cb, cb_data);
-}
-
-/**
- * Remove event source for an SCPI device.
- *
- * @param scpi Previously initialized SCPI device structure.
- *
- * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments, or
- *         SR_ERR_MALLOC upon memory allocation errors, SR_ERR_BUG upon
- *         internal errors.
- */
-SR_PRIV int sr_scpi_source_remove(struct sr_session *session,
-               struct sr_scpi_dev_inst *scpi)
-{
-       return scpi->source_remove(session, scpi->priv);
-}
-
-/**
- * Send a SCPI command.
- *
- * @param scpi Previously initialized SCPI device structure.
- * @param format Format string, to be followed by any necessary arguments.
- *
- * @return SR_OK on success, SR_ERR on failure.
- */
-SR_PRIV int sr_scpi_send(struct sr_scpi_dev_inst *scpi,
-                        const char *format, ...)
-{
-       va_list args;
-       int ret;
-
-       va_start(args, format);
-       ret = sr_scpi_send_variadic(scpi, format, args);
-       va_end(args);
-
-       return ret;
-}
-
-/**
- * Send a SCPI command with a variadic argument list.
- *
- * @param scpi Previously initialized SCPI device structure.
- * @param format Format string.
- * @param args Argument list.
- *
- * @return SR_OK on success, SR_ERR on failure.
- */
-SR_PRIV int sr_scpi_send_variadic(struct sr_scpi_dev_inst *scpi,
-                        const char *format, va_list args)
-{
-       va_list args_copy;
-       char *buf;
-       int len, ret;
-
-       /* Get length of buffer required. */
-       va_copy(args_copy, args);
-       len = vsnprintf(NULL, 0, format, args_copy);
-       va_end(args_copy);
-
-       /* Allocate buffer and write out command. */
-       buf = g_malloc(len + 1);
-       vsprintf(buf, format, args);
-
-       /* Send command. */
-       ret = scpi->send(scpi->priv, buf);
-
-       /* Free command buffer. */
-       g_free(buf);
-
-       return ret;
-}
-
-/**
- * Begin receiving an SCPI reply.
- *
- * @param scpi Previously initialised SCPI device structure.
- *
- * @return SR_OK on success, SR_ERR on failure.
- */
-SR_PRIV int sr_scpi_read_begin(struct sr_scpi_dev_inst *scpi)
-{
-       return scpi->read_begin(scpi->priv);
-}
-
-/**
- * Read part of a response from SCPI device.
- *
- * @param scpi Previously initialised SCPI device structure.
- * @param buf Buffer to store result.
- * @param maxlen Maximum number of bytes to read.
- *
- * @return Number of bytes read, or SR_ERR upon failure.
- */
-SR_PRIV int sr_scpi_read_data(struct sr_scpi_dev_inst *scpi,
-                       char *buf, int maxlen)
-{
-       return scpi->read_data(scpi->priv, buf, maxlen);
-}
-
-/**
- * Check whether a complete SCPI response has been received.
- *
- * @param scpi Previously initialised SCPI device structure.
- *
- * @return 1 if complete, 0 otherwise.
- */
-SR_PRIV int sr_scpi_read_complete(struct sr_scpi_dev_inst *scpi)
-{
-       return scpi->read_complete(scpi->priv);
-}
-
-/**
- * Close SCPI device.
- *
- * @param scpi Previously initialized SCPI device structure.
- *
- * @return SR_OK on success, SR_ERR on failure.
- */
-SR_PRIV int sr_scpi_close(struct sr_scpi_dev_inst *scpi)
-{
-       return scpi->close(scpi->priv);
-}
-
-/**
- * Free SCPI device.
- *
- * @param scpi Previously initialized SCPI device structure.
- *
- * @return SR_OK on success, SR_ERR on failure.
- */
-SR_PRIV void sr_scpi_free(struct sr_scpi_dev_inst *scpi)
-{
-       scpi->free(scpi->priv);
-       g_free(scpi->priv);
-       g_free(scpi);
-}
-
-/**
- * Send a SCPI command, receive the reply and store the reply in scpi_response.
- *
- * @param scpi Previously initialised SCPI device structure.
- * @param command The SCPI command to send to the device (can be NULL).
- * @param scpi_response Pointer where to store the SCPI response.
- *
- * @return SR_OK on success, SR_ERR on failure.
- */
-SR_PRIV int sr_scpi_get_string(struct sr_scpi_dev_inst *scpi,
-                              const char *command, char **scpi_response)
-{
-       char buf[256];
-       int len;
-       GString *response;
-
-       if (command)
-               if (sr_scpi_send(scpi, command) != SR_OK)
-                       return SR_ERR;
-
-       if (sr_scpi_read_begin(scpi) != SR_OK)
-               return SR_ERR;
-
-       response = g_string_new("");
-
-       *scpi_response = NULL;
-
-       while (!sr_scpi_read_complete(scpi)) {
-               len = sr_scpi_read_data(scpi, buf, sizeof(buf));
-               if (len < 0) {
-                       g_string_free(response, TRUE);
-                       return SR_ERR;
-               }
-               g_string_append_len(response, buf, len);
-       }
-
-       /* Get rid of trailing linefeed if present */
-       if (response->len >= 1 && response->str[response->len - 1] == '\n')
-               g_string_truncate(response, response->len - 1);
-
-       *scpi_response = response->str;
-       g_string_free(response, FALSE);
-
-       sr_spew("Got response: '%.70s'.", *scpi_response);
-
-       return SR_OK;
-}
-
-/**
- * Send a SCPI command, read the reply, parse it as a bool value and store the
- * result in scpi_response.
- *
- * @param scpi Previously initialised SCPI device structure.
- * @param command The SCPI command to send to the device (can be NULL).
- * @param scpi_response Pointer where to store the parsed result.
- *
- * @return SR_OK on success, SR_ERR on failure.
- */
-SR_PRIV int sr_scpi_get_bool(struct sr_scpi_dev_inst *scpi,
-                            const char *command, gboolean *scpi_response)
-{
-       int ret;
-       char *response;
-
-       response = NULL;
-
-       if (sr_scpi_get_string(scpi, command, &response) != SR_OK)
-               if (!response)
-                       return SR_ERR;
-
-       if (parse_strict_bool(response, scpi_response) == SR_OK)
-               ret = SR_OK;
-       else
-               ret = SR_ERR;
-
-       g_free(response);
-
-       return ret;
-}
-
-/**
- * Send a SCPI command, read the reply, parse it as an integer and store the
- * result in scpi_response.
- *
- * @param scpi Previously initialised SCPI device structure.
- * @param command The SCPI command to send to the device (can be NULL).
- * @param scpi_response Pointer where to store the parsed result.
- *
- * @return SR_OK on success, SR_ERR on failure.
- */
-SR_PRIV int sr_scpi_get_int(struct sr_scpi_dev_inst *scpi,
-                           const char *command, int *scpi_response)
-{
-       int ret;
-       char *response;
-
-       response = NULL;
-
-       if (sr_scpi_get_string(scpi, command, &response) != SR_OK)
-               if (!response)
-                       return SR_ERR;
-
-       if (sr_atoi(response, scpi_response) == SR_OK)
-               ret = SR_OK;
-       else
-               ret = SR_ERR;
-
-       g_free(response);
-
-       return ret;
-}
-
-/**
- * Send a SCPI command, read the reply, parse it as a float and store the
- * result in scpi_response.
- *
- * @param scpi Previously initialised SCPI device structure.
- * @param command The SCPI command to send to the device (can be NULL).
- * @param scpi_response Pointer where to store the parsed result.
- *
- * @return SR_OK on success, SR_ERR on failure.
- */
-SR_PRIV int sr_scpi_get_float(struct sr_scpi_dev_inst *scpi,
-                             const char *command, float *scpi_response)
-{
-       int ret;
-       char *response;
-
-       response = NULL;
-
-       if (sr_scpi_get_string(scpi, command, &response) != SR_OK)
-               if (!response)
-                       return SR_ERR;
-
-       if (sr_atof_ascii(response, scpi_response) == SR_OK)
-               ret = SR_OK;
-       else
-               ret = SR_ERR;
-
-       g_free(response);
-
-       return ret;
-}
-
-/**
- * Send a SCPI command, read the reply, parse it as a double and store the
- * result in scpi_response.
- *
- * @param scpi Previously initialised SCPI device structure.
- * @param command The SCPI command to send to the device (can be NULL).
- * @param scpi_response Pointer where to store the parsed result.
- *
- * @return SR_OK on success, SR_ERR on failure.
- */
-SR_PRIV int sr_scpi_get_double(struct sr_scpi_dev_inst *scpi,
-                              const char *command, double *scpi_response)
-{
-       int ret;
-       char *response;
-
-       response = NULL;
-
-       if (sr_scpi_get_string(scpi, command, &response) != SR_OK)
-               if (!response)
-                       return SR_ERR;
-
-       if (sr_atod(response, scpi_response) == SR_OK)
-               ret = SR_OK;
-       else
-               ret = SR_ERR;
-
-       g_free(response);
-
-       return ret;
-}
-
-/**
- * Send a SCPI *OPC? command, read the reply and return the result of the
- * command.
- *
- * @param scpi Previously initialised SCPI device structure.
- *
- * @return SR_OK on success, SR_ERR on failure.
- */
-SR_PRIV int sr_scpi_get_opc(struct sr_scpi_dev_inst *scpi)
-{
-       unsigned int i;
-       gboolean opc;
-
-       for (i = 0; i < SCPI_READ_RETRIES; ++i) {
-               sr_scpi_get_bool(scpi, SCPI_CMD_OPC, &opc);
-               if (opc)
-                       return SR_OK;
-               g_usleep(SCPI_READ_RETRY_TIMEOUT);
-       }
-
-       return SR_ERR;
-}
-
-/**
- * Send a SCPI command, read the reply, parse it as comma separated list of
- * floats and store the as an result in scpi_response.
- *
- * @param scpi Previously initialised SCPI device structure.
- * @param command The SCPI command to send to the device (can be NULL).
- * @param scpi_response Pointer where to store the parsed result.
- *
- * @return SR_OK upon successfully parsing all values, SR_ERR upon a parsing
- *         error or upon no response. The allocated response must be freed by
- *         the caller in the case of an SR_OK as well as in the case of
- *         parsing error.
- */
-SR_PRIV int sr_scpi_get_floatv(struct sr_scpi_dev_inst *scpi,
-                              const char *command, GArray **scpi_response)
-{
-       int ret;
-       float tmp;
-       char *response;
-       gchar **ptr, **tokens;
-       GArray *response_array;
-
-       ret = SR_OK;
-       response = NULL;
-       tokens = NULL;
-
-       if (sr_scpi_get_string(scpi, command, &response) != SR_OK)
-               if (!response)
-                       return SR_ERR;
-
-       tokens = g_strsplit(response, ",", 0);
-       ptr = tokens;
-
-       response_array = g_array_sized_new(TRUE, FALSE, sizeof(float), 256);
-
-       while (*ptr) {
-               if (sr_atof_ascii(*ptr, &tmp) == SR_OK)
-                       response_array = g_array_append_val(response_array,
-                                                           tmp);
-               else
-                       ret = SR_ERR;
-
-               ptr++;
-       }
-       g_strfreev(tokens);
-       g_free(response);
-
-       if (ret == SR_ERR && response_array->len == 0) {
-               g_array_free(response_array, TRUE);
-               *scpi_response = NULL;
-               return SR_ERR;
-       }
-
-       *scpi_response = response_array;
-
-       return ret;
-}
-
-/**
- * Send a SCPI command, read the reply, parse it as comma separated list of
- * unsigned 8 bit integers and store the as an result in scpi_response.
- *
- * @param scpi Previously initialised SCPI device structure.
- * @param command The SCPI command to send to the device (can be NULL).
- * @param scpi_response Pointer where to store the parsed result.
- *
- * @return SR_OK upon successfully parsing all values, SR_ERR upon a parsing
- *         error or upon no response. The allocated response must be freed by
- *         the caller in the case of an SR_OK as well as in the case of
- *         parsing error.
- */
-SR_PRIV int sr_scpi_get_uint8v(struct sr_scpi_dev_inst *scpi,
-                              const char *command, GArray **scpi_response)
-{
-       int tmp, ret;
-       char *response;
-       gchar **ptr, **tokens;
-       GArray *response_array;
-
-       ret = SR_OK;
-       response = NULL;
-       tokens = NULL;
-
-       if (sr_scpi_get_string(scpi, command, &response) != SR_OK)
-               if (!response)
-                       return SR_ERR;
-
-       tokens = g_strsplit(response, ",", 0);
-       ptr = tokens;
-
-       response_array = g_array_sized_new(TRUE, FALSE, sizeof(uint8_t), 256);
-
-       while (*ptr) {
-               if (sr_atoi(*ptr, &tmp) == SR_OK)
-                       response_array = g_array_append_val(response_array,
-                                                           tmp);
-               else
-                       ret = SR_ERR;
-
-               ptr++;
-       }
-       g_strfreev(tokens);
-       g_free(response);
-
-       if (response_array->len == 0) {
-               g_array_free(response_array, TRUE);
-               *scpi_response = NULL;
-               return SR_ERR;
-       }
-
-       *scpi_response = response_array;
-
-       return ret;
-}
-
-/**
- * Send the *IDN? SCPI command, receive the reply, parse it and store the
- * reply as a sr_scpi_hw_info structure in the supplied scpi_response pointer.
- *
- * The hw_info structure must be freed by the caller via sr_scpi_hw_info_free().
- *
- * @param scpi Previously initialised SCPI device structure.
- * @param scpi_response Pointer where to store the hw_info structure.
- *
- * @return SR_OK upon success, SR_ERR on failure.
- */
-SR_PRIV int sr_scpi_get_hw_id(struct sr_scpi_dev_inst *scpi,
-                             struct sr_scpi_hw_info **scpi_response)
-{
-       int num_tokens;
-       char *response;
-       gchar **tokens;
-       struct sr_scpi_hw_info *hw_info;
-
-       response = NULL;
-       tokens = NULL;
-
-       if (sr_scpi_get_string(scpi, SCPI_CMD_IDN, &response) != SR_OK)
-               if (!response)
-                       return SR_ERR;
-
-       sr_info("Got IDN string: '%s'", response);
-
-       /*
-        * The response to a '*IDN?' is specified by the SCPI spec. It contains
-        * a comma-separated list containing the manufacturer name, instrument
-        * model, serial number of the instrument and the firmware version.
-        */
-       tokens = g_strsplit(response, ",", 0);
-
-       for (num_tokens = 0; tokens[num_tokens] != NULL; num_tokens++);
-
-       if (num_tokens != 4) {
-               sr_dbg("IDN response not according to spec: %80.s.", response);
-               g_strfreev(tokens);
-               g_free(response);
-               return SR_ERR;
-       }
-       g_free(response);
-
-       hw_info = g_try_malloc(sizeof(struct sr_scpi_hw_info));
-       if (!hw_info) {
-               g_strfreev(tokens);
-               return SR_ERR_MALLOC;
-       }
-
-       hw_info->manufacturer = g_strdup(tokens[0]);
-       hw_info->model = g_strdup(tokens[1]);
-       hw_info->serial_number = g_strdup(tokens[2]);
-       hw_info->firmware_version = g_strdup(tokens[3]);
-
-       g_strfreev(tokens);
-
-       *scpi_response = hw_info;
-
-       return SR_OK;
-}
-
-/**
- * Free a sr_scpi_hw_info struct.
- *
- * @param hw_info Pointer to the struct to free.
- *
- * This function is safe to call with a NULL pointer.
- */
-SR_PRIV void sr_scpi_hw_info_free(struct sr_scpi_hw_info *hw_info)
-{
-       if (hw_info) {
-               g_free(hw_info->manufacturer);
-               g_free(hw_info->model);
-               g_free(hw_info->serial_number);
-               g_free(hw_info->firmware_version);
-               g_free(hw_info);
-       }
-}
diff --git a/hardware/common/scpi_serial.c b/hardware/common/scpi_serial.c
deleted file mode 100644 (file)
index feb3317..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 poljar (Damir Jelić) <poljarinho@gmail.com>
- * Copyright (C) 2013 Martin Ling <martin-sigrok@earth.li>
- *
- * 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 "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#include <glib.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define LOG_PREFIX "scpi_serial"
-
-#define BUFFER_SIZE 1024
-
-struct scpi_serial {
-       struct sr_serial_dev_inst *serial;
-       char buffer[BUFFER_SIZE];
-       size_t count;
-       size_t read;
-};
-
-static struct {
-       uint16_t vendor_id;
-       uint16_t product_id;
-       const char *serialcomm;
-} scpi_serial_usb_ids[] = {
-       { 0x0403, 0xed72, "115200/8n1/flow=1" }, /* Hameg HO720 */
-       { 0x0403, 0xed73, "115200/8n1/flow=1" }, /* Hameg HO730 */
-};
-
-static GSList *scpi_serial_scan(struct drv_context *drvc)
-{
-       GSList *l, *r, *resources = NULL;
-       gchar *res;
-       unsigned i;
-
-       (void)drvc;
-
-       for (i = 0; i < ARRAY_SIZE(scpi_serial_usb_ids); i++) {
-               if ((l = sr_serial_find_usb(scpi_serial_usb_ids[i].vendor_id,
-                                           scpi_serial_usb_ids[i].product_id)) == NULL)
-                       continue;
-               for (r = l; r; r = r->next) {
-                       if (scpi_serial_usb_ids[i].serialcomm)
-                               res = g_strdup_printf("%s:%s", (char *) r->data,
-                                                     scpi_serial_usb_ids[i].serialcomm);
-                       else
-                               res = g_strdup(r->data);
-                       resources = g_slist_append(resources, res);
-               }
-               g_slist_free_full(l, g_free);
-       }
-
-       return resources;
-}
-
-static int scpi_serial_dev_inst_new(void *priv, struct drv_context *drvc,
-               const char *resource, char **params, const char *serialcomm)
-{
-       struct scpi_serial *sscpi = priv;
-
-       (void)drvc;
-       (void)params;
-
-       if (!(sscpi->serial = sr_serial_dev_inst_new(resource, serialcomm)))
-               return SR_ERR;
-
-       return SR_OK;
-}
-
-static int scpi_serial_open(void *priv)
-{
-       struct scpi_serial *sscpi = priv;
-       struct sr_serial_dev_inst *serial = sscpi->serial;
-
-       if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
-               return SR_ERR;
-
-       if (serial_flush(serial) != SR_OK)
-               return SR_ERR;
-
-       sscpi->count = 0;
-       sscpi->read = 0;
-
-       return SR_OK;
-}
-
-static int scpi_serial_source_add(struct sr_session *session, void *priv,
-               int events, int timeout, sr_receive_data_callback cb, void *cb_data)
-{
-       struct scpi_serial *sscpi = priv;
-       struct sr_serial_dev_inst *serial = sscpi->serial;
-
-       return serial_source_add(session, serial, events, timeout, cb, cb_data);
-}
-
-static int scpi_serial_source_remove(struct sr_session *session, void *priv)
-{
-       struct scpi_serial *sscpi = priv;
-       struct sr_serial_dev_inst *serial = sscpi->serial;
-
-       return serial_source_remove(session, serial);
-}
-
-static int scpi_serial_send(void *priv, const char *command)
-{
-       int len, result, written;
-       gchar *terminated_command;
-       struct scpi_serial *sscpi = priv;
-       struct sr_serial_dev_inst *serial = sscpi->serial;
-
-       terminated_command = g_strconcat(command, "\n", NULL);
-       len = strlen(terminated_command);
-       written = 0;
-       while (written < len) {
-               result = serial_write(serial, terminated_command + written, len - written);
-               if (result < 0) {
-                       sr_err("Error while sending SCPI command: '%s'.", command);
-                       g_free(terminated_command);
-                       return SR_ERR;
-               }
-               written += result;
-       }
-
-       g_free(terminated_command);
-
-       sr_spew("Successfully sent SCPI command: '%s'.", command);
-
-       return SR_OK;
-}
-
-static int scpi_serial_read_begin(void *priv)
-{
-       (void) priv;
-
-       return SR_OK;
-}
-
-static int scpi_serial_read_data(void *priv, char *buf, int maxlen)
-{
-       struct scpi_serial *sscpi = priv;
-       int len, ret;
-
-       len = BUFFER_SIZE - sscpi->count;
-
-       /* Try to read new data into the buffer if there is space. */
-       if (len > 0) {
-               ret = serial_read(sscpi->serial, sscpi->buffer + sscpi->read,
-                               BUFFER_SIZE - sscpi->count);
-
-               if (ret < 0)
-                       return ret;
-
-               sscpi->count += ret;
-
-               if (ret > 0)
-                       sr_spew("Read %d bytes into buffer.", ret);
-       }
-
-       /* Return as many bytes as possible from buffer, excluding any trailing newline. */
-       if (sscpi->read < sscpi->count) {
-               len = sscpi->count - sscpi->read;
-               if (len > maxlen)
-                       len = maxlen;
-               if (sscpi->buffer[sscpi->read + len - 1] == '\n')
-                       len--;
-               sr_spew("Returning %d bytes from buffer.", len);
-               memcpy(buf, sscpi->buffer + sscpi->read, len);
-               sscpi->read += len;
-               if (sscpi->read == BUFFER_SIZE) {
-                       sr_spew("Resetting buffer.");
-                       sscpi->count = 0;
-                       sscpi->read = 0;
-               }
-               return len;
-       }
-
-       return 0;
-}
-
-static int scpi_serial_read_complete(void *priv)
-{
-       struct scpi_serial *sscpi = priv;
-
-       /* If the next character is a newline, discard it and report complete. */
-       if (sscpi->read < sscpi->count && sscpi->buffer[sscpi->read] == '\n') {
-               sscpi->read++;
-               return 1;
-       } else {
-               return 0;
-       }
-}
-
-static int scpi_serial_close(void *priv)
-{
-       struct scpi_serial *sscpi = priv;
-
-       return serial_close(sscpi->serial);
-}
-
-static void scpi_serial_free(void *priv)
-{
-       struct scpi_serial *sscpi = priv;
-
-       sr_serial_dev_inst_free(sscpi->serial);
-}
-
-SR_PRIV const struct sr_scpi_dev_inst scpi_serial_dev = {
-       .name          = "serial",
-       .prefix        = "",
-       .priv_size     = sizeof(struct scpi_serial),
-       .scan          = scpi_serial_scan,
-       .dev_inst_new  = scpi_serial_dev_inst_new,
-       .open          = scpi_serial_open,
-       .source_add    = scpi_serial_source_add,
-       .source_remove = scpi_serial_source_remove,
-       .send          = scpi_serial_send,
-       .read_begin    = scpi_serial_read_begin,
-       .read_data     = scpi_serial_read_data,
-       .read_complete = scpi_serial_read_complete,
-       .close         = scpi_serial_close,
-       .free          = scpi_serial_free,
-};
diff --git a/hardware/common/scpi_tcp.c b/hardware/common/scpi_tcp.c
deleted file mode 100644 (file)
index ef3a6c7..0000000
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Martin Ling <martin-sigrok@earth.li>
- *
- * 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/>.
- */
-
-#ifdef _WIN32
-#define _WIN32_WINNT 0x0501
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#endif
-
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#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>
-
-#define LOG_PREFIX "scpi_tcp"
-
-#define LENGTH_BYTES 4
-
-struct scpi_tcp {
-       char *address;
-       char *port;
-       int socket;
-       char length_buf[LENGTH_BYTES];
-       int length_bytes_read;
-       int response_length;
-       int response_bytes_read;
-};
-
-static int scpi_tcp_dev_inst_new(void *priv, struct drv_context *drvc,
-               const char *resource, char **params, const char *serialcomm)
-{
-       struct scpi_tcp *tcp = priv;
-
-       (void)drvc;
-       (void)resource;
-       (void)serialcomm;
-
-       if (!params || !params[1] || !params[2]) {
-               sr_err("Invalid parameters.");
-               return SR_ERR;
-       }
-
-       tcp->address = g_strdup(params[1]);
-       tcp->port    = g_strdup(params[2]);
-       tcp->socket  = -1;
-
-       return SR_OK;
-}
-
-static int scpi_tcp_open(void *priv)
-{
-       struct scpi_tcp *tcp = priv;
-       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(tcp->address, tcp->port, &hints, &results);
-
-       if (err) {
-               sr_err("Address lookup failed: %s:%d: %s", tcp->address, tcp->port,
-                       gai_strerror(err));
-               return SR_ERR;
-       }
-
-       for (res = results; res; res = res->ai_next) {
-               if ((tcp->socket = socket(res->ai_family, res->ai_socktype,
-                                               res->ai_protocol)) < 0)
-                       continue;
-               if (connect(tcp->socket, res->ai_addr, res->ai_addrlen) != 0) {
-                       close(tcp->socket);
-                       tcp->socket = -1;
-                       continue;
-               }
-               break;
-       }
-
-       freeaddrinfo(results);
-
-       if (tcp->socket < 0) {
-               sr_err("Failed to connect to %s:%s: %s", tcp->address, tcp->port,
-                               strerror(errno));
-               return SR_ERR;
-       }
-
-       return SR_OK;
-}
-
-static int scpi_tcp_source_add(struct sr_session *session, void *priv,
-               int events, int timeout, sr_receive_data_callback cb, void *cb_data)
-{
-       struct scpi_tcp *tcp = priv;
-
-       return sr_session_source_add(session, tcp->socket, events, timeout,
-                       cb, cb_data);
-}
-
-static int scpi_tcp_source_remove(struct sr_session *session, void *priv)
-{
-       struct scpi_tcp *tcp = priv;
-
-       return sr_session_source_remove(session, tcp->socket);
-}
-
-static int scpi_tcp_send(void *priv, const char *command)
-{
-       struct scpi_tcp *tcp = priv;
-       int len, out;
-       char *terminated_command;
-
-       terminated_command = g_strdup_printf("%s\r\n", command);
-       len = strlen(terminated_command);
-       out = send(tcp->socket, terminated_command, len, 0);
-       g_free(terminated_command);
-
-       if (out < 0) {
-               sr_err("Send error: %s", strerror(errno));
-               return SR_ERR;
-       }
-
-       if (out < len) {
-               sr_dbg("Only sent %d/%d bytes of SCPI command: '%s'.", out,
-                      len, command);
-       }
-
-       sr_spew("Successfully sent SCPI command: '%s'.", command);
-
-       return SR_OK;
-}
-
-static int scpi_tcp_read_begin(void *priv)
-{
-       struct scpi_tcp *tcp = priv;
-
-       tcp->response_bytes_read = 0;
-       tcp->length_bytes_read = 0;
-
-       return SR_OK;
-}
-
-static int scpi_tcp_raw_read_data(void *priv, char *buf, int maxlen)
-{
-       struct scpi_tcp *tcp = priv;
-       int len;
-
-       len = recv(tcp->socket, buf, maxlen, 0);
-
-       if (len < 0) {
-               sr_err("Receive error: %s", strerror(errno));
-               return SR_ERR;
-       }
-
-       tcp->length_bytes_read = LENGTH_BYTES;
-       tcp->response_length = len < maxlen ? len : maxlen + 1;
-       tcp->response_bytes_read = len;
-
-       return len;
-}
-
-static int scpi_tcp_rigol_read_data(void *priv, char *buf, int maxlen)
-{
-       struct scpi_tcp *tcp = priv;
-       int len;
-
-       if (tcp->length_bytes_read < LENGTH_BYTES) {
-               len = recv(tcp->socket, tcp->length_buf + tcp->length_bytes_read,
-                               LENGTH_BYTES - tcp->length_bytes_read, 0);
-               if (len < 0) {
-                       sr_err("Receive error: %s", strerror(errno));
-                       return SR_ERR;
-               }
-
-               tcp->length_bytes_read += len;
-
-               if (tcp->length_bytes_read < LENGTH_BYTES)
-                       return 0;
-               else
-                       tcp->response_length = RL32(tcp->length_buf);
-       }
-
-       if (tcp->response_bytes_read >= tcp->response_length)
-               return SR_ERR;
-
-       len = recv(tcp->socket, buf, maxlen, 0);
-
-       if (len < 0) {
-               sr_err("Receive error: %s", strerror(errno));
-               return SR_ERR;
-       }
-
-       tcp->response_bytes_read += len;
-
-       return len;
-}
-
-static int scpi_tcp_read_complete(void *priv)
-{
-       struct scpi_tcp *tcp = priv;
-
-       return (tcp->length_bytes_read == LENGTH_BYTES &&
-                       tcp->response_bytes_read >= tcp->response_length);
-}
-
-static int scpi_tcp_close(void *priv)
-{
-       struct scpi_tcp *tcp = priv;
-
-       if (close(tcp->socket) < 0)
-               return SR_ERR;
-
-       return SR_OK;
-}
-
-static void scpi_tcp_free(void *priv)
-{
-       struct scpi_tcp *tcp = priv;
-
-       g_free(tcp->address);
-       g_free(tcp->port);
-}
-
-SR_PRIV const struct sr_scpi_dev_inst scpi_tcp_raw_dev = {
-       .name          = "RAW TCP",
-       .prefix        = "tcp-raw",
-       .priv_size     = sizeof(struct scpi_tcp),
-       .dev_inst_new  = scpi_tcp_dev_inst_new,
-       .open          = scpi_tcp_open,
-       .source_add    = scpi_tcp_source_add,
-       .source_remove = scpi_tcp_source_remove,
-       .send          = scpi_tcp_send,
-       .read_begin    = scpi_tcp_read_begin,
-       .read_data     = scpi_tcp_raw_read_data,
-       .read_complete = scpi_tcp_read_complete,
-       .close         = scpi_tcp_close,
-       .free          = scpi_tcp_free,
-};
-
-SR_PRIV const struct sr_scpi_dev_inst scpi_tcp_rigol_dev = {
-       .name          = "RIGOL TCP",
-       .prefix        = "tcp-rigol",
-       .priv_size     = sizeof(struct scpi_tcp),
-       .dev_inst_new  = scpi_tcp_dev_inst_new,
-       .open          = scpi_tcp_open,
-       .source_add    = scpi_tcp_source_add,
-       .source_remove = scpi_tcp_source_remove,
-       .send          = scpi_tcp_send,
-       .read_begin    = scpi_tcp_read_begin,
-       .read_data     = scpi_tcp_rigol_read_data,
-       .read_complete = scpi_tcp_read_complete,
-       .close         = scpi_tcp_close,
-       .free          = scpi_tcp_free,
-};
diff --git a/hardware/common/scpi_usbtmc_libusb.c b/hardware/common/scpi_usbtmc_libusb.c
deleted file mode 100644 (file)
index c4470b5..0000000
+++ /dev/null
@@ -1,585 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <string.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "scpi_usbtmc"
-
-#define MAX_TRANSFER_LENGTH 2048
-#define TRANSFER_TIMEOUT 1000
-
-struct scpi_usbtmc_libusb {
-       struct sr_context *ctx;
-       struct sr_usb_dev_inst *usb;
-       int detached_kernel_driver;
-       uint8_t interface;
-       uint8_t bulk_in_ep;
-       uint8_t bulk_out_ep;
-       uint8_t interrupt_ep;
-       uint8_t usbtmc_int_cap;
-       uint8_t usbtmc_dev_cap;
-       uint8_t usb488_dev_cap;
-       uint8_t bTag;
-       uint8_t bulkin_attributes;
-       uint8_t buffer[MAX_TRANSFER_LENGTH];
-       int response_length;
-       int response_bytes_read;
-       int remaining_length;
-       int rigol_ds1000;
-};
-
-/* Some USBTMC-specific enums, as defined in the USBTMC standard. */
-#define SUBCLASS_USBTMC  0x03
-#define USBTMC_USB488    0x01
-
-enum {
-       /* USBTMC control requests */
-       INITIATE_ABORT_BULK_OUT     =   1,
-       CHECK_ABORT_BULK_OUT_STATUS =   2,
-       INITIATE_ABORT_BULK_IN      =   3,
-       CHECK_ABORT_BULK_IN_STATUS  =   4,
-       INITIATE_CLEAR              =   5,
-       CHECK_CLEAR_STATUS          =   6,
-       GET_CAPABILITIES            =   7,
-       INDICATOR_PULSE             =  64,
-
-       /* USB488 control requests */
-       READ_STATUS_BYTE            = 128,
-       REN_CONTROL                 = 160,
-       GO_TO_LOCAL                 = 161,
-       LOCAL_LOCKOUT               = 162,
-};
-
-/* USBTMC capabilities */
-#define USBTMC_INT_CAP_LISTEN_ONLY 0x01
-#define USBTMC_INT_CAP_TALK_ONLY   0x02
-#define USBTMC_INT_CAP_INDICATOR   0x04
-
-#define USBTMC_DEV_CAP_TERMCHAR    0x01
-
-#define USB488_DEV_CAP_DT1         0x01
-#define USB488_DEV_CAP_RL1         0x02
-#define USB488_DEV_CAP_SR1         0x04
-#define USB488_DEV_CAP_SCPI        0x08
-
-/* Bulk messages constants */
-#define USBTMC_BULK_HEADER_SIZE  12
-
-/* Bulk MsgID values */
-#define DEV_DEP_MSG_OUT         1
-#define REQUEST_DEV_DEP_MSG_IN  2
-#define DEV_DEP_MSG_IN          2
-
-/* bmTransferAttributes */
-#define EOM                0x01
-#define TERM_CHAR_ENABLED  0x02
-
-
-static GSList *scpi_usbtmc_libusb_scan(struct drv_context *drvc)
-{
-       struct libusb_device **devlist;
-       struct libusb_device_descriptor des;
-       struct libusb_config_descriptor *confdes;
-       const struct libusb_interface_descriptor *intfdes;
-       GSList *resources = NULL;
-       int confidx, intfidx, ret, i;
-       char *res;
-
-       ret = libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
-       if (ret < 0) {
-               sr_err("Failed to get device list: %s.",
-                      libusb_error_name(ret));
-               return NULL;
-       }
-       for (i = 0; devlist[i]; i++) {
-               if ((ret = libusb_get_device_descriptor(devlist[i], &des)) < 0) {
-                       sr_err("Failed to get device descriptor: %s.",
-                              libusb_error_name(ret));
-                       continue;
-               }
-
-               for (confidx = 0; confidx < des.bNumConfigurations; confidx++) {
-                       if ((ret = libusb_get_config_descriptor(devlist[i], confidx, &confdes)) < 0) {
-                               sr_dbg("Failed to get configuration descriptor: %s, "
-                                      "ignoring device.", libusb_error_name(ret));
-                               break;
-                       }
-                       for (intfidx = 0; intfidx < confdes->bNumInterfaces; intfidx++) {
-                               intfdes = confdes->interface[intfidx].altsetting;
-                               if (intfdes->bInterfaceClass    != LIBUSB_CLASS_APPLICATION ||
-                                   intfdes->bInterfaceSubClass != SUBCLASS_USBTMC          ||
-                                   intfdes->bInterfaceProtocol != USBTMC_USB488)
-                                       continue;
-                               sr_dbg("Found USBTMC device (VID:PID = %04x:%04x, "
-                                      "bus.address = %d.%d).", des.idVendor, des.idProduct,
-                                      libusb_get_bus_number(devlist[i]),
-                                      libusb_get_device_address(devlist[i]));
-                               res = g_strdup_printf("usbtmc/%d.%d",
-                                                     libusb_get_bus_number(devlist[i]),
-                                                     libusb_get_device_address(devlist[i]));
-                               resources = g_slist_append(resources, res);
-                       }
-                       libusb_free_config_descriptor(confdes);
-               }
-       }
-       libusb_free_device_list(devlist, 1);
-
-       sr_dbg("Found %d device(s).", g_slist_length(resources));
-
-       return resources;
-}
-
-static int scpi_usbtmc_libusb_dev_inst_new(void *priv, struct drv_context *drvc,
-               const char *resource, char **params, const char *serialcomm)
-{
-       struct scpi_usbtmc_libusb *uscpi = priv;
-       GSList *devices;
-
-       (void)resource;
-       (void)serialcomm;
-
-       if (!params || !params[1]) {
-               sr_err("Invalid parameters.");
-               return SR_ERR;
-       }
-
-       uscpi->ctx = drvc->sr_ctx;
-       devices = sr_usb_find(uscpi->ctx->libusb_ctx, params[1]);
-       if (g_slist_length(devices) != 1) {
-               sr_err("Failed to find USB device '%s'.", params[1]);
-               g_slist_free_full(devices, (GDestroyNotify)sr_usb_dev_inst_free);
-               return SR_ERR;
-       }
-       uscpi->usb = devices->data;
-       g_slist_free(devices);
-
-       return SR_OK;
-}
-
-static int scpi_usbtmc_libusb_open(void *priv)
-{
-       struct scpi_usbtmc_libusb *uscpi = priv;
-       struct sr_usb_dev_inst *usb = uscpi->usb;
-       struct libusb_device *dev;
-       struct libusb_device_descriptor des;
-       struct libusb_config_descriptor *confdes;
-       const struct libusb_interface_descriptor *intfdes;
-       const struct libusb_endpoint_descriptor *ep;
-       int confidx, intfidx, epidx, config = 0;
-       uint8_t capabilities[24];
-       int ret, found = 0;
-
-       if (usb->devhdl)
-               return SR_OK;
-
-       if (sr_usb_open(uscpi->ctx->libusb_ctx, usb) != SR_OK)
-               return SR_ERR;
-
-       dev = libusb_get_device(usb->devhdl);
-       if ((ret = libusb_get_device_descriptor(dev, &des)) < 0) {
-               sr_err("Failed to get device descriptor: %s.",
-                      libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-       for (confidx = 0; confidx < des.bNumConfigurations; confidx++) {
-               if ((ret = libusb_get_config_descriptor(dev, confidx, &confdes)) < 0) {
-                       sr_dbg("Failed to get configuration descriptor: %s, "
-                              "ignoring device.", libusb_error_name(ret));
-                       continue;
-               }
-               for (intfidx = 0; intfidx < confdes->bNumInterfaces; intfidx++) {
-                       intfdes = confdes->interface[intfidx].altsetting;
-                       if (intfdes->bInterfaceClass    != LIBUSB_CLASS_APPLICATION ||
-                           intfdes->bInterfaceSubClass != SUBCLASS_USBTMC          ||
-                           intfdes->bInterfaceProtocol != USBTMC_USB488)
-                               continue;
-                       uscpi->interface = intfdes->bInterfaceNumber;
-                       sr_dbg("Interface %d", uscpi->interface);
-                       config = confdes->bConfigurationValue;
-                       sr_dbg("Configuration %d", config);
-                       for (epidx = 0; epidx < intfdes->bNumEndpoints; epidx++) {
-                               ep = &intfdes->endpoint[epidx];
-                               if (ep->bmAttributes == LIBUSB_TRANSFER_TYPE_BULK &&
-                                   !(ep->bEndpointAddress & (LIBUSB_ENDPOINT_DIR_MASK))) {
-                                       uscpi->bulk_out_ep = ep->bEndpointAddress;
-                                       sr_dbg("Bulk OUT EP %d", uscpi->bulk_out_ep);
-                               }
-                               if (ep->bmAttributes == LIBUSB_TRANSFER_TYPE_BULK &&
-                                   ep->bEndpointAddress & (LIBUSB_ENDPOINT_DIR_MASK)) {
-                                       uscpi->bulk_in_ep = ep->bEndpointAddress;
-                                       sr_dbg("Bulk IN EP %d", uscpi->bulk_in_ep);
-                               }
-                               if (ep->bmAttributes == LIBUSB_TRANSFER_TYPE_INTERRUPT &&
-                                   ep->bEndpointAddress & (LIBUSB_ENDPOINT_DIR_MASK)) {
-                                       uscpi->interrupt_ep = ep->bEndpointAddress;
-                                       sr_dbg("Interrupt EP %d", uscpi->interrupt_ep);
-                               }
-                       }
-                       found = 1;
-                       uscpi->rigol_ds1000 = des.idVendor  == 0x1ab1 &&
-                                             des.idProduct == 0x0588;
-               }
-               libusb_free_config_descriptor(confdes);
-               if (found)
-                       break;
-       }
-
-       if (!found) {
-               sr_err("Failed to find USBTMC interface.");
-               return SR_ERR;
-       }
-
-       if (libusb_kernel_driver_active(usb->devhdl, uscpi->interface) == 1) {
-               if ((ret = libusb_detach_kernel_driver(usb->devhdl,
-                                                      uscpi->interface)) < 0) {
-                       sr_err("Failed to detach kernel driver: %s.",
-                              libusb_error_name(ret));
-                       return SR_ERR;
-               }
-               uscpi->detached_kernel_driver = 1;
-       }
-
-       if ((ret = libusb_set_configuration(usb->devhdl, config)) < 0) {
-               sr_err("Failed to set configuration: %s.",
-                      libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-       if ((ret = libusb_claim_interface(usb->devhdl, uscpi->interface)) < 0) {
-               sr_err("Failed to claim interface: %s.",
-                      libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-       if (!uscpi->rigol_ds1000) {
-       if ((ret = libusb_clear_halt(usb->devhdl, uscpi->bulk_in_ep)) < 0) {
-               sr_err("Failed to clear halt/stall condition for EP %d: %s.",
-                      uscpi->bulk_in_ep, libusb_error_name(ret));
-               return SR_ERR;
-       }
-       if ((ret = libusb_clear_halt(usb->devhdl, uscpi->bulk_out_ep)) < 0) {
-               sr_err("Failed to clear halt/stall condition for EP %d: %s.",
-                      uscpi->bulk_out_ep, libusb_error_name(ret));
-               return SR_ERR;
-       }
-       if ((ret = libusb_clear_halt(usb->devhdl, uscpi->interrupt_ep)) < 0) {
-               sr_err("Failed to clear halt/stall condition for EP %d: %s.",
-                      uscpi->interrupt_ep, libusb_error_name(ret));
-               return SR_ERR;
-       }
-       }
-
-       /* Get capabilities. */
-       ret = libusb_control_transfer(usb->devhdl,
-                                     LIBUSB_ENDPOINT_IN         |
-                                     LIBUSB_REQUEST_TYPE_CLASS  |
-                                     LIBUSB_RECIPIENT_INTERFACE,
-                                     GET_CAPABILITIES, 0,
-                                     uscpi->interface,
-                                     capabilities, sizeof(capabilities),
-                                     TRANSFER_TIMEOUT);
-       if (ret == sizeof(capabilities)) {
-               uscpi->usbtmc_int_cap = capabilities[ 4];
-               uscpi->usbtmc_dev_cap = capabilities[ 5];
-               uscpi->usb488_dev_cap = capabilities[15];
-       }
-       sr_dbg("Device capabilities: %s%s%s%s%s, %s, %s",
-              uscpi->usb488_dev_cap & USB488_DEV_CAP_SCPI       ? "SCPI, "    : "",
-              uscpi->usbtmc_dev_cap & USBTMC_DEV_CAP_TERMCHAR   ? "TermChar, ": "",
-              uscpi->usbtmc_int_cap & USBTMC_INT_CAP_LISTEN_ONLY? "L3, " :
-              uscpi->usbtmc_int_cap & USBTMC_INT_CAP_TALK_ONLY  ? ""     : "L4, ",
-              uscpi->usbtmc_int_cap & USBTMC_INT_CAP_TALK_ONLY  ? "T5, " :
-              uscpi->usbtmc_int_cap & USBTMC_INT_CAP_LISTEN_ONLY? ""     : "T6, ",
-              uscpi->usb488_dev_cap & USB488_DEV_CAP_SR1        ? "SR1"  : "SR0",
-              uscpi->usb488_dev_cap & USB488_DEV_CAP_RL1        ? "RL1"  : "RL0",
-              uscpi->usb488_dev_cap & USB488_DEV_CAP_DT1        ? "DT1"  : "DT0");
-
-       return SR_OK;
-}
-
-static int scpi_usbtmc_libusb_source_add(struct sr_session *session,
-               void *priv, int events, int timeout, sr_receive_data_callback cb,
-               void *cb_data)
-{
-       struct scpi_usbtmc_libusb *uscpi = priv;
-       (void)events;
-       return usb_source_add(session, uscpi->ctx, timeout, cb, cb_data);
-}
-
-static int scpi_usbtmc_libusb_source_remove(struct sr_session *session,
-               void *priv)
-{
-       struct scpi_usbtmc_libusb *uscpi = priv;
-       return usb_source_remove(session, uscpi->ctx);
-}
-
-static void usbtmc_bulk_out_header_write(void *header, uint8_t MsgID,
-                                         uint8_t bTag,
-                                         uint32_t TransferSize,
-                                         uint8_t bmTransferAttributes,
-                                         char TermChar)
-{
-         W8(header+ 0, MsgID);
-         W8(header+ 1, bTag);
-         W8(header+ 2, ~bTag);
-         W8(header+ 3, 0);
-       WL32(header+ 4, TransferSize);
-         W8(header+ 8, bmTransferAttributes);
-         W8(header+ 9, TermChar);
-       WL16(header+10, 0);
-}
-
-static int usbtmc_bulk_in_header_read(void *header, uint8_t MsgID,
-                                      unsigned char bTag,
-                                      int32_t *TransferSize,
-                                      uint8_t *bmTransferAttributes)
-{
-       if (R8(header+0) != MsgID ||
-           R8(header+1) != bTag  ||
-           R8(header+2) != (unsigned char)~bTag)
-               return SR_ERR;
-       if (TransferSize)
-               *TransferSize = RL32(header+4);
-       if (bmTransferAttributes)
-               *bmTransferAttributes = R8(header+8);
-       return SR_OK;
-}
-
-static int scpi_usbtmc_bulkout(struct scpi_usbtmc_libusb *uscpi,
-                               uint8_t msg_id, const void *data, int32_t size,
-                               uint8_t transfer_attributes)
-{
-       struct sr_usb_dev_inst *usb = uscpi->usb;
-       int padded_size, ret, transferred;
-
-       if (data && size+USBTMC_BULK_HEADER_SIZE+3 > (int)sizeof(uscpi->buffer)) {
-               sr_err("USBTMC bulk out transfer is too big.");
-               return SR_ERR;
-       }
-
-       uscpi->bTag++;
-       uscpi->bTag += !uscpi->bTag;  /* bTag == 0 is invalid so avoid it. */
-
-       usbtmc_bulk_out_header_write(uscpi->buffer, msg_id, uscpi->bTag,
-                                    size, transfer_attributes, 0);
-       if (data)
-               memcpy(uscpi->buffer+USBTMC_BULK_HEADER_SIZE, data, size);
-       else
-               size = 0;
-       size += USBTMC_BULK_HEADER_SIZE;
-       padded_size = (size + 3) & ~0x3;
-       memset(uscpi->buffer+size, 0, padded_size - size);
-
-       ret = libusb_bulk_transfer(usb->devhdl, uscpi->bulk_out_ep,
-                                  uscpi->buffer, padded_size, &transferred,
-                                  TRANSFER_TIMEOUT);
-       if (ret < 0) {
-               sr_err("USBTMC bulk out transfer error: %s.",
-                      libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-       if (transferred < padded_size) {
-               sr_dbg("USBTMC bulk out partial transfer (%d/%d bytes).",
-                      transferred, padded_size);
-               return SR_ERR;
-       }
-
-       return transferred - USBTMC_BULK_HEADER_SIZE;
-}
-
-static int scpi_usbtmc_bulkin_start(struct scpi_usbtmc_libusb *uscpi,
-                                    uint8_t msg_id, void *data, int32_t size,
-                                    uint8_t *transfer_attributes)
-{
-       struct sr_usb_dev_inst *usb = uscpi->usb;
-       int ret, transferred, message_size;
-
-       ret = libusb_bulk_transfer(usb->devhdl, uscpi->bulk_in_ep, data, size,
-                                  &transferred, TRANSFER_TIMEOUT);
-       if (ret < 0) {
-               sr_err("USBTMC bulk in transfer error: %s.",
-                      libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-       if (usbtmc_bulk_in_header_read(data, msg_id, uscpi->bTag, &message_size,
-                                      transfer_attributes) != SR_OK) {
-               sr_err("USBTMC invalid bulk in header.");
-               return SR_ERR;
-       }
-
-       message_size += USBTMC_BULK_HEADER_SIZE;
-       uscpi->response_length = MIN(transferred, message_size);
-       uscpi->response_bytes_read = USBTMC_BULK_HEADER_SIZE;
-       uscpi->remaining_length = message_size - uscpi->response_length;
-
-       return transferred - USBTMC_BULK_HEADER_SIZE;
-}
-
-static int scpi_usbtmc_bulkin_continue(struct scpi_usbtmc_libusb *uscpi,
-                                       void *data, int size)
-{
-       struct sr_usb_dev_inst *usb = uscpi->usb;
-       int ret, transferred;
-
-       ret = libusb_bulk_transfer(usb->devhdl, uscpi->bulk_in_ep, data, size,
-                                  &transferred, TRANSFER_TIMEOUT);
-       if (ret < 0) {
-               sr_err("USBTMC bulk in transfer error: %s.",
-                      libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-       uscpi->response_length = MIN(transferred, uscpi->remaining_length);
-       uscpi->response_bytes_read = 0;
-       uscpi->remaining_length -= uscpi->response_length;
-
-       return transferred;
-}
-
-static int scpi_usbtmc_libusb_send(void *priv, const char *command)
-{
-       struct scpi_usbtmc_libusb *uscpi = priv;
-
-       if (scpi_usbtmc_bulkout(uscpi, DEV_DEP_MSG_OUT,
-                               command, strlen(command), EOM) <= 0)
-               return SR_ERR;
-
-       sr_spew("Successfully sent SCPI command: '%s'.", command);
-
-       return SR_OK;
-}
-
-static int scpi_usbtmc_libusb_read_begin(void *priv)
-{
-       struct scpi_usbtmc_libusb *uscpi = priv;
-
-       uscpi->remaining_length = 0;
-
-       if (scpi_usbtmc_bulkout(uscpi, REQUEST_DEV_DEP_MSG_IN,
-           NULL, INT32_MAX, 0) < 0)
-               return SR_ERR;
-       if (scpi_usbtmc_bulkin_start(uscpi, DEV_DEP_MSG_IN,
-                                    uscpi->buffer, sizeof(uscpi->buffer),
-                                    &uscpi->bulkin_attributes) < 0)
-               return SR_ERR;
-
-       return SR_OK;
-}
-
-static int scpi_usbtmc_libusb_read_data(void *priv, char *buf, int maxlen)
-{
-       struct scpi_usbtmc_libusb *uscpi = priv;
-       int read_length;
-
-       if (uscpi->response_bytes_read >= uscpi->response_length) {
-               if (uscpi->remaining_length > 0) {
-                       if (scpi_usbtmc_bulkin_continue(uscpi, uscpi->buffer,
-                                                       sizeof(uscpi->buffer)) <= 0)
-                               return SR_ERR;
-               } else {
-                       if (uscpi->bulkin_attributes & EOM)
-                               return SR_ERR;
-                       if (scpi_usbtmc_libusb_read_begin(uscpi) < 0)
-                               return SR_ERR;
-               }
-       }
-
-       read_length = MIN(uscpi->response_length - uscpi->response_bytes_read, maxlen);
-
-       memcpy(buf, uscpi->buffer + uscpi->response_bytes_read, read_length);
-
-       uscpi->response_bytes_read += read_length;
-
-       return read_length;
-}
-
-static int scpi_usbtmc_libusb_read_complete(void *priv)
-{
-       struct scpi_usbtmc_libusb *uscpi = priv;
-       return uscpi->response_bytes_read >= uscpi->response_length &&
-              uscpi->remaining_length <= 0 &&
-              uscpi->bulkin_attributes & EOM;
-}
-
-static int scpi_usbtmc_libusb_close(void *priv)
-{
-       int ret;
-       struct scpi_usbtmc_libusb *uscpi = priv;
-       struct sr_usb_dev_inst *usb = uscpi->usb;
-
-       if (!usb->devhdl)
-               return SR_ERR;
-
-       if (!uscpi->rigol_ds1000) {
-       if ((ret = libusb_clear_halt(usb->devhdl, uscpi->bulk_in_ep)) < 0)
-               sr_err("Failed to clear halt/stall condition for EP %d: %s.",
-                      uscpi->bulk_in_ep, libusb_error_name(ret));
-       if ((ret = libusb_clear_halt(usb->devhdl, uscpi->bulk_out_ep)) < 0)
-               sr_err("Failed to clear halt/stall condition for EP %d: %s.",
-                      uscpi->bulk_out_ep, libusb_error_name(ret));
-       if ((ret = libusb_clear_halt(usb->devhdl, uscpi->interrupt_ep)) < 0)
-               sr_err("Failed to clear halt/stall condition for EP %d: %s.",
-                      uscpi->interrupt_ep, libusb_error_name(ret));
-       }
-
-       if ((ret = libusb_release_interface(usb->devhdl, uscpi->interface)) < 0)
-               sr_err("Failed to release interface: %s.",
-                      libusb_error_name(ret));
-       
-       if (uscpi->detached_kernel_driver) {
-               if ((ret = libusb_attach_kernel_driver(usb->devhdl,
-                                               uscpi->interface)) < 0)
-                       sr_err("Failed to re-attach kernel driver: %s.",
-                              libusb_error_name(ret));
-
-               uscpi->detached_kernel_driver = 0;
-       }
-       libusb_close(usb->devhdl);
-       usb->devhdl = NULL;
-
-       return SR_OK;
-}
-
-static void scpi_usbtmc_libusb_free(void *priv)
-{
-       struct scpi_usbtmc_libusb *uscpi = priv;
-       sr_usb_dev_inst_free(uscpi->usb);
-}
-
-SR_PRIV const struct sr_scpi_dev_inst scpi_usbtmc_libusb_dev = {
-       .name          = "USBTMC",
-       .prefix        = "usbtmc",
-       .priv_size     = sizeof(struct scpi_usbtmc_libusb),
-       .scan          = scpi_usbtmc_libusb_scan,
-       .dev_inst_new  = scpi_usbtmc_libusb_dev_inst_new,
-       .open          = scpi_usbtmc_libusb_open,
-       .source_add    = scpi_usbtmc_libusb_source_add,
-       .source_remove = scpi_usbtmc_libusb_source_remove,
-       .send          = scpi_usbtmc_libusb_send,
-       .read_begin    = scpi_usbtmc_libusb_read_begin,
-       .read_data     = scpi_usbtmc_libusb_read_data,
-       .read_complete = scpi_usbtmc_libusb_read_complete,
-       .close         = scpi_usbtmc_libusb_close,
-       .free          = scpi_usbtmc_libusb_free,
-};
diff --git a/hardware/common/scpi_visa.c b/hardware/common/scpi_visa.c
deleted file mode 100644 (file)
index cf34a55..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Martin Ling <martin-sigrok@earth.li>
- *
- * 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 "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#include <visa.h>
-#include <string.h>
-
-#define LOG_PREFIX "scpi_visa"
-
-struct scpi_visa {
-       char *resource;
-       ViSession rmgr;
-       ViSession vi;
-};
-
-static int scpi_visa_dev_inst_new(void *priv, struct drv_context *drvc,
-               const char *resource, char **params, const char *serialcomm)
-{
-       struct scpi_visa *vscpi = priv;
-
-       (void)drvc;
-       (void)resource;
-       (void)serialcomm;
-
-       if (!params || !params[1]) {
-               sr_err("Invalid parameters.");
-               return SR_ERR_BUG;
-       }
-
-       vscpi->resource = g_strdup(params[1]);
-
-       return SR_OK;
-}
-
-static int scpi_visa_open(void *priv)
-{
-       struct scpi_visa *vscpi = priv;
-
-       if (viOpenDefaultRM(&vscpi->rmgr) != VI_SUCCESS) {
-               sr_err("Cannot open default resource manager.");
-               return SR_ERR;
-       }
-
-       if (viOpen(vscpi->rmgr, vscpi->resource, VI_NO_LOCK, 0, &vscpi->vi) != VI_SUCCESS) {
-               sr_err("Cannot open resource.");
-               return SR_ERR;
-       }
-
-       return SR_OK;
-}
-
-static int scpi_visa_source_add(struct sr_session *session, void *priv,
-               int events, int timeout, sr_receive_data_callback cb, void *cb_data)
-{
-       (void) priv;
-
-       /* Hook up a dummy handler to receive data from the device. */
-       return sr_session_source_add(session, -1, events, timeout, cb, cb_data);
-}
-
-static int scpi_visa_source_remove(struct sr_session *session, void *priv)
-{
-       (void) priv;
-
-       return sr_session_source_remove(session, -1);
-}
-
-static int scpi_visa_send(void *priv, const char *command)
-{
-       struct scpi_visa *vscpi = priv;
-       gchar *terminated_command;
-       ViUInt32 written = 0;
-       int len;
-
-       terminated_command = g_strconcat(command, "\n", NULL);
-       len = strlen(terminated_command);
-       if (viWrite(vscpi->vi, (ViBuf) (terminated_command + written), len,
-                       &written) != VI_SUCCESS) {
-               sr_err("Error while sending SCPI command: '%s'.", command);
-               g_free(terminated_command);
-               return SR_ERR;
-       }
-
-       g_free(terminated_command);
-
-       sr_spew("Successfully sent SCPI command: '%s'.", command);
-
-       return SR_OK;
-}
-
-static int scpi_visa_read_begin(void *priv)
-{
-       (void) priv;
-
-       return SR_OK;
-}
-
-static int scpi_visa_read_data(void *priv, char *buf, int maxlen)
-{
-       struct scpi_visa *vscpi = priv;
-       ViUInt32 count;
-
-       if (viRead(vscpi->vi, (ViBuf) buf, maxlen, &count) != VI_SUCCESS) {
-               sr_err("Read failed.");
-               return SR_ERR;
-       }
-
-       return count;
-}
-
-static int scpi_visa_read_complete(void *priv)
-{
-       struct scpi_visa *vscpi = priv;
-       ViUInt16 status;
-
-       if (viReadSTB(vscpi->vi, &status) != VI_SUCCESS) {
-               sr_err("Failed to read status.");
-               return SR_ERR;
-       }
-
-       return !(status & 16);
-}
-
-static int scpi_visa_close(void *priv)
-{
-       struct scpi_visa *vscpi = priv;
-
-       viClose(vscpi->vi);
-       viClose(vscpi->rmgr);
-
-       return SR_OK;
-}
-
-static void scpi_visa_free(void *priv)
-{
-       struct scpi_visa *vscpi = priv;
-
-       g_free(vscpi->resource);
-       g_free(vscpi);
-}
-
-SR_PRIV const struct sr_scpi_dev_inst scpi_visa_dev = {
-       .name = "VISA",
-       .prefix = "visa",
-       .priv_size = sizeof(struct scpi_visa),
-       .dev_inst_new = scpi_visa_dev_inst_new,
-       .open = scpi_visa_open,
-       .source_add = scpi_visa_source_add,
-       .source_remove = scpi_visa_source_remove,
-       .send = scpi_visa_send,
-       .read_begin = scpi_visa_read_begin,
-       .read_data = scpi_visa_read_data,
-       .read_complete = scpi_visa_read_complete,
-       .close = scpi_visa_close,
-       .free = scpi_visa_free,
-};
diff --git a/hardware/common/scpi_vxi.c b/hardware/common/scpi_vxi.c
deleted file mode 100644 (file)
index 271917b..0000000
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
- *
- * Inspired by the VXI11 Ethernet Protocol for Linux:
- * http://optics.eee.nottingham.ac.uk/vxi11/
- *
- * 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 <rpc/rpc.h>
-#include <string.h>
-
-#include "vxi.h"
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "scpi_vxi"
-#define VXI_DEFAULT_TIMEOUT  2000  /* in ms */
-
-struct scpi_vxi {
-       char *address;
-       char *instrument;
-       CLIENT *client;
-       Device_Link link;
-       unsigned int max_send_size;
-       unsigned int read_complete;
-};
-
-static int scpi_vxi_dev_inst_new(void *priv, struct drv_context *drvc,
-               const char *resource, char **params, const char *serialcomm)
-{
-       struct scpi_vxi *vxi = priv;
-
-       (void)drvc;
-       (void)resource;
-       (void)serialcomm;
-
-       if (!params || !params[1]) {
-               sr_err("Invalid parameters.");
-               return SR_ERR;
-       }
-
-       vxi->address    = g_strdup(params[1]);
-       vxi->instrument = g_strdup(params[2] ? params[2] : "inst0");
-
-       return SR_OK;
-}
-
-static int scpi_vxi_open(void *priv)
-{
-       struct scpi_vxi *vxi = priv;
-       Create_LinkParms link_parms;
-       Create_LinkResp *link_resp;
-
-       vxi->client = clnt_create(vxi->address, DEVICE_CORE, DEVICE_CORE_VERSION, "tcp");
-       if (vxi->client == NULL) {
-               sr_err("Client creation failed for %s", vxi->address);
-               return SR_ERR;
-       }
-
-       /* Set link parameters */
-       link_parms.clientId = (long) vxi->client;
-       link_parms.lockDevice = 0;
-       link_parms.lock_timeout = VXI_DEFAULT_TIMEOUT;
-       link_parms.device = "inst0";
-
-       if (!(link_resp = create_link_1(&link_parms, vxi->client))) {
-               sr_err("Link creation failed for %s", vxi->address);
-               return SR_ERR;
-       }
-       vxi->link = link_resp->lid;
-       vxi->max_send_size = link_resp->maxRecvSize;
-
-       /* Set a default maxRecvSize for devices which do not specify it */
-       if (vxi->max_send_size <= 0)
-               vxi->max_send_size = 4096;
-
-       return SR_OK;
-}
-
-static int scpi_vxi_source_add(struct sr_session *session, void *priv,
-               int events, int timeout, sr_receive_data_callback cb, void *cb_data)
-{
-       (void)priv;
-
-       /* Hook up a dummy handler to receive data from the device. */
-       return sr_session_source_add(session, -1, events, timeout, cb, cb_data);
-}
-
-static int scpi_vxi_source_remove(struct sr_session *session, void *priv)
-{
-       (void)priv;
-
-       return sr_session_source_remove(session, -1);
-}
-
-/* Operation Flags */
-#define DF_WAITLOCK  0x01  /* wait if the operation is locked by another link */
-#define DF_END       0x08  /* an END indicator is sent with last byte of buffer */
-#define DF_TERM      0x80  /* a termination char is set during a read */
-
-static int scpi_vxi_send(void *priv, const char *command)
-{
-       struct scpi_vxi *vxi = priv;
-       Device_WriteResp *write_resp;
-       Device_WriteParms write_parms;
-       char *terminated_command;
-       unsigned int len;
-
-       terminated_command = g_strdup_printf("%s\r\n", command);
-       len = strlen(terminated_command);
-
-       write_parms.lid           = vxi->link;
-       write_parms.io_timeout    = VXI_DEFAULT_TIMEOUT;
-       write_parms.lock_timeout  = VXI_DEFAULT_TIMEOUT;
-       write_parms.flags         = DF_END;
-       write_parms.data.data_len = MIN(len, vxi->max_send_size);
-       write_parms.data.data_val = terminated_command;
-
-       if (!(write_resp = device_write_1(&write_parms, vxi->client))
-           || write_resp->error) {
-               sr_err("Device write failed for %s with error %d",
-                      vxi->address, write_resp->error);
-               return SR_ERR;
-       }
-
-       g_free(terminated_command);
-
-       if (write_resp->size < len)
-               sr_dbg("Only sent %d/%d bytes of SCPI command: '%s'.",
-                      write_resp->size, len, command);
-       else
-               sr_spew("Successfully sent SCPI command: '%s'.", command);
-
-       return SR_OK;
-}
-
-static int scpi_vxi_read_begin(void *priv)
-{
-       struct scpi_vxi *vxi = priv;
-
-       vxi->read_complete = 0;
-
-       return SR_OK;
-}
-
-/* Read Response Reason Flags */
-#define RRR_SIZE  0x01  /* requestSize bytes have been transferred */
-#define RRR_TERM  0x02  /* a termination char has been read */
-#define RRR_END   0x04  /* an END indicator has been read */
-
-static int scpi_vxi_read_data(void *priv, char *buf, int maxlen)
-{
-       struct scpi_vxi *vxi = priv;
-       Device_ReadParms read_parms;
-       Device_ReadResp *read_resp;
-
-       read_parms.lid          = vxi->link;
-       read_parms.io_timeout   = VXI_DEFAULT_TIMEOUT;
-       read_parms.lock_timeout = VXI_DEFAULT_TIMEOUT;
-       read_parms.flags        = 0;
-       read_parms.termChar     = 0;
-       read_parms.requestSize  = maxlen;
-
-       if (!(read_resp = device_read_1(&read_parms, vxi->client))
-           || read_resp->error) {
-               sr_err("Device read failed for %s with error %d",
-                      vxi->address, read_resp->error);
-               return SR_ERR;
-       }
-
-       memcpy(buf, read_resp->data.data_val, read_resp->data.data_len);
-       vxi->read_complete = read_resp->reason & (RRR_SIZE | RRR_TERM | RRR_END);
-       return read_resp->data.data_len;  /* actual number of bytes received */
-}
-
-static int scpi_vxi_read_complete(void *priv)
-{
-       struct scpi_vxi *vxi = priv;
-
-       return vxi->read_complete;
-}
-
-static int scpi_vxi_close(void *priv)
-{
-       struct scpi_vxi *vxi = priv;
-       Device_Error *dev_error;
-
-       if (!vxi->client)
-               return SR_ERR;
-
-       if (!(dev_error = destroy_link_1(&vxi->link, vxi->client))) {
-               sr_err("Link destruction failed for %s", vxi->address);
-               return SR_ERR;
-       }
-
-       clnt_destroy(vxi->client);
-       vxi->client = NULL;
-
-       return SR_OK;
-}
-
-static void scpi_vxi_free(void *priv)
-{
-       struct scpi_vxi *vxi = priv;
-
-       g_free(vxi->address);
-       g_free(vxi->instrument);
-}
-
-SR_PRIV const struct sr_scpi_dev_inst scpi_vxi_dev = {
-       .name          = "VXI",
-       .prefix        = "vxi",
-       .priv_size     = sizeof(struct scpi_vxi),
-       .dev_inst_new  = scpi_vxi_dev_inst_new,
-       .open          = scpi_vxi_open,
-       .source_add    = scpi_vxi_source_add,
-       .source_remove = scpi_vxi_source_remove,
-       .send          = scpi_vxi_send,
-       .read_begin    = scpi_vxi_read_begin,
-       .read_data     = scpi_vxi_read_data,
-       .read_complete = scpi_vxi_read_complete,
-       .close         = scpi_vxi_close,
-       .free          = scpi_vxi_free,
-};
diff --git a/hardware/common/serial.c b/hardware/common/serial.c
deleted file mode 100644 (file)
index 9a9a0d9..0000000
+++ /dev/null
@@ -1,911 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com>
- * Copyright (C) 2010-2012 Uwe Hermann <uwe@hermann-uwe.de>
- * 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 <string.h>
-#include <stdlib.h>
-#include <glib.h>
-#include <glib/gstdio.h>
-#include <libserialport.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "serial"
-
-/**
- * Open the specified serial port.
- *
- * @param serial Previously initialized serial port structure.
- * @param[in] flags Flags to use when opening the serial port. Possible flags
- *              include SERIAL_RDWR, SERIAL_RDONLY, SERIAL_NONBLOCK.
- *
- * If the serial structure contains a serialcomm string, it will be
- * passed to serial_set_paramstr() after the port is opened.
- *
- * @retval SR_OK Success.
- * @retval SR_ERR Failure.
- */
-SR_PRIV int serial_open(struct sr_serial_dev_inst *serial, int flags)
-{
-       int ret;
-       char *error;
-       int sp_flags = 0;
-
-       if (!serial) {
-               sr_dbg("Invalid serial port.");
-               return SR_ERR;
-       }
-
-       sr_spew("Opening serial port '%s' (flags %d).", serial->port, flags);
-
-       sp_get_port_by_name(serial->port, &serial->data);
-
-       if (flags & SERIAL_RDWR)
-               sp_flags = (SP_MODE_READ | SP_MODE_WRITE);
-       else if (flags & SERIAL_RDONLY)
-               sp_flags = SP_MODE_READ;
-
-       serial->nonblocking = (flags & SERIAL_NONBLOCK) ? 1 : 0;
-
-       ret = sp_open(serial->data, sp_flags);
-
-       switch (ret) {
-       case SP_ERR_ARG:
-               sr_err("Attempt to open serial port with invalid parameters.");
-               return SR_ERR_ARG;
-       case SP_ERR_FAIL:
-               error = sp_last_error_message();
-               sr_err("Error opening port (%d): %s.",
-                       sp_last_error_code(), error);
-               sp_free_error_message(error);
-               return SR_ERR;
-       }
-
-       if (serial->serialcomm)
-               return serial_set_paramstr(serial, serial->serialcomm);
-       else
-               return SR_OK;
-}
-
-/**
- * Close the specified serial port.
- *
- * @param serial Previously initialized serial port structure.
- *
- * @retval SR_OK Success.
- * @retval SR_ERR Failure.
- */
-SR_PRIV int serial_close(struct sr_serial_dev_inst *serial)
-{
-       int ret;
-       char *error;
-
-       if (!serial) {
-               sr_dbg("Invalid serial port.");
-               return SR_ERR;
-       }
-
-       if (!serial->data) {
-               sr_dbg("Cannot close unopened serial port %s.", serial->port);
-               return SR_ERR;
-       }
-
-       sr_spew("Closing serial port %s.", serial->port);
-
-       ret = sp_close(serial->data);
-
-       switch (ret) {
-       case SP_ERR_ARG:
-               sr_err("Attempt to close an invalid serial port.");
-               return SR_ERR_ARG;
-       case SP_ERR_FAIL:
-               error = sp_last_error_message();
-               sr_err("Error closing port (%d): %s.",
-                       sp_last_error_code(), error);
-               sp_free_error_message(error);
-               return SR_ERR;
-       }
-
-       sp_free_port(serial->data);
-       serial->data = NULL;
-
-       return SR_OK;
-}
-
-/**
- * Flush serial port buffers.
- *
- * @param serial Previously initialized serial port structure.
- *
- * @retval SR_OK Success.
- * @retval SR_ERR Failure.
- */
-SR_PRIV int serial_flush(struct sr_serial_dev_inst *serial)
-{
-       int ret;
-       char *error;
-
-       if (!serial) {
-               sr_dbg("Invalid serial port.");
-               return SR_ERR;
-       }
-
-       if (!serial->data) {
-               sr_dbg("Cannot flush unopened serial port %s.", serial->port);
-               return SR_ERR;
-       }
-
-       sr_spew("Flushing serial port %s.", serial->port);
-
-       ret = sp_flush(serial->data, SP_BUF_BOTH);
-
-       switch (ret) {
-       case SP_ERR_ARG:
-               sr_err("Attempt to flush an invalid serial port.");
-               return SR_ERR_ARG;
-       case SP_ERR_FAIL:
-               error = sp_last_error_message();
-               sr_err("Error flushing port (%d): %s.",
-                       sp_last_error_code(), error);
-               sp_free_error_message(error);
-               return SR_ERR;
-       }
-
-       return SR_OK;
-}
-
-static int _serial_write(struct sr_serial_dev_inst *serial,
-               const void *buf, size_t count, int nonblocking)
-{
-       ssize_t ret;
-       char *error;
-
-       if (!serial) {
-               sr_dbg("Invalid serial port.");
-               return SR_ERR;
-       }
-
-       if (!serial->data) {
-               sr_dbg("Cannot use unopened serial port %s.", serial->port);
-               return SR_ERR;
-       }
-
-       if (nonblocking)
-               ret = sp_nonblocking_write(serial->data, buf, count);
-       else
-               ret = sp_blocking_write(serial->data, buf, count, 0);
-
-       switch (ret) {
-       case SP_ERR_ARG:
-               sr_err("Attempted serial port write with invalid arguments.");
-               return SR_ERR_ARG;
-       case SP_ERR_FAIL:
-               error = sp_last_error_message();
-               sr_err("Write error (%d): %s.", sp_last_error_code(), error);
-               sp_free_error_message(error);
-               return SR_ERR;
-       }
-
-       sr_spew("Wrote %d/%d bytes.", ret, count);
-
-       return ret;
-}
-
-/**
- * Write a number of bytes to the specified serial port.
- *
- * @param serial Previously initialized serial port structure.
- * @param[in] buf Buffer containing the bytes to write.
- * @param[in] count Number of bytes to write.
- *
- * @retval SR_ERR_ARG Invalid argument.
- * @retval SR_ERR Other error.
- * @retval other The number of bytes written.
- */
-SR_PRIV int serial_write(struct sr_serial_dev_inst *serial,
-               const void *buf, size_t count)
-{
-       return _serial_write(serial, buf, count, serial->nonblocking);
-}
-
-/**
- * Write a number of bytes to the specified serial port, blocking until finished.
- * @copydetails serial_write()
- */
-SR_PRIV int serial_write_blocking(struct sr_serial_dev_inst *serial,
-               const void *buf, size_t count)
-{
-       return _serial_write(serial, buf, count, 0);
-}
-
-/**
- * Write a number of bytes to the specified serial port, return immediately.
- * @copydetails serial_write()
-*/
-SR_PRIV int serial_write_nonblocking(struct sr_serial_dev_inst *serial,
-               const void *buf, size_t count)
-{
-       return _serial_write(serial, buf, count, 1);
-}
-
-static int _serial_read(struct sr_serial_dev_inst *serial, void *buf,
-               size_t count, int nonblocking)
-{
-       ssize_t ret;
-       char *error;
-
-       if (!serial) {
-               sr_dbg("Invalid serial port.");
-               return SR_ERR;
-       }
-
-       if (!serial->data) {
-               sr_dbg("Cannot use unopened serial port %s.", serial->port);
-               return SR_ERR;
-       }
-
-       if (nonblocking)
-               ret = sp_nonblocking_read(serial->data, buf, count);
-       else
-               ret = sp_blocking_read(serial->data, buf, count, 0);
-
-       switch (ret) {
-       case SP_ERR_ARG:
-               sr_err("Attempted serial port read with invalid arguments.");
-               return SR_ERR_ARG;
-       case SP_ERR_FAIL:
-               error = sp_last_error_message();
-               sr_err("Read error (%d): %s.", sp_last_error_code(), error);
-               sp_free_error_message(error);
-               return SR_ERR;
-       }
-
-       if (ret > 0)
-               sr_spew("Read %d/%d bytes.", ret, count);
-
-       return ret;
-}
-
-/**
- * Read a number of bytes from the specified serial port.
- *
- * @param serial Previously initialized serial port structure.
- * @param buf Buffer where to store the bytes that are read.
- * @param[in] count The number of bytes to read.
- *
- * @retval SR_ERR_ARG Invalid argument.
- * @retval SR_ERR     Other error.
- * @retval other      The number of bytes read.
- */
-SR_PRIV int serial_read(struct sr_serial_dev_inst *serial, void *buf,
-               size_t count)
-{
-       return _serial_read(serial, buf, count, serial->nonblocking);
-}
-
-/**
- * Read a number of bytes from the specified serial port, block until finished.
- * @copydetails serial_read()
- */
-SR_PRIV int serial_read_blocking(struct sr_serial_dev_inst *serial, void *buf,
-               size_t count)
-{
-       return _serial_read(serial, buf, count, 0);
-}
-
-/**
- * Try to read up to @a count bytes from the specified serial port, return
- * immediately with what's available.
- * @copydetails serial_read()
- */
-SR_PRIV int serial_read_nonblocking(struct sr_serial_dev_inst *serial, void *buf,
-               size_t count)
-{
-       return _serial_read(serial, buf, count, 1);
-}
-
-/**
- * Set serial parameters for the specified serial port.
- *
- * @param serial Previously initialized serial port structure.
- * @param[in] baudrate The baudrate to set.
- * @param[in] bits The number of data bits to use (5, 6, 7 or 8).
- * @param[in] parity The parity setting to use (0 = none, 1 = even, 2 = odd).
- * @param[in] stopbits The number of stop bits to use (1 or 2).
- * @param[in] flowcontrol The flow control settings to use (0 = none,
- *                      1 = RTS/CTS, 2 = XON/XOFF).
- * @param[in] rts Status of RTS line (0 or 1; required by some interfaces).
- * @param[in] dtr Status of DTR line (0 or 1; required by some interfaces).
- *
- * @retval SR_OK Success.
- * @retval SR_ERR Failure.
- */
-SR_PRIV int serial_set_params(struct sr_serial_dev_inst *serial, int baudrate,
-                             int bits, int parity, int stopbits,
-                             int flowcontrol, int rts, int dtr)
-{
-       int ret;
-       char *error;
-       struct sp_port_config *config;
-
-       if (!serial) {
-               sr_dbg("Invalid serial port.");
-               return SR_ERR;
-       }
-
-       if (!serial->data) {
-               sr_dbg("Cannot configure unopened serial port %s.", serial->port);
-               return SR_ERR;
-       }
-
-       sr_spew("Setting serial parameters on port %s.", serial->port);
-
-       sp_new_config(&config);
-       sp_set_config_baudrate(config, baudrate);
-       sp_set_config_bits(config, bits);
-       switch (parity) {
-       case 0:
-               sp_set_config_parity(config, SP_PARITY_NONE);
-               break;
-       case 1:
-               sp_set_config_parity(config, SP_PARITY_EVEN);
-               break;
-       case 2:
-               sp_set_config_parity(config, SP_PARITY_ODD);
-               break;
-       default:
-               return SR_ERR_ARG;
-       }
-       sp_set_config_stopbits(config, stopbits);
-       sp_set_config_rts(config, flowcontrol == 1 ? SP_RTS_FLOW_CONTROL : rts);
-       sp_set_config_cts(config, flowcontrol == 1 ? SP_CTS_FLOW_CONTROL : SP_CTS_IGNORE);
-       sp_set_config_dtr(config, dtr);
-       sp_set_config_dsr(config, SP_DSR_IGNORE);
-       sp_set_config_xon_xoff(config, flowcontrol == 2 ? SP_XONXOFF_INOUT : SP_XONXOFF_DISABLED);
-
-       ret = sp_set_config(serial->data, config);
-       sp_free_config(config);
-
-       switch (ret) {
-       case SP_ERR_ARG:
-               sr_err("Invalid arguments for setting serial port parameters.");
-               return SR_ERR_ARG;
-       case SP_ERR_FAIL:
-               error = sp_last_error_message();
-               sr_err("Error setting serial port parameters (%d): %s.",
-                       sp_last_error_code(), error);
-               sp_free_error_message(error);
-               return SR_ERR;
-       }
-
-       return SR_OK;
-}
-
-/**
- * Set serial parameters for the specified serial port from parameter string.
- *
- * @param serial Previously initialized serial port structure.
- * @param[in] paramstr A serial communication parameters string of the form
- * "<baudrate>/<bits><parity><stopbits>{/<option>}".\n
- *  Examples: "9600/8n1", "600/7o2/dtr=1/rts=0" or "460800/8n1/flow=2".\n
- * \<baudrate\>=integer Baud rate.\n
- * \<bits\>=5|6|7|8 Number of data bits.\n
- * \<parity\>=n|e|o None, even, odd.\n
- * \<stopbits\>=1|2 One or two stop bits.\n
- * Options:\n
- * dtr=0|1 Set DTR off resp. on.\n
- * flow=0|1|2 Flow control. 0 for none, 1 for RTS/CTS, 2 for XON/XOFF.\n
- * rts=0|1 Set RTS off resp. on.\n
- * Please note that values and combinations of these parameters must be
- * supported by the concrete serial interface hardware and the drivers for it.
- * @retval SR_OK Success.
- * @retval SR_ERR Failure.
- */
-SR_PRIV int serial_set_paramstr(struct sr_serial_dev_inst *serial,
-               const char *paramstr)
-{
-#define SERIAL_COMM_SPEC "^(\\d+)/([5678])([neo])([12])(.*)$"
-
-       GRegex *reg;
-       GMatchInfo *match;
-       int speed, databits, parity, stopbits, flow, rts, dtr, i;
-       char *mstr, **opts, **kv;
-
-       speed = databits = parity = stopbits = flow = 0;
-       rts = dtr = -1;
-       sr_spew("Parsing parameters from \"%s\".", paramstr);
-       reg = g_regex_new(SERIAL_COMM_SPEC, 0, 0, NULL);
-       if (g_regex_match(reg, paramstr, 0, &match)) {
-               if ((mstr = g_match_info_fetch(match, 1)))
-                       speed = strtoul(mstr, NULL, 10);
-               g_free(mstr);
-               if ((mstr = g_match_info_fetch(match, 2)))
-                       databits = strtoul(mstr, NULL, 10);
-               g_free(mstr);
-               if ((mstr = g_match_info_fetch(match, 3))) {
-                       switch (mstr[0]) {
-                       case 'n':
-                               parity = SERIAL_PARITY_NONE;
-                               break;
-                       case 'e':
-                               parity = SERIAL_PARITY_EVEN;
-                               break;
-                       case 'o':
-                               parity = SERIAL_PARITY_ODD;
-                               break;
-                       }
-               }
-               g_free(mstr);
-               if ((mstr = g_match_info_fetch(match, 4)))
-                       stopbits = strtoul(mstr, NULL, 10);
-               g_free(mstr);
-               if ((mstr = g_match_info_fetch(match, 5)) && mstr[0] != '\0') {
-                       if (mstr[0] != '/') {
-                               sr_dbg("missing separator before extra options");
-                               speed = 0;
-                       } else {
-                               /* A set of "key=value" options separated by / */
-                               opts = g_strsplit(mstr + 1, "/", 0);
-                               for (i = 0; opts[i]; i++) {
-                                       kv = g_strsplit(opts[i], "=", 2);
-                                       if (!strncmp(kv[0], "rts", 3)) {
-                                               if (kv[1][0] == '1')
-                                                       rts = 1;
-                                               else if (kv[1][0] == '0')
-                                                       rts = 0;
-                                               else {
-                                                       sr_dbg("invalid value for rts: %c", kv[1][0]);
-                                                       speed = 0;
-                                               }
-                                       } else if (!strncmp(kv[0], "dtr", 3)) {
-                                               if (kv[1][0] == '1')
-                                                       dtr = 1;
-                                               else if (kv[1][0] == '0')
-                                                       dtr = 0;
-                                               else {
-                                                       sr_dbg("invalid value for dtr: %c", kv[1][0]);
-                                                       speed = 0;
-                                               }
-                                       } else if (!strncmp(kv[0], "flow", 4)) {
-                                               if (kv[1][0] == '0')
-                                                       flow = 0;
-                                               else if (kv[1][0] == '1')
-                                                       flow = 1;
-                                               else if (kv[1][0] == '2')
-                                                       flow = 2;
-                                               else {
-                                                       sr_dbg("invalid value for flow: %c", kv[1][0]);
-                                                       speed = 0;
-                                               }
-                                       }
-                                       g_strfreev(kv);
-                               }
-                               g_strfreev(opts);
-                       }
-               }
-               g_free(mstr);
-       }
-       g_match_info_unref(match);
-       g_regex_unref(reg);
-
-       if (speed) {
-               return serial_set_params(serial, speed, databits, parity,
-                                        stopbits, flow, rts, dtr);
-       } else {
-               sr_dbg("Could not infer speed from parameter string.");
-               return SR_ERR_ARG;
-       }
-}
-
-/**
- * Read a line from the specified serial port.
- *
- * @param serial Previously initialized serial port structure.
- * @param buf Buffer where to store the bytes that are read.
- * @param buflen Size of the buffer.
- * @param[in] timeout_ms How long to wait for a line to come in.
- *
- * Reading stops when CR of LR is found, which is stripped from the buffer.
- *
- * @retval SR_OK Success.
- * @retval SR_ERR Failure.
- */
-SR_PRIV int serial_readline(struct sr_serial_dev_inst *serial, char **buf,
-               int *buflen, gint64 timeout_ms)
-{
-       gint64 start;
-       int maxlen, len;
-
-       if (!serial) {
-               sr_dbg("Invalid serial port.");
-               return SR_ERR;
-       }
-
-       if (!serial->data) {
-               sr_dbg("Cannot use unopened serial port %s.", serial->port);
-               return -1;
-       }
-
-       timeout_ms *= 1000;
-       start = g_get_monotonic_time();
-
-       maxlen = *buflen;
-       *buflen = len = 0;
-       while(1) {
-               len = maxlen - *buflen - 1;
-               if (len < 1)
-                       break;
-               len = serial_read(serial, *buf + *buflen, 1);
-               if (len > 0) {
-                       *buflen += len;
-                       *(*buf + *buflen) = '\0';
-                       if (*buflen > 0 && (*(*buf + *buflen - 1) == '\r'
-                                       || *(*buf + *buflen - 1) == '\n')) {
-                               /* Strip CR/LF and terminate. */
-                               *(*buf + --*buflen) = '\0';
-                               break;
-                       }
-               }
-               if (g_get_monotonic_time() - start > timeout_ms)
-                       /* Timeout */
-                       break;
-               if (len < 1)
-                       g_usleep(2000);
-       }
-       if (*buflen)
-               sr_dbg("Received %d: '%s'.", *buflen, *buf);
-
-       return SR_OK;
-}
-
-/**
- * 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[in] packet_size Size, in bytes, of a valid packet.
- * @param is_valid Callback that assesses whether the packet is valid or not.
- * @param[in] timeout_ms The timeout after which, if no packet is detected, to
- *                   abort scanning.
- * @param[in] baudrate The baudrate of the serial port. This parameter is not
- *                 critical, but it helps fine tune the serial port polling
- *                 delay.
- *
- * @retval SR_OK Valid packet was found within the given timeout.
- * @retval SR_ERR Failure.
- */
-SR_PRIV int serial_stream_detect(struct sr_serial_dev_inst *serial,
-                                uint8_t *buf, size_t *buflen,
-                                size_t packet_size,
-                                packet_valid_callback is_valid,
-                                uint64_t timeout_ms, int baudrate)
-{
-       uint64_t start, time, byte_delay_us;
-       size_t ibuf, i, maxlen;
-       int len;
-
-       maxlen = *buflen;
-
-       sr_dbg("Detecting packets on %s (timeout = %" PRIu64
-              "ms, baudrate = %d).", serial->port, timeout_ms, baudrate);
-
-       if (maxlen < (packet_size / 2) ) {
-               sr_err("Buffer size must be at least twice the packet size.");
-               return SR_ERR;
-       }
-
-       /* Assume 8n1 transmission. That is 10 bits for every byte. */
-       byte_delay_us = 10 * (1000000 / baudrate);
-       start = g_get_monotonic_time();
-
-       i = ibuf = len = 0;
-       while (ibuf < maxlen) {
-               len = serial_read(serial, &buf[ibuf], 1);
-               if (len > 0) {
-                       ibuf += len;
-               } else if (len == 0) {
-                       /* No logging, already done in serial_read(). */
-               } else {
-                       /* Error reading byte, but continuing anyway. */
-               }
-
-               time = g_get_monotonic_time() - start;
-               time /= 1000;
-
-               if ((ibuf - i) >= packet_size) {
-                       /* 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.", (ibuf - i), time);
-                               *buflen = ibuf;
-                               return SR_OK;
-                       } else {
-                               sr_spew("Got %d bytes, but not a valid "
-                                       "packet.", (ibuf - i));
-                       }
-                       /* Not a valid packet. Continue searching. */
-                       i++;
-               }
-               if (time >= timeout_ms) {
-                       /* Timeout */
-                       sr_dbg("Detection timed out after %dms.", time);
-                       break;
-               }
-               if (len < 1)
-                       g_usleep(byte_delay_us);
-       }
-
-       *buflen = ibuf;
-
-       sr_err("Didn't find a valid packet (read %d bytes).", *buflen);
-
-       return SR_ERR;
-}
-
-/**
- * Extract the serial device and options from the options linked list.
- *
- * @param options List of options passed from the command line.
- * @param serial_device Pointer where to store the exctracted serial device.
- * @param serial_options Pointer where to store the optional extracted serial
- * options.
- *
- * @return SR_OK if a serial_device is found, SR_ERR if no device is found. The
- * returned string should not be freed by the caller.
- */
-SR_PRIV int sr_serial_extract_options(GSList *options, const char **serial_device,
-                                     const char **serial_options)
-{
-       GSList *l;
-       struct sr_config *src;
-
-       *serial_device = NULL;
-
-       for (l = options; l; l = l->next) {
-               src = l->data;
-               switch (src->key) {
-               case SR_CONF_CONN:
-                       *serial_device = g_variant_get_string(src->data, NULL);
-                       sr_dbg("Parsed serial device: %s", *serial_device);
-                       break;
-
-               case SR_CONF_SERIALCOMM:
-                       *serial_options = g_variant_get_string(src->data, NULL);
-                       sr_dbg("Parsed serial options: %s", *serial_options);
-                       break;
-               }
-       }
-
-       if (!*serial_device) {
-               sr_dbg("No serial device specified");
-               return SR_ERR;
-       }
-
-       return SR_OK;
-}
-
-#ifdef _WIN32
-typedef HANDLE event_handle;
-#else
-typedef int event_handle;
-#endif
-
-SR_PRIV int serial_source_add(struct sr_session *session,
-               struct sr_serial_dev_inst *serial, int events, int timeout,
-               sr_receive_data_callback cb, void *cb_data)
-{
-       enum sp_event mask = 0;
-       unsigned int i;
-
-       if (sp_new_event_set(&serial->event_set) != SP_OK)
-               return SR_ERR;
-
-       if (events & G_IO_IN)
-               mask |= SP_EVENT_RX_READY;
-       if (events & G_IO_OUT)
-               mask |= SP_EVENT_TX_READY;
-       if (events & G_IO_ERR)
-               mask |= SP_EVENT_ERROR;
-
-       if (sp_add_port_events(serial->event_set, serial->data, mask) != SP_OK) {
-               sp_free_event_set(serial->event_set);
-               return SR_ERR;
-       }
-
-       serial->pollfds = (GPollFD *) g_malloc0(sizeof(GPollFD) * serial->event_set->count);
-
-       for (i = 0; i < serial->event_set->count; i++) {
-
-               serial->pollfds[i].fd = ((event_handle *) serial->event_set->handles)[i];
-
-               mask = serial->event_set->masks[i];
-
-               if (mask & SP_EVENT_RX_READY)
-                       serial->pollfds[i].events |= G_IO_IN;
-               if (mask & SP_EVENT_TX_READY)
-                       serial->pollfds[i].events |= G_IO_OUT;
-               if (mask & SP_EVENT_ERROR)
-                       serial->pollfds[i].events |= G_IO_ERR;
-
-               if (sr_session_source_add_pollfd(session, &serial->pollfds[i],
-                                       timeout, cb, cb_data) != SR_OK)
-                       return SR_ERR;
-       }
-
-       return SR_OK;
-}
-
-SR_PRIV int serial_source_remove(struct sr_session *session,
-               struct sr_serial_dev_inst *serial)
-{
-       unsigned int i;
-
-       for (i = 0; i < serial->event_set->count; i++)
-               if (sr_session_source_remove_pollfd(session, &serial->pollfds[i]) != SR_OK)
-                       return SR_ERR;
-
-       g_free(serial->pollfds);
-       sp_free_event_set(serial->event_set);
-
-       serial->pollfds = NULL;
-       serial->event_set = NULL;
-
-       return SR_OK;
-}
-
-/**
- * Find USB serial devices via the USB vendor ID and product ID.
- *
- * @param[in] vendor_id Vendor ID of the USB device.
- * @param[in] product_id Product ID of the USB device.
- *
- * @return A GSList of strings containing the path of the serial device or
- *         NULL if no serial device is found. The returned list must be freed
- *         by the caller.
- */
-SR_PRIV GSList *sr_serial_find_usb(uint16_t vendor_id, uint16_t product_id)
-{
-#ifdef __linux__
-       const gchar *usb_dev;
-       const char device_tree[] = "/sys/bus/usb/devices/";
-       GDir *devices_dir, *device_dir;
-       GSList *l = NULL;
-       GSList *tty_devs;
-       GSList *matched_paths;
-       FILE *fd;
-       char tmp[5];
-       gchar *vendor_path, *product_path, *path_copy;
-       gchar *prefix, *subdir_path, *device_path, *tty_path;
-       unsigned long read_vendor_id, read_product_id;
-       const char *file;
-
-       l = NULL;
-       tty_devs = NULL;
-       matched_paths = NULL;
-
-       if (!(devices_dir = g_dir_open(device_tree, 0, NULL)))
-               return NULL;
-
-       /*
-        * Find potential candidates using the vendor ID and product ID
-        * and store them in matched_paths.
-        */
-       while ((usb_dev = g_dir_read_name(devices_dir))) {
-               vendor_path = g_strconcat(device_tree,
-                                         usb_dev, "/idVendor", NULL);
-               product_path = g_strconcat(device_tree,
-                                          usb_dev, "/idProduct", NULL);
-
-               if (!g_file_test(vendor_path, G_FILE_TEST_EXISTS) ||
-                   !g_file_test(product_path, G_FILE_TEST_EXISTS))
-                       goto skip_device;
-
-               if ((fd = g_fopen(vendor_path, "r")) == NULL)
-                       goto skip_device;
-
-               if (fgets(tmp, sizeof(tmp), fd) == NULL) {
-                       fclose(fd);
-                       goto skip_device;
-               }
-               read_vendor_id = strtoul(tmp, NULL, 16);
-
-               fclose(fd);
-
-               if ((fd = g_fopen(product_path, "r")) == NULL)
-                       goto skip_device;
-
-               if (fgets(tmp, sizeof(tmp), fd) == NULL) {
-                       fclose(fd);
-                       goto skip_device;
-               }
-               read_product_id = strtoul(tmp, NULL, 16);
-
-               fclose(fd);
-
-               if (vendor_id == read_vendor_id &&
-                   product_id == read_product_id) {
-                       path_copy = g_strdup(usb_dev);
-                       matched_paths = g_slist_prepend(matched_paths,
-                                                       path_copy);
-               }
-
-skip_device:
-               g_free(vendor_path);
-               g_free(product_path);
-       }
-       g_dir_close(devices_dir);
-
-       /* For every matched device try to find a ttyUSBX subfolder. */
-       for (l = matched_paths; l; l = l->next) {
-               subdir_path = NULL;
-
-               device_path = g_strconcat(device_tree, l->data, NULL);
-
-               if (!(device_dir = g_dir_open(device_path, 0, NULL))) {
-                       g_free(device_path);
-                       continue;
-               }
-
-               prefix = g_strconcat(l->data, ":", NULL);
-
-               while ((file = g_dir_read_name(device_dir))) {
-                       if (g_str_has_prefix(file, prefix)) {
-                               subdir_path = g_strconcat(device_path,
-                                               "/", file, NULL);
-                               break;
-                       }
-               }
-               g_dir_close(device_dir);
-
-               g_free(prefix);
-               g_free(device_path);
-
-               if (subdir_path) {
-                       if (!(device_dir = g_dir_open(subdir_path, 0, NULL))) {
-                               g_free(subdir_path);
-                               continue;
-                       }
-                       g_free(subdir_path);
-
-                       while ((file = g_dir_read_name(device_dir))) {
-                               if (g_str_has_prefix(file, "ttyUSB")) {
-                                       tty_path = g_strconcat("/dev/",
-                                                              file, NULL);
-                                       sr_dbg("Found USB device %04x:%04x attached to %s.",
-                                              vendor_id, product_id, tty_path);
-                                       tty_devs = g_slist_prepend(tty_devs,
-                                                       tty_path);
-                                       break;
-                               }
-                       }
-                       g_dir_close(device_dir);
-               }
-       }
-       g_slist_free_full(matched_paths, g_free);
-
-       return tty_devs;
-#else
-       (void)vendor_id;
-       (void)product_id;
-
-       return NULL;
-#endif
-}
diff --git a/hardware/common/usb.c b/hardware/common/usb.c
deleted file mode 100644 (file)
index c3279d0..0000000
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012 Uwe Hermann <uwe@hermann-uwe.de>
- * Copyright (C) 2012 Bert Vermeulen <bert@biot.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 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include <stdlib.h>
-#include <glib.h>
-#include <libusb.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-/* SR_CONF_CONN takes one of these: */
-#define CONN_USB_VIDPID  "^([0-9a-z]{4})\\.([0-9a-z]{4})$"
-#define CONN_USB_BUSADDR "^(\\d+)\\.(\\d+)$"
-
-#define LOG_PREFIX "usb"
-
-/**
- * Find USB devices according to a connection string.
- *
- * @param usb_ctx libusb context to use while scanning.
- * @param conn Connection string specifying the device(s) to match. This
- * can be of the form "<bus>.<address>", or "<vendorid>.<productid>".
- *
- * @return A GSList of struct sr_usb_dev_inst, with bus and address fields
- * matching the device that matched the connection string. The GSList and
- * its contents must be freed by the caller.
- */
-SR_PRIV GSList *sr_usb_find(libusb_context *usb_ctx, const char *conn)
-{
-       struct sr_usb_dev_inst *usb;
-       struct libusb_device **devlist;
-       struct libusb_device_descriptor des;
-       GSList *devices;
-       GRegex *reg;
-       GMatchInfo *match;
-       int vid, pid, bus, addr, b, a, ret, i;
-       char *mstr;
-
-       vid = pid = bus = addr = 0;
-       reg = g_regex_new(CONN_USB_VIDPID, 0, 0, NULL);
-       if (g_regex_match(reg, conn, 0, &match)) {
-               if ((mstr = g_match_info_fetch(match, 1)))
-                       vid = strtoul(mstr, NULL, 16);
-               g_free(mstr);
-
-               if ((mstr = g_match_info_fetch(match, 2)))
-                       pid = strtoul(mstr, NULL, 16);
-               g_free(mstr);
-               sr_dbg("Trying to find USB device with VID:PID = %04x:%04x.",
-                      vid, pid);
-       } else {
-               g_match_info_unref(match);
-               g_regex_unref(reg);
-               reg = g_regex_new(CONN_USB_BUSADDR, 0, 0, NULL);
-               if (g_regex_match(reg, conn, 0, &match)) {
-                       if ((mstr = g_match_info_fetch(match, 1)))
-                               bus = strtoul(mstr, NULL, 10);
-                       g_free(mstr);
-
-                       if ((mstr = g_match_info_fetch(match, 2)))
-                               addr = strtoul(mstr, NULL, 10);
-                       g_free(mstr);
-                       sr_dbg("Trying to find USB device with bus.address = "
-                              "%d.%d.", bus, addr);
-               }
-       }
-       g_match_info_unref(match);
-       g_regex_unref(reg);
-
-       if (vid + pid + bus + addr == 0) {
-               sr_err("Neither VID:PID nor bus.address was specified.");
-               return NULL;
-       }
-
-       if (bus > 64) {
-               sr_err("Invalid bus specified: %d.", bus);
-               return NULL;
-       }
-
-       if (addr > 127) {
-               sr_err("Invalid address specified: %d.", addr);
-               return NULL;
-       }
-
-       /* Looks like a valid USB device specification, but is it connected? */
-       devices = NULL;
-       libusb_get_device_list(usb_ctx, &devlist);
-       for (i = 0; devlist[i]; i++) {
-               if ((ret = libusb_get_device_descriptor(devlist[i], &des))) {
-                       sr_err("Failed to get device descriptor: %s.",
-                              libusb_error_name(ret));
-                       continue;
-               }
-
-               if (vid + pid && (des.idVendor != vid || des.idProduct != pid))
-                       continue;
-
-               b = libusb_get_bus_number(devlist[i]);
-               a = libusb_get_device_address(devlist[i]);
-               if (bus + addr && (b != bus || a != addr))
-                       continue;
-
-               sr_dbg("Found USB device (VID:PID = %04x:%04x, bus.address = "
-                      "%d.%d).", des.idVendor, des.idProduct, b, a);
-
-               usb = sr_usb_dev_inst_new(libusb_get_bus_number(devlist[i]),
-                               libusb_get_device_address(devlist[i]), NULL);
-               devices = g_slist_append(devices, usb);
-       }
-       libusb_free_device_list(devlist, 1);
-
-       sr_dbg("Found %d device(s).", g_slist_length(devices));
-       
-       return devices;
-}
-
-SR_PRIV int sr_usb_open(libusb_context *usb_ctx, struct sr_usb_dev_inst *usb)
-{
-       struct libusb_device **devlist;
-       struct libusb_device_descriptor des;
-       int ret, r, cnt, i, a, b;
-
-       sr_dbg("Trying to open USB device %d.%d.", usb->bus, usb->address);
-
-       if ((cnt = libusb_get_device_list(usb_ctx, &devlist)) < 0) {
-               sr_err("Failed to retrieve device list: %s.",
-                      libusb_error_name(cnt));
-               return SR_ERR;
-       }
-
-       ret = SR_ERR;
-       for (i = 0; i < cnt; i++) {
-               if ((r = libusb_get_device_descriptor(devlist[i], &des)) < 0) {
-                       sr_err("Failed to get device descriptor: %s.",
-                              libusb_error_name(r));
-                       continue;
-               }
-
-               b = libusb_get_bus_number(devlist[i]);
-               a = libusb_get_device_address(devlist[i]);
-               if (b != usb->bus || a != usb->address)
-                       continue;
-
-               if ((r = libusb_open(devlist[i], &usb->devhdl)) < 0) {
-                       sr_err("Failed to open device: %s.",
-                              libusb_error_name(r));
-                       break;
-               }
-
-               sr_dbg("Opened USB device (VID:PID = %04x:%04x, bus.address = "
-                      "%d.%d).", des.idVendor, des.idProduct, b, a);
-
-               ret = SR_OK;
-               break;
-       }
-
-       libusb_free_device_list(devlist, 1);
-
-       return ret;
-}
-
-#ifdef _WIN32
-static gpointer usb_thread(gpointer data)
-{
-       struct sr_context *ctx = data;
-
-       while (ctx->usb_thread_running) {
-               g_mutex_lock(&ctx->usb_mutex);
-               libusb_wait_for_event(ctx->libusb_ctx, NULL);
-               SetEvent(ctx->usb_event);
-               g_mutex_unlock(&ctx->usb_mutex);
-               g_thread_yield();
-       }
-
-       return NULL;
-}
-
-static int usb_callback(int fd, int revents, void *cb_data)
-{
-       struct sr_context *ctx = cb_data;
-       int ret;
-
-       g_mutex_lock(&ctx->usb_mutex);
-       ret = ctx->usb_cb(fd, revents, ctx->usb_cb_data);
-
-       if (ctx->usb_thread_running) {
-               ResetEvent(ctx->usb_event);
-               g_mutex_unlock(&ctx->usb_mutex);
-       }
-
-       return ret;
-}
-#endif
-
-SR_PRIV int usb_source_add(struct sr_session *session, struct sr_context *ctx,
-               int timeout, sr_receive_data_callback cb, void *cb_data)
-{
-       if (ctx->usb_source_present) {
-               sr_err("A USB event source is already present.");
-               return SR_ERR;
-       }
-
-#ifdef _WIN32
-       ctx->usb_event = CreateEvent(NULL, TRUE, FALSE, NULL);
-       g_mutex_init(&ctx->usb_mutex);
-       ctx->usb_thread_running = TRUE;
-       ctx->usb_thread = g_thread_new("usb", usb_thread, ctx);
-       ctx->usb_pollfd.fd = ctx->usb_event;
-       ctx->usb_pollfd.events = G_IO_IN;
-       ctx->usb_cb = cb;
-       ctx->usb_cb_data = cb_data;
-       sr_session_source_add_pollfd(session, &ctx->usb_pollfd, timeout,
-                       usb_callback, ctx);
-#else
-       const struct libusb_pollfd **lupfd;
-       unsigned int i;
-
-       lupfd = libusb_get_pollfds(ctx->libusb_ctx);
-       for (i = 0; lupfd[i]; i++)
-               sr_session_source_add(session, lupfd[i]->fd, lupfd[i]->events,
-                               timeout, cb, cb_data);
-       free(lupfd);
-#endif
-       ctx->usb_source_present = TRUE;
-
-       return SR_OK;
-}
-
-SR_PRIV int usb_source_remove(struct sr_session *session, struct sr_context *ctx)
-{
-       if (!ctx->usb_source_present)
-               return SR_OK;
-
-#ifdef _WIN32
-       ctx->usb_thread_running = FALSE;
-       g_mutex_unlock(&ctx->usb_mutex);
-       libusb_unlock_events(ctx->libusb_ctx);
-       g_thread_join(ctx->usb_thread);
-       g_mutex_clear(&ctx->usb_mutex);
-       sr_session_source_remove_pollfd(session, &ctx->usb_pollfd);
-       CloseHandle(ctx->usb_event);
-#else
-       const struct libusb_pollfd **lupfd;
-       unsigned int i;
-
-       lupfd = libusb_get_pollfds(ctx->libusb_ctx);
-       for (i = 0; lupfd[i]; i++)
-               sr_session_source_remove(session, lupfd[i]->fd);
-       free(lupfd);
-#endif
-       ctx->usb_source_present = FALSE;
-
-       return SR_OK;
-}
diff --git a/hardware/common/vxi.h b/hardware/common/vxi.h
deleted file mode 100644 (file)
index 61a51f6..0000000
+++ /dev/null
@@ -1,342 +0,0 @@
-/*
- * Please do not edit this file.
- * It was generated using rpcgen.
- */
-
-#ifndef _VXI_H_RPCGEN
-#define _VXI_H_RPCGEN
-
-#include <rpc/rpc.h>
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-typedef long Device_Link;
-
-enum Device_AddrFamily {
-       DEVICE_TCP = 0,
-       DEVICE_UDP = 1,
-};
-typedef enum Device_AddrFamily Device_AddrFamily;
-
-typedef long Device_Flags;
-
-typedef long Device_ErrorCode;
-
-struct Device_Error {
-       Device_ErrorCode error;
-};
-typedef struct Device_Error Device_Error;
-
-struct Create_LinkParms {
-       long clientId;
-       bool_t lockDevice;
-       u_long lock_timeout;
-       char *device;
-};
-typedef struct Create_LinkParms Create_LinkParms;
-
-struct Create_LinkResp {
-       Device_ErrorCode error;
-       Device_Link lid;
-       u_short abortPort;
-       u_long maxRecvSize;
-};
-typedef struct Create_LinkResp Create_LinkResp;
-
-struct Device_WriteParms {
-       Device_Link lid;
-       u_long io_timeout;
-       u_long lock_timeout;
-       Device_Flags flags;
-       struct {
-               u_int data_len;
-               char *data_val;
-       } data;
-};
-typedef struct Device_WriteParms Device_WriteParms;
-
-struct Device_WriteResp {
-       Device_ErrorCode error;
-       u_long size;
-};
-typedef struct Device_WriteResp Device_WriteResp;
-
-struct Device_ReadParms {
-       Device_Link lid;
-       u_long requestSize;
-       u_long io_timeout;
-       u_long lock_timeout;
-       Device_Flags flags;
-       char termChar;
-};
-typedef struct Device_ReadParms Device_ReadParms;
-
-struct Device_ReadResp {
-       Device_ErrorCode error;
-       long reason;
-       struct {
-               u_int data_len;
-               char *data_val;
-       } data;
-};
-typedef struct Device_ReadResp Device_ReadResp;
-
-struct Device_ReadStbResp {
-       Device_ErrorCode error;
-       u_char stb;
-};
-typedef struct Device_ReadStbResp Device_ReadStbResp;
-
-struct Device_GenericParms {
-       Device_Link lid;
-       Device_Flags flags;
-       u_long lock_timeout;
-       u_long io_timeout;
-};
-typedef struct Device_GenericParms Device_GenericParms;
-
-struct Device_RemoteFunc {
-       u_long hostAddr;
-       u_short hostPort;
-       u_long progNum;
-       u_long progVers;
-       Device_AddrFamily progFamily;
-};
-typedef struct Device_RemoteFunc Device_RemoteFunc;
-
-struct Device_EnableSrqParms {
-       Device_Link lid;
-       bool_t enable;
-       struct {
-               u_int handle_len;
-               char *handle_val;
-       } handle;
-};
-typedef struct Device_EnableSrqParms Device_EnableSrqParms;
-
-struct Device_LockParms {
-       Device_Link lid;
-       Device_Flags flags;
-       u_long lock_timeout;
-};
-typedef struct Device_LockParms Device_LockParms;
-
-struct Device_DocmdParms {
-       Device_Link lid;
-       Device_Flags flags;
-       u_long io_timeout;
-       u_long lock_timeout;
-       long cmd;
-       bool_t network_order;
-       long datasize;
-       struct {
-               u_int data_in_len;
-               char *data_in_val;
-       } data_in;
-};
-typedef struct Device_DocmdParms Device_DocmdParms;
-
-struct Device_DocmdResp {
-       Device_ErrorCode error;
-       struct {
-               u_int data_out_len;
-               char *data_out_val;
-       } data_out;
-};
-typedef struct Device_DocmdResp Device_DocmdResp;
-
-struct Device_SrqParms {
-       struct {
-               u_int handle_len;
-               char *handle_val;
-       } handle;
-};
-typedef struct Device_SrqParms Device_SrqParms;
-
-#define DEVICE_ASYNC 0x0607B0
-#define DEVICE_ASYNC_VERSION 1
-
-#if defined(__STDC__) || defined(__cplusplus)
-#define device_abort 1
-extern  Device_Error * device_abort_1(Device_Link *, CLIENT *);
-extern  Device_Error * device_abort_1_svc(Device_Link *, struct svc_req *);
-extern int device_async_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
-
-#else /* K&R C */
-#define device_abort 1
-extern  Device_Error * device_abort_1();
-extern  Device_Error * device_abort_1_svc();
-extern int device_async_1_freeresult ();
-#endif /* K&R C */
-
-#define DEVICE_CORE 0x0607AF
-#define DEVICE_CORE_VERSION 1
-
-#if defined(__STDC__) || defined(__cplusplus)
-#define create_link 10
-extern  Create_LinkResp * create_link_1(Create_LinkParms *, CLIENT *);
-extern  Create_LinkResp * create_link_1_svc(Create_LinkParms *, struct svc_req *);
-#define device_write 11
-extern  Device_WriteResp * device_write_1(Device_WriteParms *, CLIENT *);
-extern  Device_WriteResp * device_write_1_svc(Device_WriteParms *, struct svc_req *);
-#define device_read 12
-extern  Device_ReadResp * device_read_1(Device_ReadParms *, CLIENT *);
-extern  Device_ReadResp * device_read_1_svc(Device_ReadParms *, struct svc_req *);
-#define device_readstb 13
-extern  Device_ReadStbResp * device_readstb_1(Device_GenericParms *, CLIENT *);
-extern  Device_ReadStbResp * device_readstb_1_svc(Device_GenericParms *, struct svc_req *);
-#define device_trigger 14
-extern  Device_Error * device_trigger_1(Device_GenericParms *, CLIENT *);
-extern  Device_Error * device_trigger_1_svc(Device_GenericParms *, struct svc_req *);
-#define device_clear 15
-extern  Device_Error * device_clear_1(Device_GenericParms *, CLIENT *);
-extern  Device_Error * device_clear_1_svc(Device_GenericParms *, struct svc_req *);
-#define device_remote 16
-extern  Device_Error * device_remote_1(Device_GenericParms *, CLIENT *);
-extern  Device_Error * device_remote_1_svc(Device_GenericParms *, struct svc_req *);
-#define device_local 17
-extern  Device_Error * device_local_1(Device_GenericParms *, CLIENT *);
-extern  Device_Error * device_local_1_svc(Device_GenericParms *, struct svc_req *);
-#define device_lock 18
-extern  Device_Error * device_lock_1(Device_LockParms *, CLIENT *);
-extern  Device_Error * device_lock_1_svc(Device_LockParms *, struct svc_req *);
-#define device_unlock 19
-extern  Device_Error * device_unlock_1(Device_Link *, CLIENT *);
-extern  Device_Error * device_unlock_1_svc(Device_Link *, struct svc_req *);
-#define device_enable_srq 20
-extern  Device_Error * device_enable_srq_1(Device_EnableSrqParms *, CLIENT *);
-extern  Device_Error * device_enable_srq_1_svc(Device_EnableSrqParms *, struct svc_req *);
-#define device_docmd 22
-extern  Device_DocmdResp * device_docmd_1(Device_DocmdParms *, CLIENT *);
-extern  Device_DocmdResp * device_docmd_1_svc(Device_DocmdParms *, struct svc_req *);
-#define destroy_link 23
-extern  Device_Error * destroy_link_1(Device_Link *, CLIENT *);
-extern  Device_Error * destroy_link_1_svc(Device_Link *, struct svc_req *);
-#define create_intr_chan 25
-extern  Device_Error * create_intr_chan_1(Device_RemoteFunc *, CLIENT *);
-extern  Device_Error * create_intr_chan_1_svc(Device_RemoteFunc *, struct svc_req *);
-#define destroy_intr_chan 26
-extern  Device_Error * destroy_intr_chan_1(void *, CLIENT *);
-extern  Device_Error * destroy_intr_chan_1_svc(void *, struct svc_req *);
-extern int device_core_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
-
-#else /* K&R C */
-#define create_link 10
-extern  Create_LinkResp * create_link_1();
-extern  Create_LinkResp * create_link_1_svc();
-#define device_write 11
-extern  Device_WriteResp * device_write_1();
-extern  Device_WriteResp * device_write_1_svc();
-#define device_read 12
-extern  Device_ReadResp * device_read_1();
-extern  Device_ReadResp * device_read_1_svc();
-#define device_readstb 13
-extern  Device_ReadStbResp * device_readstb_1();
-extern  Device_ReadStbResp * device_readstb_1_svc();
-#define device_trigger 14
-extern  Device_Error * device_trigger_1();
-extern  Device_Error * device_trigger_1_svc();
-#define device_clear 15
-extern  Device_Error * device_clear_1();
-extern  Device_Error * device_clear_1_svc();
-#define device_remote 16
-extern  Device_Error * device_remote_1();
-extern  Device_Error * device_remote_1_svc();
-#define device_local 17
-extern  Device_Error * device_local_1();
-extern  Device_Error * device_local_1_svc();
-#define device_lock 18
-extern  Device_Error * device_lock_1();
-extern  Device_Error * device_lock_1_svc();
-#define device_unlock 19
-extern  Device_Error * device_unlock_1();
-extern  Device_Error * device_unlock_1_svc();
-#define device_enable_srq 20
-extern  Device_Error * device_enable_srq_1();
-extern  Device_Error * device_enable_srq_1_svc();
-#define device_docmd 22
-extern  Device_DocmdResp * device_docmd_1();
-extern  Device_DocmdResp * device_docmd_1_svc();
-#define destroy_link 23
-extern  Device_Error * destroy_link_1();
-extern  Device_Error * destroy_link_1_svc();
-#define create_intr_chan 25
-extern  Device_Error * create_intr_chan_1();
-extern  Device_Error * create_intr_chan_1_svc();
-#define destroy_intr_chan 26
-extern  Device_Error * destroy_intr_chan_1();
-extern  Device_Error * destroy_intr_chan_1_svc();
-extern int device_core_1_freeresult ();
-#endif /* K&R C */
-
-#define DEVICE_INTR 0x0607B1
-#define DEVICE_INTR_VERSION 1
-
-#if defined(__STDC__) || defined(__cplusplus)
-#define device_intr_srq 30
-extern  void * device_intr_srq_1(Device_SrqParms *, CLIENT *);
-extern  void * device_intr_srq_1_svc(Device_SrqParms *, struct svc_req *);
-extern int device_intr_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
-
-#else /* K&R C */
-#define device_intr_srq 30
-extern  void * device_intr_srq_1();
-extern  void * device_intr_srq_1_svc();
-extern int device_intr_1_freeresult ();
-#endif /* K&R C */
-
-/* the xdr functions */
-
-#if defined(__STDC__) || defined(__cplusplus)
-extern  bool_t xdr_Device_Link (XDR *, Device_Link*);
-extern  bool_t xdr_Device_AddrFamily (XDR *, Device_AddrFamily*);
-extern  bool_t xdr_Device_Flags (XDR *, Device_Flags*);
-extern  bool_t xdr_Device_ErrorCode (XDR *, Device_ErrorCode*);
-extern  bool_t xdr_Device_Error (XDR *, Device_Error*);
-extern  bool_t xdr_Create_LinkParms (XDR *, Create_LinkParms*);
-extern  bool_t xdr_Create_LinkResp (XDR *, Create_LinkResp*);
-extern  bool_t xdr_Device_WriteParms (XDR *, Device_WriteParms*);
-extern  bool_t xdr_Device_WriteResp (XDR *, Device_WriteResp*);
-extern  bool_t xdr_Device_ReadParms (XDR *, Device_ReadParms*);
-extern  bool_t xdr_Device_ReadResp (XDR *, Device_ReadResp*);
-extern  bool_t xdr_Device_ReadStbResp (XDR *, Device_ReadStbResp*);
-extern  bool_t xdr_Device_GenericParms (XDR *, Device_GenericParms*);
-extern  bool_t xdr_Device_RemoteFunc (XDR *, Device_RemoteFunc*);
-extern  bool_t xdr_Device_EnableSrqParms (XDR *, Device_EnableSrqParms*);
-extern  bool_t xdr_Device_LockParms (XDR *, Device_LockParms*);
-extern  bool_t xdr_Device_DocmdParms (XDR *, Device_DocmdParms*);
-extern  bool_t xdr_Device_DocmdResp (XDR *, Device_DocmdResp*);
-extern  bool_t xdr_Device_SrqParms (XDR *, Device_SrqParms*);
-
-#else /* K&R C */
-extern bool_t xdr_Device_Link ();
-extern bool_t xdr_Device_AddrFamily ();
-extern bool_t xdr_Device_Flags ();
-extern bool_t xdr_Device_ErrorCode ();
-extern bool_t xdr_Device_Error ();
-extern bool_t xdr_Create_LinkParms ();
-extern bool_t xdr_Create_LinkResp ();
-extern bool_t xdr_Device_WriteParms ();
-extern bool_t xdr_Device_WriteResp ();
-extern bool_t xdr_Device_ReadParms ();
-extern bool_t xdr_Device_ReadResp ();
-extern bool_t xdr_Device_ReadStbResp ();
-extern bool_t xdr_Device_GenericParms ();
-extern bool_t xdr_Device_RemoteFunc ();
-extern bool_t xdr_Device_EnableSrqParms ();
-extern bool_t xdr_Device_LockParms ();
-extern bool_t xdr_Device_DocmdParms ();
-extern bool_t xdr_Device_DocmdResp ();
-extern bool_t xdr_Device_SrqParms ();
-
-#endif /* K&R C */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* !_VXI_H_RPCGEN */
diff --git a/hardware/common/vxi.x b/hardware/common/vxi.x
deleted file mode 100644 (file)
index 31ca4c4..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-/* This is taken straight from Appendix C of the specification */
-
-typedef long Device_Link;
-
-enum Device_AddrFamily {
-       DEVICE_TCP,
-       DEVICE_UDP
-};
-
-typedef long Device_Flags;
-
-typedef long Device_ErrorCode;
-
-struct Device_Error {
-       Device_ErrorCode  error;
-};
-
-struct Create_LinkParms {
-       long              clientId;      /* implementation specific value */
-       bool              lockDevice;    /* attempt to lock the device */
-       unsigned long     lock_timeout;  /* time to wait on a lock */
-       string            device<>;      /* name of device */
-};
-
-struct Create_LinkResp {
-       Device_ErrorCode  error;
-       Device_Link       lid;
-       unsigned short    abortPort;     /* for the abort RPC */
-       unsigned long     maxRecvSize;   /* specifies max data size in bytes
-                                           device will accept on a write */
-};
-
-struct Device_WriteParms {
-       Device_Link       lid;           /* link id from create_link */
-       unsigned long     io_timeout;    /* time to wait for I/O */
-       unsigned long     lock_timeout;  /* time to wait for lock */
-       Device_Flags      flags;
-       opaque            data<>;        /* data length and the data itself */
-};
-
-struct Device_WriteResp {
-       Device_ErrorCode  error;
-       unsigned          long size;     /* number of bytes written */
-};
-
-struct Device_ReadParms {
-       Device_Link       lid;           /* link id from create_link */
-       unsigned long     requestSize;   /* bytes requested */
-       unsigned long     io_timeout;    /* time to wait for I/O */
-       unsigned long     lock_timeout;  /* time to wait for lock */
-       Device_Flags      flags;
-       char              termChar;      /* valid if flags & termchrset */
-};
-
-struct Device_ReadResp {
-       Device_ErrorCode  error;
-       long              reason;        /* reason(s) read completed */
-       opaque            data<>;        /* data.len and data.val */
-};
-
-struct Device_ReadStbResp {
-       Device_ErrorCode  error;         /* error code */
-       unsigned char     stb;           /* the returned status byte */
-};
-
-struct Device_GenericParms {
-       Device_Link       lid;           /* Device_Link id from connect call */
-       Device_Flags      flags;         /* flags with options */
-       unsigned long     lock_timeout;  /* time to wait for lock */
-       unsigned long     io_timeout;    /* time to wait for I/O */
-};
-
-struct Device_RemoteFunc {
-       unsigned long     hostAddr;      /* host servicing interrupt */
-       unsigned short    hostPort;      /* valid port # on client */
-       unsigned long     progNum;       /* DEVICE_INTR */
-       unsigned long     progVers;      /* DEVICE_INTR_VERSION */
-       Device_AddrFamily progFamily;    /* DEVICE_UDP | DEVICE_TCP */
-};
-
-struct Device_EnableSrqParms {
-       Device_Link       lid;
-       bool              enable;        /* enable or disable interrupts */
-       opaque            handle<40>;    /* host specific data */
-};
-
-struct Device_LockParms {
-       Device_Link       lid;           /* link id from create_link */
-       Device_Flags      flags;         /* contains the waitlock flag */
-       unsigned long     lock_timeout;  /* time to wait to acquire lock */
-};
-
-struct Device_DocmdParms {
-       Device_Link       lid;           /* link id from create_link */
-       Device_Flags      flags;         /* flags specifying various options */
-       unsigned long     io_timeout;    /* time to wait for I/O to complete */
-       unsigned long     lock_timeout;  /* time to wait on a lock */
-       long              cmd;           /* which command to execute */
-       bool              network_order; /* client's byte order */
-       long              datasize;      /* size of individual data elements */
-       opaque            data_in<>;     /* docmd data parameters */
-};
-
-struct Device_DocmdResp {
-       Device_ErrorCode  error;         /* returned status */
-       opaque            data_out<>;    /* returned data parameter */
-};
-
-struct Device_SrqParms {
-       opaque            handle<>;
-};
-
-program DEVICE_ASYNC{
-       version DEVICE_ASYNC_VERSION {
-               Device_Error       device_abort(Device_Link)               =  1;
-       } = 1;
-} = 0x0607B0;
-
-program DEVICE_CORE {
-       version DEVICE_CORE_VERSION {
-               Create_LinkResp    create_link(Create_LinkParms)           = 10;
-               Device_WriteResp   device_write(Device_WriteParms)         = 11;
-               Device_ReadResp    device_read(Device_ReadParms)           = 12;
-               Device_ReadStbResp device_readstb(Device_GenericParms)     = 13;
-               Device_Error       device_trigger(Device_GenericParms)     = 14;
-               Device_Error       device_clear(Device_GenericParms)       = 15;
-               Device_Error       device_remote(Device_GenericParms)      = 16;
-               Device_Error       device_local(Device_GenericParms)       = 17;
-               Device_Error       device_lock(Device_LockParms)           = 18;
-               Device_Error       device_unlock(Device_Link)              = 19;
-               Device_Error       device_enable_srq(Device_EnableSrqParms)= 20;
-               Device_DocmdResp   device_docmd(Device_DocmdParms)         = 22;
-               Device_Error       destroy_link(Device_Link)               = 23;
-               Device_Error       create_intr_chan(Device_RemoteFunc)     = 25;
-               Device_Error       destroy_intr_chan(void)                 = 26;
-       } = 1;
-} = 0x0607AF;
-
-program DEVICE_INTR {
-       version DEVICE_INTR_VERSION {
-               void               device_intr_srq(Device_SrqParms)        = 30;
-       } = 1;
-} = 0x0607B1;
diff --git a/hardware/common/vxi_clnt.c b/hardware/common/vxi_clnt.c
deleted file mode 100644 (file)
index 55a72dc..0000000
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * Please do not edit this file.
- * It was generated using rpcgen.
- */
-
-#include <memory.h> /* for memset */
-#include "vxi.h"
-
-/* Default timeout can be changed using clnt_control() */
-static struct timeval TIMEOUT = { 25, 0 };
-
-Device_Error *
-device_abort_1(Device_Link *argp, CLIENT *clnt)
-{
-       static Device_Error clnt_res;
-
-       memset((char *)&clnt_res, 0, sizeof(clnt_res));
-       if (clnt_call (clnt, device_abort,
-               (xdrproc_t) xdr_Device_Link, (caddr_t) argp,
-               (xdrproc_t) xdr_Device_Error, (caddr_t) &clnt_res,
-               TIMEOUT) != RPC_SUCCESS) {
-               return (NULL);
-       }
-       return (&clnt_res);
-}
-
-Create_LinkResp *
-create_link_1(Create_LinkParms *argp, CLIENT *clnt)
-{
-       static Create_LinkResp clnt_res;
-
-       memset((char *)&clnt_res, 0, sizeof(clnt_res));
-       if (clnt_call (clnt, create_link,
-               (xdrproc_t) xdr_Create_LinkParms, (caddr_t) argp,
-               (xdrproc_t) xdr_Create_LinkResp, (caddr_t) &clnt_res,
-               TIMEOUT) != RPC_SUCCESS) {
-               return (NULL);
-       }
-       return (&clnt_res);
-}
-
-Device_WriteResp *
-device_write_1(Device_WriteParms *argp, CLIENT *clnt)
-{
-       static Device_WriteResp clnt_res;
-
-       memset((char *)&clnt_res, 0, sizeof(clnt_res));
-       if (clnt_call (clnt, device_write,
-               (xdrproc_t) xdr_Device_WriteParms, (caddr_t) argp,
-               (xdrproc_t) xdr_Device_WriteResp, (caddr_t) &clnt_res,
-               TIMEOUT) != RPC_SUCCESS) {
-               return (NULL);
-       }
-       return (&clnt_res);
-}
-
-Device_ReadResp *
-device_read_1(Device_ReadParms *argp, CLIENT *clnt)
-{
-       static Device_ReadResp clnt_res;
-
-       memset((char *)&clnt_res, 0, sizeof(clnt_res));
-       if (clnt_call (clnt, device_read,
-               (xdrproc_t) xdr_Device_ReadParms, (caddr_t) argp,
-               (xdrproc_t) xdr_Device_ReadResp, (caddr_t) &clnt_res,
-               TIMEOUT) != RPC_SUCCESS) {
-               return (NULL);
-       }
-       return (&clnt_res);
-}
-
-Device_ReadStbResp *
-device_readstb_1(Device_GenericParms *argp, CLIENT *clnt)
-{
-       static Device_ReadStbResp clnt_res;
-
-       memset((char *)&clnt_res, 0, sizeof(clnt_res));
-       if (clnt_call (clnt, device_readstb,
-               (xdrproc_t) xdr_Device_GenericParms, (caddr_t) argp,
-               (xdrproc_t) xdr_Device_ReadStbResp, (caddr_t) &clnt_res,
-               TIMEOUT) != RPC_SUCCESS) {
-               return (NULL);
-       }
-       return (&clnt_res);
-}
-
-Device_Error *
-device_trigger_1(Device_GenericParms *argp, CLIENT *clnt)
-{
-       static Device_Error clnt_res;
-
-       memset((char *)&clnt_res, 0, sizeof(clnt_res));
-       if (clnt_call (clnt, device_trigger,
-               (xdrproc_t) xdr_Device_GenericParms, (caddr_t) argp,
-               (xdrproc_t) xdr_Device_Error, (caddr_t) &clnt_res,
-               TIMEOUT) != RPC_SUCCESS) {
-               return (NULL);
-       }
-       return (&clnt_res);
-}
-
-Device_Error *
-device_clear_1(Device_GenericParms *argp, CLIENT *clnt)
-{
-       static Device_Error clnt_res;
-
-       memset((char *)&clnt_res, 0, sizeof(clnt_res));
-       if (clnt_call (clnt, device_clear,
-               (xdrproc_t) xdr_Device_GenericParms, (caddr_t) argp,
-               (xdrproc_t) xdr_Device_Error, (caddr_t) &clnt_res,
-               TIMEOUT) != RPC_SUCCESS) {
-               return (NULL);
-       }
-       return (&clnt_res);
-}
-
-Device_Error *
-device_remote_1(Device_GenericParms *argp, CLIENT *clnt)
-{
-       static Device_Error clnt_res;
-
-       memset((char *)&clnt_res, 0, sizeof(clnt_res));
-       if (clnt_call (clnt, device_remote,
-               (xdrproc_t) xdr_Device_GenericParms, (caddr_t) argp,
-               (xdrproc_t) xdr_Device_Error, (caddr_t) &clnt_res,
-               TIMEOUT) != RPC_SUCCESS) {
-               return (NULL);
-       }
-       return (&clnt_res);
-}
-
-Device_Error *
-device_local_1(Device_GenericParms *argp, CLIENT *clnt)
-{
-       static Device_Error clnt_res;
-
-       memset((char *)&clnt_res, 0, sizeof(clnt_res));
-       if (clnt_call (clnt, device_local,
-               (xdrproc_t) xdr_Device_GenericParms, (caddr_t) argp,
-               (xdrproc_t) xdr_Device_Error, (caddr_t) &clnt_res,
-               TIMEOUT) != RPC_SUCCESS) {
-               return (NULL);
-       }
-       return (&clnt_res);
-}
-
-Device_Error *
-device_lock_1(Device_LockParms *argp, CLIENT *clnt)
-{
-       static Device_Error clnt_res;
-
-       memset((char *)&clnt_res, 0, sizeof(clnt_res));
-       if (clnt_call (clnt, device_lock,
-               (xdrproc_t) xdr_Device_LockParms, (caddr_t) argp,
-               (xdrproc_t) xdr_Device_Error, (caddr_t) &clnt_res,
-               TIMEOUT) != RPC_SUCCESS) {
-               return (NULL);
-       }
-       return (&clnt_res);
-}
-
-Device_Error *
-device_unlock_1(Device_Link *argp, CLIENT *clnt)
-{
-       static Device_Error clnt_res;
-
-       memset((char *)&clnt_res, 0, sizeof(clnt_res));
-       if (clnt_call (clnt, device_unlock,
-               (xdrproc_t) xdr_Device_Link, (caddr_t) argp,
-               (xdrproc_t) xdr_Device_Error, (caddr_t) &clnt_res,
-               TIMEOUT) != RPC_SUCCESS) {
-               return (NULL);
-       }
-       return (&clnt_res);
-}
-
-Device_Error *
-device_enable_srq_1(Device_EnableSrqParms *argp, CLIENT *clnt)
-{
-       static Device_Error clnt_res;
-
-       memset((char *)&clnt_res, 0, sizeof(clnt_res));
-       if (clnt_call (clnt, device_enable_srq,
-               (xdrproc_t) xdr_Device_EnableSrqParms, (caddr_t) argp,
-               (xdrproc_t) xdr_Device_Error, (caddr_t) &clnt_res,
-               TIMEOUT) != RPC_SUCCESS) {
-               return (NULL);
-       }
-       return (&clnt_res);
-}
-
-Device_DocmdResp *
-device_docmd_1(Device_DocmdParms *argp, CLIENT *clnt)
-{
-       static Device_DocmdResp clnt_res;
-
-       memset((char *)&clnt_res, 0, sizeof(clnt_res));
-       if (clnt_call (clnt, device_docmd,
-               (xdrproc_t) xdr_Device_DocmdParms, (caddr_t) argp,
-               (xdrproc_t) xdr_Device_DocmdResp, (caddr_t) &clnt_res,
-               TIMEOUT) != RPC_SUCCESS) {
-               return (NULL);
-       }
-       return (&clnt_res);
-}
-
-Device_Error *
-destroy_link_1(Device_Link *argp, CLIENT *clnt)
-{
-       static Device_Error clnt_res;
-
-       memset((char *)&clnt_res, 0, sizeof(clnt_res));
-       if (clnt_call (clnt, destroy_link,
-               (xdrproc_t) xdr_Device_Link, (caddr_t) argp,
-               (xdrproc_t) xdr_Device_Error, (caddr_t) &clnt_res,
-               TIMEOUT) != RPC_SUCCESS) {
-               return (NULL);
-       }
-       return (&clnt_res);
-}
-
-Device_Error *
-create_intr_chan_1(Device_RemoteFunc *argp, CLIENT *clnt)
-{
-       static Device_Error clnt_res;
-
-       memset((char *)&clnt_res, 0, sizeof(clnt_res));
-       if (clnt_call (clnt, create_intr_chan,
-               (xdrproc_t) xdr_Device_RemoteFunc, (caddr_t) argp,
-               (xdrproc_t) xdr_Device_Error, (caddr_t) &clnt_res,
-               TIMEOUT) != RPC_SUCCESS) {
-               return (NULL);
-       }
-       return (&clnt_res);
-}
-
-Device_Error *
-destroy_intr_chan_1(void *argp, CLIENT *clnt)
-{
-       static Device_Error clnt_res;
-
-       memset((char *)&clnt_res, 0, sizeof(clnt_res));
-       if (clnt_call (clnt, destroy_intr_chan,
-               (xdrproc_t) xdr_void, (caddr_t) argp,
-               (xdrproc_t) xdr_Device_Error, (caddr_t) &clnt_res,
-               TIMEOUT) != RPC_SUCCESS) {
-               return (NULL);
-       }
-       return (&clnt_res);
-}
-
-void *
-device_intr_srq_1(Device_SrqParms *argp, CLIENT *clnt)
-{
-       static char clnt_res;
-
-       memset((char *)&clnt_res, 0, sizeof(clnt_res));
-       if (clnt_call (clnt, device_intr_srq,
-               (xdrproc_t) xdr_Device_SrqParms, (caddr_t) argp,
-               (xdrproc_t) xdr_void, (caddr_t) &clnt_res,
-               TIMEOUT) != RPC_SUCCESS) {
-               return (NULL);
-       }
-       return ((void *)&clnt_res);
-}
diff --git a/hardware/common/vxi_xdr.c b/hardware/common/vxi_xdr.c
deleted file mode 100644 (file)
index bc7d79f..0000000
+++ /dev/null
@@ -1,428 +0,0 @@
-/*
- * Please do not edit this file.
- * It was generated using rpcgen.
- */
-
-#include "vxi.h"
-
-bool_t
-xdr_Device_Link (XDR *xdrs, Device_Link *objp)
-{
-        if (!xdr_long (xdrs, objp))
-                return FALSE;
-       return TRUE;
-}
-
-bool_t
-xdr_Device_AddrFamily (XDR *xdrs, Device_AddrFamily *objp)
-{
-        if (!xdr_enum (xdrs, (enum_t *) objp))
-                return FALSE;
-       return TRUE;
-}
-
-bool_t
-xdr_Device_Flags (XDR *xdrs, Device_Flags *objp)
-{
-        if (!xdr_long (xdrs, objp))
-                return FALSE;
-       return TRUE;
-}
-
-bool_t
-xdr_Device_ErrorCode (XDR *xdrs, Device_ErrorCode *objp)
-{
-        if (!xdr_long (xdrs, objp))
-                return FALSE;
-       return TRUE;
-}
-
-bool_t
-xdr_Device_Error (XDR *xdrs, Device_Error *objp)
-{
-        if (!xdr_Device_ErrorCode (xdrs, &objp->error))
-                return FALSE;
-       return TRUE;
-}
-
-bool_t
-xdr_Create_LinkParms (XDR *xdrs, Create_LinkParms *objp)
-{
-       register int32_t *buf;
-
-       if (xdrs->x_op == XDR_ENCODE) {
-               buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT);
-               if (buf == NULL) {
-                        if (!xdr_long (xdrs, &objp->clientId))
-                                return FALSE;
-                        if (!xdr_bool (xdrs, &objp->lockDevice))
-                                return FALSE;
-                        if (!xdr_u_long (xdrs, &objp->lock_timeout))
-                                return FALSE;
-
-               } else {
-               IXDR_PUT_LONG(buf, objp->clientId);
-               IXDR_PUT_BOOL(buf, objp->lockDevice);
-               IXDR_PUT_U_LONG(buf, objp->lock_timeout);
-               }
-                if (!xdr_string (xdrs, &objp->device, ~0))
-                        return FALSE;
-               return TRUE;
-       } else if (xdrs->x_op == XDR_DECODE) {
-               buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT);
-               if (buf == NULL) {
-                        if (!xdr_long (xdrs, &objp->clientId))
-                                return FALSE;
-                        if (!xdr_bool (xdrs, &objp->lockDevice))
-                                return FALSE;
-                        if (!xdr_u_long (xdrs, &objp->lock_timeout))
-                                return FALSE;
-
-               } else {
-               objp->clientId = IXDR_GET_LONG(buf);
-               objp->lockDevice = IXDR_GET_BOOL(buf);
-               objp->lock_timeout = IXDR_GET_U_LONG(buf);
-               }
-                if (!xdr_string (xdrs, &objp->device, ~0))
-                        return FALSE;
-        return TRUE;
-       }
-
-        if (!xdr_long (xdrs, &objp->clientId))
-                return FALSE;
-        if (!xdr_bool (xdrs, &objp->lockDevice))
-                return FALSE;
-        if (!xdr_u_long (xdrs, &objp->lock_timeout))
-                return FALSE;
-        if (!xdr_string (xdrs, &objp->device, ~0))
-                return FALSE;
-       return TRUE;
-}
-
-bool_t
-xdr_Create_LinkResp (XDR *xdrs, Create_LinkResp *objp)
-{
-        if (!xdr_Device_ErrorCode (xdrs, &objp->error))
-                return FALSE;
-        if (!xdr_Device_Link (xdrs, &objp->lid))
-                return FALSE;
-        if (!xdr_u_short (xdrs, &objp->abortPort))
-                return FALSE;
-        if (!xdr_u_long (xdrs, &objp->maxRecvSize))
-                return FALSE;
-       return TRUE;
-}
-
-bool_t
-xdr_Device_WriteParms (XDR *xdrs, Device_WriteParms *objp)
-{
-        if (!xdr_Device_Link (xdrs, &objp->lid))
-                return FALSE;
-        if (!xdr_u_long (xdrs, &objp->io_timeout))
-                return FALSE;
-        if (!xdr_u_long (xdrs, &objp->lock_timeout))
-                return FALSE;
-        if (!xdr_Device_Flags (xdrs, &objp->flags))
-                return FALSE;
-        if (!xdr_bytes (xdrs, (char **)&objp->data.data_val, (u_int *) &objp->data.data_len, ~0))
-                return FALSE;
-       return TRUE;
-}
-
-bool_t
-xdr_Device_WriteResp (XDR *xdrs, Device_WriteResp *objp)
-{
-        if (!xdr_Device_ErrorCode (xdrs, &objp->error))
-                return FALSE;
-        if (!xdr_u_long (xdrs, &objp->size))
-                return FALSE;
-       return TRUE;
-}
-
-bool_t
-xdr_Device_ReadParms (XDR *xdrs, Device_ReadParms *objp)
-{
-       register int32_t *buf;
-
-       if (xdrs->x_op == XDR_ENCODE) {
-                if (!xdr_Device_Link (xdrs, &objp->lid))
-                        return FALSE;
-               buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT);
-               if (buf == NULL) {
-                        if (!xdr_u_long (xdrs, &objp->requestSize))
-                                return FALSE;
-                        if (!xdr_u_long (xdrs, &objp->io_timeout))
-                                return FALSE;
-                        if (!xdr_u_long (xdrs, &objp->lock_timeout))
-                                return FALSE;
-
-               } else {
-               IXDR_PUT_U_LONG(buf, objp->requestSize);
-               IXDR_PUT_U_LONG(buf, objp->io_timeout);
-               IXDR_PUT_U_LONG(buf, objp->lock_timeout);
-               }
-                if (!xdr_Device_Flags (xdrs, &objp->flags))
-                        return FALSE;
-                if (!xdr_char (xdrs, &objp->termChar))
-                        return FALSE;
-               return TRUE;
-       } else if (xdrs->x_op == XDR_DECODE) {
-                if (!xdr_Device_Link (xdrs, &objp->lid))
-                        return FALSE;
-               buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT);
-               if (buf == NULL) {
-                        if (!xdr_u_long (xdrs, &objp->requestSize))
-                                return FALSE;
-                        if (!xdr_u_long (xdrs, &objp->io_timeout))
-                                return FALSE;
-                        if (!xdr_u_long (xdrs, &objp->lock_timeout))
-                                return FALSE;
-
-               } else {
-               objp->requestSize = IXDR_GET_U_LONG(buf);
-               objp->io_timeout = IXDR_GET_U_LONG(buf);
-               objp->lock_timeout = IXDR_GET_U_LONG(buf);
-               }
-                if (!xdr_Device_Flags (xdrs, &objp->flags))
-                        return FALSE;
-                if (!xdr_char (xdrs, &objp->termChar))
-                        return FALSE;
-        return TRUE;
-       }
-
-        if (!xdr_Device_Link (xdrs, &objp->lid))
-                return FALSE;
-        if (!xdr_u_long (xdrs, &objp->requestSize))
-                return FALSE;
-        if (!xdr_u_long (xdrs, &objp->io_timeout))
-                return FALSE;
-        if (!xdr_u_long (xdrs, &objp->lock_timeout))
-                return FALSE;
-        if (!xdr_Device_Flags (xdrs, &objp->flags))
-                return FALSE;
-        if (!xdr_char (xdrs, &objp->termChar))
-                return FALSE;
-       return TRUE;
-}
-
-bool_t
-xdr_Device_ReadResp (XDR *xdrs, Device_ReadResp *objp)
-{
-        if (!xdr_Device_ErrorCode (xdrs, &objp->error))
-                return FALSE;
-        if (!xdr_long (xdrs, &objp->reason))
-                return FALSE;
-        if (!xdr_bytes (xdrs, (char **)&objp->data.data_val, (u_int *) &objp->data.data_len, ~0))
-                return FALSE;
-       return TRUE;
-}
-
-bool_t
-xdr_Device_ReadStbResp (XDR *xdrs, Device_ReadStbResp *objp)
-{
-        if (!xdr_Device_ErrorCode (xdrs, &objp->error))
-                return FALSE;
-        if (!xdr_u_char (xdrs, &objp->stb))
-                return FALSE;
-       return TRUE;
-}
-
-bool_t
-xdr_Device_GenericParms (XDR *xdrs, Device_GenericParms *objp)
-{
-        if (!xdr_Device_Link (xdrs, &objp->lid))
-                return FALSE;
-        if (!xdr_Device_Flags (xdrs, &objp->flags))
-                return FALSE;
-        if (!xdr_u_long (xdrs, &objp->lock_timeout))
-                return FALSE;
-        if (!xdr_u_long (xdrs, &objp->io_timeout))
-                return FALSE;
-       return TRUE;
-}
-
-bool_t
-xdr_Device_RemoteFunc (XDR *xdrs, Device_RemoteFunc *objp)
-{
-       register int32_t *buf;
-
-       if (xdrs->x_op == XDR_ENCODE) {
-               buf = XDR_INLINE (xdrs, 4 * BYTES_PER_XDR_UNIT);
-               if (buf == NULL) {
-                        if (!xdr_u_long (xdrs, &objp->hostAddr))
-                                return FALSE;
-                        if (!xdr_u_short (xdrs, &objp->hostPort))
-                                return FALSE;
-                        if (!xdr_u_long (xdrs, &objp->progNum))
-                                return FALSE;
-                        if (!xdr_u_long (xdrs, &objp->progVers))
-                                return FALSE;
-
-               } else {
-               IXDR_PUT_U_LONG(buf, objp->hostAddr);
-               IXDR_PUT_U_SHORT(buf, objp->hostPort);
-               IXDR_PUT_U_LONG(buf, objp->progNum);
-               IXDR_PUT_U_LONG(buf, objp->progVers);
-               }
-                if (!xdr_Device_AddrFamily (xdrs, &objp->progFamily))
-                        return FALSE;
-               return TRUE;
-       } else if (xdrs->x_op == XDR_DECODE) {
-               buf = XDR_INLINE (xdrs, 4 * BYTES_PER_XDR_UNIT);
-               if (buf == NULL) {
-                        if (!xdr_u_long (xdrs, &objp->hostAddr))
-                                return FALSE;
-                        if (!xdr_u_short (xdrs, &objp->hostPort))
-                                return FALSE;
-                        if (!xdr_u_long (xdrs, &objp->progNum))
-                                return FALSE;
-                        if (!xdr_u_long (xdrs, &objp->progVers))
-                                return FALSE;
-
-               } else {
-               objp->hostAddr = IXDR_GET_U_LONG(buf);
-               objp->hostPort = IXDR_GET_U_SHORT(buf);
-               objp->progNum = IXDR_GET_U_LONG(buf);
-               objp->progVers = IXDR_GET_U_LONG(buf);
-               }
-                if (!xdr_Device_AddrFamily (xdrs, &objp->progFamily))
-                        return FALSE;
-        return TRUE;
-       }
-
-        if (!xdr_u_long (xdrs, &objp->hostAddr))
-                return FALSE;
-        if (!xdr_u_short (xdrs, &objp->hostPort))
-                return FALSE;
-        if (!xdr_u_long (xdrs, &objp->progNum))
-                return FALSE;
-        if (!xdr_u_long (xdrs, &objp->progVers))
-                return FALSE;
-        if (!xdr_Device_AddrFamily (xdrs, &objp->progFamily))
-                return FALSE;
-       return TRUE;
-}
-
-bool_t
-xdr_Device_EnableSrqParms (XDR *xdrs, Device_EnableSrqParms *objp)
-{
-        if (!xdr_Device_Link (xdrs, &objp->lid))
-                return FALSE;
-        if (!xdr_bool (xdrs, &objp->enable))
-                return FALSE;
-        if (!xdr_bytes (xdrs, (char **)&objp->handle.handle_val, (u_int *) &objp->handle.handle_len, 40))
-                return FALSE;
-       return TRUE;
-}
-
-bool_t
-xdr_Device_LockParms (XDR *xdrs, Device_LockParms *objp)
-{
-        if (!xdr_Device_Link (xdrs, &objp->lid))
-                return FALSE;
-        if (!xdr_Device_Flags (xdrs, &objp->flags))
-                return FALSE;
-        if (!xdr_u_long (xdrs, &objp->lock_timeout))
-                return FALSE;
-       return TRUE;
-}
-
-bool_t
-xdr_Device_DocmdParms (XDR *xdrs, Device_DocmdParms *objp)
-{
-       register int32_t *buf;
-
-       if (xdrs->x_op == XDR_ENCODE) {
-                if (!xdr_Device_Link (xdrs, &objp->lid))
-                        return FALSE;
-                if (!xdr_Device_Flags (xdrs, &objp->flags))
-                        return FALSE;
-               buf = XDR_INLINE (xdrs, 5 * BYTES_PER_XDR_UNIT);
-               if (buf == NULL) {
-                        if (!xdr_u_long (xdrs, &objp->io_timeout))
-                                return FALSE;
-                        if (!xdr_u_long (xdrs, &objp->lock_timeout))
-                                return FALSE;
-                        if (!xdr_long (xdrs, &objp->cmd))
-                                return FALSE;
-                        if (!xdr_bool (xdrs, &objp->network_order))
-                                return FALSE;
-                        if (!xdr_long (xdrs, &objp->datasize))
-                                return FALSE;
-
-               } else {
-               IXDR_PUT_U_LONG(buf, objp->io_timeout);
-               IXDR_PUT_U_LONG(buf, objp->lock_timeout);
-               IXDR_PUT_LONG(buf, objp->cmd);
-               IXDR_PUT_BOOL(buf, objp->network_order);
-               IXDR_PUT_LONG(buf, objp->datasize);
-               }
-                if (!xdr_bytes (xdrs, (char **)&objp->data_in.data_in_val, (u_int *) &objp->data_in.data_in_len, ~0))
-                        return FALSE;
-               return TRUE;
-       } else if (xdrs->x_op == XDR_DECODE) {
-                if (!xdr_Device_Link (xdrs, &objp->lid))
-                        return FALSE;
-                if (!xdr_Device_Flags (xdrs, &objp->flags))
-                        return FALSE;
-               buf = XDR_INLINE (xdrs, 5 * BYTES_PER_XDR_UNIT);
-               if (buf == NULL) {
-                        if (!xdr_u_long (xdrs, &objp->io_timeout))
-                                return FALSE;
-                        if (!xdr_u_long (xdrs, &objp->lock_timeout))
-                                return FALSE;
-                        if (!xdr_long (xdrs, &objp->cmd))
-                                return FALSE;
-                        if (!xdr_bool (xdrs, &objp->network_order))
-                                return FALSE;
-                        if (!xdr_long (xdrs, &objp->datasize))
-                                return FALSE;
-
-               } else {
-               objp->io_timeout = IXDR_GET_U_LONG(buf);
-               objp->lock_timeout = IXDR_GET_U_LONG(buf);
-               objp->cmd = IXDR_GET_LONG(buf);
-               objp->network_order = IXDR_GET_BOOL(buf);
-               objp->datasize = IXDR_GET_LONG(buf);
-               }
-                if (!xdr_bytes (xdrs, (char **)&objp->data_in.data_in_val, (u_int *) &objp->data_in.data_in_len, ~0))
-                        return FALSE;
-        return TRUE;
-       }
-
-        if (!xdr_Device_Link (xdrs, &objp->lid))
-                return FALSE;
-        if (!xdr_Device_Flags (xdrs, &objp->flags))
-                return FALSE;
-        if (!xdr_u_long (xdrs, &objp->io_timeout))
-                return FALSE;
-        if (!xdr_u_long (xdrs, &objp->lock_timeout))
-                return FALSE;
-        if (!xdr_long (xdrs, &objp->cmd))
-                return FALSE;
-        if (!xdr_bool (xdrs, &objp->network_order))
-                return FALSE;
-        if (!xdr_long (xdrs, &objp->datasize))
-                return FALSE;
-        if (!xdr_bytes (xdrs, (char **)&objp->data_in.data_in_val, (u_int *) &objp->data_in.data_in_len, ~0))
-                return FALSE;
-       return TRUE;
-}
-
-bool_t
-xdr_Device_DocmdResp (XDR *xdrs, Device_DocmdResp *objp)
-{
-        if (!xdr_Device_ErrorCode (xdrs, &objp->error))
-                return FALSE;
-        if (!xdr_bytes (xdrs, (char **)&objp->data_out.data_out_val, (u_int *) &objp->data_out.data_out_len, ~0))
-                return FALSE;
-       return TRUE;
-}
-
-bool_t
-xdr_Device_SrqParms (XDR *xdrs, Device_SrqParms *objp)
-{
-        if (!xdr_bytes (xdrs, (char **)&objp->handle.handle_val, (u_int *) &objp->handle.handle_len, ~0))
-                return FALSE;
-       return TRUE;
-}
diff --git a/hardware/conrad-digi-35-cpu/api.c b/hardware/conrad-digi-35-cpu/api.c
deleted file mode 100644 (file)
index 01adcef..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2014 Matthias Heidbrink <m-sigrok@heidbrink.biz>
- *
- * 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
- *  <em>Conrad DIGI 35 CPU</em> power supply driver
- *  @internal
- */
-
-#include "protocol.h"
-
-#define SERIALCOMM "9600/8n1"
-
-static const int32_t hwopts[] = {
-       SR_CONF_CONN,
-       SR_CONF_SERIALCOMM,
-};
-
-static const int32_t hwcaps[] = {
-       SR_CONF_POWER_SUPPLY,
-       SR_CONF_OUTPUT_VOLTAGE,
-       SR_CONF_OUTPUT_CURRENT,
-       /* There's no SR_CONF_OUTPUT_ENABLED; can't know/set status remotely. */
-       SR_CONF_OVER_CURRENT_PROTECTION,
-};
-
-SR_PRIV struct sr_dev_driver conrad_digi_35_cpu_driver_info;
-static struct sr_dev_driver *di = &conrad_digi_35_cpu_driver_info;
-
-static int init(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, di, LOG_PREFIX);
-}
-
-static GSList *scan(GSList *options)
-{
-       struct sr_dev_inst *sdi;
-       struct drv_context *drvc;
-       struct sr_config *src;
-       struct sr_channel *ch;
-       struct sr_serial_dev_inst *serial;
-       GSList *l, *devices;
-       const char *conn, *serialcomm;
-
-       devices = NULL;
-       drvc = di->priv;
-       drvc->instances = NULL;
-       conn = serialcomm = NULL;
-
-       for (l = options; l; l = l->next) {
-               src = l->data;
-               switch (src->key) {
-               case SR_CONF_CONN:
-                       conn = g_variant_get_string(src->data, NULL);
-                       break;
-               case SR_CONF_SERIALCOMM:
-                       serialcomm = g_variant_get_string(src->data, NULL);
-                       break;
-               }
-       }
-       if (!conn)
-               return NULL;
-       if (!serialcomm)
-               serialcomm = SERIALCOMM;
-
-       /*
-        * We cannot scan for this device because it is write-only.
-        * So just check that the port parameters are valid and assume that
-        * the device is there.
-        */
-
-       if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
-               return NULL;
-
-       if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
-               return NULL;
-
-       serial_flush(serial);
-       serial_close(serial);
-
-       sr_spew("Conrad DIGI 35 CPU assumed at %s.", conn);
-
-       if (!(sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, "Conrad", "DIGI 35 CPU", NULL)))
-               return NULL;
-
-       sdi->conn = serial;
-       sdi->priv = NULL;
-       sdi->driver = di;
-       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "CH1")))
-               return NULL;
-       sdi->channels = g_slist_append(sdi->channels, ch);
-
-       drvc->instances = g_slist_append(drvc->instances, sdi);
-       devices = g_slist_append(devices, sdi);
-
-       return devices;
-}
-
-static GSList *dev_list(void)
-{
-       return ((struct drv_context *)(di->priv))->instances;
-}
-
-static int cleanup(void)
-{
-       return std_dev_clear(di, NULL);
-}
-
-static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       int ret;
-       double dblval;
-
-       (void)cg;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       ret = SR_OK;
-       switch (key) {
-       case SR_CONF_OUTPUT_VOLTAGE:
-               dblval = g_variant_get_double(data);
-               if ((dblval < 0.0) || (dblval > 35.0)) {
-                       sr_err("Voltage out of range (0 - 35.0)!");
-                       return SR_ERR_ARG;
-               }
-               ret = send_msg1(sdi, 'V', (int) (dblval * 10 + 0.5));
-               break;
-       case SR_CONF_OUTPUT_CURRENT:
-               dblval = g_variant_get_double(data);
-               if ((dblval < 0.01) || (dblval > 2.55)) {
-                       sr_err("Current out of range (0 - 2.55)!");
-                       return SR_ERR_ARG;
-               }
-               ret = send_msg1(sdi, 'C', (int) (dblval * 100 + 0.5));
-               break;
-       /* No SR_CONF_OUTPUT_ENABLED :-( . */
-       case SR_CONF_OVER_CURRENT_PROTECTION:
-               if (g_variant_get_boolean(data))
-                       ret = send_msg1(sdi, 'V', 900);
-               else /* Constant current mode */
-                       ret = send_msg1(sdi, 'V', 901);
-               break;
-       default:
-               ret = SR_ERR_NA;
-       }
-
-       return ret;
-}
-
-static int config_list(int 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_INT32,
-                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
-               break;
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return ret;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
-{
-       (void)cb_data;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       return SR_OK;
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       (void)cb_data;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       return SR_OK;
-}
-
-SR_PRIV struct sr_dev_driver conrad_digi_35_cpu_driver_info = {
-       .name = "conrad-digi-35-cpu",
-       .longname = "Conrad DIGI 35 CPU",
-       .api_version = 1,
-       .init = init,
-       .cleanup = cleanup,
-       .scan = scan,
-       .dev_list = 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 = dev_acquisition_stop,
-       .priv = NULL,
-};
diff --git a/hardware/conrad-digi-35-cpu/protocol.c b/hardware/conrad-digi-35-cpu/protocol.c
deleted file mode 100644 (file)
index 7657b31..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2014 Matthias Heidbrink <m-sigrok@heidbrink.biz>
- *
- * 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
- * <em>Conrad DIGI 35 CPU</em> power supply driver
- * @internal
- */
-
-#include "protocol.h"
-
-/**
- * Send command with parameter.
- *
- * @param[in] cmd Command
- * @param[in] param Parameter (0..999, depending on command).
- *
- * @retval SR_OK Success.
- * @retval SR_ERR_ARG Invalid argument.
- * @retval SR_ERR Error.
- */
-SR_PRIV int send_msg1(const struct sr_dev_inst *sdi, char cmd, int param)
-{
-       struct sr_serial_dev_inst *serial;
-       char buf[5];
-
-       if (!sdi || !(serial = sdi->conn))
-               return SR_ERR_ARG;
-
-       snprintf(buf, sizeof(buf), "%c%03d", cmd, param);
-       buf[4] = '\r';
-
-       sr_spew("send_msg1(): %c%c%c%c\\r", buf[0], buf[1], buf[2], buf[3]);
-
-       if (serial_write(serial, buf, sizeof(buf)) == -1) {
-               sr_err("Write error for cmd=%c: %d %s", cmd, errno, strerror(errno));
-               return SR_ERR;
-       }
-
-       /*
-        * Wait 50ms to ensure that the device does not swallow any of the
-        * following commands.
-        */
-       g_usleep(50000);
-
-       return SR_OK;
-}
diff --git a/hardware/conrad-digi-35-cpu/protocol.h b/hardware/conrad-digi-35-cpu/protocol.h
deleted file mode 100644 (file)
index fcde852..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2014 Matthias Heidbrink <m-sigrok@heidbrink.biz>
- *
- * 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
- * <em>Conrad DIGI 35 CPU</em> power supply driver
- * @internal
- */
-
-#ifndef LIBSIGROK_HARDWARE_CONRAD_DIGI_35_CPU_PROTOCOL_H
-#define LIBSIGROK_HARDWARE_CONRAD_DIGI_35_CPU_PROTOCOL_H
-
-#include <stdint.h>
-#include <errno.h>
-#include <string.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "conrad-digi-35-cpu"
-
-SR_PRIV int send_msg1(const struct sr_dev_inst *sdi, char cmd, int param);
-
-#endif
diff --git a/hardware/demo/demo.c b/hardware/demo/demo.c
deleted file mode 100644 (file)
index b2f3a50..0000000
+++ /dev/null
@@ -1,782 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
- * Copyright (C) 2011 Olivier Fauchon <olivier@aixmarseille.com>
- * 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 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <math.h>
-#ifdef _WIN32
-#include <io.h>
-#include <fcntl.h>
-#define pipe(fds) _pipe(fds, 4096, _O_BINARY)
-#endif
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "demo"
-
-#define DEFAULT_NUM_LOGIC_CHANNELS     8
-#define DEFAULT_NUM_ANALOG_CHANNELS    4
-
-/* The size in bytes of chunks to send through the session bus. */
-#define LOGIC_BUFSIZE        4096
-/* Size of the analog pattern space per channel. */
-#define ANALOG_BUFSIZE       4096
-
-#define ANALOG_AMPLITUDE 25
-#define ANALOG_SAMPLES_PER_PERIOD 20
-
-/* Logic patterns we can generate. */
-enum {
-       /**
-        * Spells "sigrok" across 8 channels using '0's (with '1's as
-        * "background") when displayed using the 'bits' output format.
-        * The pattern is repeated every 8 channels, shifted to the right
-        * in time by one bit.
-        */
-       PATTERN_SIGROK,
-
-       /** Pseudo-random values on all channels. */
-       PATTERN_RANDOM,
-
-       /**
-        * Incrementing number across 8 channels. The pattern is repeated
-        * every 8 channels, shifted to the right in time by one bit.
-        */
-       PATTERN_INC,
-
-       /** All channels have a low logic state. */
-       PATTERN_ALL_LOW,
-
-       /** All channels have a high logic state. */
-       PATTERN_ALL_HIGH,
-};
-
-/* Analog patterns we can generate. */
-enum {
-       /**
-        * Square wave.
-        */
-       PATTERN_SQUARE,
-       PATTERN_SINE,
-       PATTERN_TRIANGLE,
-       PATTERN_SAWTOOTH,
-};
-
-static const char *logic_pattern_str[] = {
-       "sigrok",
-       "random",
-       "incremental",
-       "all-low",
-       "all-high",
-};
-
-static const char *analog_pattern_str[] = {
-       "square",
-       "sine",
-       "triangle",
-       "sawtooth",
-};
-
-struct analog_gen {
-       int pattern;
-       float pattern_data[ANALOG_BUFSIZE];
-       unsigned int num_samples;
-       struct sr_datafeed_analog packet;
-};
-
-/* Private, per-device-instance driver context. */
-struct dev_context {
-       int pipe_fds[2];
-       GIOChannel *channel;
-       uint64_t cur_samplerate;
-       uint64_t limit_samples;
-       uint64_t limit_msec;
-       uint64_t logic_counter;
-       uint64_t analog_counter;
-       int64_t starttime;
-       uint64_t step;
-       /* Logic */
-       int32_t num_logic_channels;
-       unsigned int logic_unitsize;
-       /* There is only ever one logic channel group, so its pattern goes here. */
-       uint8_t logic_pattern;
-       unsigned char logic_data[LOGIC_BUFSIZE];
-       /* Analog */
-       int32_t num_analog_channels;
-       GSList *analog_channel_groups;
-};
-
-static const int32_t scanopts[] = {
-       SR_CONF_NUM_LOGIC_CHANNELS,
-       SR_CONF_NUM_ANALOG_CHANNELS,
-};
-
-static const int devopts[] = {
-       SR_CONF_LOGIC_ANALYZER,
-       SR_CONF_DEMO_DEV,
-       SR_CONF_SAMPLERATE,
-       SR_CONF_LIMIT_SAMPLES,
-       SR_CONF_LIMIT_MSEC,
-};
-
-static const int devopts_cg[] = {
-       SR_CONF_PATTERN_MODE,
-};
-
-static const uint64_t samplerates[] = {
-       SR_HZ(1),
-       SR_GHZ(1),
-       SR_HZ(1),
-};
-
-static uint8_t pattern_sigrok[] = {
-       0x4c, 0x92, 0x92, 0x92, 0x64, 0x00, 0x00, 0x00,
-       0x82, 0xfe, 0xfe, 0x82, 0x00, 0x00, 0x00, 0x00,
-       0x7c, 0x82, 0x82, 0x92, 0x74, 0x00, 0x00, 0x00,
-       0xfe, 0x12, 0x12, 0x32, 0xcc, 0x00, 0x00, 0x00,
-       0x7c, 0x82, 0x82, 0x82, 0x7c, 0x00, 0x00, 0x00,
-       0xfe, 0x10, 0x28, 0x44, 0x82, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0xbe, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
-SR_PRIV struct sr_dev_driver demo_driver_info;
-static struct sr_dev_driver *di = &demo_driver_info;
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data);
-
-
-static int init(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, di, LOG_PREFIX);
-}
-
-static void generate_analog_pattern(const struct sr_channel_group *cg, uint64_t sample_rate)
-{
-       struct analog_gen *ag;
-       double t, frequency;
-       float value;
-       unsigned int num_samples, i;
-       int last_end;
-
-       ag = cg->priv;
-       num_samples = ANALOG_BUFSIZE / sizeof(float);
-
-       sr_dbg("Generating %s pattern for channel group %s",
-              analog_pattern_str[ag->pattern], cg->name);
-
-       switch (ag->pattern) {
-       case PATTERN_SQUARE:
-               value = ANALOG_AMPLITUDE;
-               last_end = 0;
-               for (i = 0; i < num_samples; i++) {
-                       if (i % 5 == 0)
-                               value = -value;
-                       if (i % 10 == 0)
-                               last_end = i - 1;
-                       ag->pattern_data[i] = value;
-               }
-               ag->num_samples = last_end;
-               break;
-
-       case PATTERN_SINE:
-               frequency = (double) sample_rate / ANALOG_SAMPLES_PER_PERIOD;
-
-               /* Make sure the number of samples we put out is an integer
-                * multiple of our period size */
-               /* FIXME we actually need only one period. A ringbuffer would be
-                * usefull here.*/
-               while (num_samples % ANALOG_SAMPLES_PER_PERIOD != 0)
-                       num_samples--;
-
-               for (i = 0; i < num_samples; i++) {
-                       t = (double) i / (double) sample_rate;
-                       ag->pattern_data[i] = ANALOG_AMPLITUDE *
-                                               sin(2 * M_PI * frequency * t);
-               }
-
-               ag->num_samples = num_samples;
-               break;
-
-       case PATTERN_TRIANGLE:
-               frequency = (double) sample_rate / ANALOG_SAMPLES_PER_PERIOD;
-
-               while (num_samples % ANALOG_SAMPLES_PER_PERIOD != 0)
-                       num_samples--;
-
-               for (i = 0; i < num_samples; i++) {
-                       t = (double) i / (double) sample_rate;
-                       ag->pattern_data[i] = (2 * ANALOG_AMPLITUDE / M_PI) *
-                                               asin(sin(2 * M_PI * frequency * t));
-               }
-
-               ag->num_samples = num_samples;
-               break;
-
-       case PATTERN_SAWTOOTH:
-               frequency = (double) sample_rate / ANALOG_SAMPLES_PER_PERIOD;
-
-               while (num_samples % ANALOG_SAMPLES_PER_PERIOD != 0)
-                       num_samples--;
-
-               for (i = 0; i < num_samples; i++) {
-                       t = (double) i / (double) sample_rate;
-                       ag->pattern_data[i] = 2 * ANALOG_AMPLITUDE *
-                                               ((t * frequency) - floor(0.5f + t * frequency));
-               }
-
-               ag->num_samples = num_samples;
-               break;
-       }
-}
-
-static GSList *scan(GSList *options)
-{
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       struct sr_dev_inst *sdi;
-       struct sr_channel *ch;
-       struct sr_channel_group *cg;
-       struct sr_config *src;
-       struct analog_gen *ag;
-       GSList *devices, *l;
-       int num_logic_channels, num_analog_channels, pattern, i;
-       char channel_name[16];
-
-       drvc = di->priv;
-
-       num_logic_channels = DEFAULT_NUM_LOGIC_CHANNELS;
-       num_analog_channels = DEFAULT_NUM_ANALOG_CHANNELS;
-       for (l = options; l; l = l->next) {
-               src = l->data;
-               switch (src->key) {
-               case SR_CONF_NUM_LOGIC_CHANNELS:
-                       num_logic_channels = g_variant_get_int32(src->data);
-                       break;
-               case SR_CONF_NUM_ANALOG_CHANNELS:
-                       num_analog_channels = g_variant_get_int32(src->data);
-                       break;
-               }
-       }
-
-       devices = NULL;
-       sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, "Demo device", NULL, NULL);
-       if (!sdi) {
-               sr_err("Device instance creation failed.");
-               return NULL;
-       }
-       sdi->driver = di;
-
-       if (!(devc = g_try_malloc(sizeof(struct dev_context)))) {
-               sr_err("Device context malloc failed.");
-               return NULL;
-       }
-       devc->cur_samplerate = SR_KHZ(200);
-       devc->limit_samples = 0;
-       devc->limit_msec = 0;
-       devc->step = 0;
-       devc->num_logic_channels = num_logic_channels;
-       devc->logic_unitsize = (devc->num_logic_channels + 7) / 8;
-       devc->logic_pattern = PATTERN_SIGROK;
-       devc->num_analog_channels = num_analog_channels;
-       devc->analog_channel_groups = NULL;
-
-       /* Logic channels, all in one channel group. */
-       if (!(cg = g_try_malloc(sizeof(struct sr_channel_group))))
-               return NULL;
-       cg->name = g_strdup("Logic");
-       cg->channels = NULL;
-       cg->priv = NULL;
-       for (i = 0; i < num_logic_channels; i++) {
-               sprintf(channel_name, "D%d", i);
-               if (!(ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE, channel_name)))
-                       return NULL;
-               sdi->channels = g_slist_append(sdi->channels, ch);
-               cg->channels = g_slist_append(cg->channels, ch);
-       }
-       sdi->channel_groups = g_slist_append(NULL, cg);
-
-       /* Analog channels, channel groups and pattern generators. */
-
-       pattern = 0;
-       for (i = 0; i < num_analog_channels; i++) {
-               sprintf(channel_name, "A%d", i);
-               if (!(ch = sr_channel_new(i + num_logic_channels,
-                               SR_CHANNEL_ANALOG, TRUE, channel_name)))
-                       return NULL;
-               sdi->channels = g_slist_append(sdi->channels, ch);
-
-               /* Every analog channel gets its own channel group. */
-               if (!(cg = g_try_malloc(sizeof(struct sr_channel_group))))
-                       return NULL;
-               cg->name = g_strdup(channel_name);
-               cg->channels = g_slist_append(NULL, ch);
-
-               /* Every channel group gets a generator struct. */
-               if (!(ag = g_try_malloc(sizeof(struct analog_gen))))
-                       return NULL;
-               ag->packet.channels = cg->channels;
-               ag->packet.mq = 0;
-               ag->packet.mqflags = 0;
-               ag->packet.unit = SR_UNIT_VOLT;
-               ag->packet.data = ag->pattern_data;
-               ag->pattern = pattern;
-               cg->priv = ag;
-
-               sdi->channel_groups = g_slist_append(sdi->channel_groups, cg);
-               devc->analog_channel_groups = g_slist_append(devc->analog_channel_groups, cg);
-
-               if (++pattern == ARRAY_SIZE(analog_pattern_str))
-                       pattern = 0;
-       }
-
-       sdi->priv = devc;
-       devices = g_slist_append(devices, sdi);
-       drvc->instances = g_slist_append(drvc->instances, sdi);
-
-       return devices;
-}
-
-static GSList *dev_list(void)
-{
-       return ((struct drv_context *)(di->priv))->instances;
-}
-
-static int dev_open(struct sr_dev_inst *sdi)
-{
-       sdi->status = SR_ST_ACTIVE;
-
-       return SR_OK;
-}
-
-static int dev_close(struct sr_dev_inst *sdi)
-{
-       sdi->status = SR_ST_INACTIVE;
-
-       return SR_OK;
-}
-
-static int cleanup(void)
-{
-       return std_dev_clear(di, NULL);
-}
-
-static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       struct sr_channel *ch;
-       struct analog_gen *ag;
-       int pattern;
-
-       if (!sdi)
-               return SR_ERR_ARG;
-
-       devc = sdi->priv;
-       switch (id) {
-       case SR_CONF_SAMPLERATE:
-               *data = g_variant_new_uint64(devc->cur_samplerate);
-               break;
-       case SR_CONF_LIMIT_SAMPLES:
-               *data = g_variant_new_uint64(devc->limit_samples);
-               break;
-       case SR_CONF_LIMIT_MSEC:
-               *data = g_variant_new_uint64(devc->limit_msec);
-               break;
-       case SR_CONF_PATTERN_MODE:
-               if (!cg)
-                       return SR_ERR_CHANNEL_GROUP;
-               ch = cg->channels->data;
-               if (ch->type == SR_CHANNEL_LOGIC) {
-                       pattern = devc->logic_pattern;
-                       *data = g_variant_new_string(logic_pattern_str[pattern]);
-               } else if (ch->type == SR_CHANNEL_ANALOG) {
-                       ag = cg->priv;
-                       pattern = ag->pattern;
-                       *data = g_variant_new_string(analog_pattern_str[pattern]);
-               } else
-                       return SR_ERR_BUG;
-               break;
-       case SR_CONF_NUM_LOGIC_CHANNELS:
-               *data = g_variant_new_int32(devc->num_logic_channels);
-               break;
-       case SR_CONF_NUM_ANALOG_CHANNELS:
-               *data = g_variant_new_int32(devc->num_analog_channels);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       struct analog_gen *ag;
-       struct sr_channel *ch;
-       int pattern, ret;
-       unsigned int i;
-       const char *stropt;
-
-       devc = sdi->priv;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       ret = SR_OK;
-       switch (id) {
-       case SR_CONF_SAMPLERATE:
-               devc->cur_samplerate = g_variant_get_uint64(data);
-               sr_dbg("Setting samplerate to %" PRIu64, devc->cur_samplerate);
-               break;
-       case SR_CONF_LIMIT_SAMPLES:
-               devc->limit_msec = 0;
-               devc->limit_samples = g_variant_get_uint64(data);
-               sr_dbg("Setting sample limit to %" PRIu64, devc->limit_samples);
-               break;
-       case SR_CONF_LIMIT_MSEC:
-               devc->limit_msec = g_variant_get_uint64(data);
-               devc->limit_samples = 0;
-               sr_dbg("Setting time limit to %" PRIu64"ms", devc->limit_msec);
-               break;
-       case SR_CONF_PATTERN_MODE:
-               if (!cg)
-                       return SR_ERR_CHANNEL_GROUP;
-               stropt = g_variant_get_string(data, NULL);
-               ch = cg->channels->data;
-               pattern = -1;
-               if (ch->type == SR_CHANNEL_LOGIC) {
-                       for (i = 0; i < ARRAY_SIZE(logic_pattern_str); i++) {
-                               if (!strcmp(stropt, logic_pattern_str[i])) {
-                                       pattern = i;
-                                       break;
-                               }
-                       }
-                       if (pattern == -1)
-                               return SR_ERR_ARG;
-                       devc->logic_pattern = pattern;
-
-                       /* Might as well do this now, these are static. */
-                       if (pattern == PATTERN_ALL_LOW)
-                               memset(devc->logic_data, 0x00, LOGIC_BUFSIZE);
-                       else if (pattern == PATTERN_ALL_HIGH)
-                               memset(devc->logic_data, 0xff, LOGIC_BUFSIZE);
-                       sr_dbg("Setting logic pattern to %s",
-                                       logic_pattern_str[pattern]);
-               } else if (ch->type == SR_CHANNEL_ANALOG) {
-                       for (i = 0; i < ARRAY_SIZE(analog_pattern_str); i++) {
-                               if (!strcmp(stropt, analog_pattern_str[i])) {
-                                       pattern = i;
-                                       break;
-                               }
-                       }
-                       if (pattern == -1)
-                               return SR_ERR_ARG;
-                       sr_dbg("Setting analog pattern for channel group %s to %s",
-                                       cg->name, analog_pattern_str[pattern]);
-                       ag = cg->priv;
-                       ag->pattern = pattern;
-               } else
-                       return SR_ERR_BUG;
-               break;
-       default:
-               ret = SR_ERR_NA;
-       }
-
-       return ret;
-}
-
-static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct sr_channel *ch;
-       GVariant *gvar;
-       GVariantBuilder gvb;
-
-       (void)sdi;
-
-       if (key == SR_CONF_SCAN_OPTIONS) {
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               scanopts, ARRAY_SIZE(scanopts), sizeof(int32_t));
-               return SR_OK;
-       }
-
-       if (!sdi)
-               return SR_ERR_ARG;
-
-       if (!cg) {
-               switch (key) {
-               case SR_CONF_DEVICE_OPTIONS:
-                       *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                                       devopts, ARRAY_SIZE(devopts), sizeof(int32_t));
-                       break;
-               case SR_CONF_SAMPLERATE:
-                       g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
-                       gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), samplerates,
-                                       ARRAY_SIZE(samplerates), sizeof(uint64_t));
-                       g_variant_builder_add(&gvb, "{sv}", "samplerate-steps", gvar);
-                       *data = g_variant_builder_end(&gvb);
-                       break;
-               default:
-                       return SR_ERR_NA;
-               }
-       } else {
-               ch = cg->channels->data;
-               switch (key) {
-               case SR_CONF_DEVICE_OPTIONS:
-                       *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                                       devopts_cg, ARRAY_SIZE(devopts_cg), sizeof(int32_t));
-                       break;
-               case SR_CONF_PATTERN_MODE:
-                       if (ch->type == SR_CHANNEL_LOGIC)
-                               *data = g_variant_new_strv(logic_pattern_str,
-                                               ARRAY_SIZE(logic_pattern_str));
-                       else if (ch->type == SR_CHANNEL_ANALOG)
-                               *data = g_variant_new_strv(analog_pattern_str,
-                                               ARRAY_SIZE(analog_pattern_str));
-                       else
-                               return SR_ERR_BUG;
-                       break;
-               default:
-                       return SR_ERR_NA;
-               }
-       }
-
-       return SR_OK;
-}
-
-static void logic_generator(struct sr_dev_inst *sdi, uint64_t size)
-{
-       struct dev_context *devc;
-       uint64_t i, j;
-       uint8_t pat;
-
-       devc = sdi->priv;
-
-       switch (devc->logic_pattern) {
-       case PATTERN_SIGROK:
-               memset(devc->logic_data, 0x00, size);
-               for (i = 0; i < size; i += devc->logic_unitsize) {
-                       for (j = 0; j < devc->logic_unitsize; j++) {
-                               pat = pattern_sigrok[(devc->step + j) % sizeof(pattern_sigrok)] >> 1;
-                               devc->logic_data[i + j] = ~pat;
-                       }
-                       devc->step++;
-               }
-               break;
-       case PATTERN_RANDOM:
-               for (i = 0; i < size; i++)
-                       devc->logic_data[i] = (uint8_t)(rand() & 0xff);
-               break;
-       case PATTERN_INC:
-               for (i = 0; i < size; i++) {
-                       for (j = 0; j < devc->logic_unitsize; j++) {
-                               devc->logic_data[i + j] = devc->step;
-                       }
-                       devc->step++;
-               }
-               break;
-       case PATTERN_ALL_LOW:
-       case PATTERN_ALL_HIGH:
-               /* These were set when the pattern mode was selected. */
-               break;
-       default:
-               sr_err("Unknown pattern: %d.", devc->logic_pattern);
-               break;
-       }
-}
-
-/* Callback handling data */
-static int prepare_data(int fd, int revents, void *cb_data)
-{
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_logic logic;
-       struct sr_channel_group *cg;
-       struct analog_gen *ag;
-       GSList *l;
-       uint64_t logic_todo, analog_todo, expected_samplenum, analog_samples, sending_now;
-       int64_t time, elapsed;
-
-       (void)fd;
-       (void)revents;
-
-       sdi = cb_data;
-       devc = sdi->priv;
-
-       /* How many "virtual" samples should we have collected by now? */
-       time = g_get_monotonic_time();
-       elapsed = time - devc->starttime;
-       expected_samplenum = elapsed * devc->cur_samplerate / 1000000;
-
-       /* Of those, how many do we still have to send? */
-       logic_todo = MIN(expected_samplenum, devc->limit_samples) - devc->logic_counter;
-       analog_todo = MIN(expected_samplenum, devc->limit_samples) - devc->analog_counter;
-
-       while (logic_todo || analog_todo) {
-               /* Logic */
-               if (devc->num_logic_channels > 0 && logic_todo > 0) {
-                       sending_now = MIN(logic_todo,
-                                       LOGIC_BUFSIZE / devc->logic_unitsize);
-                       logic_generator(sdi, sending_now * devc->logic_unitsize);
-                       packet.type = SR_DF_LOGIC;
-                       packet.payload = &logic;
-                       logic.length = sending_now * devc->logic_unitsize;
-                       logic.unitsize = devc->logic_unitsize;
-                       logic.data = devc->logic_data;
-                       sr_session_send(sdi, &packet);
-                       logic_todo -= sending_now;
-                       devc->logic_counter += sending_now;
-               }
-
-               /* Analog, one channel at a time */
-               if (devc->num_analog_channels > 0 && analog_todo > 0) {
-                       sending_now = 0;
-                       for (l = devc->analog_channel_groups; l; l = l->next) {
-                               cg = l->data;
-                               ag = cg->priv;
-                               packet.type = SR_DF_ANALOG;
-                               packet.payload = &ag->packet;
-
-                               /* FIXME we should make sure we output a whole
-                                * period of data before we send out again the
-                                * beginning of our buffer. A ring buffer would
-                                * help here as well */
-
-                               analog_samples = MIN(analog_todo, ag->num_samples);
-                               /* Whichever channel group gets there first. */
-                               sending_now = MAX(sending_now, analog_samples);
-                               ag->packet.num_samples = analog_samples;
-                               sr_session_send(sdi, &packet);
-                       }
-                       analog_todo -= sending_now;
-                       devc->analog_counter += sending_now;
-               }
-       }
-
-       if (devc->logic_counter >= devc->limit_samples &&
-                       devc->analog_counter >= devc->limit_samples) {
-               sr_dbg("Requested number of samples reached.");
-               dev_acquisition_stop(sdi, cb_data);
-               return TRUE;
-       }
-
-       return TRUE;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
-{
-       GSList *l;
-       struct dev_context *devc;
-
-       (void)cb_data;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       devc = sdi->priv;
-       if (devc->limit_samples == 0)
-               return SR_ERR;
-       devc->logic_counter = devc->analog_counter = 0;
-
-       /*
-        * Setting two channels connected by a pipe is a remnant from when the
-        * demo driver generated data in a thread, and collected and sent the
-        * data in the main program loop.
-        * They are kept here because it provides a convenient way of setting
-        * up a timeout-based polling mechanism.
-        */
-       if (pipe(devc->pipe_fds)) {
-               sr_err("%s: pipe() failed", __func__);
-               return SR_ERR;
-       }
-
-       for (l = devc->analog_channel_groups; l; l = l->next) {
-               generate_analog_pattern(l->data, devc->cur_samplerate);
-       }
-
-       devc->channel = g_io_channel_unix_new(devc->pipe_fds[0]);
-
-       g_io_channel_set_flags(devc->channel, G_IO_FLAG_NONBLOCK, NULL);
-
-       /* Set channel encoding to binary (default is UTF-8). */
-       g_io_channel_set_encoding(devc->channel, NULL, NULL);
-
-       /* Make channels to unbuffered. */
-       g_io_channel_set_buffered(devc->channel, FALSE);
-
-       sr_session_source_add_channel(sdi->session, devc->channel, G_IO_IN | G_IO_ERR,
-                       40, prepare_data, (void *)sdi);
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(sdi, LOG_PREFIX);
-
-       /* We use this timestamp to decide how many more samples to send. */
-       devc->starttime = g_get_monotonic_time();
-
-       return SR_OK;
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct dev_context *devc;
-       struct sr_datafeed_packet packet;
-
-       (void)cb_data;
-
-       devc = sdi->priv;
-       sr_dbg("Stopping acquisition.");
-
-       sr_session_source_remove_channel(sdi->session, devc->channel);
-       g_io_channel_shutdown(devc->channel, FALSE, NULL);
-       g_io_channel_unref(devc->channel);
-       devc->channel = NULL;
-
-       /* Send last packet. */
-       packet.type = SR_DF_END;
-       sr_session_send(sdi, &packet);
-
-       return SR_OK;
-}
-
-SR_PRIV struct sr_dev_driver demo_driver_info = {
-       .name = "demo",
-       .longname = "Demo driver and pattern generator",
-       .api_version = 1,
-       .init = init,
-       .cleanup = cleanup,
-       .scan = scan,
-       .dev_list = 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,
-       .priv = NULL,
-};
diff --git a/hardware/fluke-dmm/api.c b/hardware/fluke-dmm/api.c
deleted file mode 100644 (file)
index 3d739a1..0000000
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012 Bert Vermeulen <bert@biot.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 <glib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <string.h>
-#include <errno.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-#include "fluke-dmm.h"
-
-static const int32_t hwopts[] = {
-       SR_CONF_CONN,
-       SR_CONF_SERIALCOMM,
-};
-
-static const int32_t hwcaps[] = {
-       SR_CONF_MULTIMETER,
-       SR_CONF_LIMIT_SAMPLES,
-       SR_CONF_LIMIT_MSEC,
-       SR_CONF_CONTINUOUS,
-};
-
-SR_PRIV struct sr_dev_driver flukedmm_driver_info;
-static struct sr_dev_driver *di = &flukedmm_driver_info;
-
-static char *scan_conn[] = {
-       /* 287/289 */
-       "115200/8n1",
-       /* 187/189 */
-       "9600/8n1",
-       /* Scopemeter 190 series */
-       "1200/8n1",
-       NULL
-};
-
-static const struct flukedmm_profile supported_flukedmm[] = {
-       { FLUKE_187, "187", 100, 1000 },
-       { FLUKE_189, "189", 100, 1000 },
-       { FLUKE_287, "287", 100, 1000 },
-       { FLUKE_190, "199B", 1000, 3500 },
-};
-
-static int init(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, di, LOG_PREFIX);
-}
-
-static GSList *fluke_scan(const char *conn, const char *serialcomm)
-{
-       struct sr_dev_inst *sdi;
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       struct sr_channel *ch;
-       struct sr_serial_dev_inst *serial;
-       GSList *devices;
-       int retry, len, i, s;
-       char buf[128], *b, **tokens;
-
-       if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
-               return NULL;
-
-       if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
-               return NULL;
-
-       drvc = di->priv;
-       b = buf;
-       retry = 0;
-       devices = NULL;
-       /* We'll try the discovery sequence three times in case the device
-        * is not in an idle state when we send ID. */
-       while (!devices && retry < 3) {
-               retry++;
-               serial_flush(serial);
-               if (serial_write(serial, "ID\r", 3) == -1) {
-                       sr_err("Unable to send ID string: %s.",
-                              strerror(errno));
-                       continue;
-               }
-
-               /* Response is first a CMD_ACK byte (ASCII '0' for OK,
-                * or '1' to signify an error. */
-               len = 128;
-               serial_readline(serial, &b, &len, 150);
-               if (len != 1)
-                       continue;
-               if (buf[0] != '0')
-                       continue;
-
-               /* If CMD_ACK was OK, ID string follows. */
-               len = 128;
-               serial_readline(serial, &b, &len, 850);
-               if (len < 10)
-                       continue;
-               if (strcspn(buf, ",") < 15)
-                       /* Looks like it's comma-separated. */
-                       tokens = g_strsplit(buf, ",", 3);
-               else
-                       /* Fluke 199B, at least, uses semicolon. */
-                       tokens = g_strsplit(buf, ";", 3);
-               if (!strncmp("FLUKE", tokens[0], 5)
-                               && tokens[1] && tokens[2]) {
-                       for (i = 0; supported_flukedmm[i].model; i++) {
-                               if (strcmp(supported_flukedmm[i].modelname, tokens[0] + 6))
-                                       continue;
-                               /* Skip leading spaces in version number. */
-                               for (s = 0; tokens[1][s] == ' '; s++);
-                               if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "Fluke",
-                                               tokens[0] + 6, tokens[1] + s)))
-                                       return NULL;
-                               if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
-                                       sr_err("Device context malloc failed.");
-                                       return NULL;
-                               }
-                               devc->profile = &supported_flukedmm[i];
-                               sdi->inst_type = SR_INST_SERIAL;
-                               sdi->conn = serial;
-                               sdi->priv = devc;
-                               sdi->driver = di;
-                               if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1")))
-                                       return NULL;
-                               sdi->channels = g_slist_append(sdi->channels, ch);
-                               drvc->instances = g_slist_append(drvc->instances, sdi);
-                               devices = g_slist_append(devices, sdi);
-                               break;
-                       }
-               }
-               g_strfreev(tokens);
-               if (devices)
-                       /* Found one. */
-                       break;
-       }
-       serial_close(serial);
-       if (!devices)
-               sr_serial_dev_inst_free(serial);
-
-       return devices;
-}
-
-static GSList *scan(GSList *options)
-{
-       struct sr_config *src;
-       GSList *l, *devices;
-       int i;
-       const char *conn, *serialcomm;
-
-       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 = fluke_scan(conn, serialcomm);
-       } else {
-               for (i = 0; scan_conn[i]; i++) {
-                       if ((devices = fluke_scan(conn, scan_conn[i])))
-                               break;
-                       /* The Scopemeter 199B, at least, requires this
-                        * after all the 115k/9.6k confusion. */
-                       g_usleep(5000);
-               }
-       }
-
-       return devices;
-}
-
-static GSList *dev_list(void)
-{
-       return ((struct drv_context *)(di->priv))->instances;
-}
-
-static int cleanup(void)
-{
-       return std_dev_clear(di, NULL);
-}
-
-static int config_set(int id, 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;
-
-       if (!(devc = sdi->priv)) {
-               sr_err("sdi->priv was NULL.");
-               return SR_ERR_BUG;
-       }
-
-       switch (id) {
-       case SR_CONF_LIMIT_MSEC:
-               /* TODO: not yet implemented */
-               if (g_variant_get_uint64(data) == 0) {
-                       sr_err("LIMIT_MSEC can't be 0.");
-                       return SR_ERR;
-               }
-               devc->limit_msec = g_variant_get_uint64(data);
-               sr_dbg("Setting time limit to %" PRIu64 "ms.",
-                      devc->limit_msec);
-               break;
-       case SR_CONF_LIMIT_SAMPLES:
-               devc->limit_samples = g_variant_get_uint64(data);
-               sr_dbg("Setting sample limit to %" PRIu64 ".",
-                      devc->limit_samples);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_list(int 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_INT32,
-                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
-               break;
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       if (!(devc = sdi->priv)) {
-               sr_err("sdi->priv was NULL.");
-               return SR_ERR_BUG;
-       }
-
-       devc->cb_data = cb_data;
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(cb_data, LOG_PREFIX);
-
-       /* Poll every 100ms, or whenever some data comes in. */
-       serial = sdi->conn;
-       serial_source_add(sdi->session, serial, G_IO_IN, 50,
-                       fluke_receive_data, (void *)sdi);
-
-       if (serial_write(serial, "QM\r", 3) == -1) {
-               sr_err("Unable to send QM: %s.", strerror(errno));
-               return SR_ERR;
-       }
-       devc->cmd_sent_at = g_get_monotonic_time() / 1000;
-       devc->expect_response = TRUE;
-
-       return SR_OK;
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       return std_serial_dev_acquisition_stop(sdi, cb_data, std_serial_dev_close,
-                       sdi->conn, LOG_PREFIX);
-}
-
-SR_PRIV struct sr_dev_driver flukedmm_driver_info = {
-       .name = "fluke-dmm",
-       .longname = "Fluke 18x/28x series DMMs",
-       .api_version = 1,
-       .init = init,
-       .cleanup = cleanup,
-       .scan = scan,
-       .dev_list = 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 = dev_acquisition_stop,
-       .priv = NULL,
-};
diff --git a/hardware/fluke-dmm/fluke-dmm.h b/hardware/fluke-dmm/fluke-dmm.h
deleted file mode 100644 (file)
index d162bdd..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012 Bert Vermeulen <bert@biot.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef LIBSIGROK_HARDWARE_FLUKE_DMM_FLUKE_DMM_H
-#define LIBSIGROK_HARDWARE_FLUKE_DMM_FLUKE_DMM_H
-
-#define LOG_PREFIX "fluke-dmm"
-
-#define FLUKEDMM_BUFSIZE  256
-
-/* Supported models */
-enum {
-       FLUKE_187 = 1,
-       FLUKE_189,
-       FLUKE_287,
-       FLUKE_190,
-};
-
-/* Supported device profiles */
-struct flukedmm_profile {
-       int model;
-       const char *modelname;
-       /* How often to poll, in ms. */
-       int poll_period;
-       /* If no response received, how long to wait before retrying. */
-       int timeout;
-};
-
-/* Private, per-device-instance driver context. */
-struct dev_context {
-       const struct flukedmm_profile *profile;
-       uint64_t limit_samples;
-       uint64_t limit_msec;
-
-       /* Opaque pointer passed in by the frontend. */
-       void *cb_data;
-
-       /* Runtime. */
-       uint64_t num_samples;
-       char buf[FLUKEDMM_BUFSIZE];
-       int buflen;
-       int64_t cmd_sent_at;
-       int expect_response;
-       int meas_type;
-       int is_relative;
-       int mq;
-       int unit;
-       int mqflags;
-};
-
-SR_PRIV int fluke_receive_data(int fd, int revents, void *cb_data);
-
-#endif
diff --git a/hardware/fluke-dmm/fluke.c b/hardware/fluke-dmm/fluke.c
deleted file mode 100644 (file)
index edb6734..0000000
+++ /dev/null
@@ -1,536 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012 Bert Vermeulen <bert@biot.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 <stdlib.h>
-#include <math.h>
-#include <string.h>
-#include <errno.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-#include "fluke-dmm.h"
-
-static struct sr_datafeed_analog *handle_qm_18x(const struct sr_dev_inst *sdi,
-               char **tokens)
-{
-       struct sr_datafeed_analog *analog;
-       float fvalue;
-       char *e, *u;
-       gboolean is_oor;
-
-       if (strcmp(tokens[0], "QM") || !tokens[1])
-               return NULL;
-
-       if ((e = strstr(tokens[1], "Out of range"))) {
-               is_oor = TRUE;
-               fvalue = -1;
-               while(*e && *e != '.')
-                       e++;
-       } else {
-               is_oor = FALSE;
-               /* Delimit the float, since sr_atof_ascii() wants only
-                * a valid float here. */
-               e = tokens[1];
-               while(*e && *e != ' ')
-                       e++;
-               *e++ = '\0';
-               if (sr_atof_ascii(tokens[1], &fvalue) != SR_OK || fvalue == 0.0) {
-                       /* Happens all the time, when switching modes. */
-                       sr_dbg("Invalid float.");
-                       return NULL;
-               }
-       }
-       while(*e && *e == ' ')
-               e++;
-
-       if (!(analog = g_try_malloc0(sizeof(struct sr_datafeed_analog))))
-               return NULL;
-       if (!(analog->data = g_try_malloc(sizeof(float))))
-               return NULL;
-       analog->channels = sdi->channels;
-       analog->num_samples = 1;
-       if (is_oor)
-               *analog->data = NAN;
-       else
-               *analog->data = fvalue;
-       analog->mq = -1;
-
-       if ((u = strstr(e, "V DC")) || (u = strstr(e, "V AC"))) {
-               analog->mq = SR_MQ_VOLTAGE;
-               analog->unit = SR_UNIT_VOLT;
-               if (!is_oor && e[0] == 'm')
-                       *analog->data /= 1000;
-               /* This catches "V AC", "V DC" and "V AC+DC". */
-               if (strstr(u, "AC"))
-                       analog->mqflags |= SR_MQFLAG_AC | SR_MQFLAG_RMS;
-               if (strstr(u, "DC"))
-                       analog->mqflags |= SR_MQFLAG_DC;
-       } else if ((u = strstr(e, "dBV")) || (u = strstr(e, "dBm"))) {
-               analog->mq = SR_MQ_VOLTAGE;
-               if (u[2] == 'm')
-                       analog->unit = SR_UNIT_DECIBEL_MW;
-               else
-                       analog->unit = SR_UNIT_DECIBEL_VOLT;
-               analog->mqflags |= SR_MQFLAG_AC | SR_MQFLAG_RMS;
-       } else if ((u = strstr(e, "Ohms"))) {
-               analog->mq = SR_MQ_RESISTANCE;
-               analog->unit = SR_UNIT_OHM;
-               if (is_oor)
-                       *analog->data = INFINITY;
-               else if (e[0] == 'k')
-                       *analog->data *= 1000;
-               else if (e[0] == 'M')
-                       *analog->data *= 1000000;
-       } else if (!strcmp(e, "nS")) {
-               analog->mq = SR_MQ_CONDUCTANCE;
-               analog->unit = SR_UNIT_SIEMENS;
-               *analog->data /= 1e+9;
-       } else if ((u = strstr(e, "Farads"))) {
-               analog->mq = SR_MQ_CAPACITANCE;
-               analog->unit = SR_UNIT_FARAD;
-               if (!is_oor) {
-                       if (e[0] == 'm')
-                               *analog->data /= 1e+3;
-                       else if (e[0] == 'u')
-                               *analog->data /= 1e+6;
-                       else if (e[0] == 'n')
-                               *analog->data /= 1e+9;
-               }
-       } else if ((u = strstr(e, "Deg C")) || (u = strstr(e, "Deg F"))) {
-               analog->mq = SR_MQ_TEMPERATURE;
-               if (u[4] == 'C')
-                       analog->unit = SR_UNIT_CELSIUS;
-               else
-                       analog->unit = SR_UNIT_FAHRENHEIT;
-       } else if ((u = strstr(e, "A AC")) || (u = strstr(e, "A DC"))) {
-               analog->mq = SR_MQ_CURRENT;
-               analog->unit = SR_UNIT_AMPERE;
-               /* This catches "A AC", "A DC" and "A AC+DC". */
-               if (strstr(u, "AC"))
-                       analog->mqflags |= SR_MQFLAG_AC | SR_MQFLAG_RMS;
-               if (strstr(u, "DC"))
-                       analog->mqflags |= SR_MQFLAG_DC;
-               if (!is_oor) {
-                       if (e[0] == 'm')
-                               *analog->data /= 1e+3;
-                       else if (e[0] == 'u')
-                               *analog->data /= 1e+6;
-               }
-       } else if ((u = strstr(e, "Hz"))) {
-               analog->mq = SR_MQ_FREQUENCY;
-               analog->unit = SR_UNIT_HERTZ;
-               if (e[0] == 'k')
-                       *analog->data *= 1e+3;
-       } else if (!strcmp(e, "%")) {
-               analog->mq = SR_MQ_DUTY_CYCLE;
-               analog->unit = SR_UNIT_PERCENTAGE;
-       } else if ((u = strstr(e, "ms"))) {
-               analog->mq = SR_MQ_PULSE_WIDTH;
-               analog->unit = SR_UNIT_SECOND;
-               *analog->data /= 1e+3;
-       }
-
-       if (analog->mq == -1) {
-               /* Not a valid measurement. */
-               g_free(analog->data);
-               g_free(analog);
-               analog = NULL;
-       }
-
-       return analog;
-}
-
-static struct sr_datafeed_analog *handle_qm_28x(const struct sr_dev_inst *sdi,
-               char **tokens)
-{
-       struct sr_datafeed_analog *analog;
-       float fvalue;
-
-       if (!tokens[1])
-               return NULL;
-
-       if (sr_atof_ascii(tokens[0], &fvalue) != SR_OK || fvalue == 0.0) {
-               sr_err("Invalid float '%s'.", tokens[0]);
-               return NULL;
-       }
-
-       if (!(analog = g_try_malloc0(sizeof(struct sr_datafeed_analog))))
-               return NULL;
-       if (!(analog->data = g_try_malloc(sizeof(float))))
-               return NULL;
-       analog->channels = sdi->channels;
-       analog->num_samples = 1;
-       *analog->data = fvalue;
-       analog->mq = -1;
-
-       if (!strcmp(tokens[1], "VAC") || !strcmp(tokens[1], "VDC")) {
-               analog->mq = SR_MQ_VOLTAGE;
-               analog->unit = SR_UNIT_VOLT;
-               if (!strcmp(tokens[2], "NORMAL")) {
-                       if (tokens[1][1] == 'A') {
-                               analog->mqflags |= SR_MQFLAG_AC;
-                               analog->mqflags |= SR_MQFLAG_RMS;
-                       } else
-                               analog->mqflags |= SR_MQFLAG_DC;
-               } else if (!strcmp(tokens[2], "OL") || !strcmp(tokens[2], "OL_MINUS")) {
-                       *analog->data = NAN;
-               } else
-                       analog->mq = -1;
-       } else if (!strcmp(tokens[1], "dBV") || !strcmp(tokens[1], "dBm")) {
-               analog->mq = SR_MQ_VOLTAGE;
-               if (tokens[1][2] == 'm')
-                       analog->unit = SR_UNIT_DECIBEL_MW;
-               else
-                       analog->unit = SR_UNIT_DECIBEL_VOLT;
-               analog->mqflags |= SR_MQFLAG_AC | SR_MQFLAG_RMS;
-       } else if (!strcmp(tokens[1], "CEL") || !strcmp(tokens[1], "FAR")) {
-               if (!strcmp(tokens[2], "NORMAL")) {
-                       analog->mq = SR_MQ_TEMPERATURE;
-                       if (tokens[1][0] == 'C')
-                               analog->unit = SR_UNIT_CELSIUS;
-                       else
-                               analog->unit = SR_UNIT_FAHRENHEIT;
-               }
-       } else if (!strcmp(tokens[1], "OHM")) {
-               if (!strcmp(tokens[3], "NONE")) {
-                       analog->mq = SR_MQ_RESISTANCE;
-                       analog->unit = SR_UNIT_OHM;
-                       if (!strcmp(tokens[2], "OL") || !strcmp(tokens[2], "OL_MINUS")) {
-                               *analog->data = INFINITY;
-                       } else if (strcmp(tokens[2], "NORMAL"))
-                               analog->mq = -1;
-               } else if (!strcmp(tokens[3], "OPEN_CIRCUIT")) {
-                       analog->mq = SR_MQ_CONTINUITY;
-                       analog->unit = SR_UNIT_BOOLEAN;
-                       *analog->data = 0.0;
-               } else if (!strcmp(tokens[3], "SHORT_CIRCUIT")) {
-                       analog->mq = SR_MQ_CONTINUITY;
-                       analog->unit = SR_UNIT_BOOLEAN;
-                       *analog->data = 1.0;
-               }
-       } else if (!strcmp(tokens[1], "F")
-                       && !strcmp(tokens[2], "NORMAL")
-                       && !strcmp(tokens[3], "NONE")) {
-               analog->mq = SR_MQ_CAPACITANCE;
-               analog->unit = SR_UNIT_FARAD;
-       } else if (!strcmp(tokens[1], "AAC") || !strcmp(tokens[1], "ADC")) {
-               analog->mq = SR_MQ_CURRENT;
-               analog->unit = SR_UNIT_AMPERE;
-               if (!strcmp(tokens[2], "NORMAL")) {
-                       if (tokens[1][1] == 'A') {
-                               analog->mqflags |= SR_MQFLAG_AC;
-                               analog->mqflags |= SR_MQFLAG_RMS;
-                       } else
-                               analog->mqflags |= SR_MQFLAG_DC;
-               } else if (!strcmp(tokens[2], "OL") || !strcmp(tokens[2], "OL_MINUS")) {
-                       *analog->data = NAN;
-               } else
-                       analog->mq = -1;
-       } if (!strcmp(tokens[1], "Hz") && !strcmp(tokens[2], "NORMAL")) {
-               analog->mq = SR_MQ_FREQUENCY;
-               analog->unit = SR_UNIT_HERTZ;
-       } else if (!strcmp(tokens[1], "PCT") && !strcmp(tokens[2], "NORMAL")) {
-               analog->mq = SR_MQ_DUTY_CYCLE;
-               analog->unit = SR_UNIT_PERCENTAGE;
-       } else if (!strcmp(tokens[1], "S") && !strcmp(tokens[2], "NORMAL")) {
-               analog->mq = SR_MQ_PULSE_WIDTH;
-               analog->unit = SR_UNIT_SECOND;
-       } else if (!strcmp(tokens[1], "SIE") && !strcmp(tokens[2], "NORMAL")) {
-               analog->mq = SR_MQ_CONDUCTANCE;
-               analog->unit = SR_UNIT_SIEMENS;
-       }
-
-       if (analog->mq == -1) {
-               /* Not a valid measurement. */
-               g_free(analog->data);
-               g_free(analog);
-               analog = NULL;
-       }
-
-       return analog;
-}
-
-static void handle_qm_19x_meta(const struct sr_dev_inst *sdi, char **tokens)
-{
-       struct dev_context *devc;
-       int meas_type, meas_unit, meas_char, i;
-
-       /* Make sure we have 7 valid tokens. */
-       for (i = 0; tokens[i] && i < 7; i++);
-       if (i != 7)
-               return;
-
-       if (strcmp(tokens[1], "1"))
-               /* Invalid measurement. */
-               return;
-
-       if (strcmp(tokens[2], "3"))
-               /* Only interested in input from the meter mode source. */
-               return;
-
-       devc = sdi->priv;
-
-       /* Measurement type 11 == absolute, 19 = relative */
-       meas_type = strtol(tokens[0], NULL, 10);
-       if (meas_type != 11 && meas_type != 19)
-               /* Device is in some mode we don't support. */
-               return;
-
-       /* We might get metadata for absolute and relative mode (if the device
-        * is in relative mode). In that case, relative takes precedence. */
-       if (meas_type == 11 && devc->meas_type == 19)
-               return;
-
-       meas_unit = strtol(tokens[3], NULL, 10);
-       if (meas_unit == 0)
-               /* Device is turned off. Really. */
-               return;
-       meas_char = strtol(tokens[4], NULL, 10);
-
-       devc->mq = devc->unit = -1;
-       devc->mqflags = 0;
-       switch (meas_unit) {
-       case 1:
-               devc->mq = SR_MQ_VOLTAGE;
-               devc->unit = SR_UNIT_VOLT;
-               if (meas_char == 1)
-                       devc->mqflags |= SR_MQFLAG_DC;
-               else if (meas_char == 2)
-                       devc->mqflags |= SR_MQFLAG_AC;
-               else if (meas_char == 3)
-                       devc->mqflags |= SR_MQFLAG_DC | SR_MQFLAG_AC;
-               else if (meas_char == 15)
-                       devc->mqflags |= SR_MQFLAG_DIODE;
-               break;
-       case 2:
-               devc->mq = SR_MQ_CURRENT;
-               devc->unit = SR_UNIT_AMPERE;
-               if (meas_char == 1)
-                       devc->mqflags |= SR_MQFLAG_DC;
-               else if (meas_char == 2)
-                       devc->mqflags |= SR_MQFLAG_AC;
-               else if (meas_char == 3)
-                       devc->mqflags |= SR_MQFLAG_DC | SR_MQFLAG_AC;
-               break;
-       case 3:
-               if (meas_char == 1) {
-                       devc->mq = SR_MQ_RESISTANCE;
-                       devc->unit = SR_UNIT_OHM;
-               } else if (meas_char == 16) {
-                       devc->mq = SR_MQ_CONTINUITY;
-                       devc->unit = SR_UNIT_BOOLEAN;
-               }
-               break;
-       case 12:
-               devc->mq = SR_MQ_TEMPERATURE;
-               devc->unit = SR_UNIT_CELSIUS;
-               break;
-       case 13:
-               devc->mq = SR_MQ_TEMPERATURE;
-               devc->unit = SR_UNIT_FAHRENHEIT;
-               break;
-       default:
-               sr_dbg("unknown unit: %d", meas_unit);
-       }
-       if (devc->mq == -1 && devc->unit == -1)
-               return;
-
-       /* If we got here, we know how to interpret the measurement. */
-       devc->meas_type = meas_type;
-       if (meas_type == 11)
-               /* Absolute meter reading. */
-               devc->is_relative = FALSE;
-       else if (!strcmp(tokens[0], "19"))
-               /* Relative meter reading. */
-               devc->is_relative = TRUE;
-
-}
-
-static void handle_qm_19x_data(const struct sr_dev_inst *sdi, char **tokens)
-{
-       struct dev_context *devc;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_analog analog;
-       float fvalue;
-
-       if (!strcmp(tokens[0], "9.9E+37")) {
-               /* An invalid measurement shows up on the display as "OL", but
-                * comes through like this. Since comparing 38-digit floats
-                * is rather problematic, we'll cut through this here. */
-               fvalue = NAN;
-       } else {
-               if (sr_atof_ascii(tokens[0], &fvalue) != SR_OK || fvalue == 0.0) {
-                       sr_err("Invalid float '%s'.", tokens[0]);
-                       return;
-               }
-       }
-
-       devc = sdi->priv;
-       if (devc->mq == -1 || devc->unit == -1)
-               /* Don't have valid metadata yet. */
-               return;
-
-
-       if (devc->mq == SR_MQ_RESISTANCE && isnan(fvalue))
-               fvalue = INFINITY;
-       else if (devc->mq == SR_MQ_CONTINUITY) {
-               if (isnan(fvalue))
-                       fvalue = 0.0;
-               else
-                       fvalue = 1.0;
-       }
-
-       analog.channels = sdi->channels;
-       analog.num_samples = 1;
-       analog.data = &fvalue;
-       analog.mq = devc->mq;
-       analog.unit = devc->unit;
-       analog.mqflags = 0;
-       packet.type = SR_DF_ANALOG;
-       packet.payload = &analog;
-       sr_session_send(devc->cb_data, &packet);
-       devc->num_samples++;
-
-}
-
-static void handle_line(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_analog *analog;
-       int num_tokens, n, i;
-       char cmd[16], **tokens;
-
-       devc = sdi->priv;
-       serial = sdi->conn;
-       sr_spew("Received line '%s' (%d).", devc->buf, devc->buflen);
-
-       if (devc->buflen == 1) {
-               if (devc->buf[0] != '0') {
-                       /* Not just a CMD_ACK from the query command. */
-                       sr_dbg("Got CMD_ACK '%c'.", devc->buf[0]);
-                       devc->expect_response = FALSE;
-               }
-               devc->buflen = 0;
-               return;
-       }
-
-       analog = NULL;
-       tokens = g_strsplit(devc->buf, ",", 0);
-       if (tokens[0]) {
-               if (devc->profile->model == FLUKE_187 || devc->profile->model == FLUKE_189) {
-                       devc->expect_response = FALSE;
-                       analog = handle_qm_18x(sdi, tokens);
-               } else if (devc->profile->model == FLUKE_287) {
-                       devc->expect_response = FALSE;
-                       analog = handle_qm_28x(sdi, tokens);
-               } else if (devc->profile->model == FLUKE_190) {
-                       devc->expect_response = FALSE;
-                       for (num_tokens = 0; tokens[num_tokens]; num_tokens++);
-                       if (num_tokens >= 7) {
-                               /* Response to QM: this is a comma-separated list of
-                                * fields with metadata about the measurement. This
-                                * format can return multiple sets of metadata,
-                                * split into sets of 7 tokens each. */
-                               devc->meas_type = 0;
-                               for (i = 0; i < num_tokens; i += 7)
-                                       handle_qm_19x_meta(sdi, tokens + i);
-                               if (devc->meas_type) {
-                                       /* Slip the request in now, before the main
-                                        * timer loop asks for metadata again. */
-                                       n = sprintf(cmd, "QM %d\r", devc->meas_type);
-                                       if (serial_write(serial, cmd, n) == -1)
-                                               sr_err("Unable to send QM (measurement): %s.",
-                                                               strerror(errno));
-                               }
-                       } else {
-                               /* Response to QM <n> measurement request. */
-                               handle_qm_19x_data(sdi, tokens);
-                       }
-               }
-       }
-       g_strfreev(tokens);
-       devc->buflen = 0;
-
-       if (analog) {
-               /* Got a measurement. */
-               packet.type = SR_DF_ANALOG;
-               packet.payload = analog;
-               sr_session_send(devc->cb_data, &packet);
-               devc->num_samples++;
-               g_free(analog->data);
-               g_free(analog);
-       }
-
-}
-
-SR_PRIV int fluke_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 len;
-       int64_t now, elapsed;
-
-       (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. */
-               while(FLUKEDMM_BUFSIZE - devc->buflen - 1 > 0) {
-                       len = serial_read(serial, devc->buf + devc->buflen, 1);
-                       if (len < 1)
-                               break;
-                       devc->buflen++;
-                       *(devc->buf + devc->buflen) = '\0';
-                       if (*(devc->buf + devc->buflen - 1) == '\r') {
-                               *(devc->buf + --devc->buflen) = '\0';
-                               handle_line(sdi);
-                               break;
-                       }
-               }
-       }
-
-       if (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
-               sdi->driver->dev_acquisition_stop(sdi, cb_data);
-               return TRUE;
-       }
-
-       now = g_get_monotonic_time() / 1000;
-       elapsed = now - devc->cmd_sent_at;
-       /* Send query command at poll_period interval, or after 1 second
-        * has elapsed. This will make it easier to recover from any
-        * out-of-sync or temporary disconnect issues. */
-       if ((devc->expect_response == FALSE && elapsed > devc->profile->poll_period)
-                       || elapsed > devc->profile->timeout) {
-               if (serial_write(serial, "QM\r", 3) == -1)
-                       sr_err("Unable to send QM: %s.", strerror(errno));
-               devc->cmd_sent_at = now;
-               devc->expect_response = TRUE;
-       }
-
-       return TRUE;
-}
diff --git a/hardware/fx2lafw/api.c b/hardware/fx2lafw/api.c
deleted file mode 100644 (file)
index 3242afc..0000000
+++ /dev/null
@@ -1,618 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
- * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "protocol.h"
-
-static const struct fx2lafw_profile supported_fx2[] = {
-       /*
-        * CWAV USBee AX
-        * EE Electronics ESLA201A
-        * ARMFLY AX-Pro
-        */
-       { 0x08a9, 0x0014, "CWAV", "USBee AX", NULL,
-               FIRMWARE_DIR "/fx2lafw-cwav-usbeeax.fw",
-               0, NULL, NULL},
-       /*
-        * CWAV USBee DX
-        * XZL-Studio DX
-        */
-       { 0x08a9, 0x0015, "CWAV", "USBee DX", NULL,
-               FIRMWARE_DIR "/fx2lafw-cwav-usbeedx.fw",
-               DEV_CAPS_16BIT, NULL, NULL },
-
-       /*
-        * CWAV USBee SX
-        */
-       { 0x08a9, 0x0009, "CWAV", "USBee SX", NULL,
-               FIRMWARE_DIR "/fx2lafw-cwav-usbeesx.fw",
-               0, NULL, NULL},
-
-       /*
-        * Saleae Logic
-        * EE Electronics ESLA100
-        * Robomotic MiniLogic
-        * Robomotic BugLogic 3
-        */
-       { 0x0925, 0x3881, "Saleae", "Logic", NULL,
-               FIRMWARE_DIR "/fx2lafw-saleae-logic.fw",
-               0, NULL, NULL},
-
-       /*
-        * Default Cypress FX2 without EEPROM, e.g.:
-        * Lcsoft Mini Board
-        * Braintechnology USB Interface V2.x
-        */
-       { 0x04B4, 0x8613, "Cypress", "FX2", NULL,
-               FIRMWARE_DIR "/fx2lafw-cypress-fx2.fw",
-               DEV_CAPS_16BIT, NULL, NULL },
-
-       /*
-        * Braintechnology USB-LPS
-        */
-       { 0x16d0, 0x0498, "Braintechnology", "USB-LPS", NULL,
-               FIRMWARE_DIR "/fx2lafw-braintechnology-usb-lps.fw",
-               DEV_CAPS_16BIT, NULL, NULL },
-
-       { 0, 0, 0, 0, 0, 0, 0, 0, 0 }
-};
-
-static const int32_t hwopts[] = {
-       SR_CONF_CONN,
-};
-
-static const int32_t hwcaps[] = {
-       SR_CONF_LOGIC_ANALYZER,
-       SR_CONF_TRIGGER_MATCH,
-       SR_CONF_SAMPLERATE,
-
-       /* These are really implemented in the driver, not the hardware. */
-       SR_CONF_LIMIT_SAMPLES,
-       SR_CONF_CONTINUOUS,
-};
-
-static const char *channel_names[] = {
-       "0",  "1",  "2",  "3",  "4",  "5",  "6",  "7",
-       "8",  "9", "10", "11", "12", "13", "14", "15",
-       NULL,
-};
-
-static const int32_t soft_trigger_matches[] = {
-       SR_TRIGGER_ZERO,
-       SR_TRIGGER_ONE,
-       SR_TRIGGER_RISING,
-       SR_TRIGGER_FALLING,
-       SR_TRIGGER_EDGE,
-};
-
-static const uint64_t samplerates[] = {
-       SR_KHZ(20),
-       SR_KHZ(25),
-       SR_KHZ(50),
-       SR_KHZ(100),
-       SR_KHZ(200),
-       SR_KHZ(250),
-       SR_KHZ(500),
-       SR_MHZ(1),
-       SR_MHZ(2),
-       SR_MHZ(3),
-       SR_MHZ(4),
-       SR_MHZ(6),
-       SR_MHZ(8),
-       SR_MHZ(12),
-       SR_MHZ(16),
-       SR_MHZ(24),
-};
-
-SR_PRIV struct sr_dev_driver fx2lafw_driver_info;
-static struct sr_dev_driver *di = &fx2lafw_driver_info;
-
-static int init(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, di, LOG_PREFIX);
-}
-
-static GSList *scan(GSList *options)
-{
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       struct sr_dev_inst *sdi;
-       struct sr_usb_dev_inst *usb;
-       struct sr_channel *ch;
-       struct sr_config *src;
-       const struct fx2lafw_profile *prof;
-       GSList *l, *devices, *conn_devices;
-       struct libusb_device_descriptor des;
-       libusb_device **devlist;
-       struct libusb_device_handle *hdl;
-       int devcnt, num_logic_channels, ret, i, j;
-       const char *conn;
-       char manufacturer[64], product[64];
-
-       drvc = di->priv;
-
-       conn = NULL;
-       for (l = options; l; l = l->next) {
-               src = l->data;
-               switch (src->key) {
-               case SR_CONF_CONN:
-                       conn = g_variant_get_string(src->data, NULL);
-                       break;
-               }
-       }
-       if (conn)
-               conn_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn);
-       else
-               conn_devices = NULL;
-
-       /* Find all fx2lafw compatible devices and upload firmware to them. */
-       devices = NULL;
-       libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
-       for (i = 0; devlist[i]; i++) {
-               if (conn) {
-                       usb = NULL;
-                       for (l = conn_devices; l; l = l->next) {
-                               usb = l->data;
-                               if (usb->bus == libusb_get_bus_number(devlist[i])
-                                       && usb->address == libusb_get_device_address(devlist[i]))
-                                       break;
-                       }
-                       if (!l)
-                               /* This device matched none of the ones that
-                                * matched the conn specification. */
-                               continue;
-               }
-
-               if ((ret = libusb_get_device_descriptor( devlist[i], &des)) != 0) {
-                       sr_warn("Failed to get device descriptor: %s.",
-                               libusb_error_name(ret));
-                       continue;
-               }
-
-               if ((ret = libusb_open(devlist[i], &hdl)) < 0)
-                       continue;
-
-               if (des.iManufacturer == 0) {
-                       manufacturer[0] = '\0';
-               } else if ((ret = libusb_get_string_descriptor_ascii(hdl,
-                               des.iManufacturer, (unsigned char *) manufacturer,
-                               sizeof(manufacturer))) < 0) {
-                       sr_warn("Failed to get manufacturer string descriptor: %s.",
-                               libusb_error_name(ret));
-                       continue;
-               }
-
-               if (des.iProduct == 0) {
-                       product[0] = '\0';
-               } else if ((ret = libusb_get_string_descriptor_ascii(hdl,
-                               des.iProduct, (unsigned char *) product,
-                               sizeof(product))) < 0) {
-                       sr_warn("Failed to get product string descriptor: %s.",
-                               libusb_error_name(ret));
-                       continue;
-               }
-
-               libusb_close(hdl);
-
-               prof = NULL;
-               for (j = 0; supported_fx2[j].vid; j++) {
-                       if (des.idVendor == supported_fx2[j].vid &&
-                                       des.idProduct == supported_fx2[j].pid &&
-                                       (!supported_fx2[j].usb_manufacturer ||
-                                        !strcmp(manufacturer, supported_fx2[j].usb_manufacturer)) &&
-                                       (!supported_fx2[j].usb_manufacturer ||
-                                        !strcmp(product, supported_fx2[j].usb_product))) {
-                               prof = &supported_fx2[j];
-                               break;
-                       }
-               }
-
-               /* Skip if the device was not found. */
-               if (!prof)
-                       continue;
-
-               devcnt = g_slist_length(drvc->instances);
-               sdi = sr_dev_inst_new(devcnt, SR_ST_INITIALIZING,
-                       prof->vendor, prof->model, prof->model_version);
-               if (!sdi)
-                       return NULL;
-               sdi->driver = di;
-
-               /* Fill in channellist according to this device's profile. */
-               num_logic_channels = prof->dev_caps & DEV_CAPS_16BIT ? 16 : 8;
-               for (j = 0; j < num_logic_channels; j++) {
-                       if (!(ch = sr_channel_new(j, SR_CHANNEL_LOGIC, TRUE,
-                                       channel_names[j])))
-                               return NULL;
-                       sdi->channels = g_slist_append(sdi->channels, ch);
-               }
-
-               devc = fx2lafw_dev_new();
-               devc->profile = prof;
-               sdi->priv = devc;
-               drvc->instances = g_slist_append(drvc->instances, sdi);
-               devices = g_slist_append(devices, sdi);
-
-               if (fx2lafw_check_conf_profile(devlist[i])) {
-                       /* Already has the firmware, so fix the new address. */
-                       sr_dbg("Found an fx2lafw device.");
-                       sdi->status = SR_ST_INACTIVE;
-                       sdi->inst_type = SR_INST_USB;
-                       sdi->conn = sr_usb_dev_inst_new(libusb_get_bus_number(devlist[i]),
-                                       libusb_get_device_address(devlist[i]), NULL);
-               } else {
-                       if (ezusb_upload_firmware(devlist[i], USB_CONFIGURATION,
-                               prof->firmware) == SR_OK)
-                               /* Store when this device's FW was updated. */
-                               devc->fw_updated = g_get_monotonic_time();
-                       else
-                               sr_err("Firmware upload failed for "
-                                      "device %d.", devcnt);
-                       sdi->inst_type = SR_INST_USB;
-                       sdi->conn = sr_usb_dev_inst_new(libusb_get_bus_number(devlist[i]),
-                                       0xff, NULL);
-               }
-       }
-       libusb_free_device_list(devlist, 1);
-       g_slist_free_full(conn_devices, (GDestroyNotify)sr_usb_dev_inst_free);
-
-       return devices;
-}
-
-static GSList *dev_list(void)
-{
-       return ((struct drv_context *)(di->priv))->instances;
-}
-
-static int dev_open(struct sr_dev_inst *sdi)
-{
-       struct sr_usb_dev_inst *usb;
-       struct dev_context *devc;
-       int ret;
-       int64_t timediff_us, timediff_ms;
-
-       devc = sdi->priv;
-       usb = sdi->conn;
-
-       /*
-        * If the firmware was recently uploaded, wait up to MAX_RENUM_DELAY_MS
-        * milliseconds for the FX2 to renumerate.
-        */
-       ret = SR_ERR;
-       if (devc->fw_updated > 0) {
-               sr_info("Waiting for device to reset.");
-               /* Takes >= 300ms for the FX2 to be gone from the USB bus. */
-               g_usleep(300 * 1000);
-               timediff_ms = 0;
-               while (timediff_ms < MAX_RENUM_DELAY_MS) {
-                       if ((ret = fx2lafw_dev_open(sdi, di)) == SR_OK)
-                               break;
-                       g_usleep(100 * 1000);
-
-                       timediff_us = g_get_monotonic_time() - devc->fw_updated;
-                       timediff_ms = timediff_us / 1000;
-                       sr_spew("Waited %" PRIi64 "ms.", timediff_ms);
-               }
-               if (ret != SR_OK) {
-                       sr_err("Device failed to renumerate.");
-                       return SR_ERR;
-               }
-               sr_info("Device came back after %" PRIi64 "ms.", timediff_ms);
-       } else {
-               sr_info("Firmware upload was not needed.");
-               ret = fx2lafw_dev_open(sdi, di);
-       }
-
-       if (ret != SR_OK) {
-               sr_err("Unable to open device.");
-               return SR_ERR;
-       }
-
-       ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE);
-       if (ret != 0) {
-               switch (ret) {
-               case LIBUSB_ERROR_BUSY:
-                       sr_err("Unable to claim USB interface. Another "
-                              "program or driver has already claimed it.");
-                       break;
-               case LIBUSB_ERROR_NO_DEVICE:
-                       sr_err("Device has been disconnected.");
-                       break;
-               default:
-                       sr_err("Unable to claim interface: %s.",
-                              libusb_error_name(ret));
-                       break;
-               }
-
-               return SR_ERR;
-       }
-
-       if (devc->cur_samplerate == 0) {
-               /* Samplerate hasn't been set; default to the slowest one. */
-               devc->cur_samplerate = samplerates[0];
-       }
-
-       return SR_OK;
-}
-
-static int dev_close(struct sr_dev_inst *sdi)
-{
-       struct sr_usb_dev_inst *usb;
-
-       usb = sdi->conn;
-       if (usb->devhdl == NULL)
-               return SR_ERR;
-
-       sr_info("fx2lafw: Closing device %d on %d.%d interface %d.",
-               sdi->index, usb->bus, usb->address, USB_INTERFACE);
-       libusb_release_interface(usb->devhdl, USB_INTERFACE);
-       libusb_close(usb->devhdl);
-       usb->devhdl = NULL;
-       sdi->status = SR_ST_INACTIVE;
-
-       return SR_OK;
-}
-
-static int cleanup(void)
-{
-       int ret;
-       struct drv_context *drvc;
-
-       if (!(drvc = di->priv))
-               return SR_OK;
-
-       ret = std_dev_clear(di, NULL);
-
-       g_free(drvc);
-       di->priv = NULL;
-
-       return ret;
-}
-
-static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       struct sr_usb_dev_inst *usb;
-       char str[128];
-
-       (void)cg;
-
-       if (!sdi)
-               return SR_ERR_ARG;
-
-       devc = sdi->priv;
-
-       switch (id) {
-       case SR_CONF_CONN:
-               if (!sdi->conn)
-                       return SR_ERR_ARG;
-               usb = sdi->conn;
-               if (usb->address == 255)
-                       /* Device still needs to re-enumerate after firmware
-                        * upload, so we don't know its (future) address. */
-                       return SR_ERR;
-               snprintf(str, 128, "%d.%d", usb->bus, usb->address);
-               *data = g_variant_new_string(str);
-               break;
-       case SR_CONF_LIMIT_SAMPLES:
-               *data = g_variant_new_uint64(devc->limit_samples);
-               break;
-       case SR_CONF_SAMPLERATE:
-               *data = g_variant_new_uint64(devc->cur_samplerate);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       int ret;
-
-       (void)cg;
-
-       if (!sdi)
-               return SR_ERR_ARG;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR;
-
-       devc = sdi->priv;
-
-       ret = SR_OK;
-
-       switch (id)
-       {
-               case SR_CONF_SAMPLERATE:
-                       devc->cur_samplerate = g_variant_get_uint64(data);
-                       break;
-               case SR_CONF_LIMIT_SAMPLES:
-                       devc->limit_samples = g_variant_get_uint64(data);
-                       break;
-               default:
-                       ret = SR_ERR_NA;
-       }
-
-       return ret;
-}
-
-static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       GVariant *gvar;
-       GVariantBuilder gvb;
-
-       (void)sdi;
-       (void)cg;
-
-       switch (key) {
-       case SR_CONF_SCAN_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
-               break;
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
-               break;
-       case SR_CONF_SAMPLERATE:
-               g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
-               gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), samplerates,
-                               ARRAY_SIZE(samplerates), sizeof(uint64_t));
-               g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar);
-               *data = g_variant_builder_end(&gvb);
-               break;
-       case SR_CONF_TRIGGER_MATCH:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               soft_trigger_matches, ARRAY_SIZE(soft_trigger_matches),
-                               sizeof(int32_t));
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int receive_data(int fd, int revents, void *cb_data)
-{
-       struct timeval tv;
-       struct drv_context *drvc;
-
-       (void)fd;
-       (void)revents;
-       (void)cb_data;
-
-       drvc = di->priv;
-
-       tv.tv_sec = tv.tv_usec = 0;
-       libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
-
-       return TRUE;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct dev_context *devc;
-       struct drv_context *drvc;
-       struct sr_usb_dev_inst *usb;
-       struct sr_trigger *trigger;
-       struct libusb_transfer *transfer;
-       unsigned int i, timeout, num_transfers;
-       int ret;
-       unsigned char *buf;
-       size_t size;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       drvc = di->priv;
-       devc = sdi->priv;
-       usb = sdi->conn;
-
-       devc->cb_data = cb_data;
-       devc->sent_samples = 0;
-       devc->acq_aborted = FALSE;
-       devc->empty_transfer_count = 0;
-
-       if ((trigger = sr_session_trigger_get(sdi->session))) {
-               devc->stl = soft_trigger_logic_new(sdi, trigger);
-               devc->trigger_fired = FALSE;
-       } else
-               devc->trigger_fired = TRUE;
-
-       timeout = fx2lafw_get_timeout(devc);
-       num_transfers = fx2lafw_get_number_of_transfers(devc);
-       size = fx2lafw_get_buffer_size(devc);
-       devc->submitted_transfers = 0;
-
-       devc->transfers = g_try_malloc0(sizeof(*devc->transfers) * num_transfers);
-       if (!devc->transfers) {
-               sr_err("USB transfers malloc failed.");
-               return SR_ERR_MALLOC;
-       }
-
-       devc->num_transfers = num_transfers;
-       for (i = 0; i < num_transfers; i++) {
-               if (!(buf = g_try_malloc(size))) {
-                       sr_err("USB transfer buffer malloc failed.");
-                       return SR_ERR_MALLOC;
-               }
-               transfer = libusb_alloc_transfer(0);
-               libusb_fill_bulk_transfer(transfer, usb->devhdl,
-                               2 | LIBUSB_ENDPOINT_IN, buf, size,
-                               fx2lafw_receive_transfer, (void *)sdi, timeout);
-               if ((ret = libusb_submit_transfer(transfer)) != 0) {
-                       sr_err("Failed to submit transfer: %s.",
-                              libusb_error_name(ret));
-                       libusb_free_transfer(transfer);
-                       g_free(buf);
-                       fx2lafw_abort_acquisition(devc);
-                       return SR_ERR;
-               }
-               devc->transfers[i] = transfer;
-               devc->submitted_transfers++;
-       }
-
-       devc->ctx = drvc->sr_ctx;
-
-       usb_source_add(sdi->session, devc->ctx, timeout, receive_data, NULL);
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(cb_data, LOG_PREFIX);
-
-       if ((ret = fx2lafw_command_start_acquisition(sdi)) != SR_OK) {
-               fx2lafw_abort_acquisition(devc);
-               return ret;
-       }
-
-       return SR_OK;
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       (void)cb_data;
-
-       fx2lafw_abort_acquisition(sdi->priv);
-
-       return SR_OK;
-}
-
-SR_PRIV struct sr_dev_driver fx2lafw_driver_info = {
-       .name = "fx2lafw",
-       .longname = "fx2lafw (generic driver for FX2 based LAs)",
-       .api_version = 1,
-       .init = init,
-       .cleanup = cleanup,
-       .scan = scan,
-       .dev_list = 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,
-       .priv = NULL,
-};
diff --git a/hardware/fx2lafw/protocol.c b/hardware/fx2lafw/protocol.c
deleted file mode 100644 (file)
index 433f907..0000000
+++ /dev/null
@@ -1,532 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
- * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "protocol.h"
-
-/* Protocol commands */
-#define CMD_GET_FW_VERSION             0xb0
-#define CMD_START                      0xb1
-#define CMD_GET_REVID_VERSION          0xb2
-
-#define CMD_START_FLAGS_WIDE_POS       5
-#define CMD_START_FLAGS_CLK_SRC_POS    6
-
-#define CMD_START_FLAGS_SAMPLE_8BIT    (0 << CMD_START_FLAGS_WIDE_POS)
-#define CMD_START_FLAGS_SAMPLE_16BIT   (1 << CMD_START_FLAGS_WIDE_POS)
-
-#define CMD_START_FLAGS_CLK_30MHZ      (0 << CMD_START_FLAGS_CLK_SRC_POS)
-#define CMD_START_FLAGS_CLK_48MHZ      (1 << CMD_START_FLAGS_CLK_SRC_POS)
-
-#pragma pack(push, 1)
-
-struct version_info {
-       uint8_t major;
-       uint8_t minor;
-};
-
-struct cmd_start_acquisition {
-       uint8_t flags;
-       uint8_t sample_delay_h;
-       uint8_t sample_delay_l;
-};
-
-#pragma pack(pop)
-
-static int command_get_fw_version(libusb_device_handle *devhdl,
-                                 struct version_info *vi)
-{
-       int ret;
-
-       ret = libusb_control_transfer(devhdl, LIBUSB_REQUEST_TYPE_VENDOR |
-               LIBUSB_ENDPOINT_IN, CMD_GET_FW_VERSION, 0x0000, 0x0000,
-               (unsigned char *)vi, sizeof(struct version_info), 100);
-
-       if (ret < 0) {
-               sr_err("Unable to get version info: %s.",
-                      libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-       return SR_OK;
-}
-
-static int command_get_revid_version(struct sr_dev_inst *sdi, uint8_t *revid)
-{
-       struct sr_usb_dev_inst *usb = sdi->conn;
-       libusb_device_handle *devhdl = usb->devhdl;
-       int ret;
-
-       ret = libusb_control_transfer(devhdl, LIBUSB_REQUEST_TYPE_VENDOR |
-               LIBUSB_ENDPOINT_IN, CMD_GET_REVID_VERSION, 0x0000, 0x0000,
-               revid, 1, 100);
-
-       if (ret < 0) {
-               sr_err("Unable to get REVID: %s.", libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-       return SR_OK;
-}
-
-SR_PRIV int fx2lafw_command_start_acquisition(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc = sdi->priv;
-       struct sr_usb_dev_inst *usb = sdi->conn;
-       libusb_device_handle *devhdl = usb->devhdl;
-       uint64_t samplerate = devc->cur_samplerate;
-       gboolean samplewide = devc->sample_wide;
-       struct cmd_start_acquisition cmd = { 0 };
-       int delay = 0, ret;
-
-       /* Compute the sample rate. */
-       if (samplewide && samplerate > MAX_16BIT_SAMPLE_RATE) {
-               sr_err("Unable to sample at %" PRIu64 "Hz "
-                      "when collecting 16-bit samples.", samplerate);
-               return SR_ERR;
-       }
-
-       if ((SR_MHZ(48) % samplerate) == 0) {
-               cmd.flags = CMD_START_FLAGS_CLK_48MHZ;
-               delay = SR_MHZ(48) / samplerate - 1;
-               if (delay > MAX_SAMPLE_DELAY)
-                       delay = 0;
-       }
-
-       if (delay == 0 && (SR_MHZ(30) % samplerate) == 0) {
-               cmd.flags = CMD_START_FLAGS_CLK_30MHZ;
-               delay = SR_MHZ(30) / samplerate - 1;
-       }
-
-       sr_info("GPIF delay = %d, clocksource = %sMHz.", delay,
-               (cmd.flags & CMD_START_FLAGS_CLK_48MHZ) ? "48" : "30");
-
-       if (delay <= 0 || delay > MAX_SAMPLE_DELAY) {
-               sr_err("Unable to sample at %" PRIu64 "Hz.", samplerate);
-               return SR_ERR;
-       }
-
-       cmd.sample_delay_h = (delay >> 8) & 0xff;
-       cmd.sample_delay_l = delay & 0xff;
-
-       /* Select the sampling width. */
-       cmd.flags |= samplewide ? CMD_START_FLAGS_SAMPLE_16BIT :
-               CMD_START_FLAGS_SAMPLE_8BIT;
-
-       /* Send the control message. */
-       ret = libusb_control_transfer(devhdl, LIBUSB_REQUEST_TYPE_VENDOR |
-                       LIBUSB_ENDPOINT_OUT, CMD_START, 0x0000, 0x0000,
-                       (unsigned char *)&cmd, sizeof(cmd), 100);
-       if (ret < 0) {
-               sr_err("Unable to send start command: %s.",
-                      libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-       return SR_OK;
-}
-
-/**
- * Check the USB configuration to determine if this is an fx2lafw device.
- *
- * @return TRUE if the device's configuration profile match fx2lafw
- *         configuration, FALSE otherwise.
- */
-SR_PRIV gboolean fx2lafw_check_conf_profile(libusb_device *dev)
-{
-       struct libusb_device_descriptor des;
-       struct libusb_device_handle *hdl;
-       gboolean ret;
-       unsigned char strdesc[64];
-
-       hdl = NULL;
-       ret = FALSE;
-       while (!ret) {
-               /* Assume the FW has not been loaded, unless proven wrong. */
-               if (libusb_get_device_descriptor(dev, &des) != 0)
-                       break;
-
-               if (libusb_open(dev, &hdl) != 0)
-                       break;
-
-               if (libusb_get_string_descriptor_ascii(hdl,
-                   des.iManufacturer, strdesc, sizeof(strdesc)) < 0)
-                       break;
-               if (strncmp((const char *)strdesc, "sigrok", 6))
-                       break;
-
-               if (libusb_get_string_descriptor_ascii(hdl,
-                               des.iProduct, strdesc, sizeof(strdesc)) < 0)
-                       break;
-               if (strncmp((const char *)strdesc, "fx2lafw", 7))
-                       break;
-
-               /* If we made it here, it must be an fx2lafw. */
-               ret = TRUE;
-       }
-       if (hdl)
-               libusb_close(hdl);
-
-       return ret;
-}
-
-SR_PRIV int fx2lafw_dev_open(struct sr_dev_inst *sdi, struct sr_dev_driver *di)
-{
-       libusb_device **devlist;
-       struct sr_usb_dev_inst *usb;
-       struct libusb_device_descriptor des;
-       struct dev_context *devc;
-       struct drv_context *drvc;
-       struct version_info vi;
-       int ret, skip, i, device_count;
-       uint8_t revid;
-
-       drvc = di->priv;
-       devc = sdi->priv;
-       usb = sdi->conn;
-
-       if (sdi->status == SR_ST_ACTIVE)
-               /* Device is already in use. */
-               return SR_ERR;
-
-       skip = 0;
-       device_count = libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
-       if (device_count < 0) {
-               sr_err("Failed to get device list: %s.",
-                      libusb_error_name(device_count));
-               return SR_ERR;
-       }
-
-       for (i = 0; i < device_count; i++) {
-               if ((ret = libusb_get_device_descriptor(devlist[i], &des))) {
-                       sr_err("Failed to get device descriptor: %s.",
-                              libusb_error_name(ret));
-                       continue;
-               }
-
-               if (des.idVendor != devc->profile->vid
-                   || des.idProduct != devc->profile->pid)
-                       continue;
-
-               if (sdi->status == SR_ST_INITIALIZING) {
-                       if (skip != sdi->index) {
-                               /* Skip devices of this type that aren't the one we want. */
-                               skip += 1;
-                               continue;
-                       }
-               } else if (sdi->status == SR_ST_INACTIVE) {
-                       /*
-                        * This device is fully enumerated, so we need to find
-                        * this device by vendor, product, bus and address.
-                        */
-                       if (libusb_get_bus_number(devlist[i]) != usb->bus
-                               || libusb_get_device_address(devlist[i]) != usb->address)
-                               /* This is not the one. */
-                               continue;
-               }
-
-               if (!(ret = libusb_open(devlist[i], &usb->devhdl))) {
-                       if (usb->address == 0xff)
-                               /*
-                                * First time we touch this device after FW
-                                * upload, so we don't know the address yet.
-                                */
-                               usb->address = libusb_get_device_address(devlist[i]);
-               } else {
-                       sr_err("Failed to open device: %s.",
-                              libusb_error_name(ret));
-                       break;
-               }
-
-               ret = command_get_fw_version(usb->devhdl, &vi);
-               if (ret != SR_OK) {
-                       sr_err("Failed to get firmware version.");
-                       break;
-               }
-
-               ret = command_get_revid_version(sdi, &revid);
-               if (ret != SR_OK) {
-                       sr_err("Failed to get REVID.");
-                       break;
-               }
-
-               /*
-                * Changes in major version mean incompatible/API changes, so
-                * bail out if we encounter an incompatible version.
-                * Different minor versions are OK, they should be compatible.
-                */
-               if (vi.major != FX2LAFW_REQUIRED_VERSION_MAJOR) {
-                       sr_err("Expected firmware version %d.x, "
-                              "got %d.%d.", FX2LAFW_REQUIRED_VERSION_MAJOR,
-                              vi.major, vi.minor);
-                       break;
-               }
-
-               sdi->status = SR_ST_ACTIVE;
-               sr_info("Opened device %d on %d.%d, "
-                       "interface %d, firmware %d.%d.",
-                       sdi->index, usb->bus, usb->address,
-                       USB_INTERFACE, vi.major, vi.minor);
-
-               sr_info("Detected REVID=%d, it's a Cypress CY7C68013%s.",
-                       revid, (revid != 1) ? " (FX2)" : "A (FX2LP)");
-
-               break;
-       }
-       libusb_free_device_list(devlist, 1);
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR;
-
-       return SR_OK;
-}
-
-SR_PRIV struct dev_context *fx2lafw_dev_new(void)
-{
-       struct dev_context *devc;
-
-       if (!(devc = g_try_malloc(sizeof(struct dev_context)))) {
-               sr_err("Device context malloc failed.");
-               return NULL;
-       }
-
-       devc->profile = NULL;
-       devc->fw_updated = 0;
-       devc->cur_samplerate = 0;
-       devc->limit_samples = 0;
-       devc->sample_wide = FALSE;
-       devc->stl = NULL;
-
-       return devc;
-}
-
-SR_PRIV void fx2lafw_abort_acquisition(struct dev_context *devc)
-{
-       int i;
-
-       devc->acq_aborted = TRUE;
-
-       for (i = devc->num_transfers - 1; i >= 0; i--) {
-               if (devc->transfers[i])
-                       libusb_cancel_transfer(devc->transfers[i]);
-       }
-}
-
-static void finish_acquisition(struct sr_dev_inst *sdi)
-{
-       struct sr_datafeed_packet packet;
-       struct dev_context *devc;
-
-       devc = sdi->priv;
-
-       /* Terminate session. */
-       packet.type = SR_DF_END;
-       sr_session_send(sdi, &packet);
-
-       /* Remove fds from polling. */
-       usb_source_remove(sdi->session, devc->ctx);
-
-       devc->num_transfers = 0;
-       g_free(devc->transfers);
-
-       if (devc->stl) {
-               soft_trigger_logic_free(devc->stl);
-               devc->stl = NULL;
-       }
-}
-
-static void free_transfer(struct libusb_transfer *transfer)
-{
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-       unsigned int i;
-
-       sdi = transfer->user_data;
-       devc = sdi->priv;
-
-       g_free(transfer->buffer);
-       transfer->buffer = NULL;
-       libusb_free_transfer(transfer);
-
-       for (i = 0; i < devc->num_transfers; i++) {
-               if (devc->transfers[i] == transfer) {
-                       devc->transfers[i] = NULL;
-                       break;
-               }
-       }
-
-       devc->submitted_transfers--;
-       if (devc->submitted_transfers == 0)
-               finish_acquisition(sdi);
-}
-
-static void resubmit_transfer(struct libusb_transfer *transfer)
-{
-       int ret;
-
-       if ((ret = libusb_submit_transfer(transfer)) == LIBUSB_SUCCESS)
-               return;
-
-       sr_err("%s: %s", __func__, libusb_error_name(ret));
-       free_transfer(transfer);
-
-}
-
-SR_PRIV void fx2lafw_receive_transfer(struct libusb_transfer *transfer)
-{
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-       gboolean packet_has_error = FALSE;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_logic logic;
-       unsigned int num_samples;
-       int trigger_offset, cur_sample_count, unitsize;
-
-       sdi = transfer->user_data;
-       devc = sdi->priv;
-
-       /*
-        * If acquisition has already ended, just free any queued up
-        * transfer that come in.
-        */
-       if (devc->acq_aborted) {
-               free_transfer(transfer);
-               return;
-       }
-
-       sr_info("receive_transfer(): status %d received %d bytes.",
-               transfer->status, transfer->actual_length);
-
-       /* Save incoming transfer before reusing the transfer struct. */
-       unitsize = devc->sample_wide ? 2 : 1;
-       cur_sample_count = transfer->actual_length / unitsize;
-
-       switch (transfer->status) {
-       case LIBUSB_TRANSFER_NO_DEVICE:
-               fx2lafw_abort_acquisition(devc);
-               free_transfer(transfer);
-               return;
-       case LIBUSB_TRANSFER_COMPLETED:
-       case LIBUSB_TRANSFER_TIMED_OUT: /* We may have received some data though. */
-               break;
-       default:
-               packet_has_error = TRUE;
-               break;
-       }
-
-       if (transfer->actual_length == 0 || packet_has_error) {
-               devc->empty_transfer_count++;
-               if (devc->empty_transfer_count > MAX_EMPTY_TRANSFERS) {
-                       /*
-                        * The FX2 gave up. End the acquisition, the frontend
-                        * will work out that the samplecount is short.
-                        */
-                       fx2lafw_abort_acquisition(devc);
-                       free_transfer(transfer);
-               } else {
-                       resubmit_transfer(transfer);
-               }
-               return;
-       } else {
-               devc->empty_transfer_count = 0;
-       }
-
-       if (devc->trigger_fired) {
-               if (devc->sent_samples < devc->limit_samples) {
-                       /* Send the incoming transfer to the session bus. */
-                       packet.type = SR_DF_LOGIC;
-                       packet.payload = &logic;
-                       if (devc->sent_samples + cur_sample_count > devc->limit_samples)
-                               num_samples = devc->limit_samples - devc->sent_samples;
-                       else
-                               num_samples = cur_sample_count;
-                       logic.length = num_samples * unitsize;
-                       logic.unitsize = unitsize;
-                       logic.data = transfer->buffer;
-                       sr_session_send(devc->cb_data, &packet);
-                       devc->sent_samples += num_samples;
-               }
-       } else {
-               trigger_offset = soft_trigger_logic_check(devc->stl,
-                               transfer->buffer, transfer->actual_length);
-               if (trigger_offset > -1) {
-                       packet.type = SR_DF_LOGIC;
-                       packet.payload = &logic;
-                       num_samples = cur_sample_count - trigger_offset;
-                       if (devc->limit_samples &&
-                                       num_samples > devc->limit_samples - devc->sent_samples)
-                               num_samples = devc->limit_samples - devc->sent_samples;
-                       logic.length = num_samples * unitsize;
-                       logic.unitsize = unitsize;
-                       logic.data = transfer->buffer + trigger_offset * unitsize;
-                       sr_session_send(devc->cb_data, &packet);
-                       devc->sent_samples += num_samples;
-
-                       devc->trigger_fired = TRUE;
-               }
-       }
-
-       if (devc->limit_samples && devc->sent_samples >= devc->limit_samples) {
-               fx2lafw_abort_acquisition(devc);
-               free_transfer(transfer);
-       } else
-               resubmit_transfer(transfer);
-}
-
-static unsigned int to_bytes_per_ms(unsigned int samplerate)
-{
-       return samplerate / 1000;
-}
-
-SR_PRIV size_t fx2lafw_get_buffer_size(struct dev_context *devc)
-{
-       size_t s;
-
-       /*
-        * The buffer should be large enough to hold 10ms of data and
-        * a multiple of 512.
-        */
-       s = 10 * to_bytes_per_ms(devc->cur_samplerate);
-       return (s + 511) & ~511;
-}
-
-SR_PRIV unsigned int fx2lafw_get_number_of_transfers(struct dev_context *devc)
-{
-       unsigned int n;
-
-       /* Total buffer size should be able to hold about 500ms of data. */
-       n = (500 * to_bytes_per_ms(devc->cur_samplerate) /
-               fx2lafw_get_buffer_size(devc));
-
-       if (n > NUM_SIMUL_TRANSFERS)
-               return NUM_SIMUL_TRANSFERS;
-
-       return n;
-}
-
-SR_PRIV unsigned int fx2lafw_get_timeout(struct dev_context *devc)
-{
-       size_t total_size;
-       unsigned int timeout;
-
-       total_size = fx2lafw_get_buffer_size(devc) *
-                       fx2lafw_get_number_of_transfers(devc);
-       timeout = total_size / to_bytes_per_ms(devc->cur_samplerate);
-       return timeout + timeout / 4; /* Leave a headroom of 25% percent. */
-}
diff --git a/hardware/fx2lafw/protocol.h b/hardware/fx2lafw/protocol.h
deleted file mode 100644 (file)
index fef0dd7..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
- * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef LIBSIGROK_HARDWARE_FX2LAFW_PROTOCOL_H
-#define LIBSIGROK_HARDWARE_FX2LAFW_PROTOCOL_H
-
-#include <glib.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <libusb.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "fx2lafw"
-
-#define USB_INTERFACE          0
-#define USB_CONFIGURATION      1
-#define NUM_TRIGGER_STAGES     4
-
-#define MAX_RENUM_DELAY_MS     3000
-#define NUM_SIMUL_TRANSFERS    32
-#define MAX_EMPTY_TRANSFERS    (NUM_SIMUL_TRANSFERS * 2)
-
-#define FX2LAFW_REQUIRED_VERSION_MAJOR 1
-
-#define MAX_8BIT_SAMPLE_RATE   SR_MHZ(24)
-#define MAX_16BIT_SAMPLE_RATE  SR_MHZ(12)
-
-/* 6 delay states of up to 256 clock ticks */
-#define MAX_SAMPLE_DELAY       (6 * 256)
-
-#define DEV_CAPS_16BIT_POS     0
-
-#define DEV_CAPS_16BIT         (1 << DEV_CAPS_16BIT_POS)
-
-struct fx2lafw_profile {
-       uint16_t vid;
-       uint16_t pid;
-
-       const char *vendor;
-       const char *model;
-       const char *model_version;
-
-       const char *firmware;
-
-       uint32_t dev_caps;
-
-       const char *usb_manufacturer;
-       const char *usb_product;
-};
-
-struct dev_context {
-       const struct fx2lafw_profile *profile;
-       /*
-        * Since we can't keep track of an fx2lafw device after upgrading
-        * the firmware (it renumerates into a different device address
-        * after the upgrade) this is like a global lock. No device will open
-        * until a proper delay after the last device was upgraded.
-        */
-       int64_t fw_updated;
-
-       /* Device/capture settings */
-       uint64_t cur_samplerate;
-       uint64_t limit_samples;
-
-       /* Operational settings */
-       gboolean trigger_fired;
-       gboolean acq_aborted;
-       gboolean sample_wide;
-       struct soft_trigger_logic *stl;
-
-       unsigned int sent_samples;
-       int submitted_transfers;
-       int empty_transfer_count;
-
-       void *cb_data;
-       unsigned int num_transfers;
-       struct libusb_transfer **transfers;
-       struct sr_context *ctx;
-};
-
-SR_PRIV int fx2lafw_command_start_acquisition(const struct sr_dev_inst *sdi);
-SR_PRIV gboolean fx2lafw_check_conf_profile(libusb_device *dev);
-SR_PRIV int fx2lafw_dev_open(struct sr_dev_inst *sdi, struct sr_dev_driver *di);
-SR_PRIV struct dev_context *fx2lafw_dev_new(void);
-SR_PRIV void fx2lafw_abort_acquisition(struct dev_context *devc);
-SR_PRIV void fx2lafw_receive_transfer(struct libusb_transfer *transfer);
-SR_PRIV size_t fx2lafw_get_buffer_size(struct dev_context *devc);
-SR_PRIV unsigned int fx2lafw_get_number_of_transfers(struct dev_context *devc);
-SR_PRIV unsigned int fx2lafw_get_timeout(struct dev_context *devc);
-
-#endif
diff --git a/hardware/gmc-mh-1x-2x/api.c b/hardware/gmc-mh-1x-2x/api.c
deleted file mode 100644 (file)
index 96621bb..0000000
+++ /dev/null
@@ -1,618 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013, 2014 Matthias Heidbrink <m-sigrok@heidbrink.biz>
- *
- * 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
- *  Gossen Metrawatt Metrahit 1x/2x drivers
- *  @internal
- */
-
-#include <string.h>
-#include "protocol.h"
-
-/* Serial communication parameters for Metrahit 1x/2x with 'RS232' adaptor */
-#define SERIALCOMM_1X_RS232 "8228/6n1/dtr=1/rts=1/flow=0" /* =8192, closer with divider */
-#define SERIALCOMM_2X_RS232 "9600/6n1/dtr=1/rts=1/flow=0"
-#define SERIALCOMM_2X "9600/8n1/dtr=1/rts=1/flow=0"
-#define VENDOR_GMC "Gossen Metrawatt"
-
-SR_PRIV struct sr_dev_driver gmc_mh_1x_2x_rs232_driver_info;
-SR_PRIV struct sr_dev_driver gmc_mh_2x_bd232_driver_info;
-
-static const int32_t hwopts[] = {
-       SR_CONF_CONN,
-       SR_CONF_SERIALCOMM,
-};
-
-/** Hardware capabilities for Metrahit 1x/2x devices in send mode. */
-static const int32_t hwcaps_sm[] = {
-       SR_CONF_MULTIMETER,
-       SR_CONF_THERMOMETER,    /**< All GMC 1x/2x multimeters seem to support this */
-       SR_CONF_LIMIT_SAMPLES,
-       SR_CONF_LIMIT_MSEC,
-       SR_CONF_CONTINUOUS,
-};
-
-/** Hardware capabilities for Metrahit 2x devices in bidirectional Mode. */
-static const int32_t hwcaps_bd[] = {
-       SR_CONF_MULTIMETER,
-       SR_CONF_THERMOMETER,    /**< All GMC 1x/2x multimeters seem to support this */
-       SR_CONF_LIMIT_SAMPLES,
-       SR_CONF_LIMIT_MSEC,
-       SR_CONF_CONTINUOUS,
-       SR_CONF_POWER_OFF,
-};
-
-
-/* TODO:
- * - For the 29S SR_CONF_ENERGYMETER, too.
- * - SR_CONF_PATTERN_MODE for some 2x devices
- * - SR_CONF_DATALOG for 22M, 26M, 29S and storage adaptors.
- * Need to implement device-specific lists.
- */
-
-/** Init driver gmc_mh_1x_2x_rs232. */
-static int init_1x_2x_rs232(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, &gmc_mh_1x_2x_rs232_driver_info, LOG_PREFIX);
-}
-
-/** Init driver gmc_mh_2x_bd232. */
-static int init_2x_bd232(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, &gmc_mh_2x_bd232_driver_info, LOG_PREFIX);
-}
-
-/**
- * Read single byte from serial port.
- *
- * @retval -1 Timeout or error.
- * @retval other Byte.
- */
-static int read_byte(struct sr_serial_dev_inst *serial, gint64 timeout)
-{
-       uint8_t result = 0;
-       int rc = 0;
-
-       for (;;) {
-               rc = serial_read(serial, &result, 1);
-               if (rc == 1) {
-                       sr_spew("read: 0x%02x/%d", result, result);
-                       return result;
-               }
-               if (g_get_monotonic_time() > timeout)
-                       return -1;
-               g_usleep(2000);
-       }
-}
-
-/**
- * Try to detect GMC 1x/2x multimeter model in send mode for max. 1 second.
- *
- * @param serial Configured, open serial port.
- *
- * @retval NULL Detection failed.
- * @retval other Model code.
- */
-static enum model scan_model_sm(struct sr_serial_dev_inst *serial)
-{
-       int byte, bytecnt, cnt;
-       enum model model;
-       gint64 timeout_us;
-
-       model = METRAHIT_NONE;
-       timeout_us = g_get_monotonic_time() + 1 * 1000 * 1000;
-
-       /*
-        * Try to find message consisting of device code and several
-        * (at least 4) data bytes.
-        */
-       for (bytecnt = 0; bytecnt < 100; bytecnt++) {
-               byte = read_byte(serial, timeout_us);
-               if ((byte == -1) || (timeout_us < g_get_monotonic_time()))
-                       break;
-               if ((byte & MSGID_MASK) == MSGID_INF) {
-                       if (!(model = gmc_decode_model_sm(byte & MSGC_MASK)))
-                               break;
-                       /* Now expect (at least) 4 data bytes. */
-                       for (cnt = 0; cnt < 4; cnt++) {
-                               byte = read_byte(serial, timeout_us);
-                               if ((byte == -1) ||
-                                               ((byte & MSGID_MASK) != MSGID_DATA))
-                               {
-                                       model = METRAHIT_NONE;
-                                       bytecnt = 100;
-                                       break;
-                               }
-                       }
-                       break;
-               }
-       }
-
-       return model;
-}
-
-/**
- * Scan for Metrahit 1x and Metrahit 2x in send mode using Gossen Metrawatt
- * 'RS232' interface.
- *
- * The older 1x models use 8192 baud and the newer 2x 9600 baud.
- * The DMM usually sends up to about 20 messages per second. However, depending
- * on configuration and measurement mode the intervals can be much larger and
- * then the detection might not work.
- */
-static GSList *scan_1x_2x_rs232(GSList *options)
-{
-       struct sr_dev_inst *sdi;
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       struct sr_config *src;
-       struct sr_channel *ch;
-       struct sr_serial_dev_inst *serial;
-       GSList *l, *devices;
-       const char *conn, *serialcomm;
-       enum model model;
-       gboolean serialcomm_given;
-
-       devices = NULL;
-       drvc = (&gmc_mh_1x_2x_rs232_driver_info)->priv;
-       drvc->instances = NULL;
-       conn = serialcomm = NULL;
-       model = METRAHIT_NONE;
-       serialcomm_given = FALSE;
-
-       sr_spew("scan_1x_2x_rs232() called!");
-
-       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);
-                       serialcomm_given = TRUE;
-                       break;
-               }
-       }
-       if (!conn)
-               return NULL;
-       if (!serialcomm)
-               serialcomm = SERIALCOMM_2X_RS232;
-
-       if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
-               return NULL;
-
-       if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK) {
-               sr_serial_dev_inst_free(serial);
-               return NULL;
-       }
-
-       serial_flush(serial);
-
-       model = scan_model_sm(serial);
-
-       /*
-        * If detection failed and no user-supplied parameters,
-        * try second baud rate.
-        */
-       if ((model == METRAHIT_NONE) && !serialcomm_given) {
-               serialcomm = SERIALCOMM_1X_RS232;
-               g_free(serial->serialcomm);
-               serial->serialcomm = g_strdup(serialcomm);
-               if (serial_set_paramstr(serial, serialcomm) == SR_OK) {
-                       serial_flush(serial);
-                       model = scan_model_sm(serial);
-               }
-       }
-
-       if (model != METRAHIT_NONE) {
-               sr_spew("%s %s detected!", VENDOR_GMC, gmc_model_str(model));
-               if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, VENDOR_GMC,
-                               gmc_model_str(model), NULL)))
-                       return NULL;
-               if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
-                       sr_err("Device context malloc failed.");
-                       return NULL;
-               }
-               devc->model = model;
-               devc->limit_samples = 0;
-               devc->limit_msec = 0;
-               devc->num_samples = 0;
-               devc->elapsed_msec = g_timer_new();
-               devc->settings_ok = FALSE;
-
-               sdi->conn = serial;
-               sdi->priv = devc;
-               sdi->driver = &gmc_mh_1x_2x_rs232_driver_info;
-               if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1")))
-                       return NULL;
-               sdi->channels = g_slist_append(sdi->channels, ch);
-               drvc->instances = g_slist_append(drvc->instances, sdi);
-               devices = g_slist_append(devices, sdi);
-       }
-
-       return devices;
-}
-
-/** Scan for Metrahit 2x in a bidirectional mode using Gossen Metrawatt 'BD 232' interface.
- *
- */
-static GSList *scan_2x_bd232(GSList *options)
-{
-       struct sr_dev_inst *sdi;
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       struct sr_config *src;
-       struct sr_channel *ch;
-       struct sr_serial_dev_inst *serial;
-       GSList *l, *devices;
-       const char *conn, *serialcomm;
-       int cnt, byte;
-       gint64 timeout_us;
-
-       sdi = NULL;
-       devc = NULL;
-       conn = serialcomm = NULL;
-       devices = NULL;
-
-       drvc = (&gmc_mh_2x_bd232_driver_info)->priv;
-       drvc->instances = NULL;
-
-       sr_spew("scan_2x_bd232() called!");
-
-       for (l = options; l; l = l->next) {
-               src = l->data;
-               switch (src->key) {
-               case SR_CONF_CONN:
-                       conn = g_variant_get_string(src->data, NULL);
-                       break;
-               case SR_CONF_SERIALCOMM:
-                       serialcomm = g_variant_get_string(src->data, NULL);
-                       break;
-               }
-       }
-       if (!conn)
-               return NULL;
-       if (!serialcomm)
-               serialcomm = SERIALCOMM_2X;
-
-       if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
-               return NULL;
-
-       if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
-               goto exit_err;
-
-       if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
-               sr_err("Device context malloc failed.");
-               goto exit_err;
-       }
-
-       if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, VENDOR_GMC, NULL, NULL)))
-               goto exit_err;
-
-       sdi->priv = devc;
-
-       /* Send message 03 "Query multimeter version and status" */
-       sdi->conn = serial;
-       sdi->priv = devc;
-       if (req_stat14(sdi, TRUE) != SR_OK)
-               goto exit_err;
-
-       /* Wait for reply from device(s) for up to 2s. */
-       timeout_us = g_get_monotonic_time() + 2*1000*1000;
-
-       while (timeout_us > g_get_monotonic_time()) {
-               /* Receive reply (14 bytes) */
-               devc->buflen = 0;
-               for (cnt = 0; cnt < 14; cnt++) {
-                       byte = read_byte(serial, timeout_us);
-                       if (byte != -1)
-                               devc->buf[devc->buflen++] = (byte & MASK_6BITS);
-               }
-
-               if (devc->buflen != 14)
-                       continue;
-
-               devc->addr = devc->buf[0];
-               process_msg14(sdi);
-               devc->buflen = 0;
-
-               if (devc->model != METRAHIT_NONE) {
-                       sr_spew("%s %s detected!", VENDOR_GMC, gmc_model_str(devc->model));
-
-                       devc->elapsed_msec = g_timer_new();
-
-                       sdi->model = g_strdup(gmc_model_str(devc->model));
-                       sdi->version = g_strdup_printf("Firmware %d.%d", devc->fw_ver_maj, devc->fw_ver_min);
-                       sdi->conn = serial;
-                       sdi->priv = devc;
-                       sdi->driver = &gmc_mh_2x_bd232_driver_info;
-                       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1")))
-                               goto exit_err;
-                       sdi->channels = g_slist_append(sdi->channels, ch);
-                       drvc->instances = g_slist_append(drvc->instances, sdi);
-                       devices = g_slist_append(devices, sdi);
-
-                       if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
-                               sr_err("Device context malloc failed.");
-                               goto exit_err;
-                       }
-
-                       if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, VENDOR_GMC, NULL, NULL)))
-                               goto exit_err;
-               }
-       };
-
-       /* Free last alloc if no device found */
-       if (devc->model == METRAHIT_NONE) {
-               g_free(devc);
-               sr_dev_inst_free(sdi);
-       }
-
-       return devices;
-
-exit_err:
-       sr_info("scan_2x_bd232(): Error!");
-
-       if (serial)
-               sr_serial_dev_inst_free(serial);
-       if (devc)
-               g_free(devc);
-       if (sdi)
-               sr_dev_inst_free(sdi);
-
-       return NULL;
-}
-
-/** Driver device list function */
-static GSList *dev_list_1x_2x_rs232(void)
-{
-       return ((struct drv_context *)(gmc_mh_1x_2x_rs232_driver_info.priv))->instances;
-}
-
-/** Driver device list function */
-static GSList *dev_list_2x_bd232(void)
-{
-       return ((struct drv_context *)(gmc_mh_2x_bd232_driver_info.priv))
-                       ->instances;
-}
-
-static int dev_close(struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-
-       std_serial_dev_close(sdi);
-
-       sdi->status = SR_ST_INACTIVE;
-
-       /* Free dynamically allocated resources. */
-       if ((devc = sdi->priv) && devc->elapsed_msec) {
-               g_timer_destroy(devc->elapsed_msec);
-               devc->elapsed_msec = NULL;
-               devc->model = METRAHIT_NONE;
-       }
-
-       return SR_OK;
-}
-
-static int cleanup_sm_rs232(void)
-{
-       return std_dev_clear(&gmc_mh_1x_2x_rs232_driver_info, NULL);
-}
-
-static int cleanup_2x_bd232(void)
-{
-       return std_dev_clear(&gmc_mh_2x_bd232_driver_info, NULL);
-}
-
-/** Get value of configuration item */
-static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
-                     const struct sr_channel_group *cg)
-{
-       int ret;
-       struct dev_context *devc;
-
-       (void)cg;
-
-       ret = SR_OK;
-
-       if (!sdi || !(devc = sdi->priv))
-               return SR_ERR_ARG;
-
-       ret = SR_OK;
-       switch (key) {
-       case SR_CONF_LIMIT_SAMPLES:
-               *data = g_variant_new_uint64(devc->limit_samples);
-               break;
-       case SR_CONF_LIMIT_MSEC:
-               *data = g_variant_new_uint64(devc->limit_msec);
-               break;
-       case SR_CONF_POWER_OFF:
-               *data = g_variant_new_boolean(FALSE);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return ret;
-}
-
-/** Implementation of config_list, auxiliary function for common parts, */
-static int config_list_common(int 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_INT32,
-                                                 hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-/** Implementation of config_list for Metrahit 1x/2x send mode */
-static int config_list_sm(int key, GVariant **data, const struct sr_dev_inst *sdi,
-                         const struct sr_channel_group *cg)
-{
-       switch (key) {
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                                                 hwcaps_sm, ARRAY_SIZE(hwcaps_sm), sizeof(int32_t));
-               break;
-       default:
-               return config_list_common(key, data, sdi, cg);
-       }
-
-       return SR_OK;
-}
-
-/** Implementation of config_list for Metrahit 2x bidirectional mode */
-static int config_list_bd(int key, GVariant **data, const struct sr_dev_inst *sdi,
-                         const struct sr_channel_group *cg)
-{
-       switch (key) {
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                                                 hwcaps_bd, ARRAY_SIZE(hwcaps_bd), sizeof(int32_t));
-               break;
-       default:
-               return config_list_common(key, data, sdi, cg);
-       }
-
-       return SR_OK;
-}
-
-static int dev_acquisition_start_1x_2x_rs232(const struct sr_dev_inst *sdi,
-                                            void *cb_data)
-{
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-
-       if (!sdi || !cb_data || !(devc = sdi->priv))
-               return SR_ERR_BUG;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       devc->cb_data = cb_data;
-       devc->settings_ok = FALSE;
-       devc->buflen = 0;
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(cb_data, LOG_PREFIX);
-
-       /* Start timer, if required. */
-       if (devc->limit_msec)
-               g_timer_start(devc->elapsed_msec);
-
-       /* Poll every 40ms, or whenever some data comes in. */
-       serial = sdi->conn;
-       serial_source_add(sdi->session, serial, G_IO_IN, 40,
-                       gmc_mh_1x_2x_receive_data, (void *)sdi);
-
-       return SR_OK;
-}
-
-static int dev_acquisition_start_2x_bd232(const struct sr_dev_inst *sdi,
-                                         void *cb_data)
-{
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-
-       if (!sdi || !cb_data || !(devc = sdi->priv))
-               return SR_ERR_BUG;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       devc->cb_data = cb_data;
-       devc->settings_ok = FALSE;
-       devc->buflen = 0;
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(cb_data, LOG_PREFIX);
-
-       /* Start timer, if required. */
-       if (devc->limit_msec)
-               g_timer_start(devc->elapsed_msec);
-
-       /* Poll every 40ms, or whenever some data comes in. */
-       serial = sdi->conn;
-       serial_source_add(sdi->session, serial, G_IO_IN, 40,
-                       gmc_mh_2x_receive_data, (void *)sdi);
-
-       /* Send start message */
-       return req_meas14(sdi);
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct dev_context *devc;
-
-       /* Stop timer, if required. */
-       if (sdi && (devc = sdi->priv) && devc->limit_msec)
-               g_timer_stop(devc->elapsed_msec);
-
-       return std_serial_dev_acquisition_stop(sdi, cb_data, dev_close,
-                       sdi->conn, LOG_PREFIX);
-}
-
-SR_PRIV struct sr_dev_driver gmc_mh_1x_2x_rs232_driver_info = {
-       .name = "gmc-mh-1x-2x-rs232",
-       .longname = "Gossen Metrawatt Metrahit 1x/2x, RS232 interface",
-       .api_version = 1,
-       .init = init_1x_2x_rs232,
-       .cleanup = cleanup_sm_rs232,
-       .scan = scan_1x_2x_rs232,
-       .dev_list = dev_list_1x_2x_rs232,
-       .dev_clear = NULL,
-       .config_get = config_get,
-       .config_set = config_set,
-       .config_list = config_list_sm,
-       .dev_open = std_serial_dev_open,
-       .dev_close = dev_close,
-       .dev_acquisition_start = dev_acquisition_start_1x_2x_rs232,
-       .dev_acquisition_stop = dev_acquisition_stop,
-       .priv = NULL,
-};
-
-SR_PRIV struct sr_dev_driver gmc_mh_2x_bd232_driver_info = {
-       .name = "gmc-mh-2x-bd232",
-       .longname = "Gossen Metrawatt Metrahit 2x, BD232/SI232-II interface",
-       .api_version = 1,
-       .init = init_2x_bd232,
-       .cleanup = cleanup_2x_bd232,
-       .scan = scan_2x_bd232,
-       .dev_list = dev_list_2x_bd232,
-       .dev_clear = NULL,
-       .config_get = config_get,
-       .config_set = config_set,
-       .config_list = config_list_bd,
-       .dev_open = std_serial_dev_open,
-       .dev_close = dev_close,
-       .dev_acquisition_start = dev_acquisition_start_2x_bd232,
-       .dev_acquisition_stop = dev_acquisition_stop,
-       .priv = NULL,
-};
diff --git a/hardware/gmc-mh-1x-2x/protocol.c b/hardware/gmc-mh-1x-2x/protocol.c
deleted file mode 100644 (file)
index dc1a683..0000000
+++ /dev/null
@@ -1,1551 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013, 2014 Matthias Heidbrink <m-sigrok@heidbrink.biz>
- *
- * 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
- *  Gossen Metrawatt Metrahit 1x/2x drivers
- *  @internal
- */
-
-#include <math.h>
-#include <string.h>
-#include "protocol.h"
-
-/* Internal Headers */
-static guchar calc_chksum_14(guchar* dta);
-static int chk_msg14(struct sr_dev_inst *sdi);
-
-/** Set or clear flags in devc->mqflags. */
-static void setmqf(struct dev_context *devc, uint64_t flags, gboolean set)
-{
-       if (set)
-               devc->mqflags |= flags;
-       else
-               devc->mqflags &= ~flags;
-}
-
-/** Decode current type and measured value, Metrahit 12-16. */
-static void decode_ctmv_16(uint8_t ctmv, struct dev_context *devc)
-{
-       devc->mq = 0;
-       devc->unit = 0;
-       devc->mqflags = 0;
-
-       switch (ctmv) {
-       case 0x00: /* 0000 - */
-               break;
-       case 0x01: /* 0001 mV DC */
-               devc->scale1000 = -1; /* Fall through */
-       case 0x02: /* 0010 V DC */
-       case 0x03: /* 0011 V AC+DC */
-       case 0x04: /* 0100 V AC */
-               devc->mq = SR_MQ_VOLTAGE;
-               devc->unit = SR_UNIT_VOLT;
-               if (ctmv <= 0x03)
-                       devc->mqflags |= SR_MQFLAG_DC;
-               if (ctmv >= 0x03) {
-                       devc->mqflags |= SR_MQFLAG_AC;
-                       if (devc->model >= METRAHIT_16S)
-                               devc->mqflags |= SR_MQFLAG_RMS;
-               }
-               break;
-       case 0x05: /* 0101 Hz (15S/16S only) */
-       case 0x06: /* 0110 kHz (15S/16S only) */
-               devc->mq = SR_MQ_FREQUENCY;
-               devc->unit = SR_UNIT_HERTZ;
-               if (ctmv == 0x06)
-                       devc->scale1000 = 1;
-               break;
-       case 0x07: /* 0111 % (15S/16S only) */
-               devc->mq = SR_MQ_DUTY_CYCLE;
-               devc->unit = SR_UNIT_PERCENTAGE;
-               break;
-       case 0x08: /* 1000 Diode */
-               devc->mq = SR_MQ_VOLTAGE;
-               devc->unit = SR_UNIT_VOLT;
-               devc->mqflags |= SR_MQFLAG_DIODE;
-               break;
-       case 0x09: /* 1001 Ohm, Â°C */
-       case 0x0a: /* 1010 kOhm */
-       case 0x0b: /* 1011 MOhm */
-               devc->mq = SR_MQ_RESISTANCE; /* Changed to temp. later if req.*/
-               devc->unit = SR_UNIT_OHM;
-               devc->scale1000 = ctmv - 0x09;
-               break;
-       case 0x0c: /* 1100 nF (15S/16S only) */
-       case 0x0d: /* 1101 ÂµF (15S/16S only) */
-               devc->mq = SR_MQ_CAPACITANCE;
-               devc->unit = SR_UNIT_FARAD;
-               if (ctmv == 0x0c)
-                       devc->scale1000 = -3;
-               else
-                       devc->scale1000 = -2;
-               break;
-       case 0x0e: /* mA, ÂµA */
-               devc->scale1000 = -1; /* Fall through. */
-       case 0x0f: /* A */
-               devc->mq = SR_MQ_CURRENT;
-               devc->unit = SR_UNIT_AMPERE;
-               if (devc->model == METRAHIT_16S)
-                       devc->mqflags |= SR_MQFLAG_RMS;
-               /* 16I A only with clamp, RMS questionable. */
-               break;
-       }
-}
-
-/**
- * Decode range/sign/acdc byte special chars (Metrahit 12-16).
- *
- * @param[in] rs Range and sign byte.
- */
-static void decode_rs_16(uint8_t rs, struct dev_context *devc)
-{
-       sr_spew("decode_rs_16(%d) scale = %f", rs, devc->scale);
-
-       if (rs & 0x04) /* Sign */
-               devc->scale *= -1.0;
-
-       if (devc->mq == SR_MQ_CURRENT) {
-               if (rs & 0x08) /* Current is AC */
-                       devc->mqflags |= SR_MQFLAG_AC;
-               else
-                       devc->mqflags |= SR_MQFLAG_DC;
-       }
-
-       switch (rs & 0x03) {
-       case 0:
-               if (devc->mq == SR_MQ_VOLTAGE) /* V */
-                       devc->scale *= 0.1;
-               else if (devc->mq == SR_MQ_CURRENT) /* 000.0 ÂµA */
-                       devc->scale *= 0.00001;
-               else if (devc->mq == SR_MQ_RESISTANCE) {
-                       if (devc->buflen >= 10) {
-                               /* Â°C with 10 byte msg type, otherwise GOhm. */
-                               devc->mq = SR_MQ_TEMPERATURE;
-                               devc->unit = SR_UNIT_CELSIUS;
-                               devc->scale *= 0.01;
-                       } else if (devc->scale1000 == 2) {
-                               /* 16I Iso 500/1000V 3 GOhm */
-                               devc->scale *= 0.1;
-                       }
-               }
-               break;
-       case 1:
-               devc->scale *= 0.0001;
-               break;
-       case 2:
-               devc->scale *= 0.001;
-               break;
-       case 3:
-               devc->scale *= 0.01;
-               break;
-       }
-}
-
-/**
- * Decode special chars, Metrahit 12-16.
- *
- * @param[in] spc Special characters 1 and 2 (s1 | (s2 << 4)).
- */
-static void decode_spc_16(uint8_t spc, struct dev_context *devc)
-{
-       /* xxxx1xxx ON */
-       /* TODO: What does that mean? Power on? The 16I sets this. */
-       /* xxxxx1xx BEEP */
-       /* xxxxxx1x Low battery */
-       /* xxxxxxx1 FUSE */
-       /* 1xxxxxxx MIN */
-       setmqf(devc, SR_MQFLAG_MIN, spc & 0x80);
-
-       /* x1xxxxxx MAN */
-       setmqf(devc, SR_MQFLAG_AUTORANGE, !(spc & 0x40));
-
-       /* xx1xxxxx DATA */
-       setmqf(devc, SR_MQFLAG_HOLD, spc & 0x20);
-
-       /* xxx1xxxx MAX */
-       setmqf(devc, SR_MQFLAG_MAX, spc & 0x10);
-}
-
-/** Decode current type and measured value, Metrahit 18. */
-static void decode_ctmv_18(uint8_t ctmv, struct dev_context *devc)
-{
-       devc->mq = 0;
-       devc->unit = 0;
-       devc->mqflags = 0;
-
-       switch (ctmv) {
-       case 0x00: /* 0000 - */
-               break;
-       case 0x01: /* 0001 V AC */
-       case 0x02: /* 0010 V AC+DC */
-       case 0x03: /* 0011 V DC */
-               devc->mq = SR_MQ_VOLTAGE;
-               devc->unit = SR_UNIT_VOLT;
-               if (ctmv <= 0x02)
-                       devc->mqflags |= (SR_MQFLAG_AC | SR_MQFLAG_RMS);
-               if (ctmv >= 0x02)
-                       devc->mqflags |= SR_MQFLAG_DC;
-               break;
-       case 0x04: /* 0100 Ohm/Ohm with buzzer */
-               devc->mq = SR_MQ_RESISTANCE;
-               devc->unit = SR_UNIT_OHM;
-               break;
-       case 0x05: /* 0101 Diode/Diode with buzzer */
-               devc->mq = SR_MQ_VOLTAGE;
-               devc->unit = SR_UNIT_VOLT;
-               devc->mqflags |= SR_MQFLAG_DIODE;
-               break;
-       case 0x06: /* 0110 Â°C */
-               devc->mq = SR_MQ_TEMPERATURE;
-               devc->unit = SR_UNIT_CELSIUS;
-               break;
-       case 0x07: /* 0111 F */
-               devc->mq = SR_MQ_CAPACITANCE;
-               devc->unit = SR_UNIT_FARAD;
-               break;
-       case 0x08: /* 1000 mA DC */
-       case 0x09: /* 1001 A DC */
-       case 0x0a: /* 1010 mA AC+DC */
-       case 0x0b: /* 1011 A AC+DC */
-               devc->mq = SR_MQ_CURRENT;
-               devc->unit = SR_UNIT_AMPERE;
-               devc->mqflags |= SR_MQFLAG_DC;
-               if (ctmv >= 0x0a)
-                       devc->mqflags |= (SR_MQFLAG_AC | SR_MQFLAG_RMS);
-               if ((ctmv == 0x08) || (ctmv == 0x0a))
-                       devc->scale1000 = -1;
-               break;
-       case 0x0c: /* 1100 Hz */
-               devc->mq = SR_MQ_FREQUENCY;
-               devc->unit = SR_UNIT_HERTZ;
-               break;
-       case 0x0d: /* 1101 dB */
-               devc->mq = SR_MQ_VOLTAGE;
-               devc->unit = SR_UNIT_DECIBEL_VOLT;
-               devc->mqflags |= SR_MQFLAG_AC; /* dB available for AC only */
-               break;
-       case 0x0e: /* 1110 Events AC, Events AC+DC. Actually delivers just
-               * current voltage via IR, nothing more. */
-               devc->mq = SR_MQ_VOLTAGE;
-               devc->unit = SR_UNIT_VOLT;
-               devc->mqflags |= SR_MQFLAG_AC | SR_MQFLAG_DC | SR_MQFLAG_RMS;
-               break;
-       case 0x0f: /* 1111 Clock */
-               devc->mq = SR_MQ_TIME;
-               devc->unit = SR_UNIT_SECOND;
-               devc->mqflags |= SR_MQFLAG_DURATION;
-               break;
-       }
-}
-
-/**
- * Decode range/sign/acdc byte special chars, Metrahit 18.
- *
- * @param[in] rs Rance/sign byte.
- */
-static void decode_rs_18(uint8_t rs, struct dev_context *devc)
-{
-       int range;
-
-       /* Sign */
-       if (((devc->scale > 0) && (rs & 0x08)) ||
-                       ((devc->scale < 0) && !(rs & 0x08)))
-               devc->scale *= -1.0;
-
-       /* Range */
-       range = rs & 0x07;
-       switch (devc->mq) {
-       case SR_MQ_VOLTAGE:
-               if (devc->unit == SR_UNIT_DECIBEL_VOLT) {
-                       devc->scale *= pow(10.0, -2);
-                       /*
-                        * When entering relative mode, the device switches
-                        * from 10 byte to 6 byte msg format. Unfortunately
-                        * it switches back to 10 byte when the second value
-                        * is measured, so that's not sufficient to
-                        * identify relative mode.
-                        */
-               }
-               else if (devc->vmains_29S)
-                       devc->scale *= pow(10.0, range - 2);
-               else
-                       devc->scale *= pow(10.0, range - 5);
-               break;
-       case SR_MQ_CURRENT:
-               if (devc->scale1000 == -1)
-                       devc->scale *= pow(10.0, range - 5);
-               else
-                       devc->scale *= pow(10.0, range - 4);
-               break;
-       case SR_MQ_RESISTANCE:
-               devc->scale *= pow(10.0, range - 2);
-               break;
-       case SR_MQ_FREQUENCY:
-               devc->scale *= pow(10.0, range - 2);
-               break;
-       case SR_MQ_TEMPERATURE:
-               devc->scale *= pow(10.0, range - 2);
-               break;
-       case SR_MQ_CAPACITANCE:
-               devc->scale *= pow(10.0, range - 13);
-               break;
-               /* TODO: 29S Mains measurements. */
-       }
-}
-
-/**
- * Decode special chars, Metrahit 18.
- *
- * @param[in] spc Special characters 1 and 2 (s1 | (s2 << 4)).
- */
-static void decode_spc_18(uint8_t spc, struct dev_context *devc)
-{
-       /* xxxx1xxx ZERO */
-       /* xxxxx1xx BEEP */
-       /* xxxxxx1x Low battery */
-       /* xxxxxxx1 Fuse */
-
-       if (devc->mq == SR_MQ_TIME) {
-               /* xxx1xxxx Clock running: 1; stop: 0 */
-               sr_spew("Clock running: %d", spc >> 4);
-       } else {
-               /* 1xxxxxxx MAN */
-               setmqf(devc, SR_MQFLAG_AUTORANGE, !(spc & 0x80));
-
-               /* x1xxxxxx MIN */
-               setmqf(devc, SR_MQFLAG_MIN, spc & 0x40);
-
-               /* xx1xxxxx MAX */
-               setmqf(devc, SR_MQFLAG_MAX, spc & 0x20);
-
-               /* xxx1xxxx DATA */
-               setmqf(devc, SR_MQFLAG_HOLD, spc & 0x10);
-       }
-}
-
-/**
- * Decode current type and measured value, Metrahit 2x.
- *
- * @param[in] ctmv Current type and measured value (v1 | (v2 << 4)).
- */
-static void decode_ctmv_2x(uint8_t ctmv, struct dev_context *devc)
-{
-       if ((ctmv > 0x1c) || (!devc)) {
-               sr_err("decode_ctmv_2x(%d): invalid param(s)!", ctmv);
-               return;
-       }
-
-       devc->mq = 0;
-       devc->unit = 0;
-       devc->mqflags = 0;
-
-       switch (ctmv) {
-       /* 00000 unused */
-       case 0x01: /* 00001 V DC */
-       case 0x02: /* 00010 V AC+DC */
-       case 0x03: /* 00011 V AC */
-               devc->mq = SR_MQ_VOLTAGE;
-               devc->unit = SR_UNIT_VOLT;
-               if (ctmv <= 0x02)
-                       devc->mqflags |= SR_MQFLAG_DC;
-               if (ctmv >= 0x02) {
-                       devc->mqflags |= SR_MQFLAG_AC;
-                       if (devc->model >= METRAHIT_24S)
-                               devc->mqflags |= SR_MQFLAG_RMS;
-               }
-               break;
-       case 0x04: /* 00100 mA DC */
-       case 0x05: /* 00101 mA AC+DC */
-               devc->scale1000 = -1;
-       case 0x06: /* 00110 A DC */
-       case 0x07: /* 00111 A AC+DC */
-               devc->mq = SR_MQ_CURRENT;
-               devc->unit = SR_UNIT_AMPERE;
-               devc->mqflags |= SR_MQFLAG_DC;
-               if ((ctmv == 0x05) || (ctmv == 0x07)) {
-                       devc->mqflags |= SR_MQFLAG_AC;
-                       if (devc->model >= METRAHIT_24S)
-                               devc->mqflags |= SR_MQFLAG_RMS;
-               }
-               break;
-       case 0x08: /* 01000 Ohm */
-               devc->mq = SR_MQ_RESISTANCE;
-               devc->unit = SR_UNIT_OHM;
-               break;
-       case 0x09: /* 01001 F */
-               devc->mq = SR_MQ_CAPACITANCE;
-               devc->unit = SR_UNIT_FARAD;
-               devc->scale *= 0.1;
-               break;
-       case 0x0a: /* 01010 V dB */
-               devc->mq = SR_MQ_VOLTAGE;
-               devc->unit = SR_UNIT_DECIBEL_VOLT;
-               devc->mqflags |= SR_MQFLAG_AC;
-               if (devc->model >= METRAHIT_24S)
-                       devc->mqflags |= SR_MQFLAG_RMS;
-               break;
-       case 0x0b: /* 01011 Hz U ACDC */
-       case 0x0c: /* 01100 Hz U AC */
-               devc->mq = SR_MQ_FREQUENCY;
-               devc->unit = SR_UNIT_HERTZ;
-               devc->mqflags |= SR_MQFLAG_AC;
-               if (ctmv <= 0x0b)
-                       devc->mqflags |= SR_MQFLAG_DC;
-               break;
-       case 0x0d: /* 01101 W on power, mA range (29S only) */
-               devc->scale *= 0.001;
-               /* Fall through! */
-       case 0x0e: /* 01110 W on power, A range (29S only) */
-               devc->mq = SR_MQ_POWER;
-               devc->unit = SR_UNIT_WATT;
-               break;
-       case 0x0f: /* 01111 Diode */
-       case 0x10: /* 10000 Diode with buzzer (actually cont. with voltage) */
-               devc->unit = SR_UNIT_VOLT;
-               if (ctmv == 0x0f) {
-                       devc->mq = SR_MQ_VOLTAGE;
-                       devc->mqflags |= SR_MQFLAG_DIODE;
-               } else {
-                       devc->mq = SR_MQ_CONTINUITY;
-                       devc->scale *= 0.00001;
-               }
-               devc->unit = SR_UNIT_VOLT;
-               break;
-       case 0x11: /* 10001 Ohm with buzzer */
-               devc->mq = SR_MQ_CONTINUITY;
-               devc->unit = SR_UNIT_OHM;
-               devc->scale1000 = -1;
-               break;
-       case 0x12: /* 10010 Temperature */
-               devc->mq = SR_MQ_TEMPERATURE;
-               devc->unit = SR_UNIT_CELSIUS;
-               /* This can be Fahrenheit. That is detected by range=4 later. */
-               break;
-       /* 0x13 10011, 0x14 10100 unsed */
-       case 0x15: /* 10101 Press (29S only) */
-               /* TODO: What does that mean? Possibly phase shift?
-                  Then we need a unit/flag for it. */
-               devc->mq = SR_MQ_GAIN;
-               devc->unit = SR_UNIT_PERCENTAGE;
-               break;
-       case 0x16: /* 10110 Pulse W (29S only) */
-               /* TODO: Own unit and flag for this! */
-               devc->mq = SR_MQ_POWER;
-               devc->unit = SR_UNIT_WATT;
-               break;
-       case 0x17: /* 10111 TRMS V on mains (29S only) */
-               devc->mq = SR_MQ_VOLTAGE;
-               devc->unit = SR_UNIT_VOLT;
-               devc->mqflags |= (SR_MQFLAG_AC | SR_MQFLAG_RMS);
-               devc->vmains_29S = TRUE;
-               break;
-       case 0x18: /* 11000 Counter (zero crossings of a signal) */
-               devc->mq = SR_MQ_VOLTAGE;
-               devc->unit = SR_UNIT_UNITLESS;
-               break;
-       case 0x19: /* 11001 Events U ACDC */
-       case 0x1a: /* 11010 Events U AC */
-               /* TODO: No unit or flags for this yet! */
-               devc->mq = SR_MQ_VOLTAGE;
-               devc->unit = SR_UNIT_UNITLESS;
-               devc->mqflags |= SR_MQFLAG_AC;
-               if (ctmv <= 0x19)
-                       devc->mqflags |= SR_MQFLAG_DC;
-               break;
-       case 0x1b: /* 11011 pulse on mains (29S only) */
-               /* TODO: No unit or flags for this yet! */
-               devc->mq = SR_MQ_VOLTAGE;
-               devc->unit = SR_UNIT_UNITLESS;
-               devc->mqflags |= SR_MQFLAG_AC;
-               break;
-       case 0x1c: /* 11100 dropout on mains (29S only) */
-               /* TODO: No unit or flags for this yet! */
-               devc->mq = SR_MQ_VOLTAGE;
-               devc->unit = SR_UNIT_UNITLESS;
-               devc->mqflags |= SR_MQFLAG_AC;
-               break;
-       case 0x1f: /* 11111 Undocumented: 25S in stopwatch mode.
-                       The value is voltage, not time, so treat it such. */
-               devc->mq = SR_MQ_VOLTAGE;
-               devc->unit = SR_UNIT_VOLT;
-               devc->mqflags |= SR_MQFLAG_DC;
-               break;
-       case 0x20: /* 100000 Undocumented: 25S in event count mode.
-               Value is 0 anyway. */
-               devc->mq = SR_MQ_VOLTAGE;
-               devc->unit = SR_UNIT_UNITLESS;
-               break;
-       default:
-               sr_err("decode_ctmv_2x(%d, ...): Unknown ctmv!", ctmv);
-               break;
-       }
-}
-
-/**
- * Decode range/sign/acdc byte special chars, Metrahit 2x, table TR.
- *
- * @param[in] rs Range/sign byte.
- */
-static void decode_rs_2x(uint8_t rs, struct dev_context *devc)
-{
-       int range;
-
-       /* Sign */
-       if (((devc->scale > 0) && (rs & 0x08)) ||
-                       ((devc->scale < 0) && !(rs & 0x08)))
-               devc->scale *= -1.0;
-
-       /* Range */
-       range = rs & 0x07;
-       switch (devc->mq) {
-       case SR_MQ_VOLTAGE:
-               if (devc->unit == SR_UNIT_DECIBEL_VOLT)
-                       devc->scale *= pow(10.0, -3);
-               else if (devc->vmains_29S)
-                       devc->scale *= pow(10.0, range - 2);
-               else
-                       devc->scale *= pow(10.0, range - 6);
-               break;
-       case SR_MQ_CURRENT:
-               if (devc->scale1000 != -1) /* uA, mA */
-                       range += 1;/* mA and A ranges differ by 10^4, not 10^3!*/
-               devc->scale *= pow(10.0, range - 6);
-               break;
-       case SR_MQ_RESISTANCE:
-               devc->scale *= pow(10.0, range - 3);
-               break;
-       case SR_MQ_FREQUENCY:
-               devc->scale *= pow(10.0, range - 3);
-               break;
-       case SR_MQ_TEMPERATURE:
-               if (range == 4) /* Indicator for Â°F */
-                       devc->unit = SR_UNIT_FAHRENHEIT;
-               devc->scale *= pow(10.0, - 2);
-               break;
-       case SR_MQ_CAPACITANCE:
-               if (range == 7)
-                       range -= 1; /* Same value as range 6 */
-               devc->scale *= pow(10.0, range - 13);
-               break;
-       /* TODO: 29S Mains measurements. */
-       }
-}
-
-/**
- * Decode range/sign/acdc byte special chars, Metrahit 2x, table TR 2.
- *
- * @param[in] rs Range/sign byte.
- */
-static void decode_rs_2x_TR2(uint8_t rs, struct dev_context *devc)
-{
-       int range;
-
-       /* Range */
-       range = rs & 0x07;
-       switch (devc->mq) {
-       case SR_MQ_CURRENT:
-               if (devc->scale1000 == -1) /* mA */
-                       switch(range) {
-                       case 0: case 1: /* 100, 300 ÂµA */
-                               devc->scale *= pow(10.0, -6);
-                               break;
-                       case 2: case 3: /* 1, 3 mA */
-                               devc->scale *= pow(10.0, -5);
-                               break;
-                       case 4: case 5: /* 10, 30 mA */
-                               devc->scale *= pow(10.0, -4);
-                               break;
-                       case 6: case 7: /* 100, 300 mA */
-                               devc->scale *= pow(10.0, -3);
-                               break;
-                       }
-               else /* A */
-                       switch(range) {
-                       case 0: case 1: /* 1, 3 A */
-                               devc->scale *= pow(10.0, -5);
-                               break;
-                       case 2: /* 10 A */
-                               devc->scale *= pow(10.0, -4);
-                               break;
-                       }
-               break;
-       default:
-               decode_rs_2x(rs, devc);
-               return;
-       }
-
-       /* Sign */
-       if (((devc->scale > 0) && (rs & 0x08)) ||
-                       ((devc->scale < 0) && !(rs & 0x08)))
-               devc->scale *= -1.0;
-}
-
-
-/**
- * Decode special chars (Metrahit 2x).
- *
- * @param[in] spc Special characters 1 and 2 (s1 | (s2 << 4)).
- */
-static void decode_spc_2x(uint8_t spc, struct dev_context *devc)
-{
-       /* xxxxxxx1 Fuse */
-
-       /* xxxxxx1x Low battery */
-
-       /* xxxxx1xx BEEP */
-
-       /* xxxx1xxx ZERO */
-
-       /* xxx1xxxx DATA */
-       setmqf(devc, SR_MQFLAG_HOLD, spc & 0x10);
-
-       /* x11xxxxx unused */
-       /* 1xxxxxxx MAN */
-       setmqf(devc, SR_MQFLAG_AUTORANGE, !(spc & 0x80));
-}
-
-/** Clean range and sign. */
-static void clean_rs_v(struct dev_context *devc)
-{
-       devc->value = 0.0;
-       devc->scale = 1.0;
-}
-
-/** Clean current type, measured variable, range and sign. */
-static void clean_ctmv_rs_v(struct dev_context *devc)
-{
-       devc->mq = 0;
-       devc->unit = 0;
-       devc->mqflags = 0;
-       devc->scale1000 = 0;
-       devc->vmains_29S = FALSE;
-       clean_rs_v(devc);
-}
-
-/** Send prepared value. */
-static void send_value(struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_datafeed_analog analog;
-       struct sr_datafeed_packet packet;
-
-       devc = sdi->priv;
-
-       memset(&analog, 0, sizeof(analog));
-       analog.channels = sdi->channels;
-       analog.num_samples = 1;
-       analog.mq = devc->mq;
-       analog.unit = devc->unit;
-       analog.mqflags = devc->mqflags;
-       analog.data = &devc->value;
-
-       memset(&packet, 0, sizeof(packet));
-       packet.type = SR_DF_ANALOG;
-       packet.payload = &analog;
-       sr_session_send(devc->cb_data, &packet);
-
-       devc->num_samples++;
-}
-
-/** Process 6-byte data message, Metrahit 1x/2x send mode. */
-static void process_msg_dta_6(struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       int cnt;
-       uint8_t dgt;
-
-       devc = sdi->priv;
-       clean_rs_v(devc);
-
-       /* Byte 0, range and sign */
-       if (devc->model <= METRAHIT_16X)
-               decode_rs_16(bc(devc->buf[0]), devc);
-       else if (devc->model < METRAHIT_2X)
-               decode_rs_18(bc(devc->buf[0]), devc);
-       else {
-               decode_rs_2x(bc(devc->buf[0]), devc);
-               devc->scale *= 10; /* Compensate for format having only 5 digits, decode_rs_2x() assumes 6. */
-       }
-
-       /* Bytes 1-5, digits (ls first). */
-       for (cnt = 0; cnt < 5; cnt++) {
-               dgt = bc(devc->buf[1 + cnt]);
-               if (dgt >= 10) {
-                       /* 10 Overload; on model <= 16X also 11 possible. */
-                       devc->value = NAN;
-                       devc->scale = 1.0;
-                       break;
-               }
-               devc->value += pow(10.0, cnt) * dgt;
-       }
-
-       sr_spew("process_msg_dta_6() value=%f scale=%f scale1000=%d",
-               devc->value, devc->scale, devc->scale1000);
-       if (devc->value != NAN)
-               devc->value *= devc->scale * pow(1000.0, devc->scale1000);
-
-       /* Create and send packet. */
-       send_value(sdi);
-}
-
-/** Process 5-byte info message, Metrahit 1x/2x. */
-static void process_msg_inf_5(struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       enum model model;
-
-       devc = sdi->priv;
-
-       clean_ctmv_rs_v(devc);
-
-       /* Process byte 0 */
-       model = gmc_decode_model_sm(bc(devc->buf[0]));
-       if (model != devc->model) {
-               sr_warn("Model mismatch in data: Detected %s, now %s",
-                       gmc_model_str(devc->model), gmc_model_str(model));
-       }
-
-       /* Process bytes 1-4 */
-       if (devc->model <= METRAHIT_16X) {
-               decode_ctmv_16(bc(devc->buf[1]), devc);
-               decode_spc_16(bc(devc->buf[2]) | (bc(devc->buf[3]) << 4), devc);
-               decode_rs_16(bc(devc->buf[4]), devc);
-       } else if (devc->model <= METRAHIT_18S) {
-               decode_ctmv_18(bc(devc->buf[1]), devc);
-               decode_spc_18(bc(devc->buf[2]) | (bc(devc->buf[3]) << 4), devc);
-               decode_rs_18(bc(devc->buf[4]), devc);
-       } else { /* Must be Metrahit 2x */
-               decode_ctmv_2x(bc(devc->buf[1]), devc);
-               decode_spc_2x(bc(devc->buf[2]) | (bc(devc->buf[3]) << 4), devc);
-               decode_rs_2x(bc(devc->buf[4]), devc);
-       }
-}
-
-/** Process 10-byte info/data message, Metrahit 15+. */
-static void process_msg_inf_10(struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       int cnt;
-       uint8_t dgt;
-
-       devc = sdi->priv;
-
-       process_msg_inf_5(sdi);
-
-       /* Now decode numbers */
-       for (cnt = 0; cnt < 5; cnt++) {
-               dgt = bc(devc->buf[5 + cnt]);
-               if (dgt == 11) { /* Empty digit */
-                       dgt = 0;
-               }
-               else if (dgt >= 12) { /* Overload */
-                       devc->value = NAN;
-                       devc->scale = 1.0;
-                       break;
-               }
-               devc->value += pow(10.0, cnt) * dgt;
-       }
-       sr_spew("process_msg_inf_10() value=%f scale=%f scalet=%d",
-               devc->value, devc->scale,  devc->scale1000);
-
-       if (devc->value != NAN)
-               devc->value *= devc->scale * pow(1000.0, devc->scale1000);
-
-       /* Create and send packet. */
-       send_value(sdi);
-}
-
-/** Decode send interval (Metrahit 2x only). */
-static const char *decode_send_interval(uint8_t si)
-{
-       switch (si) {
-       case 0x00:
-               return "0.05";
-       case 0x01:
-               return "0.1";
-       case 0x02:
-               return "0.2";
-       case 0x03:
-               return "0.5";
-       case 0x04:
-               return "00:01";
-       case 0x05:
-               return "00:02";
-       case 0x06:
-               return "00:05";
-       case 0x07:
-               return "00:10";
-       case 0x08:
-               return "00:20";
-       case 0x09:
-               return "00:30";
-       case 0x0a:
-               return "01:00";
-       case 0x0b:
-               return "02:00";
-       case 0x0c:
-               return "05:00";
-       case 0x0d:
-               return "10:00";
-       case 0x0e:
-               return "----";
-       case 0x0f:
-               return "data";
-       default:
-               return "Unknown value";
-       }
-}
-
-/** Process 13-byte info/data message, Metrahit 2x. */
-static void process_msg_inf_13(struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       enum model model;
-       int cnt;
-       uint8_t dgt;
-
-       devc = sdi->priv;
-
-       clean_ctmv_rs_v(devc);
-
-       /* Byte 0, model. */
-       model = gmc_decode_model_sm(bc(devc->buf[0]));
-       if (model != devc->model) {
-               sr_warn("Model mismatch in data: Detected %s, now %s",
-                       gmc_model_str(devc->model), gmc_model_str(model));
-       }
-
-       /* Bytes 1-4, 11. */
-       decode_ctmv_2x(bc(devc->buf[1]) | (bc(devc->buf[11]) << 4), devc);
-       decode_spc_2x(bc(devc->buf[2]) | (bc(devc->buf[3]) << 4), devc);
-       decode_rs_2x(bc(devc->buf[4]), devc);
-
-       /* Bytes 5-10, digits (ls first). */
-       for (cnt = 0; cnt < 6; cnt++) {
-               dgt = bc(devc->buf[5 + cnt]);
-               if (dgt == 10) { /* Overload */
-                       devc->value = NAN;
-                       devc->scale = 1.0;
-                       break;
-               }
-               devc->value += pow(10.0, cnt) * dgt;
-       }
-       sr_spew("process_msg_inf_13() value=%f scale=%f scale1000=%d mq=%d "
-               "unit=%d mqflags=0x%02llx", devc->value, devc->scale,
-               devc->scale1000, devc->mq, devc->unit, devc->mqflags);
-       if (devc->value != NAN)
-               devc->value *= devc->scale * pow(1000.0, devc->scale1000);
-
-       /* Byte 12, Send Interval */
-       sr_spew("Send interval: %s", decode_send_interval(bc(devc->buf[12])));
-
-       /* Create and send packet. */
-       send_value(sdi);
-}
-
-/** Dump contents of 14-byte message.
- *  @param buf Pointer to array of 14 data bytes.
- *  @param[in] raw Write only data bytes, no interpretation.
- */
-void dump_msg14(guchar* buf, gboolean raw)
-{
-       if (!buf)
-               return;
-
-       if (raw)
-               sr_spew("msg14: 0x %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]);
-       else
-               sr_spew("msg14: 0x a=%d c1=%02x c2=%02x cmd=%02x dta=%02x "
-                       "%02x %02x %02x %02x %02x %02x %02x %02x chs=%02x",
-                       buf[1] == 0x2b?buf[0] >> 2:buf[0] % 0x0f, 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]);
-}
-
-/** Calc checksum for 14 byte message type.
- *
- *  @param[in] dta Pointer to array of 13 data bytes.
- *  @return Checksum.
- */
-static guchar calc_chksum_14(guchar* dta)
-{
-       guchar cnt, chs;
-
-       for (chs = 0, cnt = 0; cnt < 13; cnt++)
-               chs += dta[cnt];
-
-       return (64 - chs) & MASK_6BITS;
-}
-
-/** Check 14-byte message, Metrahit 2x. */
-static int chk_msg14(struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       int retc;
-       gboolean isreq; /* Message is request to multimeter (otherwise response) */
-       uint8_t addr;  /* Adaptor address */
-
-       retc = SR_OK;
-
-       /* Check parameters and message */
-       if (!sdi || !(devc = sdi->priv))
-               return SR_ERR_ARG;
-
-       if (devc->buflen != 14) {
-               sr_err("process_msg_14(): Msg len 14 expected!");
-               return SR_ERR_ARG;
-       }
-
-       isreq = devc->buf[1] == 0x2b;
-       if (isreq)
-               addr = devc->buf[0] >> 2;
-       else
-               addr = devc->buf[0] & 0x0f;
-
-       if ((devc->addr != addr) && !(isreq && (addr == 0))) {
-               sr_err("process_msg_14(): Address mismatch, msg for other device!");
-               retc = SR_ERR_ARG;
-       }
-
-       if (devc->buf[1] == 0) { /* Error msg from device! */
-               retc = SR_ERR_ARG;
-               switch (devc->buf[2]) {
-               case 1: /* Not used */
-                       sr_err("Device: Illegal error code!");
-                       break;
-               case 2: /* Incorrect check sum of received block */
-                       sr_err("Device: Incorrect checksum in cmd!");
-                       break;
-               case 3: /* Incorrect length of received block */
-                       sr_err("Device: Incorrect block length in cmd!");
-                       break;
-               case 4: /* Incorrect 2nd or 3rd byte */
-                       sr_err("Device: Incorrect byte 2 or 3 in cmd!");
-                       break;
-               case 5: /* Parameter out of range */
-                       sr_err("Device: Parameter out of range!");
-                       break;
-               default:
-                       sr_err("Device: Unknown error code!");
-               }
-               retc = SR_ERR_ARG;
-       }
-       else if (!isreq && ((devc->buf[1] != 0x27) || (devc->buf[2] != 0x3f))) {
-               sr_err("process_msg_14(): byte 1/2 unexpected!");
-               retc = SR_ERR_ARG;
-       }
-
-       if (calc_chksum_14(devc->buf) != devc->buf[13]) {
-               sr_err("process_msg_14(): Invalid checksum!");
-               retc = SR_ERR_ARG;
-       }
-
-       if (retc != SR_OK)
-               dump_msg14(devc->buf, TRUE);
-
-       return retc;
-}
-
-/** Check 14-byte message, Metrahit 2x. */
-SR_PRIV int process_msg14(struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       int retc;
-       uint8_t addr;
-       uint8_t cnt, dgt;
-
-       if ((retc = chk_msg14(sdi)) != SR_OK)
-               return retc;
-
-       devc = sdi->priv;
-
-       clean_ctmv_rs_v(devc);
-       addr = devc->buf[0] & MASK_6BITS;
-       if (addr != devc->addr)
-               sr_info("Device address mismatch %d/%d!", addr, devc->addr);
-
-       switch (devc->buf[3]) { /* That's the command this reply is for */
-       /* 0 cannot occur, the respective message is not a 14-byte message */
-       case 1: /* Read first free and occupied address */
-               sr_spew("Cmd %d unimplemented!", devc->buf[3]);
-               break;
-       case 2: /* Clear all RAM in multimeter */
-               sr_spew("Cmd %d unimplemented!", devc->buf[3]);
-               break;
-       case 3: /* Read firmware version and status */
-               sr_spew("Cmd 3, Read firmware and status", devc->buf[3]);
-               switch (devc->cmd_idx) {
-               case 0:
-                       devc->fw_ver_maj = devc->buf[5];
-                       devc->fw_ver_min = devc->buf[4];
-                       sr_spew("Firmware version %d.%d", (int)devc->fw_ver_maj, (int)devc->fw_ver_min);
-                       sr_spew("Rotary Switch Position (1..10): %d", (int)devc->buf[6]);
-                       /** Docs say values 0..9, but that's not true */
-                       sr_spew("Measurement Function: %d ", (int)devc->buf[7]);
-                       decode_ctmv_2x(devc->buf[7], devc);
-                       sr_spew("Range: 0x%x", devc->buf[8]);
-                       decode_rs_2x_TR2(devc->buf[8] & 0x0f, devc);  /* Docs wrong, uses conversion table TR_2! */
-                       devc->autorng = (devc->buf[8] & 0x20) == 0;
-                       // TODO 9, 10: 29S special functions
-                       devc->ubatt = 0.1 * (float)devc->buf[11];
-                       devc->model = gmc_decode_model_bd(devc->buf[12]);
-                       sr_spew("Model=%s, battery voltage=%2.1f V", gmc_model_str(devc->model), (double)devc->ubatt);
-                       break;
-               case 1:
-                       sr_spew("Internal version %d.%d", (int)devc->buf[5], (int)devc->buf[4]);
-                       sr_spew("Comm mode: 0x%x", (int)devc->buf[6]);
-                       sr_spew("Block cnt%%64: %d", (int)devc->buf[7]);
-                       sr_spew("drpCi: %d  drpCh: %d", (int)devc->buf[8], (int)devc->buf[9]);
-                       // Semantics undocumented. Possibly Metrahit 29S dropouts stuff?
-                       break;
-               default:
-                       sr_spew("Cmd 3: Unknown cmd_idx=%d", devc->cmd_idx);
-                       break;
-               }
-               break;
-       case 4: /* Set real time, date, sample rate, trigger, ... */
-               sr_spew("Cmd %d unimplemented!", devc->buf[3]);
-               break;
-       case 5: /* Read real time, date, sample rate, trigger... */
-               sr_spew("Cmd %d unimplemented!", devc->buf[3]);
-               break;
-       case 6: /* Set modes or power off */
-               sr_spew("Cmd %d unimplemented!", devc->buf[3]);
-               break;
-       case 7: /* Set measurement function, range, autom/man. */
-               sr_spew("Cmd %d unimplemented!", devc->buf[3]);
-               break;
-       case 8: /* Get one measurement value */
-               sr_spew("Cmd 8, get one measurement value");
-               sr_spew("Measurement Function: %d ", (int)devc->buf[5]);
-               decode_ctmv_2x(devc->buf[5], devc);
-               if (!(devc->buf[6] & 0x10)) /* If bit4=0, old data. */
-                       return SR_OK;
-
-               decode_rs_2x_TR2(devc->buf[6] & 0x0f, devc); // The docs say conversion table TR_3, but that does not work
-               setmqf(devc, SR_MQFLAG_AUTORANGE, devc->autorng);
-               /* 6 digits */
-               for (cnt = 0; cnt < 6; cnt++) {
-                       dgt = bc(devc->buf[7 + cnt]);
-                       if (dgt == 10) { /* Overload */
-                               devc->value = NAN;
-                               devc->scale = 1.0;
-                               break;
-                       }
-                       else if (dgt == 13) { /* FUSE */
-                               sr_err("FUSE!");
-                       }
-                       else if (dgt == 14) { /* Function recognition mode, OPEN */
-                               sr_info("Function recognition mode, OPEN!");
-                               devc->value = NAN;
-                               devc->scale = 1.0;
-                               break;
-                       }
-                       devc->value += pow(10.0, cnt) * dgt;
-               }
-               sr_spew("process_msg14() value=%f scale=%f scale1000=%d mq=%d "
-                       "unit=%d mqflags=0x%02llx", devc->value, devc->scale,
-                       devc->scale1000, devc->mq, devc->unit, devc->mqflags);
-               if (devc->value != NAN)
-                       devc->value *= devc->scale * pow(1000.0, devc->scale1000);
-
-               send_value(sdi);
-
-               break;
-       default:
-               sr_spew("Unknown cmd %d!", devc->buf[3]);
-               break;
-       }
-
-       return SR_OK;
-}
-
-/** Data reception callback function. */
-SR_PRIV int gmc_mh_1x_2x_receive_data(int fd, int revents, void *cb_data)
-{
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-       uint8_t buf, msgt;
-       int len;
-       gdouble elapsed_s;
-
-       (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. */
-               while (GMC_BUFSIZE - devc->buflen - 1 > 0) {
-                       len = serial_read(serial, devc->buf + devc->buflen, 1);
-                       if (len < 1)
-                               break;
-                       buf = *(devc->buf + devc->buflen);
-                       sr_spew("read 0x%02x/%d/%d", buf, buf, buf & MSGC_MASK);
-                       devc->buflen += len;
-                       if (!devc->settings_ok) {
-                               /*
-                                * If no device type/settings record processed
-                                * yet, wait for one.
-                                */
-                               if ((devc->buf[0] & MSGID_MASK) != MSGID_INF) {
-                                       devc->buflen = 0;
-                                       continue;
-                               }
-                               devc->settings_ok = TRUE;
-                       }
-
-                       msgt = devc->buf[0] & MSGID_MASK;
-                       switch (msgt) {
-                       case MSGID_INF:
-                               if (devc->buflen == 13) {
-                                       process_msg_inf_13(sdi);
-                                       devc->buflen = 0;
-                                       continue;
-                               } else if ((devc->buflen == 10) &&
-                                          (devc->model <= METRAHIT_18S)) {
-                                       process_msg_inf_10(sdi);
-                                       devc->buflen = 0;
-                                       continue;
-                               }
-                               else if ((devc->buflen >= 5) &&
-                                        (devc->buf[devc->buflen - 1] &
-                                         MSGID_MASK) != MSGID_DATA) {
-                                       /*
-                                        * Char just received is beginning
-                                        * of next message.
-                                        */
-                                       process_msg_inf_5(sdi);
-                                       devc->buf[0] =
-                                                       devc->buf[devc->buflen - 1];
-                                       devc->buflen = 1;
-                                       continue;
-                               }
-                               break;
-                       case MSGID_DTA:
-                       case MSGID_D10:
-                               if (devc->buflen == 6) {
-                                       process_msg_dta_6(sdi);
-                                       devc->buflen = 0;
-                               }
-                               break;
-                       case MSGID_DATA:
-                               sr_err("Comm error, unexpected data byte!");
-                               devc->buflen = 0;
-                               break;
-                       }
-               }
-       }
-
-       /* If number of samples or time limit reached, stop acquisition. */
-       if (devc->limit_samples && (devc->num_samples >= devc->limit_samples))
-               sdi->driver->dev_acquisition_stop(sdi, cb_data);
-
-       if (devc->limit_msec) {
-               elapsed_s = g_timer_elapsed(devc->elapsed_msec, NULL);
-               if ((elapsed_s * 1000) >= devc->limit_msec)
-                       sdi->driver->dev_acquisition_stop(sdi, cb_data);
-       }
-
-       return TRUE;
-}
-
-SR_PRIV int gmc_mh_2x_receive_data(int fd, int revents, void *cb_data)
-{
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-       uint8_t buf;
-       int len;
-       gdouble elapsed_s;
-
-       (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. */
-               while (GMC_BUFSIZE - devc->buflen - 1 > 0) {
-                       len = serial_read(serial, devc->buf + devc->buflen, 1);
-                       if (len < 1)
-                               break;
-                       buf = *(devc->buf + devc->buflen);
-                       sr_spew("read 0x%02x/%d/%d", buf, buf, buf & MASK_6BITS);
-                       devc->buf[devc->buflen] &= MASK_6BITS;
-                       devc->buflen += len;
-
-                       if (devc->buflen == 14) {
-                               devc->response_pending = FALSE;
-                               sr_spew("gmc_mh_2x_receive_data processing msg");
-                               process_msg14(sdi);
-                               devc->buflen = 0;
-                       }
-               }
-       }
-
-       /* If number of samples or time limit reached, stop acquisition. */
-       if (devc->limit_samples && (devc->num_samples >= devc->limit_samples))
-               sdi->driver->dev_acquisition_stop(sdi, cb_data);
-
-       if (devc->limit_msec) {
-               elapsed_s = g_timer_elapsed(devc->elapsed_msec, NULL);
-               if ((elapsed_s * 1000) >= devc->limit_msec)
-                       sdi->driver->dev_acquisition_stop(sdi, cb_data);
-       }
-
-       /* Request next data set, if required */
-       if (sdi->status == SR_ST_ACTIVE) {
-               if (devc->response_pending) {
-                       gint64 elapsed_us = g_get_monotonic_time() - devc->req_sent_at;
-                       if (elapsed_us > 1*1000*1000) /* Timeout! */
-                               devc->response_pending = FALSE;
-               }
-               if (!devc->response_pending) {
-                       devc->cmd_seq++;
-                       if (devc->cmd_seq % 10 == 0) {
-                               if (req_stat14(sdi, FALSE) != SR_OK)
-                                       return FALSE;
-                       }
-                       else if (req_meas14(sdi) != SR_OK)
-                               return FALSE;
-               }
-       }
-
-       return TRUE;
-}
-
-/** Create 14 (42) byte command for Metrahit 2x multimeter in bidir mode.
- *
- *  Actually creates 42 bytes due to the encoding method used.
- *  @param[in] addr Device address (0=adapter, 1..15 multimeter; for byte 0).
- *  @param[in] func Function code (byte 3).
- *  @param[in] params Further parameters (9 bytes)
- *  @param[out] buf Buffer to create msg in (42 bytes).
- */
-void create_cmd_14(guchar addr, guchar func, guchar* params, guchar* buf)
-{
-       uint8_t dta[14];        /* Unencoded message */
-       int cnt;
-
-       if (!params || !buf)
-               return;
-
-       /* 0: Address */
-       dta[0] = ((addr << 2) | 0x03) & MASK_6BITS;
-
-       /* 1-3: Set command header */
-       dta[1] = 0x2b;
-       dta[2] = 0x3f;
-       dta[3] = func;
-
-       /* 4-12: Copy further parameters */
-       for (cnt = 0; cnt < 9; cnt++)
-               dta[cnt+4] = (params[cnt] & MASK_6BITS);
-
-       /* 13: Checksum (b complement) */
-       dta[13] = calc_chksum_14(dta);
-
-       /* The whole message is packed into 3 bytes per byte now (lower 6 bits only) the most
-        * peculiar way I have ever seen. Possibly to improve IR communication? */
-       for (cnt = 0; cnt < 14; cnt++) {
-               buf[3*cnt] = (dta[cnt] & 0x01 ? 0x0f : 0) | (dta[cnt] & 0x02 ? 0xf0 : 0);
-               buf[3*cnt + 1] = (dta[cnt] & 0x04 ? 0x0f : 0) | (dta[cnt] & 0x08 ? 0xf0 : 0);
-               buf[3*cnt + 2] = (dta[cnt] & 0x10 ? 0x0f : 0) | (dta[cnt] & 0x20 ? 0xf0 : 0);
-       }
-}
-
-/** Request one measurement from 2x multimeter (msg 8).
- *
- */
-int req_meas14(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-       uint8_t params[9];
-       uint8_t msg[42];
-
-       if (!sdi || !(devc = sdi->priv) || !(serial = sdi->conn))
-               return SR_ERR;
-
-       memset(params, 0, sizeof(params));
-       params[0] = 0;
-       devc->cmd_idx = 0;
-       create_cmd_14(devc->addr, 8, params, msg);
-       devc->req_sent_at = g_get_monotonic_time();
-       if (serial_write(serial, msg, sizeof(msg)) == -1) {
-               return SR_ERR;
-       }
-
-       devc->response_pending = TRUE;
-
-       return SR_OK;
-}
-
-/** Request status from 2x multimeter (msg 3).
- *  @param[in] power_on Try to power on powered off multimeter by sending additional messages.
- */
-int req_stat14(const struct sr_dev_inst *sdi, gboolean power_on)
-{
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-       uint8_t params[9];
-       uint8_t msg[42];
-
-       if (!sdi || !(devc = sdi->priv) || !(serial = sdi->conn))
-               return SR_ERR;
-
-       memset(params, 0, sizeof(params));
-       params[0] = 0;
-       devc->cmd_idx = 0;
-       create_cmd_14(devc->addr, 3, params, msg);
-
-       if (power_on) {
-               sr_info("Write some data and wait 3s to turn on powered off device...");
-               if (serial_write(serial, msg, sizeof(msg)) < 0)
-                       return SR_ERR;
-               g_usleep(1*1000*1000);
-               if (serial_write(serial, msg, sizeof(msg)) < 0)
-                       return SR_ERR;
-               g_usleep(1*1000*1000);
-               if (serial_write(serial, msg, sizeof(msg)) < 0)
-                       return SR_ERR;
-               g_usleep(1*1000*1000);
-               serial_flush(serial);
-       }
-
-       /* Write message and wait for reply */
-       devc->req_sent_at = g_get_monotonic_time();
-       if (serial_write(serial, msg, sizeof(msg)) == -1) {
-               return SR_ERR;
-       }
-
-       devc->response_pending = TRUE;
-
-       return SR_OK;
-}
-
-/** Decode model in "send mode".
- *
- * @param[in] mcode Model code.
- * @return Model code.
- */
-SR_PRIV int gmc_decode_model_sm(uint8_t mcode)
-{
-       if (mcode > 0xf) {
-               sr_err("decode_model(%d): Model code 0..15 expected!", mcode);
-               return METRAHIT_NONE;
-       }
-
-       switch(mcode) {
-       case 0x04: /* 0100b */
-               return METRAHIT_12S;
-       case 0x08: /* 1000b */
-               return METRAHIT_13S14A;
-       case 0x09: /* 1001b */
-               return METRAHIT_14S;
-       case 0x0A: /* 1010b */
-               return METRAHIT_15S;
-       case 0x0B: /* 1011b */
-               return METRAHIT_16S;
-       case 0x06: /* 0110b (undocumented by GMC!) */
-               return METRAHIT_16I;
-       case 0x07: /* 0111b (undocumented by GMC!) */
-               return METRAHIT_16T;
-       case 0x0D: /* 1101b */
-               return METRAHIT_18S;
-       case 0x02: /* 0010b */
-               return METRAHIT_22SM;
-       case 0x03: /* 0011b */
-               return METRAHIT_23S;
-       case 0x0F: /* 1111b */
-               return METRAHIT_24S;
-       case 0x05: /* 0101b */
-               return METRAHIT_25S;
-       case 0x01: /* 0001b */
-               return METRAHIT_26SM;
-       case 0x0C: /* 1100b */
-               return METRAHIT_28S;
-       case 0x0E: /* 1110b */
-               return METRAHIT_29S;
-       default:
-               sr_err("Unknown model code %d!", mcode);
-               return METRAHIT_NONE;
-       }
-}
-
-/** Convert GMC model code in bidirectional mode to sigrok-internal one.
- *
- *  @param[in] mcode Model code.
- *
- *  @return Model code.
- */
-SR_PRIV int gmc_decode_model_bd(uint8_t mcode)
-{
-       switch (mcode & 0x1f) {
-       case 2:
-               if (mcode & 0x20)
-                       return METRAHIT_22M;
-               else
-                       return METRAHIT_22S;
-       case 3:
-               return METRAHIT_23S;
-       case 4:
-               return METRAHIT_24S;
-       case 5:
-               return METRAHIT_25S;
-       case 1:
-               if (mcode & 0x20)
-                       return METRAHIT_26M;
-               else
-                       return METRAHIT_26S;
-       case 12:
-               return METRAHIT_28S;
-       case 14:
-               return METRAHIT_29S;
-       default:
-               sr_err("Unknown model code %d!", mcode);
-               return METRAHIT_NONE;
-       }
-}
-
-/** Convert sigrok-internal model code to string.
- *
- *  @param[in] mcode Model code.
- *
- *  @return Model code string.
- */
-SR_PRIV const char *gmc_model_str(enum model mcode)
-{
-       switch (mcode) {
-       case METRAHIT_NONE:
-               return "-uninitialized model variable-";
-       case METRAHIT_12S:
-               return "METRAHit 12S";
-       case METRAHIT_13S14A:
-               return "METRAHit 13S/14A";
-       case METRAHIT_14S:
-               return "METRAHit 14S";
-       case METRAHIT_15S:
-               return "METRAHit 15S";
-       case METRAHIT_16S:
-               return "METRAHit 16S";
-       case METRAHIT_16I:
-               return "METRAHit 16I/16L";
-       case METRAHIT_16T:
-               return "METRAHit 16T/16U/KMM2002";
-       case METRAHIT_18S:
-               return "METRAHit 18S";
-       case METRAHIT_22SM:
-               return "METRAHit 22S/M";
-       case METRAHIT_22S:
-               return "METRAHit 22S";
-       case METRAHIT_22M:
-               return "METRAHit 22M";
-       case METRAHIT_23S:
-               return "METRAHit 23S";
-       case METRAHIT_24S:
-               return "METRAHit 24S";
-       case METRAHIT_25S:
-               return "METRAHit 25S";
-       case METRAHIT_26SM:
-               return "METRAHit 26S/M";
-       case METRAHIT_26S:
-               return "METRAHit 26S";
-       case METRAHIT_26M:
-               return "METRAHit 26M";
-       case METRAHIT_28S:
-               return "METRAHit 28S";
-       case METRAHIT_29S:
-               return "METRAHit 29S";
-       default:
-               return "Unknown model code";
-       }
-}
-
-
-/** @copydoc sr_dev_driver.config_set
- */
-SR_PRIV int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
-                      const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       uint8_t params[9];
-       uint8_t msg[42];
-
-       (void)cg;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       if (!(devc = sdi->priv)) {
-               sr_err("sdi->priv was NULL.");
-               return SR_ERR_BUG;
-       }
-
-       switch (key) {
-       case SR_CONF_POWER_OFF:
-               if (devc->model < METRAHIT_2X)
-                       return SR_ERR_NA;
-               if (!g_variant_get_boolean(data))
-                       return SR_ERR;
-               sr_info("Powering device off.");
-
-               memset(params, 0, sizeof(params));
-               params[0] = 5;
-               params[1] = 5;
-               create_cmd_14(devc->addr, 6, params, msg);
-               if (serial_write(sdi->conn, msg, sizeof(msg)) == -1)
-                       return SR_ERR;
-               else
-                       g_usleep(2000000); /* Wait to ensure transfer before interface switched off. */
-               break;
-       case SR_CONF_LIMIT_MSEC:
-               if (g_variant_get_uint64(data) == 0) {
-                       sr_err("LIMIT_MSEC can't be 0.");
-                       return SR_ERR;
-               }
-               devc->limit_msec = g_variant_get_uint64(data);
-               sr_dbg("Setting time limit to %" PRIu64 "ms.",
-                       devc->limit_msec);
-               break;
-       case SR_CONF_LIMIT_SAMPLES:
-               devc->limit_samples = g_variant_get_uint64(data);
-               sr_dbg("Setting sample limit to %" PRIu64 ".",
-                       devc->limit_samples);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
diff --git a/hardware/gmc-mh-1x-2x/protocol.h b/hardware/gmc-mh-1x-2x/protocol.h
deleted file mode 100644 (file)
index aa19be3..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013, 2014 Matthias Heidbrink <m-sigrok@heidbrink.biz>
- *
- * 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
- *  Gossen Metrawatt Metrahit 1x/2x drivers
- *  @internal
- */
-
-#ifndef LIBSIGROK_HARDWARE_GMC_MH_1X_2X_PROTOCOL_H
-#define LIBSIGROK_HARDWARE_GMC_MH_1X_2X_PROTOCOL_H
-
-#include <stdint.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "gmc-mh-1x-2x"
-
-#define GMC_BUFSIZE  266
-
-/** Message ID bits 4, 5 */
-#define MSGID_MASK  0x30 /**< Mask to get message ID bits */
-#define MSGID_INF   0x00 /**< Start of message with device info */
-#define MSGID_D10   0x10 /**< Start of data message, non-displayed intermediate */
-#define MSGID_DTA   0x20 /**< Start of data message, displayed, averaged */
-#define MSGID_DATA  0x30 /**< Data byte in message */
-
-#define MSGC_MASK   0x0f  /**< Mask to get message byte contents in send mode */
-
-#define MSGSRC_MASK 0xc0 /**< Mask to get bits related to message source */
-
-#define bc(x) (x & MSGC_MASK) /**< Get contents from a byte */
-
-#define MASK_6BITS  0x3f /**< Mask lower six bits. */
-
-/**
- * Internal multimeter model codes. In opposite to the multimeter models from
- * protocol (see decode_model()), these codes allow working with ranges.
- */
-enum model {
-       METRAHIT_NONE           = 0,  /**< Value for uninitialized variable */
-       METRAHIT_12S            = 12,
-       METRAHIT_13S14A         = 13,
-       METRAHIT_14S            = 14,
-       METRAHIT_15S            = 15,
-       METRAHIT_16S            = 16,
-       METRAHIT_16I            = 17, /**< Metrahit 16I, L */
-       METRAHIT_16T            = 18, /**< Metrahit 16T, U, KMM2002 */
-       METRAHIT_16X = METRAHIT_16T,  /**< All Metrahit 16 */
-       /* A Metrahit 17 exists, but seems not to have an IR interface. */
-       METRAHIT_18S            = 19,
-       METRAHIT_2X             = 20, /**< For model type comparisons */
-       METRAHIT_22SM           = METRAHIT_2X + 1,      /**< Send mode */
-       METRAHIT_22S            = METRAHIT_22SM + 1,    /**< Bidi mode */
-       METRAHIT_22M            = METRAHIT_22S + 1,     /**< Bidi mode */
-       METRAHIT_23S            = METRAHIT_22M + 1,
-       METRAHIT_24S            = METRAHIT_23S + 1,
-       METRAHIT_25S            = METRAHIT_24S + 1,
-       METRAHIT_26SM           = METRAHIT_25S + 1,     /**< Send mode */
-       METRAHIT_26S            = METRAHIT_26SM + 1,    /**< Bidi mode */
-       METRAHIT_26M            = METRAHIT_26S + 1,     /**< Bidi mode */
-       METRAHIT_28S            = METRAHIT_26M + 1,
-       METRAHIT_29S            = METRAHIT_28S + 1,
-};
-
-/** Private, per-device-instance driver context. */
-struct dev_context {
-       /* Model-specific information */
-       enum model model;       /**< Model code. */
-
-       /* Acquisition settings */
-       uint64_t limit_samples; /**< Target number of samples */
-       uint64_t limit_msec;    /**< Target sampling time */
-
-       /* Opaque pointer passed in by frontend. */
-       void *cb_data;
-
-       /* Operational state */
-       gboolean settings_ok;   /**< Settings msg received yet. */
-       int msg_type;       /**< Message type (MSGID_INF, ...). */
-       int msg_len;        /**< Message lengh (valid when msg, curr. type known).*/
-       int mq;             /**< Measured quantity */
-       int unit;           /**< Measured unit */
-       uint64_t mqflags;       /**< Measured quantity flags */
-       float value;            /**< Measured value */
-       float scale;            /**< Scale for value. */
-       int8_t scale1000;   /**< Additional scale factor 1000x. */
-       gboolean vmains_29S;    /**< Measured ctmv is V mains (29S only). */
-       int addr;           /**< Device address (1..15). */
-       int cmd_idx;        /**< Parameter "Idx" (Index) of current command, if required. */
-       int cmd_seq;        /**< Command sequence. Used to query status every n messages. */
-       gboolean autorng;   /**< Auto range enabled. */
-       float ubatt;        /**< Battery voltage. */
-       uint8_t fw_ver_maj; /**< Firmware version major. */
-       uint8_t fw_ver_min; /**< Firmware version minor. */
-       int64_t req_sent_at;    /**< Request sent. */
-       gboolean response_pending; /**< Request sent, response is pending. */
-
-       /* Temporary state across callbacks */
-       uint64_t num_samples;   /**< Current #samples for limit_samples */
-       GTimer *elapsed_msec;   /**< Used for sampling with limit_msec  */
-       uint8_t buf[GMC_BUFSIZE];       /**< Buffer for read callback */
-       int buflen;                     /**< Data len in buf */
-};
-
-/* Forward declarations */
-SR_PRIV int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg);
-SR_PRIV void create_cmd_14(guchar addr, guchar func, guchar* params, guchar* buf);
-SR_PRIV void dump_msg14(guchar* buf, gboolean raw);
-SR_PRIV int gmc_decode_model_bd(uint8_t mcode);
-SR_PRIV int gmc_decode_model_sm(uint8_t mcode);
-SR_PRIV int gmc_mh_1x_2x_receive_data(int fd, int revents, void *cb_data);
-SR_PRIV int gmc_mh_2x_receive_data(int fd, int revents, void *cb_data);
-SR_PRIV const char *gmc_model_str(enum model mcode);
-SR_PRIV int process_msg14(struct sr_dev_inst *sdi);
-SR_PRIV int req_meas14(const struct sr_dev_inst *sdi);
-SR_PRIV int req_stat14(const struct sr_dev_inst *sdi, gboolean power_on);
-
-#endif
diff --git a/hardware/hameg-hmo/api.c b/hardware/hameg-hmo/api.c
deleted file mode 100644 (file)
index ff045f1..0000000
+++ /dev/null
@@ -1,806 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * 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 <stdlib.h>
-#include "protocol.h"
-
-#define SERIALCOMM "115200/8n1/flow=1"
-
-SR_PRIV struct sr_dev_driver hameg_hmo_driver_info;
-static struct sr_dev_driver *di = &hameg_hmo_driver_info;
-
-static const char *manufacturers[] = {
-       "HAMEG",
-};
-
-static const int32_t hwopts[] = {
-       SR_CONF_CONN,
-       SR_CONF_SERIALCOMM,
-};
-
-enum {
-       CG_INVALID = -1,
-       CG_NONE,
-       CG_ANALOG,
-       CG_DIGITAL,
-};
-
-static int init(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, di, LOG_PREFIX);
-}
-
-static int check_manufacturer(const char *manufacturer)
-{
-       unsigned int i;
-
-       for (i = 0; i < ARRAY_SIZE(manufacturers); ++i)
-               if (!strcmp(manufacturer, manufacturers[i]))
-                       return SR_OK;
-
-       return SR_ERR;
-}
-
-static struct sr_dev_inst *hmo_probe_serial_device(struct sr_scpi_dev_inst *scpi)
-{
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-       struct sr_scpi_hw_info *hw_info;
-
-       sdi = NULL;
-       devc = NULL;
-       hw_info = NULL;
-
-       if (sr_scpi_get_hw_id(scpi, &hw_info) != SR_OK) {
-               sr_info("Couldn't get IDN response.");
-               goto fail;
-       }
-
-       if (check_manufacturer(hw_info->manufacturer) != SR_OK)
-               goto fail;
-
-       if (!(sdi = sr_dev_inst_new(0, SR_ST_ACTIVE,
-                                   hw_info->manufacturer, hw_info->model,
-                                   hw_info->firmware_version))) {
-               goto fail;
-       }
-       sr_scpi_hw_info_free(hw_info);
-       hw_info = NULL;
-
-       if (!(devc = g_try_malloc0(sizeof(struct dev_context))))
-               goto fail;
-
-       sdi->driver = di;
-       sdi->priv = devc;
-       sdi->inst_type = SR_INST_SCPI;
-       sdi->conn = scpi;
-
-       if (hmo_init_device(sdi) != SR_OK)
-               goto fail;
-
-       sr_scpi_close(sdi->conn);
-
-       sdi->status = SR_ST_INACTIVE;
-
-       return sdi;
-
-fail:
-       if (hw_info)
-               sr_scpi_hw_info_free(hw_info);
-       if (sdi)
-               sr_dev_inst_free(sdi);
-       if (devc)
-               g_free(devc);
-
-       return NULL;
-}
-
-static GSList *scan(GSList *options)
-{
-       return sr_scpi_scan(di->priv, options, hmo_probe_serial_device);
-}
-
-static GSList *dev_list(void)
-{
-       return ((struct drv_context *)(di->priv))->instances;
-}
-
-static void clear_helper(void *priv)
-{
-       unsigned int i;
-       struct dev_context *devc;
-       struct scope_config *model;
-
-       devc = priv;
-       model = devc->model_config;
-
-       hmo_scope_state_free(devc->model_state);
-
-       for (i = 0; i < model->analog_channels; ++i)
-               g_slist_free(devc->analog_groups[i].channels);
-
-       for (i = 0; i < model->digital_pods; ++i) {
-               g_slist_free(devc->digital_groups[i].channels);
-               g_free(devc->digital_groups[i].name);
-       }
-
-       g_free(devc->analog_groups);
-       g_free(devc->digital_groups);
-
-       g_free(devc);
-}
-
-static int dev_clear(void)
-{
-       return std_dev_clear(di, clear_helper);
-}
-
-static int dev_open(struct sr_dev_inst *sdi)
-{
-       if (sdi->status != SR_ST_ACTIVE && sr_scpi_open(sdi->conn) != SR_OK)
-               return SR_ERR;
-
-       if (hmo_scope_state_get(sdi) != SR_OK)
-               return SR_ERR;
-
-       sdi->status = SR_ST_ACTIVE;
-
-       return SR_OK;
-}
-
-static int dev_close(struct sr_dev_inst *sdi)
-{
-       if (sdi->status == SR_ST_INACTIVE)
-               return SR_OK;
-
-       sr_scpi_close(sdi->conn);
-
-       sdi->status = SR_ST_INACTIVE;
-
-       return SR_OK;
-}
-
-static int cleanup(void)
-{
-       dev_clear();
-
-       return SR_OK;
-}
-
-static int check_channel_group(struct dev_context *devc,
-                            const struct sr_channel_group *cg)
-{
-       unsigned int i;
-       struct scope_config *model;
-
-       model = devc->model_config;
-
-       if (!cg)
-               return CG_NONE;
-
-       for (i = 0; i < model->analog_channels; ++i)
-               if (cg == &devc->analog_groups[i])
-                       return CG_ANALOG;
-
-       for (i = 0; i < model->digital_pods; ++i)
-               if (cg == &devc->digital_groups[i])
-                       return CG_DIGITAL;
-
-       sr_err("Invalid channel group specified.");
-
-       return CG_INVALID;
-}
-
-static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
-                     const struct sr_channel_group *cg)
-{
-       int ret, cg_type;
-       unsigned int i;
-       struct dev_context *devc;
-       struct scope_config *model;
-       struct scope_state *state;
-
-       if (!sdi || !(devc = sdi->priv))
-               return SR_ERR_ARG;
-
-       if ((cg_type = check_channel_group(devc, cg)) == CG_INVALID)
-               return SR_ERR;
-
-       ret = SR_ERR_NA;
-       model = devc->model_config;
-       state = devc->model_state;
-
-       switch (key) {
-       case SR_CONF_NUM_TIMEBASE:
-               *data = g_variant_new_int32(model->num_xdivs);
-               ret = SR_OK;
-               break;
-       case SR_CONF_TIMEBASE:
-               *data = g_variant_new("(tt)", (*model->timebases)[state->timebase][0],
-                                     (*model->timebases)[state->timebase][1]);
-               ret = SR_OK;
-               break;
-       case SR_CONF_NUM_VDIV:
-               if (cg_type == CG_NONE) {
-                       sr_err("No channel group specified.");
-                       return SR_ERR_CHANNEL_GROUP;
-               } else if (cg_type == CG_ANALOG) {
-                       for (i = 0; i < model->analog_channels; ++i) {
-                               if (cg != &devc->analog_groups[i])
-                                       continue;
-                               *data = g_variant_new_int32(model->num_ydivs);
-                               ret = SR_OK;
-                               break;
-                       }
-
-               } else {
-                       ret = SR_ERR_NA;
-               }
-               break;
-       case SR_CONF_VDIV:
-               if (cg_type == CG_NONE) {
-                       sr_err("No channel group specified.");
-                       return SR_ERR_CHANNEL_GROUP;
-               } else if (cg_type == CG_ANALOG) {
-                       for (i = 0; i < model->analog_channels; ++i) {
-                               if (cg != &devc->analog_groups[i])
-                                       continue;
-                               *data = g_variant_new("(tt)",
-                                                     (*model->vdivs)[state->analog_channels[i].vdiv][0],
-                                                     (*model->vdivs)[state->analog_channels[i].vdiv][1]);
-                               ret = SR_OK;
-                               break;
-                       }
-
-               } else {
-                       ret = SR_ERR_NA;
-               }
-               break;
-       case SR_CONF_TRIGGER_SOURCE:
-               *data = g_variant_new_string((*model->trigger_sources)[state->trigger_source]);
-               ret = SR_OK;
-               break;
-       case SR_CONF_TRIGGER_SLOPE:
-               *data = g_variant_new_string((*model->trigger_slopes)[state->trigger_slope]);
-               ret = SR_OK;
-               break;
-       case SR_CONF_HORIZ_TRIGGERPOS:
-               *data = g_variant_new_double(state->horiz_triggerpos);
-               ret = SR_OK;
-               break;
-       case SR_CONF_COUPLING:
-               if (cg_type == CG_NONE) {
-                       sr_err("No channel group specified.");
-                       return SR_ERR_CHANNEL_GROUP;
-               } else if (cg_type == CG_ANALOG) {
-                       for (i = 0; i < model->analog_channels; ++i) {
-                               if (cg != &devc->analog_groups[i])
-                                       continue;
-                               *data = g_variant_new_string((*model->coupling_options)[state->analog_channels[i].coupling]);
-                               ret = SR_OK;
-                               break;
-                       }
-
-               } else {
-                       ret = SR_ERR_NA;
-               }
-               break;
-       case SR_CONF_SAMPLERATE:
-               *data = g_variant_new_uint64(state->sample_rate);
-               ret = SR_OK;
-               break;
-       default:
-               ret = SR_ERR_NA;
-       }
-
-       return ret;
-}
-
-static GVariant *build_tuples(const uint64_t (*array)[][2], unsigned int n)
-{
-       unsigned int i;
-       GVariant *rational[2];
-       GVariantBuilder gvb;
-
-       g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
-
-       for (i = 0; i < n; i++) {
-               rational[0] = g_variant_new_uint64((*array)[i][0]);
-               rational[1] = g_variant_new_uint64((*array)[i][1]);
-
-               /* FIXME: Valgrind reports a memory leak here. */
-               g_variant_builder_add_value(&gvb, g_variant_new_tuple(rational, 2));
-       }
-
-       return g_variant_builder_end(&gvb);
-}
-
-static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
-                     const struct sr_channel_group *cg)
-{
-       int ret, cg_type;
-       unsigned int i, j;
-       char command[MAX_COMMAND_SIZE], float_str[30];
-       struct dev_context *devc;
-       struct scope_config *model;
-       struct scope_state *state;
-       const char *tmp;
-       uint64_t p, q;
-       double tmp_d;
-       gboolean update_sample_rate;
-
-       if (!sdi || !(devc = sdi->priv))
-               return SR_ERR_ARG;
-
-       if ((cg_type = check_channel_group(devc, cg)) == CG_INVALID)
-               return SR_ERR;
-
-       model = devc->model_config;
-       state = devc->model_state;
-       update_sample_rate = FALSE;
-
-       ret = SR_ERR_NA;
-
-       switch (key) {
-       case SR_CONF_LIMIT_FRAMES:
-               devc->frame_limit = g_variant_get_uint64(data);
-               ret = SR_OK;
-               break;
-       case SR_CONF_TRIGGER_SOURCE:
-               tmp = g_variant_get_string(data, NULL);
-               for (i = 0; (*model->trigger_sources)[i]; i++) {
-                       if (g_strcmp0(tmp, (*model->trigger_sources)[i]) != 0)
-                               continue;
-                       state->trigger_source = i;
-                       g_snprintf(command, sizeof(command),
-                                  (*model->scpi_dialect)[SCPI_CMD_SET_TRIGGER_SOURCE],
-                                  (*model->trigger_sources)[i]);
-
-                       ret = sr_scpi_send(sdi->conn, command);
-                       break;
-               }
-               break;
-       case SR_CONF_VDIV:
-               if (cg_type == CG_NONE) {
-                       sr_err("No channel group specified.");
-                       return SR_ERR_CHANNEL_GROUP;
-               }
-
-               g_variant_get(data, "(tt)", &p, &q);
-
-               for (i = 0; i < model->num_vdivs; i++) {
-                       if (p != (*model->vdivs)[i][0] ||
-                           q != (*model->vdivs)[i][1])
-                               continue;
-                       for (j = 1; j <= model->analog_channels; ++j) {
-                               if (cg != &devc->analog_groups[j - 1])
-                                       continue;
-                               state->analog_channels[j - 1].vdiv = i;
-                               g_ascii_formatd(float_str, sizeof(float_str), "%E", (float) p / q);
-                               g_snprintf(command, sizeof(command),
-                                          (*model->scpi_dialect)[SCPI_CMD_SET_VERTICAL_DIV],
-                                          j, float_str);
-
-                               if (sr_scpi_send(sdi->conn, command) != SR_OK ||
-                                   sr_scpi_get_opc(sdi->conn) != SR_OK)
-                                       return SR_ERR;
-
-                               break;
-                       }
-
-                       ret = SR_OK;
-                       break;
-               }
-               break;
-       case SR_CONF_TIMEBASE:
-               g_variant_get(data, "(tt)", &p, &q);
-
-               for (i = 0; i < model->num_timebases; i++) {
-                       if (p != (*model->timebases)[i][0] ||
-                           q != (*model->timebases)[i][1])
-                               continue;
-                       state->timebase = i;
-                       g_ascii_formatd(float_str, sizeof(float_str), "%E", (float) p / q);
-                       g_snprintf(command, sizeof(command),
-                                  (*model->scpi_dialect)[SCPI_CMD_SET_TIMEBASE],
-                                  float_str);
-
-                       ret = sr_scpi_send(sdi->conn, command);
-                       update_sample_rate = TRUE;
-                       break;
-               }
-               break;
-       case SR_CONF_HORIZ_TRIGGERPOS:
-               tmp_d = g_variant_get_double(data);
-
-               if (tmp_d < 0.0 || tmp_d > 1.0)
-                       return SR_ERR;
-
-               state->horiz_triggerpos = tmp_d;
-               tmp_d = -(tmp_d - 0.5) *
-                       ((double) (*model->timebases)[state->timebase][0] /
-                       (*model->timebases)[state->timebase][1])
-                        * model->num_xdivs;
-
-               g_ascii_formatd(float_str, sizeof(float_str), "%E", tmp_d);
-               g_snprintf(command, sizeof(command),
-                          (*model->scpi_dialect)[SCPI_CMD_SET_HORIZ_TRIGGERPOS],
-                          float_str);
-
-               ret = sr_scpi_send(sdi->conn, command);
-               break;
-       case SR_CONF_TRIGGER_SLOPE:
-               tmp = g_variant_get_string(data, NULL);
-
-               if (!tmp || !(tmp[0] == 'f' || tmp[0] == 'r'))
-                       return SR_ERR_ARG;
-
-               state->trigger_slope = (tmp[0] == 'r') ? 0 : 1;
-
-               g_snprintf(command, sizeof(command),
-                          (*model->scpi_dialect)[SCPI_CMD_SET_TRIGGER_SLOPE],
-                          (state->trigger_slope == 0) ? "POS" : "NEG");
-
-               ret = sr_scpi_send(sdi->conn, command);
-               break;
-       case SR_CONF_COUPLING:
-               if (cg_type == CG_NONE) {
-                       sr_err("No channel group specified.");
-                       return SR_ERR_CHANNEL_GROUP;
-               }
-
-               tmp = g_variant_get_string(data, NULL);
-
-               for (i = 0; (*model->coupling_options)[i]; i++) {
-                       if (strcmp(tmp, (*model->coupling_options)[i]) != 0)
-                               continue;
-                       for (j = 1; j <= model->analog_channels; ++j) {
-                               if (cg != &devc->analog_groups[j - 1])
-                                       continue;
-                               state->analog_channels[j-1].coupling = i;
-
-                               g_snprintf(command, sizeof(command),
-                                          (*model->scpi_dialect)[SCPI_CMD_SET_COUPLING],
-                                          j, tmp);
-
-                               if (sr_scpi_send(sdi->conn, command) != SR_OK ||
-                                   sr_scpi_get_opc(sdi->conn) != SR_OK)
-                                       return SR_ERR;
-                               break;
-                       }
-
-                       ret = SR_OK;
-                       break;
-               }
-               break;
-       default:
-               ret = SR_ERR_NA;
-               break;
-       }
-
-       if (ret == SR_OK)
-               ret = sr_scpi_get_opc(sdi->conn);
-
-       if (ret == SR_OK && update_sample_rate)
-               ret = hmo_update_sample_rate(sdi);
-
-       return ret;
-}
-
-static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
-                      const struct sr_channel_group *cg)
-{
-       int cg_type;
-       struct dev_context *devc;
-       struct scope_config *model;
-
-       if (!sdi || !(devc = sdi->priv))
-               return SR_ERR_ARG;
-
-       if ((cg_type = check_channel_group(devc, cg)) == CG_INVALID)
-               return SR_ERR;
-
-       model = devc->model_config;
-
-       switch (key) {
-       case SR_CONF_DEVICE_OPTIONS:
-               if (cg_type == CG_NONE) {
-                       *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               model->hw_caps, model->num_hwcaps,
-                               sizeof(int32_t));
-               } else if (cg_type == CG_ANALOG) {
-                       *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               model->analog_hwcaps, model->num_analog_hwcaps,
-                               sizeof(int32_t));
-               } else {
-                       *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               NULL, 0, sizeof(int32_t));
-               }
-               break;
-       case SR_CONF_COUPLING:
-               if (cg_type == CG_NONE)
-                       return SR_ERR_CHANNEL_GROUP;
-               *data = g_variant_new_strv(*model->coupling_options,
-                          g_strv_length((char **)*model->coupling_options));
-               break;
-       case SR_CONF_TRIGGER_SOURCE:
-               *data = g_variant_new_strv(*model->trigger_sources,
-                          g_strv_length((char **)*model->trigger_sources));
-               break;
-       case SR_CONF_TRIGGER_SLOPE:
-               *data = g_variant_new_strv(*model->trigger_slopes,
-                          g_strv_length((char **)*model->trigger_slopes));
-               break;
-       case SR_CONF_TIMEBASE:
-               *data = build_tuples(model->timebases, model->num_timebases);
-               break;
-       case SR_CONF_VDIV:
-               if (cg_type == CG_NONE)
-                       return SR_ERR_CHANNEL_GROUP;
-               *data = build_tuples(model->vdivs, model->num_vdivs);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-SR_PRIV int hmo_request_data(const struct sr_dev_inst *sdi)
-{
-       char command[MAX_COMMAND_SIZE];
-       struct sr_channel *ch;
-       struct dev_context *devc;
-       struct scope_config *model;
-
-       devc = sdi->priv;
-       model = devc->model_config;
-
-       ch = devc->current_channel->data;
-
-       switch (ch->type) {
-       case SR_CHANNEL_ANALOG:
-               g_snprintf(command, sizeof(command),
-                          (*model->scpi_dialect)[SCPI_CMD_GET_ANALOG_DATA],
-                          ch->index + 1);
-               break;
-       case SR_CHANNEL_LOGIC:
-               g_snprintf(command, sizeof(command),
-                          (*model->scpi_dialect)[SCPI_CMD_GET_DIG_DATA],
-                          ch->index < 8 ? 1 : 2);
-               break;
-       default:
-               sr_err("Invalid channel type.");
-               break;
-       }
-
-       return sr_scpi_send(sdi->conn, command);
-}
-
-static int hmo_check_channels(GSList *channels)
-{
-       GSList *l;
-       struct sr_channel *ch;
-       gboolean enabled_pod1, enabled_pod2, enabled_chan3, enabled_chan4;
-
-       enabled_pod1 = enabled_pod2 = enabled_chan3 = enabled_chan4 = FALSE;
-
-       for (l = channels; l; l = l->next) {
-               ch = l->data;
-               switch (ch->type) {
-               case SR_CHANNEL_ANALOG:
-                       if (ch->index == 2)
-                               enabled_chan3 = TRUE;
-                       else if (ch->index == 3)
-                               enabled_chan4 = TRUE;
-                       break;
-               case SR_CHANNEL_LOGIC:
-                       if (ch->index < 8)
-                               enabled_pod1 = TRUE;
-                       else
-                               enabled_pod2 = TRUE;
-                       break;
-               default:
-                       return SR_ERR;
-               }
-       }
-
-       if ((enabled_pod1 && enabled_chan3) ||
-           (enabled_pod2 && enabled_chan4))
-               return SR_ERR;
-
-       return SR_OK;
-}
-
-static int hmo_setup_channels(const struct sr_dev_inst *sdi)
-{
-       GSList *l;
-       unsigned int i;
-       gboolean *pod_enabled, setup_changed;
-       char command[MAX_COMMAND_SIZE];
-       struct scope_state *state;
-       struct scope_config *model;
-       struct sr_channel *ch;
-       struct dev_context *devc;
-       struct sr_scpi_dev_inst *scpi;
-
-       devc = sdi->priv;
-       scpi = sdi->conn;
-       state = devc->model_state;
-       model = devc->model_config;
-       setup_changed = FALSE;
-
-       pod_enabled = g_try_malloc0(sizeof(gboolean) * model->digital_pods);
-
-       for (l = sdi->channels; l; l = l->next) {
-               ch = l->data;
-               switch (ch->type) {
-               case SR_CHANNEL_ANALOG:
-                       if (ch->enabled == state->analog_channels[ch->index].state)
-                               break;
-                       g_snprintf(command, sizeof(command),
-                                  (*model->scpi_dialect)[SCPI_CMD_SET_ANALOG_CHAN_STATE],
-                                  ch->index + 1, ch->enabled);
-
-                       if (sr_scpi_send(scpi, command) != SR_OK)
-                               return SR_ERR;
-                       state->analog_channels[ch->index].state = ch->enabled;
-                       setup_changed = TRUE;
-                       break;
-               case SR_CHANNEL_LOGIC:
-                       /*
-                        * A digital POD needs to be enabled for every group of
-                        * 8 channels.
-                        */
-                       if (ch->enabled)
-                               pod_enabled[ch->index < 8 ? 0 : 1] = TRUE;
-
-                       if (ch->enabled == state->digital_channels[ch->index])
-                               break;
-                       g_snprintf(command, sizeof(command),
-                                  (*model->scpi_dialect)[SCPI_CMD_SET_DIG_CHAN_STATE],
-                                  ch->index, ch->enabled);
-
-                       if (sr_scpi_send(scpi, command) != SR_OK)
-                               return SR_ERR;
-
-                       state->digital_channels[ch->index] = ch->enabled;
-                       setup_changed = TRUE;
-                       break;
-               default:
-                       return SR_ERR;
-               }
-       }
-
-       for (i = 1; i <= model->digital_pods; ++i) {
-               if (state->digital_pods[i - 1] == pod_enabled[i - 1])
-                       continue;
-               g_snprintf(command, sizeof(command),
-                          (*model->scpi_dialect)[SCPI_CMD_SET_DIG_POD_STATE],
-                          i, pod_enabled[i - 1]);
-               if (sr_scpi_send(scpi, command) != SR_OK)
-                       return SR_ERR;
-               state->digital_pods[i - 1] = pod_enabled[i - 1];
-               setup_changed = TRUE;
-       }
-
-       g_free(pod_enabled);
-
-       if (setup_changed && hmo_update_sample_rate(sdi) != SR_OK)
-               return SR_ERR;
-
-       return SR_OK;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
-{
-       GSList *l;
-       gboolean digital_added;
-       struct sr_channel *ch;
-       struct dev_context *devc;
-       struct sr_scpi_dev_inst *scpi;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       scpi = sdi->conn;
-       devc = sdi->priv;
-       digital_added = FALSE;
-
-       for (l = sdi->channels; l; l = l->next) {
-               ch = l->data;
-               if (!ch->enabled)
-                       continue;
-               /* Only add a single digital channel. */
-               if (ch->type != SR_CHANNEL_LOGIC || !digital_added) {
-                       devc->enabled_channels = g_slist_append(
-                                       devc->enabled_channels, ch);
-                       if (ch->type == SR_CHANNEL_LOGIC)
-                               digital_added = TRUE;
-               }
-       }
-
-       if (!devc->enabled_channels)
-               return SR_ERR;
-
-       if (hmo_check_channels(devc->enabled_channels) != SR_OK) {
-               sr_err("Invalid channel configuration specified!");
-               return SR_ERR_NA;
-       }
-
-       if (hmo_setup_channels(sdi) != SR_OK) {
-               sr_err("Failed to setup channel configuration!");
-               return SR_ERR;
-       }
-
-       sr_scpi_source_add(sdi->session, scpi, G_IO_IN, 50,
-                       hmo_receive_data, (void *)sdi);
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(cb_data, LOG_PREFIX);
-
-       devc->current_channel = devc->enabled_channels;
-
-       return hmo_request_data(sdi);
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct dev_context *devc;
-       struct sr_scpi_dev_inst *scpi;
-       struct sr_datafeed_packet packet;
-
-       (void)cb_data;
-
-       packet.type = SR_DF_END;
-       packet.payload = NULL;
-       sr_session_send(sdi, &packet);
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       devc = sdi->priv;
-
-       devc->num_frames = 0;
-       g_slist_free(devc->enabled_channels);
-       devc->enabled_channels = NULL;
-       scpi = sdi->conn;
-       sr_scpi_source_remove(sdi->session, scpi);
-
-       return SR_OK;
-}
-
-SR_PRIV struct sr_dev_driver hameg_hmo_driver_info = {
-       .name = "hameg-hmo",
-       .longname = "Hameg HMO",
-       .api_version = 1,
-       .init = init,
-       .cleanup = cleanup,
-       .scan = scan,
-       .dev_list = dev_list,
-       .dev_clear = dev_clear,
-       .config_get = config_get,
-       .config_set = config_set,
-       .config_list = config_list,
-       .dev_open = dev_open,
-       .dev_close = dev_close,
-       .dev_acquisition_start = dev_acquisition_start,
-       .dev_acquisition_stop = dev_acquisition_stop,
-       .priv = NULL,
-};
diff --git a/hardware/hameg-hmo/protocol.c b/hardware/hameg-hmo/protocol.c
deleted file mode 100644 (file)
index afa6efe..0000000
+++ /dev/null
@@ -1,741 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * 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 "protocol.h"
-
-static const char *hameg_scpi_dialect[] = {
-       [SCPI_CMD_GET_DIG_DATA]             = ":POD%d:DATA?",
-       [SCPI_CMD_GET_TIMEBASE]             = ":TIM:SCAL?",
-       [SCPI_CMD_SET_TIMEBASE]             = ":TIM:SCAL %s",
-       [SCPI_CMD_GET_COUPLING]             = ":CHAN%d:COUP?",
-       [SCPI_CMD_SET_COUPLING]             = ":CHAN%d:COUP %s",
-       [SCPI_CMD_GET_SAMPLE_RATE]          = ":ACQ:SRAT?",
-       [SCPI_CMD_GET_SAMPLE_RATE_LIVE]     = ":%s:DATA:POINTS?",
-       [SCPI_CMD_GET_ANALOG_DATA]          = ":CHAN%d:DATA?",
-       [SCPI_CMD_GET_VERTICAL_DIV]         = ":CHAN%d:SCAL?",
-       [SCPI_CMD_SET_VERTICAL_DIV]         = ":CHAN%d:SCAL %s",
-       [SCPI_CMD_GET_DIG_POD_STATE]        = ":POD%d:STAT?",
-       [SCPI_CMD_SET_DIG_POD_STATE]        = ":POD%d:STAT %d",
-       [SCPI_CMD_GET_TRIGGER_SLOPE]        = ":TRIG:A:EDGE:SLOP?",
-       [SCPI_CMD_SET_TRIGGER_SLOPE]        = ":TRIG:A:EDGE:SLOP %s",
-       [SCPI_CMD_GET_TRIGGER_SOURCE]       = ":TRIG:A:SOUR?",
-       [SCPI_CMD_SET_TRIGGER_SOURCE]       = ":TRIG:A:SOUR %s",
-       [SCPI_CMD_GET_DIG_CHAN_STATE]       = ":LOG%d:STAT?",
-       [SCPI_CMD_SET_DIG_CHAN_STATE]       = ":LOG%d:STAT %d",
-       [SCPI_CMD_GET_VERTICAL_OFFSET]      = ":CHAN%d:POS?",
-       [SCPI_CMD_GET_HORIZ_TRIGGERPOS]     = ":TIM:POS?",
-       [SCPI_CMD_SET_HORIZ_TRIGGERPOS]     = ":TIM:POS %s",
-       [SCPI_CMD_GET_ANALOG_CHAN_STATE]    = ":CHAN%d:STAT?",
-       [SCPI_CMD_SET_ANALOG_CHAN_STATE]    = ":CHAN%d:STAT %d",
-};
-
-static const int32_t hmo_hwcaps[] = {
-       SR_CONF_OSCILLOSCOPE,
-       SR_CONF_TRIGGER_SOURCE,
-       SR_CONF_TIMEBASE,
-       SR_CONF_NUM_TIMEBASE,
-       SR_CONF_TRIGGER_SLOPE,
-       SR_CONF_HORIZ_TRIGGERPOS,
-       SR_CONF_SAMPLERATE,
-       SR_CONF_LIMIT_FRAMES,
-};
-
-static const int32_t hmo_analog_caps[] = {
-       SR_CONF_NUM_VDIV,
-       SR_CONF_COUPLING,
-       SR_CONF_VDIV,
-};
-
-static const char *hmo_coupling_options[] = {
-       "AC",
-       "ACL",
-       "DC",
-       "DCL",
-       "GND",
-       NULL,
-};
-
-static const char *scope_trigger_slopes[] = {
-       "POS",
-       "NEG",
-       NULL,
-};
-
-static const char *hmo_compact2_trigger_sources[] = {
-       "CH1",
-       "CH2",
-       "LINE",
-       "EXT",
-       "D0",
-       "D1",
-       "D2",
-       "D3",
-       "D4",
-       "D5",
-       "D6",
-       "D7",
-       NULL,
-};
-
-static const char *hmo_compact4_trigger_sources[] = {
-       "CH1",
-       "CH2",
-       "CH3",
-       "CH4",
-       "LINE",
-       "EXT",
-       "D0",
-       "D1",
-       "D2",
-       "D3",
-       "D4",
-       "D5",
-       "D6",
-       "D7",
-       NULL,
-};
-
-static const uint64_t hmo_timebases[][2] = {
-       /* nanoseconds */
-       { 2, 1000000000 },
-       { 5, 1000000000 },
-       { 10, 1000000000 },
-       { 20, 1000000000 },
-       { 50, 1000000000 },
-       { 100, 1000000000 },
-       { 200, 1000000000 },
-       { 500, 1000000000 },
-       /* microseconds */
-       { 1, 1000000 },
-       { 2, 1000000 },
-       { 5, 1000000 },
-       { 10, 1000000 },
-       { 20, 1000000 },
-       { 50, 1000000 },
-       { 100, 1000000 },
-       { 200, 1000000 },
-       { 500, 1000000 },
-       /* milliseconds */
-       { 1, 1000 },
-       { 2, 1000 },
-       { 5, 1000 },
-       { 10, 1000 },
-       { 20, 1000 },
-       { 50, 1000 },
-       { 100, 1000 },
-       { 200, 1000 },
-       { 500, 1000 },
-       /* seconds */
-       { 1, 1 },
-       { 2, 1 },
-       { 5, 1 },
-       { 10, 1 },
-       { 20, 1 },
-       { 50, 1 },
-};
-
-static const uint64_t hmo_vdivs[][2] = {
-       /* millivolts */
-       { 1, 1000 },
-       { 2, 1000 },
-       { 5, 1000 },
-       { 10, 1000 },
-       { 20, 1000 },
-       { 50, 1000 },
-       { 100, 1000 },
-       { 200, 1000 },
-       { 500, 1000 },
-       /* volts */
-       { 1, 1 },
-       { 2, 1 },
-       { 5, 1 },
-       { 10, 1 },
-};
-
-static const char *scope_analog_channel_names[] = {
-       "CH1",
-       "CH2",
-       "CH3",
-       "CH4",
-};
-
-static const char *scope_digital_channel_names[] = {
-       "D0",
-       "D1",
-       "D2",
-       "D3",
-       "D4",
-       "D5",
-       "D6",
-       "D7",
-       "D8",
-       "D9",
-       "D10",
-       "D11",
-       "D12",
-       "D13",
-       "D14",
-       "D15",
-};
-
-static struct scope_config scope_models[] = {
-       {
-               .name = {"HMO722", "HMO1022", "HMO1522", "HMO2022", NULL},
-               .analog_channels = 2,
-               .digital_channels = 8,
-               .digital_pods = 1,
-
-               .analog_names = &scope_analog_channel_names,
-               .digital_names = &scope_digital_channel_names,
-
-               .hw_caps = &hmo_hwcaps,
-               .num_hwcaps = ARRAY_SIZE(hmo_hwcaps),
-
-               .analog_hwcaps = &hmo_analog_caps,
-               .num_analog_hwcaps = ARRAY_SIZE(hmo_analog_caps),
-
-               .coupling_options = &hmo_coupling_options,
-               .trigger_sources = &hmo_compact2_trigger_sources,
-               .trigger_slopes = &scope_trigger_slopes,
-
-               .timebases = &hmo_timebases,
-               .num_timebases = ARRAY_SIZE(hmo_timebases),
-
-               .vdivs = &hmo_vdivs,
-               .num_vdivs = ARRAY_SIZE(hmo_vdivs),
-
-               .num_xdivs = 12,
-               .num_ydivs = 8,
-
-               .scpi_dialect = &hameg_scpi_dialect,
-       },
-       {
-               .name = {"HMO724", "HMO1024", "HMO1524", "HMO2024", NULL},
-               .analog_channels = 4,
-               .digital_channels = 8,
-               .digital_pods = 1,
-
-               .analog_names = &scope_analog_channel_names,
-               .digital_names = &scope_digital_channel_names,
-
-               .hw_caps = &hmo_hwcaps,
-               .num_hwcaps = ARRAY_SIZE(hmo_hwcaps),
-
-               .analog_hwcaps = &hmo_analog_caps,
-               .num_analog_hwcaps = ARRAY_SIZE(hmo_analog_caps),
-
-               .coupling_options = &hmo_coupling_options,
-               .trigger_sources = &hmo_compact4_trigger_sources,
-               .trigger_slopes = &scope_trigger_slopes,
-
-               .timebases = &hmo_timebases,
-               .num_timebases = ARRAY_SIZE(hmo_timebases),
-
-               .vdivs = &hmo_vdivs,
-               .num_vdivs = ARRAY_SIZE(hmo_vdivs),
-
-               .num_xdivs = 12,
-               .num_ydivs = 8,
-
-               .scpi_dialect = &hameg_scpi_dialect,
-       },
-};
-
-static void scope_state_dump(struct scope_config *config,
-                            struct scope_state *state)
-{
-       unsigned int i;
-       char *tmp;
-
-       for (i = 0; i < config->analog_channels; ++i) {
-               tmp = sr_voltage_string((*config->vdivs)[state->analog_channels[i].vdiv][0],
-                                            (*config->vdivs)[state->analog_channels[i].vdiv][1]);
-               sr_info("State of analog channel  %d -> %s : %s (coupling) %s (vdiv) %2.2e (offset)",
-                       i + 1, state->analog_channels[i].state ? "On" : "Off",
-                       (*config->coupling_options)[state->analog_channels[i].coupling],
-                       tmp, state->analog_channels[i].vertical_offset);
-       }
-
-       for (i = 0; i < config->digital_channels; ++i) {
-               sr_info("State of digital channel %d -> %s", i,
-                       state->digital_channels[i] ? "On" : "Off");
-       }
-
-       for (i = 0; i < config->digital_pods; ++i) {
-               sr_info("State of digital POD %d -> %s", i,
-                       state->digital_pods[i] ? "On" : "Off");
-       }
-
-       tmp = sr_period_string((*config->timebases)[state->timebase][0] *
-                              (*config->timebases)[state->timebase][1]);
-       sr_info("Current timebase: %s", tmp);
-       g_free(tmp);
-
-       tmp = sr_samplerate_string(state->sample_rate);
-       sr_info("Current samplerate: %s", tmp);
-       g_free(tmp);
-
-       sr_info("Current trigger: %s (source), %s (slope) %.2f (offset)",
-               (*config->trigger_sources)[state->trigger_source],
-               (*config->trigger_slopes)[state->trigger_slope],
-               state->horiz_triggerpos);
-}
-
-static int scope_state_get_array_option(struct sr_scpi_dev_inst *scpi,
-               const char *command, const char *(*array)[], int *result)
-{
-       char *tmp;
-       unsigned int i;
-
-       if (sr_scpi_get_string(scpi, command, &tmp) != SR_OK) {
-               g_free(tmp);
-               return SR_ERR;
-       }
-
-       for (i = 0; (*array)[i]; ++i) {
-               if (!g_strcmp0(tmp, (*array)[i])) {
-                       *result = i;
-                       g_free(tmp);
-                       tmp = NULL;
-                       break;
-               }
-       }
-
-       if (tmp) {
-               g_free(tmp);
-               return SR_ERR;
-       }
-
-       return SR_OK;
-}
-
-static int analog_channel_state_get(struct sr_scpi_dev_inst *scpi,
-                                   struct scope_config *config,
-                                   struct scope_state *state)
-{
-       unsigned int i, j;
-       float tmp_float;
-       char command[MAX_COMMAND_SIZE];
-
-       for (i = 0; i < config->analog_channels; ++i) {
-               g_snprintf(command, sizeof(command),
-                          (*config->scpi_dialect)[SCPI_CMD_GET_ANALOG_CHAN_STATE],
-                          i + 1);
-
-               if (sr_scpi_get_bool(scpi, command,
-                                    &state->analog_channels[i].state) != SR_OK)
-                       return SR_ERR;
-
-               g_snprintf(command, sizeof(command),
-                          (*config->scpi_dialect)[SCPI_CMD_GET_VERTICAL_DIV],
-                          i + 1);
-
-               if (sr_scpi_get_float(scpi, command, &tmp_float) != SR_OK)
-                       return SR_ERR;
-               for (j = 0; j < config->num_vdivs; j++) {
-                       if (tmp_float == ((float) (*config->vdivs)[j][0] /
-                                         (*config->vdivs)[j][1])) {
-                               state->analog_channels[i].vdiv = j;
-                               break;
-                       }
-               }
-               if (i == config->num_vdivs)
-                       return SR_ERR;
-
-               g_snprintf(command, sizeof(command),
-                          (*config->scpi_dialect)[SCPI_CMD_GET_VERTICAL_OFFSET],
-                          i + 1);
-
-               if (sr_scpi_get_float(scpi, command,
-                                    &state->analog_channels[i].vertical_offset) != SR_OK)
-                       return SR_ERR;
-
-               g_snprintf(command, sizeof(command),
-                          (*config->scpi_dialect)[SCPI_CMD_GET_COUPLING],
-                          i + 1);
-
-               if (scope_state_get_array_option(scpi, command, config->coupling_options,
-                                        &state->analog_channels[i].coupling) != SR_OK)
-                       return SR_ERR;
-       }
-
-       return SR_OK;
-}
-
-static int digital_channel_state_get(struct sr_scpi_dev_inst *scpi,
-                                    struct scope_config *config,
-                                    struct scope_state *state)
-{
-       unsigned int i;
-       char command[MAX_COMMAND_SIZE];
-
-       for (i = 0; i < config->digital_channels; ++i) {
-               g_snprintf(command, sizeof(command),
-                          (*config->scpi_dialect)[SCPI_CMD_GET_DIG_CHAN_STATE],
-                          i);
-
-               if (sr_scpi_get_bool(scpi, command,
-                                    &state->digital_channels[i]) != SR_OK)
-                       return SR_ERR;
-       }
-
-       for (i = 0; i < config->digital_pods; ++i) {
-               g_snprintf(command, sizeof(command),
-                          (*config->scpi_dialect)[SCPI_CMD_GET_DIG_POD_STATE],
-                          i + 1);
-
-               if (sr_scpi_get_bool(scpi, command,
-                                    &state->digital_pods[i]) != SR_OK)
-                       return SR_ERR;
-       }
-
-       return SR_OK;
-}
-
-SR_PRIV int hmo_update_sample_rate(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct scope_state *state;
-       struct scope_config *config;
-
-       int tmp;
-       unsigned int i;
-       float tmp_float;
-       gboolean channel_found;
-       char tmp_str[MAX_COMMAND_SIZE];
-       char chan_name[20];
-
-       devc = sdi->priv;
-       config = devc->model_config;
-       state = devc->model_state;
-       channel_found = FALSE;
-
-       for (i = 0; i < config->analog_channels; ++i) {
-               if (state->analog_channels[i].state) {
-                       g_snprintf(chan_name, sizeof(chan_name), "CHAN%d", i + 1);
-                       g_snprintf(tmp_str, sizeof(tmp_str),
-                                  (*config->scpi_dialect)[SCPI_CMD_GET_SAMPLE_RATE_LIVE],
-                                  chan_name);
-                       channel_found = TRUE;
-                       break;
-               }
-       }
-
-       if (!channel_found) {
-               for (i = 0; i < config->digital_pods; i++) {
-                       if (state->digital_pods[i]) {
-                               g_snprintf(chan_name, sizeof(chan_name), "POD%d", i);
-                               g_snprintf(tmp_str, sizeof(tmp_str),
-                                          (*config->scpi_dialect)[SCPI_CMD_GET_SAMPLE_RATE_LIVE],
-                                          chan_name);
-                               channel_found = TRUE;
-                               break;
-                       }
-               }
-       }
-
-       /* No channel is active, ask the instrument for the sample rate
-        * in single shot mode */
-       if (!channel_found) {
-               if (sr_scpi_get_float(sdi->conn,
-                                     (*config->scpi_dialect)[SCPI_CMD_GET_SAMPLE_RATE],
-                                     &tmp_float) != SR_OK)
-                       return SR_ERR;
-
-               state->sample_rate = tmp_float;
-       } else {
-               if (sr_scpi_get_int(sdi->conn, tmp_str, &tmp) != SR_OK)
-                       return SR_ERR;
-               state->sample_rate = tmp / (((float) (*config->timebases)[state->timebase][0] /
-                                            (*config->timebases)[state->timebase][1]) *
-                                           config->num_xdivs);
-       }
-
-       return SR_OK;
-}
-
-SR_PRIV int hmo_scope_state_get(struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct scope_state *state;
-       struct scope_config *config;
-       float tmp_float;
-       unsigned int i;
-
-       devc = sdi->priv;
-       config = devc->model_config;
-       state = devc->model_state;
-
-       sr_info("Fetching scope state");
-
-       if (analog_channel_state_get(sdi->conn, config, state) != SR_OK)
-               return SR_ERR;
-
-       if (digital_channel_state_get(sdi->conn, config, state) != SR_OK)
-               return SR_ERR;
-
-       if (sr_scpi_get_float(sdi->conn,
-                       (*config->scpi_dialect)[SCPI_CMD_GET_TIMEBASE],
-                       &tmp_float) != SR_OK)
-               return SR_ERR;
-
-       for (i = 0; i < config->num_timebases; i++) {
-               if (tmp_float == ((float) (*config->timebases)[i][0] /
-                                 (*config->timebases)[i][1])) {
-                       state->timebase = i;
-                       break;
-               }
-       }
-       if (i == config->num_timebases)
-               return SR_ERR;
-
-       if (sr_scpi_get_float(sdi->conn,
-                       (*config->scpi_dialect)[SCPI_CMD_GET_HORIZ_TRIGGERPOS],
-                       &tmp_float) != SR_OK)
-               return SR_ERR;
-       state->horiz_triggerpos = tmp_float /
-               (((double) (*config->timebases)[state->timebase][0] /
-                 (*config->timebases)[state->timebase][1]) * config->num_xdivs);
-       state->horiz_triggerpos -= 0.5;
-       state->horiz_triggerpos *= -1;
-
-       if (scope_state_get_array_option(sdi->conn,
-                       (*config->scpi_dialect)[SCPI_CMD_GET_TRIGGER_SOURCE],
-                       config->trigger_sources, &state->trigger_source) != SR_OK)
-               return SR_ERR;
-
-       if (scope_state_get_array_option(sdi->conn,
-               (*config->scpi_dialect)[SCPI_CMD_GET_TRIGGER_SLOPE],
-               config->trigger_slopes, &state->trigger_slope) != SR_OK)
-               return SR_ERR;
-
-       if (hmo_update_sample_rate(sdi) != SR_OK)
-               return SR_ERR;
-
-       sr_info("Fetching finished.");
-
-       scope_state_dump(config, state);
-
-       return SR_OK;
-}
-
-static struct scope_state *scope_state_new(struct scope_config *config)
-{
-       struct scope_state *state;
-
-       if (!(state = g_try_malloc0(sizeof(struct scope_state))))
-               return NULL;
-
-       if (!(state->analog_channels = g_try_malloc0_n(config->analog_channels,
-                                   sizeof(struct analog_channel_state))))
-           goto fail;
-
-       if (!(state->digital_channels = g_try_malloc0_n(
-                       config->digital_channels, sizeof(gboolean))))
-           goto fail;
-
-       if (!(state->digital_pods = g_try_malloc0_n(config->digital_pods,
-                                                    sizeof(gboolean))))
-           goto fail;
-
-       return state;
-
-fail:
-       if (state->analog_channels)
-               g_free(state->analog_channels);
-       if (state->digital_channels)
-               g_free(state->digital_channels);
-       if (state->digital_pods)
-               g_free(state->digital_pods);
-       g_free(state);
-
-       return NULL;
-}
-
-SR_PRIV void hmo_scope_state_free(struct scope_state *state)
-{
-       g_free(state->analog_channels);
-       g_free(state->digital_channels);
-       g_free(state->digital_pods);
-       g_free(state);
-}
-
-SR_PRIV int hmo_init_device(struct sr_dev_inst *sdi)
-{
-       char tmp[25];
-       int model_index;
-       unsigned int i, j;
-       struct sr_channel *ch;
-       struct dev_context *devc;
-
-       devc = sdi->priv;
-       model_index = -1;
-
-       /* Find the exact model. */
-       for (i = 0; i < ARRAY_SIZE(scope_models); i++) {
-               for (j = 0; scope_models[i].name[j]; j++) {
-                       if (!strcmp(sdi->model, scope_models[i].name[j])) {
-                               model_index = i;
-                               break;
-                       }
-               }
-               if (model_index != -1)
-                       break;
-       }
-
-       if (model_index == -1) {
-               sr_dbg("Unsupported HMO device.");
-               return SR_ERR_NA;
-       }
-
-       if (!(devc->analog_groups = g_try_malloc0(sizeof(struct sr_channel_group) *
-                                                 scope_models[model_index].analog_channels)))
-                       return SR_ERR_MALLOC;
-
-       if (!(devc->digital_groups = g_try_malloc0(sizeof(struct sr_channel_group) *
-                                                  scope_models[model_index].digital_pods)))
-                       return SR_ERR_MALLOC;
-
-       /* Add analog channels. */
-       for (i = 0; i < scope_models[model_index].analog_channels; i++) {
-               if (!(ch = sr_channel_new(i, SR_CHANNEL_ANALOG, TRUE,
-                          (*scope_models[model_index].analog_names)[i])))
-                       return SR_ERR_MALLOC;
-               sdi->channels = g_slist_append(sdi->channels, ch);
-
-               devc->analog_groups[i].name =
-                       (char *)(*scope_models[model_index].analog_names)[i];
-               devc->analog_groups[i].channels = g_slist_append(NULL, ch);
-
-               sdi->channel_groups = g_slist_append(sdi->channel_groups,
-                                                  &devc->analog_groups[i]);
-       }
-
-       /* Add digital channel groups. */
-       for (i = 0; i < scope_models[model_index].digital_pods; ++i) {
-               g_snprintf(tmp, 25, "POD%d", i);
-               devc->digital_groups[i].name = g_strdup(tmp);
-               sdi->channel_groups = g_slist_append(sdi->channel_groups,
-                                  &devc->digital_groups[i < 8 ? 0 : 1]);
-       }
-
-       /* Add digital channels. */
-       for (i = 0; i < scope_models[model_index].digital_channels; i++) {
-               if (!(ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE,
-                          (*scope_models[model_index].digital_names)[i])))
-                       return SR_ERR_MALLOC;
-               sdi->channels = g_slist_append(sdi->channels, ch);
-
-               devc->digital_groups[i < 8 ? 0 : 1].channels = g_slist_append(
-                       devc->digital_groups[i < 8 ? 0 : 1].channels, ch);
-       }
-
-       devc->model_config = &scope_models[model_index];
-       devc->frame_limit = 0;
-
-       if (!(devc->model_state = scope_state_new(devc->model_config)))
-               return SR_ERR_MALLOC;
-
-       return SR_OK;
-}
-
-SR_PRIV int hmo_receive_data(int fd, int revents, void *cb_data)
-{
-       struct sr_channel *ch;
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-       struct sr_datafeed_packet packet;
-       GArray *data;
-       struct sr_datafeed_analog analog;
-       struct sr_datafeed_logic logic;
-
-       (void)fd;
-
-       if (!(sdi = cb_data))
-               return TRUE;
-
-       if (!(devc = sdi->priv))
-               return TRUE;
-
-       if (revents == G_IO_IN) {
-               ch = devc->current_channel->data;
-
-               switch (ch->type) {
-               case SR_CHANNEL_ANALOG:
-                       if (sr_scpi_get_floatv(sdi->conn, NULL, &data) != SR_OK) {
-                               if (data)
-                                       g_array_free(data, TRUE);
-
-                               return TRUE;
-                       }
-
-                       packet.type = SR_DF_FRAME_BEGIN;
-                       sr_session_send(sdi, &packet);
-
-                       analog.channels = g_slist_append(NULL, ch);
-                       analog.num_samples = data->len;
-                       analog.data = (float *) data->data;
-                       analog.mq = SR_MQ_VOLTAGE;
-                       analog.unit = SR_UNIT_VOLT;
-                       analog.mqflags = 0;
-                       packet.type = SR_DF_ANALOG;
-                       packet.payload = &analog;
-                       sr_session_send(cb_data, &packet);
-                       g_slist_free(analog.channels);
-                       g_array_free(data, TRUE);
-                       break;
-               case SR_CHANNEL_LOGIC:
-                       if (sr_scpi_get_uint8v(sdi->conn, NULL, &data) != SR_OK) {
-                               if (data)
-                                       g_free(data);
-                               return TRUE;
-                       }
-
-                       packet.type = SR_DF_FRAME_BEGIN;
-                       sr_session_send(sdi, &packet);
-
-                       logic.length = data->len;
-                       logic.unitsize = 1;
-                       logic.data = data->data;
-                       packet.type = SR_DF_LOGIC;
-                       packet.payload = &logic;
-                       sr_session_send(cb_data, &packet);
-                       g_array_free(data, TRUE);
-                       break;
-               default:
-                       sr_err("Invalid channel type.");
-                       break;
-               }
-
-               packet.type = SR_DF_FRAME_END;
-               sr_session_send(sdi, &packet);
-
-               if (devc->current_channel->next) {
-                       devc->current_channel = devc->current_channel->next;
-                       hmo_request_data(sdi);
-               } else if (++devc->num_frames == devc->frame_limit) {
-                       sdi->driver->dev_acquisition_stop(sdi, cb_data);
-               } else {
-                       devc->current_channel = devc->enabled_channels;
-                       hmo_request_data(sdi);
-               }
-       }
-
-       return TRUE;
-}
diff --git a/hardware/hameg-hmo/protocol.h b/hardware/hameg-hmo/protocol.h
deleted file mode 100644 (file)
index bdf70fc..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * 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/>.
- */
-
-#ifndef LIBSIGROK_HARDWARE_HAMEG_HMO_PROTOCOL_H
-#define LIBSIGROK_HARDWARE_HAMEG_HMO_PROTOCOL_H
-
-#include <glib.h>
-#include <stdint.h>
-#include <string.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "hameg-hmo"
-
-#define MAX_INSTRUMENT_VERSIONS 10
-#define MAX_COMMAND_SIZE 31
-
-struct scope_config {
-       const char *name[MAX_INSTRUMENT_VERSIONS];
-       const uint8_t analog_channels;
-       const uint8_t digital_channels;
-       const uint8_t digital_pods;
-
-       const char *(*analog_names)[];
-       const char *(*digital_names)[];
-
-       const int32_t (*hw_caps)[];
-       const uint8_t num_hwcaps;
-
-       const int32_t (*analog_hwcaps)[];
-       const uint8_t num_analog_hwcaps;
-
-       const char *(*coupling_options)[];
-       const uint8_t num_coupling_options;
-
-       const char *(*trigger_sources)[];
-       const uint8_t num_trigger_sources;
-
-       const char *(*trigger_slopes)[];
-
-       const uint64_t (*timebases)[][2];
-       const uint8_t num_timebases;
-
-       const uint64_t (*vdivs)[][2];
-       const uint8_t num_vdivs;
-
-       const uint8_t num_xdivs;
-       const uint8_t num_ydivs;
-
-       const char *(*scpi_dialect)[];
-};
-
-struct analog_channel_state {
-       int coupling;
-
-       int vdiv;
-       float vertical_offset;
-
-       gboolean state;
-};
-
-struct scope_state {
-       struct analog_channel_state *analog_channels;
-       gboolean *digital_channels;
-       gboolean *digital_pods;
-
-       int timebase;
-       float horiz_triggerpos;
-
-       int trigger_source;
-       int trigger_slope;
-       uint64_t sample_rate;
-};
-
-/** Private, per-device-instance driver context. */
-struct dev_context {
-       void *model_config;
-       void *model_state;
-
-       struct sr_channel_group *analog_groups;
-       struct sr_channel_group *digital_groups;
-
-       GSList *enabled_channels;
-       GSList *current_channel;
-       uint64_t num_frames;
-
-       uint64_t frame_limit;
-};
-
-SR_PRIV int hmo_init_device(struct sr_dev_inst *sdi);
-SR_PRIV int hmo_request_data(const struct sr_dev_inst *sdi);
-SR_PRIV int hmo_receive_data(int fd, int revents, void *cb_data);
-
-SR_PRIV struct scope_state *hmo_scope_state_new(struct scope_config *config);
-SR_PRIV void hmo_scope_state_free(struct scope_state *state);
-SR_PRIV int hmo_scope_state_get(struct sr_dev_inst *sdi);
-SR_PRIV int hmo_update_sample_rate(const struct sr_dev_inst *sdi);
-
-#endif
diff --git a/hardware/hantek-dso/api.c b/hardware/hantek-dso/api.c
deleted file mode 100644 (file)
index c948e42..0000000
+++ /dev/null
@@ -1,976 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012 Bert Vermeulen <bert@biot.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#include <sys/time.h>
-#include <inttypes.h>
-#include <glib.h>
-#include <libusb.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-#include "dso.h"
-
-/* Max time in ms before we want to check on USB events */
-/* TODO tune this properly */
-#define TICK 1
-
-#define NUM_TIMEBASE  10
-#define NUM_VDIV      8
-
-static const int32_t scanopts[] = {
-       SR_CONF_CONN,
-};
-
-static const int32_t devopts[] = {
-       SR_CONF_OSCILLOSCOPE,
-       SR_CONF_LIMIT_FRAMES,
-       SR_CONF_CONTINUOUS,
-       SR_CONF_TIMEBASE,
-       SR_CONF_BUFFERSIZE,
-       SR_CONF_TRIGGER_SOURCE,
-       SR_CONF_TRIGGER_SLOPE,
-       SR_CONF_HORIZ_TRIGGERPOS,
-       SR_CONF_FILTER,
-       SR_CONF_VDIV,
-       SR_CONF_COUPLING,
-       SR_CONF_NUM_TIMEBASE,
-       SR_CONF_NUM_VDIV,
-};
-
-static const char *channel_names[] = {
-       "CH1", "CH2",
-       NULL,
-};
-
-static const uint64_t buffersizes_32k[] = {
-       10240, 32768,
-};
-static const uint64_t buffersizes_512k[] = {
-       10240, 524288,
-};
-static const uint64_t buffersizes_14k[] = {
-       10240, 14336,
-};
-
-static const struct dso_profile dev_profiles[] = {
-       {       0x04b4, 0x2090, 0x04b5, 0x2090,
-               "Hantek", "DSO-2090",
-               buffersizes_32k,
-               FIRMWARE_DIR "/hantek-dso-2090.fw" },
-       {       0x04b4, 0x2150, 0x04b5, 0x2150,
-               "Hantek", "DSO-2150",
-               buffersizes_32k,
-               FIRMWARE_DIR "/hantek-dso-2150.fw" },
-       {       0x04b4, 0x2250, 0x04b5, 0x2250,
-               "Hantek", "DSO-2250",
-               buffersizes_512k,
-               FIRMWARE_DIR "/hantek-dso-2250.fw" },
-       {       0x04b4, 0x5200, 0x04b5, 0x5200,
-               "Hantek", "DSO-5200",
-               buffersizes_14k,
-               FIRMWARE_DIR "/hantek-dso-5200.fw" },
-       {       0x04b4, 0x520a, 0x04b5, 0x520a,
-               "Hantek", "DSO-5200A",
-               buffersizes_512k,
-               FIRMWARE_DIR "/hantek-dso-5200A.fw" },
-       { 0, 0, 0, 0, 0, 0, 0, 0 },
-};
-
-static const uint64_t timebases[][2] = {
-       /* microseconds */
-       { 10, 1000000 },
-       { 20, 1000000 },
-       { 40, 1000000 },
-       { 100, 1000000 },
-       { 200, 1000000 },
-       { 400, 1000000 },
-       /* milliseconds */
-       { 1, 1000 },
-       { 2, 1000 },
-       { 4, 1000 },
-       { 10, 1000 },
-       { 20, 1000 },
-       { 40, 1000 },
-       { 100, 1000 },
-       { 200, 1000 },
-       { 400, 1000 },
-};
-
-static const uint64_t vdivs[][2] = {
-       /* millivolts */
-       { 10, 1000 },
-       { 20, 1000 },
-       { 50, 1000 },
-       { 100, 1000 },
-       { 200, 1000 },
-       { 500, 1000 },
-       /* volts */
-       { 1, 1 },
-       { 2, 1 },
-       { 5, 1 },
-};
-
-static const char *trigger_sources[] = {
-       "CH1",
-       "CH2",
-       "EXT",
-       /* TODO: forced */
-};
-
-static const char *filter_targets[] = {
-       "CH1",
-       "CH2",
-       /* TODO: "TRIGGER", */
-};
-
-static const char *coupling[] = {
-       "AC",
-       "DC",
-       "GND",
-};
-
-SR_PRIV struct sr_dev_driver hantek_dso_driver_info;
-static struct sr_dev_driver *di = &hantek_dso_driver_info;
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data);
-
-static struct sr_dev_inst *dso_dev_new(int index, const struct dso_profile *prof)
-{
-       struct sr_dev_inst *sdi;
-       struct sr_channel *ch;
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       int i;
-
-       sdi = sr_dev_inst_new(index, SR_ST_INITIALIZING,
-               prof->vendor, prof->model, NULL);
-       if (!sdi)
-               return NULL;
-       sdi->driver = di;
-
-       /*
-        * Add only the real channels -- EXT isn't a source of data, only
-        * a trigger source internal to the device.
-        */
-       for (i = 0; channel_names[i]; i++) {
-               if (!(ch = sr_channel_new(i, SR_CHANNEL_ANALOG, TRUE,
-                               channel_names[i])))
-                       return NULL;
-               sdi->channels = g_slist_append(sdi->channels, ch);
-       }
-
-       if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
-               sr_err("Device context malloc failed.");
-               return NULL;
-       }
-
-       devc->profile = prof;
-       devc->dev_state = IDLE;
-       devc->timebase = DEFAULT_TIMEBASE;
-       devc->ch1_enabled = TRUE;
-       devc->ch2_enabled = TRUE;
-       devc->voltage_ch1 = DEFAULT_VOLTAGE;
-       devc->voltage_ch2 = DEFAULT_VOLTAGE;
-       devc->coupling_ch1 = DEFAULT_COUPLING;
-       devc->coupling_ch2 = DEFAULT_COUPLING;
-       devc->voffset_ch1 = DEFAULT_VERT_OFFSET;
-       devc->voffset_ch2 = DEFAULT_VERT_OFFSET;
-       devc->voffset_trigger = DEFAULT_VERT_TRIGGERPOS;
-       devc->framesize = DEFAULT_FRAMESIZE;
-       devc->triggerslope = SLOPE_POSITIVE;
-       devc->triggersource = g_strdup(DEFAULT_TRIGGER_SOURCE);
-       devc->triggerposition = DEFAULT_HORIZ_TRIGGERPOS;
-       sdi->priv = devc;
-       drvc = di->priv;
-       drvc->instances = g_slist_append(drvc->instances, sdi);
-
-       return sdi;
-}
-
-static int configure_channels(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_channel *ch;
-       const GSList *l;
-       int p;
-
-       devc = sdi->priv;
-
-       g_slist_free(devc->enabled_channels);
-       devc->ch1_enabled = devc->ch2_enabled = FALSE;
-       for (l = sdi->channels, p = 0; l; l = l->next, p++) {
-               ch = l->data;
-               if (p == 0)
-                       devc->ch1_enabled = ch->enabled;
-               else
-                       devc->ch2_enabled = ch->enabled;
-               if (ch->enabled)
-                       devc->enabled_channels = g_slist_append(devc->enabled_channels, ch);
-       }
-
-       return SR_OK;
-}
-
-static void clear_dev_context(void *priv)
-{
-       struct dev_context *devc;
-
-       devc = priv;
-       g_free(devc->triggersource);
-       g_slist_free(devc->enabled_channels);
-
-}
-
-static int dev_clear(void)
-{
-       return std_dev_clear(di, clear_dev_context);
-}
-
-static int init(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, di, LOG_PREFIX);
-}
-
-static GSList *scan(GSList *options)
-{
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       struct sr_dev_inst *sdi;
-       struct sr_usb_dev_inst *usb;
-       struct sr_config *src;
-       const struct dso_profile *prof;
-       GSList *l, *devices, *conn_devices;
-       struct libusb_device_descriptor des;
-       libusb_device **devlist;
-       int devcnt, ret, i, j;
-       const char *conn;
-
-       drvc = di->priv;
-
-       devcnt = 0;
-       devices = 0;
-
-       conn = NULL;
-       for (l = options; l; l = l->next) {
-               src = l->data;
-               if (src->key == SR_CONF_CONN) {
-                       conn = g_variant_get_string(src->data, NULL);
-                       break;
-               }
-       }
-       if (conn)
-               conn_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn);
-       else
-               conn_devices = NULL;
-
-       /* Find all Hantek DSO devices and upload firmware to all of them. */
-       libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
-       for (i = 0; devlist[i]; i++) {
-               if (conn) {
-                       usb = NULL;
-                       for (l = conn_devices; l; l = l->next) {
-                               usb = l->data;
-                               if (usb->bus == libusb_get_bus_number(devlist[i])
-                                       && usb->address == libusb_get_device_address(devlist[i]))
-                                       break;
-                       }
-                       if (!l)
-                               /* This device matched none of the ones that
-                                * matched the conn specification. */
-                               continue;
-               }
-
-               if ((ret = libusb_get_device_descriptor(devlist[i], &des))) {
-                       sr_err("Failed to get device descriptor: %s.",
-                                       libusb_error_name(ret));
-                       continue;
-               }
-
-               prof = NULL;
-               for (j = 0; dev_profiles[j].orig_vid; j++) {
-                       if (des.idVendor == dev_profiles[j].orig_vid
-                               && des.idProduct == dev_profiles[j].orig_pid) {
-                               /* Device matches the pre-firmware profile. */
-                               prof = &dev_profiles[j];
-                               sr_dbg("Found a %s %s.", prof->vendor, prof->model);
-                               sdi = dso_dev_new(devcnt, prof);
-                               devices = g_slist_append(devices, sdi);
-                               devc = sdi->priv;
-                               if (ezusb_upload_firmware(devlist[i], USB_CONFIGURATION,
-                                               prof->firmware) == SR_OK)
-                                       /* Remember when the firmware on this device was updated */
-                                       devc->fw_updated = g_get_monotonic_time();
-                               else
-                                       sr_err("Firmware upload failed for "
-                                               "device %d.", devcnt);
-                               /* Dummy USB address of 0xff will get overwritten later. */
-                               sdi->conn = sr_usb_dev_inst_new(
-                                               libusb_get_bus_number(devlist[i]), 0xff, NULL);
-                               devcnt++;
-                               break;
-                       } else if (des.idVendor == dev_profiles[j].fw_vid
-                               && des.idProduct == dev_profiles[j].fw_pid) {
-                               /* Device matches the post-firmware profile. */
-                               prof = &dev_profiles[j];
-                               sr_dbg("Found a %s %s.", prof->vendor, prof->model);
-                               sdi = dso_dev_new(devcnt, prof);
-                               sdi->status = SR_ST_INACTIVE;
-                               devices = g_slist_append(devices, sdi);
-                               devc = sdi->priv;
-                               sdi->inst_type = SR_INST_USB;
-                               sdi->conn = sr_usb_dev_inst_new(
-                                               libusb_get_bus_number(devlist[i]),
-                                               libusb_get_device_address(devlist[i]), NULL);
-                               devcnt++;
-                               break;
-                       }
-               }
-               if (!prof)
-                       /* not a supported VID/PID */
-                       continue;
-       }
-       libusb_free_device_list(devlist, 1);
-
-       return devices;
-}
-
-static GSList *dev_list(void)
-{
-       return ((struct drv_context *)(di->priv))->instances;
-}
-
-static int dev_open(struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_usb_dev_inst *usb;
-       int64_t timediff_us, timediff_ms;
-       int err;
-
-       devc = sdi->priv;
-       usb = sdi->conn;
-
-       /*
-        * If the firmware was recently uploaded, wait up to MAX_RENUM_DELAY_MS
-        * for the FX2 to renumerate.
-        */
-       err = SR_ERR;
-       if (devc->fw_updated > 0) {
-               sr_info("Waiting for device to reset.");
-               /* Takes >= 300ms for the FX2 to be gone from the USB bus. */
-               g_usleep(300 * 1000);
-               timediff_ms = 0;
-               while (timediff_ms < MAX_RENUM_DELAY_MS) {
-                       if ((err = dso_open(sdi)) == SR_OK)
-                               break;
-                       g_usleep(100 * 1000);
-                       timediff_us = g_get_monotonic_time() - devc->fw_updated;
-                       timediff_ms = timediff_us / 1000;
-                       sr_spew("Waited %" PRIi64 " ms.", timediff_ms);
-               }
-               sr_info("Device came back after %d ms.", timediff_ms);
-       } else {
-               err = dso_open(sdi);
-       }
-
-       if (err != SR_OK) {
-               sr_err("Unable to open device.");
-               return SR_ERR;
-       }
-
-       err = libusb_claim_interface(usb->devhdl, USB_INTERFACE);
-       if (err != 0) {
-               sr_err("Unable to claim interface: %s.",
-                          libusb_error_name(err));
-               return SR_ERR;
-       }
-
-       return SR_OK;
-}
-
-static int dev_close(struct sr_dev_inst *sdi)
-{
-       dso_close(sdi);
-
-       return SR_OK;
-}
-
-static int cleanup(void)
-{
-       return dev_clear();
-}
-
-static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct sr_usb_dev_inst *usb;
-       char str[128];
-
-       (void)cg;
-
-       switch (id) {
-       case SR_CONF_CONN:
-               if (!sdi || !sdi->conn)
-                       return SR_ERR_ARG;
-               usb = sdi->conn;
-               if (usb->address == 255)
-                       /* Device still needs to re-enumerate after firmware
-                        * upload, so we don't know its (future) address. */
-                       return SR_ERR;
-               snprintf(str, 128, "%d.%d", usb->bus, usb->address);
-               *data = g_variant_new_string(str);
-               break;
-       case SR_CONF_NUM_TIMEBASE:
-               *data = g_variant_new_int32(NUM_TIMEBASE);
-               break;
-       case SR_CONF_NUM_VDIV:
-               *data = g_variant_new_int32(NUM_VDIV);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       double tmp_double;
-       uint64_t tmp_u64, p, q;
-       int tmp_int, ret;
-       unsigned int i;
-       const char *tmp_str;
-       char **targets;
-
-       (void)cg;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       ret = SR_OK;
-       devc = sdi->priv;
-       switch (id) {
-       case SR_CONF_LIMIT_FRAMES:
-               devc->limit_frames = g_variant_get_uint64(data);
-               break;
-       case SR_CONF_TRIGGER_SLOPE:
-               tmp_str = g_variant_get_string(data, NULL);
-               if (!tmp_str || !(tmp_str[0] == 'f' || tmp_str[0] == 'r'))
-                       return SR_ERR_ARG;
-               devc->triggerslope = (tmp_str[0] == 'r')
-                       ? SLOPE_POSITIVE : SLOPE_NEGATIVE;
-               break;
-       case SR_CONF_HORIZ_TRIGGERPOS:
-               tmp_double = g_variant_get_double(data);
-               if (tmp_double < 0.0 || tmp_double > 1.0) {
-                       sr_err("Trigger position should be between 0.0 and 1.0.");
-                       ret = SR_ERR_ARG;
-               } else
-                       devc->triggerposition = tmp_double;
-               break;
-       case SR_CONF_BUFFERSIZE:
-               tmp_u64 = g_variant_get_uint64(data);
-               for (i = 0; i < 2; i++) {
-                       if (devc->profile->buffersizes[i] == tmp_u64) {
-                               devc->framesize = tmp_u64;
-                               break;
-                       }
-               }
-               if (i == 2)
-                       ret = SR_ERR_ARG;
-               break;
-       case SR_CONF_TIMEBASE:
-               g_variant_get(data, "(tt)", &p, &q);
-               tmp_int = -1;
-               for (i = 0; i < ARRAY_SIZE(timebases); i++) {
-                       if (timebases[i][0] == p && timebases[i][1] == q) {
-                               tmp_int = i;
-                               break;
-                       }
-               }
-               if (tmp_int >= 0)
-                       devc->timebase = tmp_int;
-               else
-                       ret = SR_ERR_ARG;
-               break;
-       case SR_CONF_TRIGGER_SOURCE:
-               tmp_str = g_variant_get_string(data, NULL);
-               for (i = 0; trigger_sources[i]; i++) {
-                       if (!strcmp(tmp_str, trigger_sources[i])) {
-                               devc->triggersource = g_strdup(tmp_str);
-                               break;
-                       }
-               }
-               if (trigger_sources[i] == 0)
-                       ret = SR_ERR_ARG;
-               break;
-       case SR_CONF_FILTER:
-               tmp_str = g_variant_get_string(data, NULL);
-               devc->filter_ch1 = devc->filter_ch2 = devc->filter_trigger = 0;
-               targets = g_strsplit(tmp_str, ",", 0);
-               for (i = 0; targets[i]; i++) {
-                       if (targets[i] == '\0')
-                               /* Empty filter string can be used to clear them all. */
-                               ;
-                       else if (!strcmp(targets[i], "CH1"))
-                               devc->filter_ch1 = TRUE;
-                       else if (!strcmp(targets[i], "CH2"))
-                               devc->filter_ch2 = TRUE;
-                       else if (!strcmp(targets[i], "TRIGGER"))
-                               devc->filter_trigger = TRUE;
-                       else {
-                               sr_err("Invalid filter target %s.", targets[i]);
-                               ret = SR_ERR_ARG;
-                       }
-               }
-               g_strfreev(targets);
-               break;
-       case SR_CONF_VDIV:
-               /* TODO: Not supporting vdiv per channel yet. */
-               g_variant_get(data, "(tt)", &p, &q);
-               tmp_int = -1;
-               for (i = 0; i < ARRAY_SIZE(vdivs); i++) {
-                       if (vdivs[i][0] == p && vdivs[i][1] == q) {
-                               tmp_int = i;
-                               break;
-                       }
-               }
-               if (tmp_int >= 0) {
-                       devc->voltage_ch1 = tmp_int;
-                       devc->voltage_ch2 = tmp_int;
-               } else
-                       ret = SR_ERR_ARG;
-               break;
-       case SR_CONF_COUPLING:
-               tmp_str = g_variant_get_string(data, NULL);
-               /* TODO: Not supporting coupling per channel yet. */
-               for (i = 0; coupling[i]; i++) {
-                       if (!strcmp(tmp_str, coupling[i])) {
-                               devc->coupling_ch1 = i;
-                               devc->coupling_ch2 = i;
-                               break;
-                       }
-               }
-               if (coupling[i] == 0)
-                       ret = SR_ERR_ARG;
-               break;
-       default:
-               ret = SR_ERR_NA;
-               break;
-       }
-
-       return ret;
-}
-
-static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       GVariant *tuple, *rational[2];
-       GVariantBuilder gvb;
-       unsigned int i;
-
-       (void)cg;
-
-       switch (key) {
-       case SR_CONF_SCAN_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               scanopts, ARRAY_SIZE(scanopts), sizeof(int32_t));
-               break;
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               devopts, ARRAY_SIZE(devopts), sizeof(int32_t));
-               break;
-       case SR_CONF_BUFFERSIZE:
-               if (!sdi)
-                       return SR_ERR_ARG;
-               devc = sdi->priv;
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT64,
-                               devc->profile->buffersizes, 2, sizeof(uint64_t));
-               break;
-       case SR_CONF_COUPLING:
-               *data = g_variant_new_strv(coupling, ARRAY_SIZE(coupling));
-               break;
-       case SR_CONF_VDIV:
-               g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
-               for (i = 0; i < ARRAY_SIZE(vdivs); i++) {
-                       rational[0] = g_variant_new_uint64(vdivs[i][0]);
-                       rational[1] = g_variant_new_uint64(vdivs[i][1]);
-                       tuple = g_variant_new_tuple(rational, 2);
-                       g_variant_builder_add_value(&gvb, tuple);
-               }
-               *data = g_variant_builder_end(&gvb);
-               break;
-       case SR_CONF_FILTER:
-               *data = g_variant_new_strv(filter_targets,
-                               ARRAY_SIZE(filter_targets));
-               break;
-       case SR_CONF_TIMEBASE:
-               g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
-               for (i = 0; i < ARRAY_SIZE(timebases); i++) {
-                       rational[0] = g_variant_new_uint64(timebases[i][0]);
-                       rational[1] = g_variant_new_uint64(timebases[i][1]);
-                       tuple = g_variant_new_tuple(rational, 2);
-                       g_variant_builder_add_value(&gvb, tuple);
-               }
-               *data = g_variant_builder_end(&gvb);
-               break;
-       case SR_CONF_TRIGGER_SOURCE:
-               *data = g_variant_new_strv(trigger_sources,
-                               ARRAY_SIZE(trigger_sources));
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static void send_chunk(struct sr_dev_inst *sdi, unsigned char *buf,
-               int num_samples)
-{
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_analog analog;
-       struct dev_context *devc;
-       float ch1, ch2, range;
-       int num_channels, data_offset, i;
-
-       devc = sdi->priv;
-       num_channels = (devc->ch1_enabled && devc->ch2_enabled) ? 2 : 1;
-       packet.type = SR_DF_ANALOG;
-       packet.payload = &analog;
-       /* TODO: support for 5xxx series 9-bit samples */
-       analog.channels = devc->enabled_channels;
-       analog.num_samples = num_samples;
-       analog.mq = SR_MQ_VOLTAGE;
-       analog.unit = SR_UNIT_VOLT;
-       /* TODO: Check malloc return value. */
-       analog.data = g_try_malloc(analog.num_samples * sizeof(float) * num_channels);
-       data_offset = 0;
-       for (i = 0; i < analog.num_samples; i++) {
-               /*
-                * The device always sends data for both channels. If a channel
-                * is disabled, it contains a copy of the enabled channel's
-                * data. However, we only send the requested channels to
-                * the bus.
-                *
-                * Voltage values are encoded as a value 0-255 (0-512 on the
-                * DSO-5200*), where the value is a point in the range
-                * represented by the vdiv setting. There are 8 vertical divs,
-                * so e.g. 500mV/div represents 4V peak-to-peak where 0 = -2V
-                * and 255 = +2V.
-                */
-               /* TODO: Support for DSO-5xxx series 9-bit samples. */
-               if (devc->ch1_enabled) {
-                       range = ((float)vdivs[devc->voltage_ch1][0] / vdivs[devc->voltage_ch1][1]) * 8;
-                       ch1 = range / 255 * *(buf + i * 2 + 1);
-                       /* Value is centered around 0V. */
-                       ch1 -= range / 2;
-                       analog.data[data_offset++] = ch1;
-               }
-               if (devc->ch2_enabled) {
-                       range = ((float)vdivs[devc->voltage_ch2][0] / vdivs[devc->voltage_ch2][1]) * 8;
-                       ch2 = range / 255 * *(buf + i * 2);
-                       ch2 -= range / 2;
-                       analog.data[data_offset++] = ch2;
-               }
-       }
-       sr_session_send(devc->cb_data, &packet);
-}
-
-/*
- * Called by libusb (as triggered by handle_event()) when a transfer comes in.
- * Only channel data comes in asynchronously, and all transfers for this are
- * queued up beforehand, so this just needs to chuck the incoming data onto
- * the libsigrok session bus.
- */
-static void receive_transfer(struct libusb_transfer *transfer)
-{
-       struct sr_datafeed_packet packet;
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-       int num_samples, pre;
-
-       sdi = transfer->user_data;
-       devc = sdi->priv;
-       sr_spew("receive_transfer(): status %d received %d bytes.",
-                  transfer->status, transfer->actual_length);
-
-       if (transfer->actual_length == 0)
-               /* Nothing to send to the bus. */
-               return;
-
-       num_samples = transfer->actual_length / 2;
-
-       sr_spew("Got %d-%d/%d samples in frame.", devc->samp_received + 1,
-                  devc->samp_received + num_samples, devc->framesize);
-
-       /*
-        * The device always sends a full frame, but the beginning of the frame
-        * doesn't represent the trigger point. The offset at which the trigger
-        * happened came in with the capture state, so we need to start sending
-        * from there up the session bus. The samples in the frame buffer
-        * before that trigger point came after the end of the device's frame
-        * buffer was reached, and it wrapped around to overwrite up until the
-        * trigger point.
-        */
-       if (devc->samp_received < devc->trigger_offset) {
-               /* Trigger point not yet reached. */
-               if (devc->samp_received + num_samples < devc->trigger_offset) {
-                       /* The entire chunk is before the trigger point. */
-                       memcpy(devc->framebuf + devc->samp_buffered * 2,
-                                       transfer->buffer, num_samples * 2);
-                       devc->samp_buffered += num_samples;
-               } else {
-                       /*
-                        * This chunk hits or overruns the trigger point.
-                        * Store the part before the trigger fired, and
-                        * send the rest up to the session bus.
-                        */
-                       pre = devc->trigger_offset - devc->samp_received;
-                       memcpy(devc->framebuf + devc->samp_buffered * 2,
-                                       transfer->buffer, pre * 2);
-                       devc->samp_buffered += pre;
-
-                       /* The rest of this chunk starts with the trigger point. */
-                       sr_dbg("Reached trigger point, %d samples buffered.",
-                                  devc->samp_buffered);
-
-                       /* Avoid the corner case where the chunk ended at
-                        * exactly the trigger point. */
-                       if (num_samples > pre)
-                               send_chunk(sdi, transfer->buffer + pre * 2,
-                                               num_samples - pre);
-               }
-       } else {
-               /* Already past the trigger point, just send it all out. */
-               send_chunk(sdi, transfer->buffer,
-                               num_samples);
-       }
-
-       devc->samp_received += num_samples;
-
-       /* Everything in this transfer was either copied to the buffer or
-        * sent to the session bus. */
-       g_free(transfer->buffer);
-       libusb_free_transfer(transfer);
-
-       if (devc->samp_received >= devc->framesize) {
-               /* That was the last chunk in this frame. Send the buffered
-                * pre-trigger samples out now, in one big chunk. */
-               sr_dbg("End of frame, sending %d pre-trigger buffered samples.",
-                          devc->samp_buffered);
-               send_chunk(sdi, devc->framebuf, devc->samp_buffered);
-
-               /* Mark the end of this frame. */
-               packet.type = SR_DF_FRAME_END;
-               sr_session_send(devc->cb_data, &packet);
-
-               if (devc->limit_frames && ++devc->num_frames == devc->limit_frames) {
-                       /* Terminate session */
-                       devc->dev_state = STOPPING;
-               } else {
-                       devc->dev_state = NEW_CAPTURE;
-               }
-       }
-}
-
-static int handle_event(int fd, int revents, void *cb_data)
-{
-       const struct sr_dev_inst *sdi;
-       struct sr_datafeed_packet packet;
-       struct timeval tv;
-       struct dev_context *devc;
-       struct drv_context *drvc = di->priv;
-       int num_channels;
-       uint32_t trigger_offset;
-       uint8_t capturestate;
-
-       (void)fd;
-       (void)revents;
-
-       sdi = cb_data;
-       devc = sdi->priv;
-       if (devc->dev_state == STOPPING) {
-               /* We've been told to wind up the acquisition. */
-               sr_dbg("Stopping acquisition.");
-               /*
-                * TODO: Doesn't really cancel pending transfers so they might
-                * come in after SR_DF_END is sent.
-                */
-               usb_source_remove(sdi->session, drvc->sr_ctx);
-
-               packet.type = SR_DF_END;
-               sr_session_send(sdi, &packet);
-
-               devc->dev_state = IDLE;
-
-               return TRUE;
-       }
-
-       /* Always handle pending libusb events. */
-       tv.tv_sec = tv.tv_usec = 0;
-       libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
-
-       /* TODO: ugh */
-       if (devc->dev_state == NEW_CAPTURE) {
-               if (dso_capture_start(sdi) != SR_OK)
-                       return TRUE;
-               if (dso_enable_trigger(sdi) != SR_OK)
-                       return TRUE;
-//             if (dso_force_trigger(sdi) != SR_OK)
-//                     return TRUE;
-               sr_dbg("Successfully requested next chunk.");
-               devc->dev_state = CAPTURE;
-               return TRUE;
-       }
-       if (devc->dev_state != CAPTURE)
-               return TRUE;
-
-       if ((dso_get_capturestate(sdi, &capturestate, &trigger_offset)) != SR_OK)
-               return TRUE;
-
-       sr_dbg("Capturestate %d.", capturestate);
-       sr_dbg("Trigger offset 0x%.6x.", trigger_offset);
-       switch (capturestate) {
-       case CAPTURE_EMPTY:
-               if (++devc->capture_empty_count >= MAX_CAPTURE_EMPTY) {
-                       devc->capture_empty_count = 0;
-                       if (dso_capture_start(sdi) != SR_OK)
-                               break;
-                       if (dso_enable_trigger(sdi) != SR_OK)
-                               break;
-//                     if (dso_force_trigger(sdi) != SR_OK)
-//                             break;
-                       sr_dbg("Successfully requested next chunk.");
-               }
-               break;
-       case CAPTURE_FILLING:
-               /* No data yet. */
-               break;
-       case CAPTURE_READY_8BIT:
-               /* Remember where in the captured frame the trigger is. */
-               devc->trigger_offset = trigger_offset;
-
-               num_channels = (devc->ch1_enabled && devc->ch2_enabled) ? 2 : 1;
-               /* TODO: Check malloc return value. */
-               devc->framebuf = g_try_malloc(devc->framesize * num_channels * 2);
-               devc->samp_buffered = devc->samp_received = 0;
-
-               /* Tell the scope to send us the first frame. */
-               if (dso_get_channeldata(sdi, receive_transfer) != SR_OK)
-                       break;
-
-               /*
-                * Don't hit the state machine again until we're done fetching
-                * the data we just told the scope to send.
-                */
-               devc->dev_state = FETCH_DATA;
-
-               /* Tell the frontend a new frame is on the way. */
-               packet.type = SR_DF_FRAME_BEGIN;
-               sr_session_send(sdi, &packet);
-               break;
-       case CAPTURE_READY_9BIT:
-               /* TODO */
-               sr_err("Not yet supported.");
-               break;
-       case CAPTURE_TIMEOUT:
-               /* Doesn't matter, we'll try again next time. */
-               break;
-       default:
-               sr_dbg("Unknown capture state: %d.", capturestate);
-               break;
-       }
-
-       return TRUE;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct dev_context *devc;
-       struct drv_context *drvc = di->priv;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       devc = sdi->priv;
-       devc->cb_data = cb_data;
-
-       if (configure_channels(sdi) != SR_OK) {
-               sr_err("Failed to configure channels.");
-               return SR_ERR;
-       }
-
-       if (dso_init(sdi) != SR_OK)
-               return SR_ERR;
-
-       if (dso_capture_start(sdi) != SR_OK)
-               return SR_ERR;
-
-       devc->dev_state = CAPTURE;
-       usb_source_add(sdi->session, drvc->sr_ctx, TICK, handle_event, (void *)sdi);
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(cb_data, LOG_PREFIX);
-
-       return SR_OK;
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct dev_context *devc;
-
-       (void)cb_data;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR;
-
-       devc = sdi->priv;
-       devc->dev_state = STOPPING;
-
-       return SR_OK;
-}
-
-SR_PRIV struct sr_dev_driver hantek_dso_driver_info = {
-       .name = "hantek-dso",
-       .longname = "Hantek DSO",
-       .api_version = 1,
-       .init = init,
-       .cleanup = cleanup,
-       .scan = scan,
-       .dev_list = dev_list,
-       .dev_clear = dev_clear,
-       .config_get = config_get,
-       .config_set = config_set,
-       .config_list = config_list,
-       .dev_open = dev_open,
-       .dev_close = dev_close,
-       .dev_acquisition_start = dev_acquisition_start,
-       .dev_acquisition_stop = dev_acquisition_stop,
-       .priv = NULL,
-};
diff --git a/hardware/hantek-dso/dso.c b/hardware/hantek-dso/dso.c
deleted file mode 100644 (file)
index da5eb12..0000000
+++ /dev/null
@@ -1,787 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012 Bert Vermeulen <bert@biot.com>
- * With protocol information from the hantekdso project,
- * Copyright (C) 2008 Oleg Khudyakov <prcoder@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 "libsigrok.h"
-#include "libsigrok-internal.h"
-#include "dso.h"
-#include <string.h>
-#include <glib.h>
-#include <libusb.h>
-
-extern struct sr_dev_driver hantek_dso_driver_info;
-
-static int send_begin(const struct sr_dev_inst *sdi)
-{
-       struct sr_usb_dev_inst *usb;
-       int ret;
-       unsigned char buffer[] = {0x0f, 0x03, 0x03, 0x03, 0x68, 0xac, 0xfe,
-       0x00, 0x01, 0x00};
-
-       sr_dbg("Sending CTRL_BEGINCOMMAND.");
-
-       usb = sdi->conn;
-       if ((ret = libusb_control_transfer(usb->devhdl,
-                       LIBUSB_REQUEST_TYPE_VENDOR, CTRL_BEGINCOMMAND,
-                       0, 0, buffer, sizeof(buffer), 200)) != sizeof(buffer)) {
-               sr_err("Failed to send begincommand: %s.",
-                      libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-       return SR_OK;
-}
-
-static int send_bulkcmd(const struct sr_dev_inst *sdi, uint8_t *cmdstring, int cmdlen)
-{
-       struct sr_usb_dev_inst *usb;
-       int ret, tmp;
-
-       usb = sdi->conn;
-
-       if (send_begin(sdi) != SR_OK)
-               return SR_ERR;
-
-       if ((ret = libusb_bulk_transfer(usb->devhdl, DSO_EP_OUT, cmdstring,
-                       cmdlen, &tmp, 200)) != 0)
-               return SR_ERR;
-
-       return SR_OK;
-}
-
-static int dso_getmps(libusb_device *dev)
-{
-       struct libusb_device_descriptor des;
-       struct libusb_config_descriptor *conf_dsc;
-       const struct libusb_interface_descriptor *intf_dsc;
-       int mps;
-
-       if (libusb_get_device_descriptor(dev, &des) != 0)
-               return 0;
-
-       if (des.bNumConfigurations != 1)
-               return 0;
-
-       if (libusb_get_config_descriptor(dev, 0, &conf_dsc) != 0)
-               return 0;
-
-       mps = 0;
-       intf_dsc = &(conf_dsc->interface[0].altsetting[0]);
-       if (intf_dsc->bNumEndpoints != 2)
-               goto err;
-
-       if ((intf_dsc->endpoint[0].bEndpointAddress & 0x8f) !=
-           (2 | LIBUSB_ENDPOINT_OUT))
-               /* The first endpoint should be 2 (outbound). */
-               goto err;
-
-       if ((intf_dsc->endpoint[1].bEndpointAddress & 0x8f) !=
-           (6 | LIBUSB_ENDPOINT_IN))
-               /* The second endpoint should be 6 (inbound). */
-               goto err;
-
-       mps = intf_dsc->endpoint[1].wMaxPacketSize;
-
-err:
-       if (conf_dsc)
-               libusb_free_config_descriptor(conf_dsc);
-
-       return mps;
-}
-
-SR_PRIV int dso_open(struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct drv_context *drvc = hantek_dso_driver_info.priv;
-       struct sr_usb_dev_inst *usb;
-       struct libusb_device_descriptor des;
-       libusb_device **devlist;
-       int err, skip, i;
-
-       devc = sdi->priv;
-       usb = sdi->conn;
-
-       if (sdi->status == SR_ST_ACTIVE)
-               /* already in use */
-               return SR_ERR;
-
-       skip = 0;
-       libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
-       for (i = 0; devlist[i]; i++) {
-               if ((err = libusb_get_device_descriptor(devlist[i], &des))) {
-                       sr_err("Failed to get device descriptor: %s.",
-                              libusb_error_name(err));
-                       continue;
-               }
-
-               if (des.idVendor != devc->profile->fw_vid
-                   || des.idProduct != devc->profile->fw_pid)
-                       continue;
-
-               if (sdi->status == SR_ST_INITIALIZING) {
-                       if (skip != sdi->index) {
-                               /* Skip devices of this type that aren't the one we want. */
-                               skip += 1;
-                               continue;
-                       }
-               } else if (sdi->status == SR_ST_INACTIVE) {
-                       /*
-                        * This device is fully enumerated, so we need to find
-                        * this device by vendor, product, bus and address.
-                        */
-                       if (libusb_get_bus_number(devlist[i]) != usb->bus
-                               || libusb_get_device_address(devlist[i]) != usb->address)
-                               /* this is not the one */
-                               continue;
-               }
-
-               if (!(err = libusb_open(devlist[i], &usb->devhdl))) {
-                       if (usb->address == 0xff)
-                               /*
-                                * first time we touch this device after firmware upload,
-                                * so we don't know the address yet.
-                                */
-                               usb->address = libusb_get_device_address(devlist[i]);
-
-                       if (!(devc->epin_maxpacketsize = dso_getmps(devlist[i])))
-                               sr_err("Wrong endpoint profile.");
-                       else {
-                               sdi->status = SR_ST_ACTIVE;
-                               sr_info("Opened device %d on %d.%d interface %d.",
-                                       sdi->index, usb->bus,
-                                       usb->address, USB_INTERFACE);
-                       }
-               } else {
-                       sr_err("Failed to open device: %s.",
-                              libusb_error_name(err));
-               }
-
-               /* If we made it here, we handled the device (somehow). */
-               break;
-       }
-       libusb_free_device_list(devlist, 1);
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR;
-
-       return SR_OK;
-}
-
-SR_PRIV void dso_close(struct sr_dev_inst *sdi)
-{
-       struct sr_usb_dev_inst *usb;
-
-       usb = sdi->conn;
-
-       if (usb->devhdl == NULL)
-               return;
-
-       sr_info("Closing device %d on %d.%d interface %d.", sdi->index,
-               usb->bus, usb->address, USB_INTERFACE);
-       libusb_release_interface(usb->devhdl, USB_INTERFACE);
-       libusb_close(usb->devhdl);
-       usb->devhdl = NULL;
-       sdi->status = SR_ST_INACTIVE;
-
-}
-
-static int get_channel_offsets(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_usb_dev_inst *usb;
-       GString *gs;
-       int chan, v, ret;
-
-       sr_dbg("Getting channel offsets.");
-
-       devc = sdi->priv;
-       usb = sdi->conn;
-
-       ret = libusb_control_transfer(usb->devhdl,
-                       LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR,
-                       CTRL_READ_EEPROM, EEPROM_CHANNEL_OFFSETS, 0,
-                       (unsigned char *)&devc->channel_levels,
-                       sizeof(devc->channel_levels), 200);
-       if (ret != sizeof(devc->channel_levels)) {
-               sr_err("Failed to get channel offsets: %s.",
-                      libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-       /* Comes in as 16-bit numbers with the second byte always 0 on
-        * the DSO-2090. Guessing this is supposed to be big-endian,
-        * since that's how voltage offsets are submitted back to the DSO.
-        * Convert to host order now, so we can use them natively.
-        */
-       for (chan = 0; chan < 2; chan++) {
-               for (v = 0; v < 9; v++) {
-                       devc->channel_levels[chan][v][0] =
-                               g_ntohs(devc->channel_levels[chan][v][0]);
-                       devc->channel_levels[chan][v][1] =
-                               g_ntohs(devc->channel_levels[chan][v][1]);
-               }
-       }
-
-       if (sr_log_loglevel_get() >= SR_LOG_DBG) {
-               gs = g_string_sized_new(128);
-               for (chan = 0; chan < 2; chan++) {
-                       g_string_printf(gs, "CH%d:", chan + 1);
-                       for (v = 0; v < 9; v++) {
-                               g_string_append_printf(gs, " %.4x-%.4x",
-                                       devc->channel_levels[chan][v][0],
-                                       devc->channel_levels[chan][v][1]);
-                       }
-                       sr_dbg("%s", gs->str);
-               }
-               g_string_free(gs, TRUE);
-       }
-
-       return SR_OK;
-}
-
-static int dso_set_trigger_samplerate(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_usb_dev_inst *usb;
-       int ret, tmp;
-       uint8_t cmdstring[12];
-       uint16_t timebase_small[] = { 0xffff, 0xfffc, 0xfff7, 0xffe8, 0xffce,
-               0xff9c, 0xff07, 0xfe0d, 0xfc19, 0xf63d, 0xec79, 0xd8f1 };
-       uint16_t timebase_large[] = { 0xffff, 0x0000, 0xfffc, 0xfff7, 0xffe8,
-               0xffce, 0xff9d, 0xff07, 0xfe0d, 0xfc19, 0xf63d, 0xec79 };
-
-       sr_dbg("Preparing CMD_SET_TRIGGER_SAMPLERATE.");
-
-       devc = sdi->priv;
-       usb = sdi->conn;
-
-       memset(cmdstring, 0, sizeof(cmdstring));
-       /* Command */
-       cmdstring[0] = CMD_SET_TRIGGER_SAMPLERATE;
-
-       /* Trigger source */
-       sr_dbg("Trigger source %s.", devc->triggersource);
-       if (!strcmp("CH2", devc->triggersource))
-               tmp = 0;
-       else if (!strcmp("CH1", devc->triggersource))
-               tmp = 1;
-       else if (!strcmp("EXT", devc->triggersource))
-               tmp = 2;
-       else {
-               sr_err("Invalid trigger source: '%s'.", devc->triggersource);
-               return SR_ERR_ARG;
-       }
-       cmdstring[2] = tmp;
-
-       /* Frame size */
-       sr_dbg("Frame size: %d.", devc->framesize);
-       cmdstring[2] |= (devc->framesize == FRAMESIZE_SMALL ? 0x01 : 0x02) << 2;
-
-       /* Timebase fast */
-       sr_dbg("Time base index: %d.", devc->timebase);
-       if (devc->framesize == FRAMESIZE_SMALL) {
-               if (devc->timebase < TIME_20us)
-                       tmp = 0;
-               else if (devc->timebase == TIME_20us)
-                       tmp = 1;
-               else if (devc->timebase == TIME_40us)
-                       tmp = 2;
-               else if (devc->timebase == TIME_100us)
-                       tmp = 3;
-               else if (devc->timebase >= TIME_200us)
-                       tmp = 4;
-       } else {
-               if (devc->timebase < TIME_40us) {
-                       sr_err("Timebase < 40us only supported with 10K buffer.");
-                       return SR_ERR_ARG;
-               }
-               else if (devc->timebase == TIME_40us)
-                       tmp = 0;
-               else if (devc->timebase == TIME_100us)
-                       tmp = 2;
-               else if (devc->timebase == TIME_200us)
-                       tmp = 3;
-               else if (devc->timebase >= TIME_400us)
-                       tmp = 4;
-       }
-       cmdstring[2] |= (tmp & 0x07) << 5;
-
-       /* Enabled channels: 00=CH1 01=CH2 10=both */
-       sr_dbg("Channels CH1=%d CH2=%d", devc->ch1_enabled, devc->ch2_enabled);
-       tmp = (((devc->ch2_enabled ? 1 : 0) << 1) + (devc->ch1_enabled ? 1 : 0)) - 1;
-       cmdstring[3] = tmp;
-
-       /* Fast rates channel */
-       /* TODO: Is this right? */
-       tmp = devc->timebase < TIME_10us ? 1 : 0;
-       cmdstring[3] |= tmp << 2;
-
-       /* Trigger slope: 0=positive 1=negative */
-       /* TODO: Does this work? */
-       sr_dbg("Trigger slope: %d.", devc->triggerslope);
-       cmdstring[3] |= (devc->triggerslope == SLOPE_NEGATIVE ? 1 : 0) << 3;
-
-       /* Timebase slow */
-       if (devc->timebase < TIME_100us)
-               tmp = 0;
-       else if (devc->timebase > TIME_400ms)
-               tmp = 0xffed;
-       else {
-               if (devc->framesize == FRAMESIZE_SMALL)
-                       tmp = timebase_small[devc->timebase - 3];
-               else
-                       tmp = timebase_large[devc->timebase - 3];
-       }
-       cmdstring[4] = tmp & 0xff;
-       cmdstring[5] = (tmp >> 8) & 0xff;
-
-       /* Horizontal trigger position */
-       sr_dbg("Trigger position: %3.2f.", devc->triggerposition);
-       tmp = 0x77fff + 0x8000 * devc->triggerposition;
-       cmdstring[6] = tmp & 0xff;
-       cmdstring[7] = (tmp >> 8) & 0xff;
-       cmdstring[10] = (tmp >> 16) & 0xff;
-
-       if (send_begin(sdi) != SR_OK)
-               return SR_ERR;
-
-       if ((ret = libusb_bulk_transfer(usb->devhdl, DSO_EP_OUT,
-                       cmdstring, sizeof(cmdstring), &tmp, 100)) != 0) {
-               sr_err("Failed to set trigger/samplerate: %s.",
-                      libusb_error_name(ret));
-               return SR_ERR;
-       }
-       sr_dbg("Sent CMD_SET_TRIGGER_SAMPLERATE.");
-
-       return SR_OK;
-}
-
-static int dso_set_filters(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_usb_dev_inst *usb;
-       int ret, tmp;
-       uint8_t cmdstring[8];
-
-       sr_dbg("Preparing CMD_SET_FILTERS.");
-
-       devc = sdi->priv;
-       usb = sdi->conn;
-
-       memset(cmdstring, 0, sizeof(cmdstring));
-       cmdstring[0] = CMD_SET_FILTERS;
-       cmdstring[1] = 0x0f;
-       if (devc->filter_ch1) {
-               sr_dbg("Turning on CH1 filter.");
-               cmdstring[2] |= 0x80;
-       }
-       if (devc->filter_ch2) {
-               sr_dbg("Turning on CH2 filter.");
-               cmdstring[2] |= 0x40;
-       }
-       if (devc->filter_trigger) {
-               /* TODO: supported on the DSO-2090? */
-               sr_dbg("Turning on trigger filter.");
-               cmdstring[2] |= 0x20;
-       }
-
-       if (send_begin(sdi) != SR_OK)
-               return SR_ERR;
-
-       if ((ret = libusb_bulk_transfer(usb->devhdl, DSO_EP_OUT,
-                       cmdstring, sizeof(cmdstring), &tmp, 100)) != 0) {
-               sr_err("Failed to set filters: %s.", libusb_error_name(ret));
-               return SR_ERR;
-       }
-       sr_dbg("Sent CMD_SET_FILTERS.");
-
-       return SR_OK;
-}
-
-static int dso_set_voltage(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_usb_dev_inst *usb;
-       int ret, tmp;
-       uint8_t cmdstring[8];
-
-       sr_dbg("Preparing CMD_SET_VOLTAGE.");
-
-       devc = sdi->priv;
-       usb = sdi->conn;
-
-       memset(cmdstring, 0, sizeof(cmdstring));
-       cmdstring[0] = CMD_SET_VOLTAGE;
-       cmdstring[1] = 0x0f;
-       cmdstring[2] = 0x30;
-
-       /* CH1 volts/div is encoded in bits 0-1 */
-       sr_dbg("CH1 vdiv index: %d.", devc->voltage_ch1);
-       switch (devc->voltage_ch1) {
-       case VDIV_1V:
-       case VDIV_100MV:
-       case VDIV_10MV:
-               cmdstring[2] |= 0x00;
-               break;
-       case VDIV_2V:
-       case VDIV_200MV:
-       case VDIV_20MV:
-               cmdstring[2] |= 0x01;
-               break;
-       case VDIV_5V:
-       case VDIV_500MV:
-       case VDIV_50MV:
-               cmdstring[2] |= 0x02;
-               break;
-       }
-
-       /* CH2 volts/div is encoded in bits 2-3 */
-       sr_dbg("CH2 vdiv index: %d.", devc->voltage_ch2);
-       switch (devc->voltage_ch2) {
-       case VDIV_1V:
-       case VDIV_100MV:
-       case VDIV_10MV:
-               cmdstring[2] |= 0x00;
-               break;
-       case VDIV_2V:
-       case VDIV_200MV:
-       case VDIV_20MV:
-               cmdstring[2] |= 0x04;
-               break;
-       case VDIV_5V:
-       case VDIV_500MV:
-       case VDIV_50MV:
-               cmdstring[2] |= 0x08;
-               break;
-       }
-
-       if (send_begin(sdi) != SR_OK)
-               return SR_ERR;
-
-       if ((ret = libusb_bulk_transfer(usb->devhdl, DSO_EP_OUT,
-                       cmdstring, sizeof(cmdstring), &tmp, 100)) != 0) {
-               sr_err("Failed to set voltage: %s.", libusb_error_name(ret));
-               return SR_ERR;
-       }
-       sr_dbg("Sent CMD_SET_VOLTAGE.");
-
-       return SR_OK;
-}
-
-static int dso_set_relays(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_usb_dev_inst *usb;
-       GString *gs;
-       int ret, i;
-       uint8_t relays[17] = { 0x00, 0x04, 0x08, 0x02, 0x20, 0x40, 0x10, 0x01,
-                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-
-       sr_dbg("Preparing CTRL_SETRELAYS.");
-
-       devc = sdi->priv;
-       usb = sdi->conn;
-
-       if (devc->voltage_ch1 < VDIV_1V)
-               relays[1] = ~relays[1];
-
-       if (devc->voltage_ch1 < VDIV_100MV)
-               relays[2] = ~relays[2];
-
-       sr_dbg("CH1 coupling: %d.", devc->coupling_ch1);
-       if (devc->coupling_ch1 != COUPLING_AC)
-               relays[3] = ~relays[3];
-
-       if (devc->voltage_ch2 < VDIV_1V)
-               relays[4] = ~relays[4];
-
-       if (devc->voltage_ch2 < VDIV_100MV)
-               relays[5] = ~relays[5];
-
-       sr_dbg("CH2 coupling: %d.", devc->coupling_ch1);
-       if (devc->coupling_ch2 != COUPLING_AC)
-               relays[6] = ~relays[6];
-
-       if (!strcmp(devc->triggersource, "EXT"))
-               relays[7] = ~relays[7];
-
-       if (sr_log_loglevel_get() >= SR_LOG_DBG) {
-               gs = g_string_sized_new(128);
-               g_string_printf(gs, "Relays:");
-               for (i = 0; i < 17; i++)
-                       g_string_append_printf(gs, " %.2x", relays[i]);
-               sr_dbg("%s", gs->str);
-               g_string_free(gs, TRUE);
-       }
-
-       if ((ret = libusb_control_transfer(usb->devhdl,
-                       LIBUSB_REQUEST_TYPE_VENDOR, CTRL_SETRELAYS,
-                       0, 0, relays, 17, 100)) != sizeof(relays)) {
-               sr_err("Failed to set relays: %s.", libusb_error_name(ret));
-               return SR_ERR;
-       }
-       sr_dbg("Sent CTRL_SETRELAYS.");
-
-       return SR_OK;
-}
-
-static int dso_set_voffsets(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_usb_dev_inst *usb;
-       int offset, ret;
-       uint16_t *ch_levels;
-       uint8_t offsets[17];
-
-       sr_dbg("Preparing CTRL_SETOFFSET.");
-
-       devc = sdi->priv;
-       usb = sdi->conn;
-
-       memset(offsets, 0, sizeof(offsets));
-       /* Channel 1 */
-       ch_levels = devc->channel_levels[0][devc->voltage_ch1];
-       offset = (ch_levels[1] - ch_levels[0]) * devc->voffset_ch1 + ch_levels[0];
-       offsets[0] = (offset >> 8) | 0x20;
-       offsets[1] = offset & 0xff;
-       sr_dbg("CH1 offset: %3.2f (%.2x%.2x).", devc->voffset_ch1,
-              offsets[0], offsets[1]);
-
-       /* Channel 2 */
-       ch_levels = devc->channel_levels[1][devc->voltage_ch2];
-       offset = (ch_levels[1] - ch_levels[0]) * devc->voffset_ch2 + ch_levels[0];
-       offsets[2] = (offset >> 8) | 0x20;
-       offsets[3] = offset & 0xff;
-       sr_dbg("CH2 offset: %3.2f (%.2x%.2x).", devc->voffset_ch2,
-              offsets[2], offsets[3]);
-
-       /* Trigger */
-       offset = MAX_VERT_TRIGGER * devc->voffset_trigger;
-       offsets[4] = (offset >> 8) | 0x20;
-       offsets[5] = offset & 0xff;
-       sr_dbg("Trigger offset: %3.2f (%.2x%.2x).", devc->voffset_trigger,
-                       offsets[4], offsets[5]);
-
-       if ((ret = libusb_control_transfer(usb->devhdl,
-                       LIBUSB_REQUEST_TYPE_VENDOR, CTRL_SETOFFSET,
-                       0, 0, offsets, sizeof(offsets), 100)) != sizeof(offsets)) {
-               sr_err("Failed to set offsets: %s.", libusb_error_name(ret));
-               return SR_ERR;
-       }
-       sr_dbg("Sent CTRL_SETOFFSET.");
-
-       return SR_OK;
-}
-
-SR_PRIV int dso_enable_trigger(const struct sr_dev_inst *sdi)
-{
-       struct sr_usb_dev_inst *usb;
-       int ret, tmp;
-       uint8_t cmdstring[2];
-
-       sr_dbg("Sending CMD_ENABLE_TRIGGER.");
-
-       usb = sdi->conn;
-
-       memset(cmdstring, 0, sizeof(cmdstring));
-       cmdstring[0] = CMD_ENABLE_TRIGGER;
-       cmdstring[1] = 0x00;
-
-       if (send_begin(sdi) != SR_OK)
-               return SR_ERR;
-
-       if ((ret = libusb_bulk_transfer(usb->devhdl, DSO_EP_OUT,
-                       cmdstring, sizeof(cmdstring), &tmp, 100)) != 0) {
-               sr_err("Failed to enable trigger: %s.", libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-       return SR_OK;
-}
-
-SR_PRIV int dso_force_trigger(const struct sr_dev_inst *sdi)
-{
-       struct sr_usb_dev_inst *usb;
-       int ret, tmp;
-       uint8_t cmdstring[2];
-
-       sr_dbg("Sending CMD_FORCE_TRIGGER.");
-
-       usb = sdi->conn;
-
-       memset(cmdstring, 0, sizeof(cmdstring));
-       cmdstring[0] = CMD_FORCE_TRIGGER;
-       cmdstring[1] = 0x00;
-
-       if (send_begin(sdi) != SR_OK)
-               return SR_ERR;
-
-       if ((ret = libusb_bulk_transfer(usb->devhdl, DSO_EP_OUT,
-                       cmdstring, sizeof(cmdstring), &tmp, 100)) != 0) {
-               sr_err("Failed to force trigger: %s.", libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-       return SR_OK;
-}
-
-SR_PRIV int dso_init(const struct sr_dev_inst *sdi)
-{
-
-       sr_dbg("Initializing DSO.");
-
-       if (get_channel_offsets(sdi) != SR_OK)
-               return SR_ERR;
-
-       if (dso_set_trigger_samplerate(sdi) != SR_OK)
-               return SR_ERR;
-
-       if (dso_set_filters(sdi) != SR_OK)
-               return SR_ERR;
-
-       if (dso_set_voltage(sdi) != SR_OK)
-               return SR_ERR;
-
-       if (dso_set_relays(sdi) != SR_OK)
-               return SR_ERR;
-
-       if (dso_set_voffsets(sdi) != SR_OK)
-               return SR_ERR;
-
-       if (dso_enable_trigger(sdi) != SR_OK)
-               return SR_ERR;
-
-       return SR_OK;
-}
-
-SR_PRIV int dso_get_capturestate(const struct sr_dev_inst *sdi,
-               uint8_t *capturestate, uint32_t *trigger_offset)
-{
-       struct sr_usb_dev_inst *usb;
-       int ret, tmp, i;
-       unsigned int bitvalue, toff;
-       uint8_t cmdstring[2], inbuf[512];
-
-       sr_dbg("Sending CMD_GET_CAPTURESTATE.");
-
-       usb = sdi->conn;
-
-       cmdstring[0] = CMD_GET_CAPTURESTATE;
-       cmdstring[1] = 0;
-
-       if ((ret = send_bulkcmd(sdi, cmdstring, sizeof(cmdstring))) != SR_OK) {
-               sr_dbg("Failed to send get_capturestate command: %s.",
-                      libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-       if ((ret = libusb_bulk_transfer(usb->devhdl, DSO_EP_IN,
-                       inbuf, 512, &tmp, 100)) != 0) {
-               sr_dbg("Failed to get capturestate: %s.",
-                      libusb_error_name(ret));
-               return SR_ERR;
-       }
-       *capturestate = inbuf[0];
-       toff = (inbuf[1] << 16) | (inbuf[3] << 8) | inbuf[2];
-
-       /*
-        * This conversion comes from the openhantek project.
-        * Each set bit in the 24-bit value inverts all bits with a lower
-        * value. No idea why the device reports the trigger point this way.
-        */
-       bitvalue = 1;
-       for (i = 0; i < 24; i++) {
-               /* Each set bit inverts all bits with a lower value. */
-               if(toff & bitvalue)
-                       toff ^= bitvalue - 1;
-               bitvalue <<= 1;
-       }
-       *trigger_offset = toff;
-
-       return SR_OK;
-}
-
-SR_PRIV int dso_capture_start(const struct sr_dev_inst *sdi)
-{
-       int ret;
-       uint8_t cmdstring[2];
-
-       sr_dbg("Sending CMD_CAPTURE_START.");
-
-       cmdstring[0] = CMD_CAPTURE_START;
-       cmdstring[1] = 0;
-
-       if ((ret = send_bulkcmd(sdi, cmdstring, sizeof(cmdstring))) != SR_OK) {
-               sr_err("Failed to send capture_start command: %s.",
-                      libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-       return SR_OK;
-}
-
-SR_PRIV int dso_get_channeldata(const struct sr_dev_inst *sdi,
-               libusb_transfer_cb_fn cb)
-{
-       struct dev_context *devc;
-       struct sr_usb_dev_inst *usb;
-       struct libusb_transfer *transfer;
-       int num_transfers, ret, i;
-       uint8_t cmdstring[2];
-       unsigned char *buf;
-
-       sr_dbg("Sending CMD_GET_CHANNELDATA.");
-
-       devc = sdi->priv;
-       usb = sdi->conn;
-
-       cmdstring[0] = CMD_GET_CHANNELDATA;
-       cmdstring[1] = 0;
-
-       if ((ret = send_bulkcmd(sdi, cmdstring, sizeof(cmdstring))) != SR_OK) {
-               sr_err("Failed to get channel data: %s.",
-                      libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-       /* TODO: DSO-2xxx only. */
-       num_transfers = devc->framesize *
-                       sizeof(unsigned short) / devc->epin_maxpacketsize;
-       sr_dbg("Queueing up %d transfers.", num_transfers);
-       for (i = 0; i < num_transfers; i++) {
-               if (!(buf = g_try_malloc(devc->epin_maxpacketsize))) {
-                       sr_err("Failed to malloc USB endpoint buffer.");
-                       return SR_ERR_MALLOC;
-               }
-               transfer = libusb_alloc_transfer(0);
-               libusb_fill_bulk_transfer(transfer, usb->devhdl, DSO_EP_IN, buf,
-                               devc->epin_maxpacketsize, cb, (void *)sdi, 40);
-               if ((ret = libusb_submit_transfer(transfer)) != 0) {
-                       sr_err("Failed to submit transfer: %s.",
-                              libusb_error_name(ret));
-                       /* TODO: Free them all. */
-                       libusb_free_transfer(transfer);
-                       g_free(buf);
-                       return SR_ERR;
-               }
-       }
-
-       return SR_OK;
-}
diff --git a/hardware/hantek-dso/dso.h b/hardware/hantek-dso/dso.h
deleted file mode 100644 (file)
index edccb72..0000000
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012 Bert Vermeulen <bert@biot.com>
- * With protocol information from the hantekdso project,
- * Copyright (C) 2008 Oleg Khudyakov <prcoder@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_HANTEK_DSO_DSO_H
-#define LIBSIGROK_HARDWARE_HANTEK_DSO_DSO_H
-
-#define LOG_PREFIX "hantek-dso"
-
-#define USB_INTERFACE           0
-#define USB_CONFIGURATION       1
-#define DSO_EP_IN               0x86
-#define DSO_EP_OUT              0x02
-
-/* FX2 renumeration delay in ms */
-#define MAX_RENUM_DELAY_MS      3000
-
-#define MAX_CAPTURE_EMPTY       3
-
-#define DEFAULT_VOLTAGE         VDIV_500MV
-#define DEFAULT_FRAMESIZE       FRAMESIZE_SMALL
-#define DEFAULT_TIMEBASE        TIME_100us
-#define DEFAULT_TRIGGER_SOURCE  "CH1"
-#define DEFAULT_COUPLING        COUPLING_DC
-#define DEFAULT_HORIZ_TRIGGERPOS 0.5
-#define DEFAULT_VERT_OFFSET     0.5
-#define DEFAULT_VERT_TRIGGERPOS 0.5
-
-#define MAX_VERT_TRIGGER        0xfe
-
-/* Hantek DSO-specific protocol values */
-#define EEPROM_CHANNEL_OFFSETS  0x08
-
-/* All models have this for their "fast" mode. */
-#define FRAMESIZE_SMALL         10240
-
-enum control_requests {
-       CTRL_READ_EEPROM = 0xa2,
-       CTRL_GETSPEED = 0xb2,
-       CTRL_BEGINCOMMAND = 0xb3,
-       CTRL_SETOFFSET = 0xb4,
-       CTRL_SETRELAYS = 0xb5,
-};
-
-enum dso_commands {
-       CMD_SET_FILTERS = 0,
-       CMD_SET_TRIGGER_SAMPLERATE,
-       CMD_FORCE_TRIGGER,
-       CMD_CAPTURE_START,
-       CMD_ENABLE_TRIGGER,
-       CMD_GET_CHANNELDATA,
-       CMD_GET_CAPTURESTATE,
-       CMD_SET_VOLTAGE,
-       /* unused */
-       CMD_SET_LOGICALDATA,
-       CMD_GET_LOGICALDATA,
-};
-
-/* Must match the coupling table. */
-enum couplings {
-       COUPLING_AC = 0,
-       COUPLING_DC,
-       /* TODO not used, how to enable? */
-       COUPLING_GND,
-};
-
-/* Must match the timebases table. */
-enum time_bases {
-       TIME_10us = 0,
-       TIME_20us,
-       TIME_40us,
-       TIME_100us,
-       TIME_200us,
-       TIME_400us,
-       TIME_1ms,
-       TIME_2ms,
-       TIME_4ms,
-       TIME_10ms,
-       TIME_20ms,
-       TIME_40ms,
-       TIME_100ms,
-       TIME_200ms,
-       TIME_400ms,
-};
-
-/* Must match the vdivs table. */
-enum {
-       VDIV_10MV,
-       VDIV_20MV,
-       VDIV_50MV,
-       VDIV_100MV,
-       VDIV_200MV,
-       VDIV_500MV,
-       VDIV_1V,
-       VDIV_2V,
-       VDIV_5V,
-};
-
-enum trigger_slopes {
-       SLOPE_POSITIVE = 0,
-       SLOPE_NEGATIVE,
-};
-
-enum trigger_sources {
-       TRIGGER_CH2 = 0,
-       TRIGGER_CH1,
-       TRIGGER_EXT,
-};
-
-enum capturestates {
-       CAPTURE_EMPTY = 0,
-       CAPTURE_FILLING = 1,
-       CAPTURE_READY_8BIT = 2,
-       CAPTURE_READY_9BIT = 7,
-       CAPTURE_TIMEOUT = 127,
-       CAPTURE_UNKNOWN = 255,
-};
-
-enum triggermodes {
-       TRIGGERMODE_AUTO,
-       TRIGGERMODE_NORMAL,
-       TRIGGERMODE_SINGLE,
-};
-
-enum states {
-       IDLE,
-       NEW_CAPTURE,
-       CAPTURE,
-       FETCH_DATA,
-       STOPPING,
-};
-
-struct dso_profile {
-       /* VID/PID after cold boot */
-       uint16_t orig_vid;
-       uint16_t orig_pid;
-       /* VID/PID after firmware upload */
-       uint16_t fw_vid;
-       uint16_t fw_pid;
-       char *vendor;
-       char *model;
-       const uint64_t *buffersizes;
-       char *firmware;
-};
-
-struct dev_context {
-       const struct dso_profile *profile;
-       void *cb_data;
-       uint64_t limit_frames;
-       uint64_t num_frames;
-       GSList *enabled_channels;
-       /* We can't keep track of an FX2-based device after upgrading
-        * the firmware (it re-enumerates into a different device address
-        * after the upgrade) this is like a global lock. No device will open
-        * until a proper delay after the last device was upgraded.
-        */
-       int64_t fw_updated;
-       int epin_maxpacketsize;
-       int capture_empty_count;
-       int dev_state;
-
-       /* Oscilloscope settings. */
-       int timebase;
-       gboolean ch1_enabled;
-       gboolean ch2_enabled;
-       int voltage_ch1;
-       int voltage_ch2;
-       int coupling_ch1;
-       int coupling_ch2;
-       // voltage offset (vertical position)
-       float voffset_ch1;
-       float voffset_ch2;
-       float voffset_trigger;
-       uint16_t channel_levels[2][9][2];
-       unsigned int framesize;
-       gboolean filter_ch1;
-       gboolean filter_ch2;
-       gboolean filter_trigger;
-       int triggerslope;
-       char *triggersource;
-       float triggerposition;
-       int triggermode;
-
-       /* Frame transfer */
-       unsigned int samp_received;
-       unsigned int samp_buffered;
-       unsigned int trigger_offset;
-       unsigned char *framebuf;
-};
-
-SR_PRIV int dso_open(struct sr_dev_inst *sdi);
-SR_PRIV void dso_close(struct sr_dev_inst *sdi);
-SR_PRIV int dso_enable_trigger(const struct sr_dev_inst *sdi);
-SR_PRIV int dso_force_trigger(const struct sr_dev_inst *sdi);
-SR_PRIV int dso_init(const struct sr_dev_inst *sdi);
-SR_PRIV int dso_get_capturestate(const struct sr_dev_inst *sdi,
-               uint8_t *capturestate, uint32_t *trigger_offset);
-SR_PRIV int dso_capture_start(const struct sr_dev_inst *sdi);
-SR_PRIV int dso_get_channeldata(const struct sr_dev_inst *sdi,
-               libusb_transfer_cb_fn cb);
-
-#endif
diff --git a/hardware/ikalogic-scanalogic2/api.c b/hardware/ikalogic-scanalogic2/api.c
deleted file mode 100644 (file)
index b4c697f..0000000
+++ /dev/null
@@ -1,537 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Marc Schink <sigrok-dev@marcschink.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 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"
-
-static const int hwcaps[] = {
-       SR_CONF_LOGIC_ANALYZER,
-       SR_CONF_SAMPLERATE,
-       SR_CONF_LIMIT_SAMPLES,
-       SR_CONF_TRIGGER_MATCH,
-       SR_CONF_CAPTURE_RATIO,
-};
-
-static const int32_t trigger_matches[] = {
-       SR_TRIGGER_RISING,
-       SR_TRIGGER_FALLING,
-       SR_TRIGGER_EDGE,
-};
-
-SR_PRIV const uint64_t sl2_samplerates[NUM_SAMPLERATES] = {
-       SR_KHZ(1.25),
-       SR_KHZ(10),
-       SR_KHZ(50),
-       SR_KHZ(100),
-       SR_KHZ(250),
-       SR_KHZ(500),
-       SR_MHZ(1),
-       SR_MHZ(2.5),
-       SR_MHZ(5),
-       SR_MHZ(10),
-       SR_MHZ(20),
-};
-
-static const char *channel_names[NUM_CHANNELS + 1] = {
-       "0", "1", "2", "3",
-       NULL,
-};
-
-SR_PRIV struct sr_dev_driver ikalogic_scanalogic2_driver_info;
-static struct sr_dev_driver *di = &ikalogic_scanalogic2_driver_info;
-
-static int init(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, di, LOG_PREFIX);
-}
-
-static GSList *scan(GSList *options)
-{
-       GSList *usb_devices, *devices, *l;
-       struct drv_context *drvc;
-       struct sr_dev_inst *sdi;
-       struct sr_channel *ch;
-       struct dev_context *devc;
-       struct sr_usb_dev_inst *usb;
-       struct device_info dev_info;
-       int ret, device_index, i;
-       char *fw_ver_str;
-
-       (void)options;
-
-       devices = NULL;
-       drvc = di->priv;
-       drvc->instances = NULL;
-       device_index = 0;
-
-       usb_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, USB_VID_PID);
-
-       if (usb_devices == NULL)
-               return NULL;
-
-       for (l = usb_devices; l; l = l->next) {
-               usb = l->data;
-
-               if ((ret = sl2_get_device_info(*usb, &dev_info)) < 0) {
-                       sr_warn("Failed to get device information: %d.", ret);
-                       sr_usb_dev_inst_free(usb);
-                       continue;
-               }
-
-               if (!(devc = g_try_malloc(sizeof(struct dev_context)))) {
-                       sr_err("Device instance malloc failed.");
-                       sr_usb_dev_inst_free(usb);
-                       continue;
-               }
-
-               if (!(devc->xfer_in = libusb_alloc_transfer(0))) {
-                       sr_err("Transfer malloc failed.");
-                       sr_usb_dev_inst_free(usb);
-                       g_free(devc);
-                       continue;
-               }
-
-               if (!(devc->xfer_out = libusb_alloc_transfer(0))) {
-                       sr_err("Transfer malloc failed.");
-                       sr_usb_dev_inst_free(usb);
-                       libusb_free_transfer(devc->xfer_in);
-                       g_free(devc);
-                       continue;
-               }
-
-               fw_ver_str = g_strdup_printf("%u.%u", dev_info.fw_ver_major,
-                       dev_info.fw_ver_minor);
-               if (!fw_ver_str) {
-                       sr_err("Firmware string malloc failed.");
-                       sr_usb_dev_inst_free(usb);
-                       libusb_free_transfer(devc->xfer_in);
-                       libusb_free_transfer(devc->xfer_out);
-                       g_free(devc);
-                       continue;
-               }
-
-               sdi = sr_dev_inst_new(device_index, SR_ST_INACTIVE, VENDOR_NAME,
-                       MODEL_NAME, fw_ver_str);
-               g_free(fw_ver_str);
-               if (!sdi) {
-                       sr_err("sr_dev_inst_new failed.");
-                       sr_usb_dev_inst_free(usb);
-                       libusb_free_transfer(devc->xfer_in);
-                       libusb_free_transfer(devc->xfer_out);
-                       g_free(devc);
-                       continue;
-               }
-
-               sdi->priv = devc;
-               sdi->driver = di;
-               sdi->inst_type = SR_INST_USB;
-               sdi->conn = usb;
-
-               for (i = 0; channel_names[i]; i++) {
-                       ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE,
-                               channel_names[i]);
-                       sdi->channels = g_slist_append(sdi->channels, ch);
-                       devc->channels[i] = ch;
-               }
-
-               devc->state = STATE_IDLE;
-               devc->next_state = STATE_IDLE;
-
-               /* Set default samplerate. */
-               sl2_set_samplerate(sdi, DEFAULT_SAMPLERATE);
-
-               /* Set default capture ratio. */
-               devc->capture_ratio = 0;
-
-               /* Set default after trigger delay. */
-               devc->after_trigger_delay = 0;
-
-               memset(devc->xfer_buf_in, 0, LIBUSB_CONTROL_SETUP_SIZE +
-                       PACKET_LENGTH);
-               memset(devc->xfer_buf_out, 0, LIBUSB_CONTROL_SETUP_SIZE +
-                       PACKET_LENGTH);
-
-               libusb_fill_control_setup(devc->xfer_buf_in,
-                       USB_REQUEST_TYPE_IN, USB_HID_GET_REPORT,
-                       USB_HID_REPORT_TYPE_FEATURE, USB_INTERFACE,
-                       PACKET_LENGTH);
-               libusb_fill_control_setup(devc->xfer_buf_out,
-                       USB_REQUEST_TYPE_OUT, USB_HID_SET_REPORT,
-                       USB_HID_REPORT_TYPE_FEATURE, USB_INTERFACE,
-                       PACKET_LENGTH);
-
-               devc->xfer_data_in = devc->xfer_buf_in +
-                       LIBUSB_CONTROL_SETUP_SIZE;
-               devc->xfer_data_out = devc->xfer_buf_out +
-                       LIBUSB_CONTROL_SETUP_SIZE;
-
-               drvc->instances = g_slist_append(drvc->instances, sdi);
-               devices = g_slist_append(devices, sdi);
-
-               device_index++;
-       }
-
-       g_slist_free(usb_devices);
-
-       return devices;
-}
-
-static GSList *dev_list(void)
-{
-       return ((struct drv_context *)(di->priv))->instances;
-}
-
-static void clear_dev_context(void *priv)
-{
-       struct dev_context *devc;
-
-       devc = priv;
-
-       sr_dbg("Device context cleared.");
-
-       libusb_free_transfer(devc->xfer_in);
-       libusb_free_transfer(devc->xfer_out);
-       g_free(devc);
-}
-
-static int dev_clear(void)
-{
-       return std_dev_clear(di, &clear_dev_context);
-}
-
-static int dev_open(struct sr_dev_inst *sdi)
-{
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       struct sr_usb_dev_inst *usb;
-       uint8_t buffer[PACKET_LENGTH];
-       int ret;
-
-       if (!(drvc = di->priv)) {
-               sr_err("Driver was not initialized.");
-               return SR_ERR;
-       }
-
-       usb = sdi->conn;
-       devc = sdi->priv;
-
-       if (sr_usb_open(drvc->sr_ctx->libusb_ctx, usb) != SR_OK)
-               return SR_ERR;
-
-       /*
-        * Determine if a kernel driver is active on this interface and, if so,
-        * detach it.
-        */
-       if (libusb_kernel_driver_active(usb->devhdl, USB_INTERFACE) == 1) {
-               ret = libusb_detach_kernel_driver(usb->devhdl, USB_INTERFACE);
-               if (ret < 0) {
-                       sr_err("Failed to detach kernel driver: %s.",
-                               libusb_error_name(ret));
-                       return SR_ERR;
-               }
-       }
-
-       if ((ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE)) < 0) {
-               sr_err("Failed to claim interface: %s.",
-                       libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-       libusb_fill_control_transfer(devc->xfer_in, usb->devhdl,
-               devc->xfer_buf_in, sl2_receive_transfer_in,
-               sdi, USB_TIMEOUT);
-
-       libusb_fill_control_transfer(devc->xfer_out, usb->devhdl,
-               devc->xfer_buf_out, sl2_receive_transfer_out,
-               sdi, USB_TIMEOUT);
-
-       memset(buffer, 0, sizeof(buffer));
-
-       buffer[0] = CMD_RESET;
-       if ((ret = sl2_transfer_out(usb->devhdl, buffer)) != PACKET_LENGTH) {
-               sr_err("Device reset failed: %s.", libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-       /*
-        * Set the device to idle state. If the device is not in idle state it
-        * possibly will reset itself after a few seconds without being used
-        * and thereby close the connection.
-        */
-       buffer[0] = CMD_IDLE;
-       if ((ret = sl2_transfer_out(usb->devhdl, buffer)) != PACKET_LENGTH) {
-               sr_err("Failed to set device in idle state: %s.",
-                       libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-       sdi->status = SR_ST_ACTIVE;
-
-       return SR_OK;
-}
-
-static int dev_close(struct sr_dev_inst *sdi)
-{
-       struct sr_usb_dev_inst *usb;
-
-       if (!di->priv) {
-               sr_err("Driver was not initialized.");
-               return SR_ERR;
-       }
-
-       usb = sdi->conn;
-
-       if (!usb->devhdl)
-               return SR_OK;
-
-       libusb_release_interface(usb->devhdl, USB_INTERFACE);
-       libusb_close(usb->devhdl);
-
-       usb->devhdl = NULL;
-       sdi->status = SR_ST_INACTIVE;
-
-       return SR_OK;
-}
-
-static int cleanup(void)
-{
-       return dev_clear();
-}
-
-static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       int ret;
-
-       (void)cg;
-
-       ret = SR_OK;
-       devc = sdi->priv;
-
-       switch (key) {
-       case SR_CONF_SAMPLERATE:
-               *data = g_variant_new_uint64(devc->samplerate);
-               break;
-       case SR_CONF_CAPTURE_RATIO:
-               *data = g_variant_new_uint64(devc->capture_ratio);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return ret;
-}
-
-static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       uint64_t samplerate, limit_samples, capture_ratio;
-       int ret;
-
-       (void)cg;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       ret = SR_OK;
-
-       switch (key) {
-       case SR_CONF_LIMIT_SAMPLES:
-               limit_samples = g_variant_get_uint64(data);
-               ret = sl2_set_limit_samples(sdi, limit_samples);
-               break;
-       case SR_CONF_SAMPLERATE:
-               samplerate = g_variant_get_uint64(data);
-               ret = sl2_set_samplerate(sdi, samplerate);
-               break;
-       case SR_CONF_CAPTURE_RATIO:
-               capture_ratio = g_variant_get_uint64(data);
-               ret = sl2_set_capture_ratio(sdi, capture_ratio);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return ret;
-}
-
-static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       GVariant *gvar, *grange[2];
-       GVariantBuilder gvb;
-       int ret;
-
-       (void)sdi;
-       (void)cg;
-
-       ret = SR_OK;
-
-       switch (key) {
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, hwcaps,
-                       ARRAY_SIZE(hwcaps), sizeof(int32_t));
-               break;
-       case SR_CONF_SAMPLERATE:
-               g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
-               gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"),
-                       sl2_samplerates, ARRAY_SIZE(sl2_samplerates),
-                       sizeof(uint64_t));
-               g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar);
-               *data = g_variant_builder_end(&gvb);
-               break;
-       case SR_CONF_TRIGGER_MATCH:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               trigger_matches, ARRAY_SIZE(trigger_matches),
-                               sizeof(int32_t));
-               break;
-       case SR_CONF_LIMIT_SAMPLES:
-               grange[0] = g_variant_new_uint64(0);
-               grange[1] = g_variant_new_uint64(MAX_SAMPLES);
-               *data = g_variant_new_tuple(grange, 2);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return ret;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       uint16_t trigger_bytes, tmp;
-       unsigned int i, j;
-       int ret;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       devc = sdi->priv;
-       drvc = di->priv;
-
-       devc->cb_data = cb_data;
-       devc->wait_data_ready_locked = TRUE;
-       devc->stopping_in_progress = FALSE;
-       devc->transfer_error = FALSE;
-       devc->samples_processed = 0;
-       devc->channel = 0;
-       devc->sample_packet = 0;
-
-       /*
-        * The trigger must be configured first because the calculation of the
-        * pre and post trigger samples depends on a configured trigger.
-        */
-       sl2_convert_trigger(sdi);
-       sl2_calculate_trigger_samples(sdi);
-
-       trigger_bytes = devc->pre_trigger_bytes + devc->post_trigger_bytes;
-
-       /* Calculate the number of expected sample packets. */
-       devc->num_sample_packets = trigger_bytes / PACKET_NUM_SAMPLE_BYTES;
-
-       /* Round up the number of expected sample packets. */
-       if (trigger_bytes % PACKET_NUM_SAMPLE_BYTES != 0)
-               devc->num_sample_packets++;
-
-       devc->num_enabled_channels = 0;
-
-       /*
-        * Count the number of enabled channels and number them for a sequential
-        * access.
-        */
-       for (i = 0, j = 0; i < NUM_CHANNELS; i++) {
-               if (devc->channels[i]->enabled) {
-                       devc->num_enabled_channels++;
-                       devc->channel_map[j] = i;
-                       j++;
-               }
-       }
-
-       sr_dbg("Number of enabled channels: %i.", devc->num_enabled_channels);
-
-       /* Set up the transfer buffer for the acquisition. */
-       devc->xfer_data_out[0] = CMD_SAMPLE;
-       devc->xfer_data_out[1] = 0x00;
-
-       tmp = GUINT16_TO_LE(devc->pre_trigger_bytes);
-       memcpy(devc->xfer_data_out + 2, &tmp, sizeof(tmp));
-
-       tmp = GUINT16_TO_LE(devc->post_trigger_bytes);
-       memcpy(devc->xfer_data_out + 4, &tmp, sizeof(tmp));
-
-       devc->xfer_data_out[6] = devc->samplerate_id;
-       devc->xfer_data_out[7] = devc->trigger_type;
-       devc->xfer_data_out[8] = devc->trigger_channel;
-       devc->xfer_data_out[9] = 0x00;
-
-       tmp = GUINT16_TO_LE(devc->after_trigger_delay);
-       memcpy(devc->xfer_data_out + 10, &tmp, sizeof(tmp));
-
-       if ((ret = libusb_submit_transfer(devc->xfer_out)) != 0) {
-               sr_err("Submit transfer failed: %s.", libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-       usb_source_add(sdi->session, drvc->sr_ctx, 100,
-                       ikalogic_scanalogic2_receive_data, (void *)sdi);
-
-       sr_dbg("Acquisition started successfully.");
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(cb_data, LOG_PREFIX);
-
-       devc->next_state = STATE_SAMPLE;
-
-       return SR_OK;
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       (void)cb_data;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       sr_dbg("Stopping acquisition.");
-
-       sdi->status = SR_ST_STOPPING;
-
-       return SR_OK;
-}
-
-SR_PRIV struct sr_dev_driver ikalogic_scanalogic2_driver_info = {
-       .name = "ikalogic-scanalogic2",
-       .longname = "IKALOGIC Scanalogic-2",
-       .api_version = 1,
-       .init = init,
-       .cleanup = cleanup,
-       .scan = scan,
-       .dev_list = dev_list,
-       .dev_clear = dev_clear,
-       .config_get = config_get,
-       .config_set = config_set,
-       .config_list = config_list,
-       .dev_open = dev_open,
-       .dev_close = dev_close,
-       .dev_acquisition_start = dev_acquisition_start,
-       .dev_acquisition_stop = dev_acquisition_stop,
-       .priv = NULL,
-};
diff --git a/hardware/ikalogic-scanalogic2/protocol.c b/hardware/ikalogic-scanalogic2/protocol.c
deleted file mode 100644 (file)
index 663ff52..0000000
+++ /dev/null
@@ -1,764 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Marc Schink <sigrok-dev@marcschink.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 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"
-
-extern struct sr_dev_driver ikalogic_scanalogic2_driver_info;
-static struct sr_dev_driver *di = &ikalogic_scanalogic2_driver_info;
-
-extern uint64_t sl2_samplerates[NUM_SAMPLERATES];
-
-static void stop_acquisition(struct sr_dev_inst *sdi)
-{
-       struct drv_context *drvc = sdi->driver->priv;
-       struct dev_context *devc;
-       struct sr_datafeed_packet packet;
-
-       devc = sdi->priv;
-
-       /* Remove USB file descriptors from polling. */
-       usb_source_remove(sdi->session, drvc->sr_ctx);
-
-       packet.type = SR_DF_END;
-       sr_session_send(devc->cb_data, &packet);
-
-       sdi->status = SR_ST_ACTIVE;
-}
-
-static void abort_acquisition(struct sr_dev_inst *sdi)
-{
-       struct drv_context *drvc = sdi->driver->priv;
-       struct dev_context *devc;
-       struct sr_datafeed_packet packet;
-
-       devc = sdi->priv;
-
-       /* Remove USB file descriptors from polling. */
-       usb_source_remove(sdi->session, drvc->sr_ctx);
-
-       packet.type = SR_DF_END;
-       sr_session_send(devc->cb_data, &packet);
-
-       sdi->driver->dev_close(sdi);
-}
-
-static void buffer_sample_data(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       unsigned int offset, packet_length;
-
-       devc = sdi->priv;
-
-       if (devc->channels[devc->channel]->enabled) {
-               offset = devc->sample_packet * PACKET_NUM_SAMPLE_BYTES;
-
-               /*
-                * Determine the packet length to ensure that the last packet
-                * will not exceed the buffer size.
-                */
-               packet_length = MIN(PACKET_NUM_SAMPLE_BYTES,
-                       MAX_DEV_SAMPLE_BYTES - offset);
-
-               /*
-                * Skip the first 4 bytes of the source buffer because they
-                * contain channel and packet information only.
-                */
-               memcpy(devc->sample_buffer[devc->channel] + offset,
-                       devc->xfer_data_in + 4, packet_length);
-       }
-}
-
-static void process_sample_data(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_logic logic;
-       uint8_t i, j, tmp, buffer[PACKET_NUM_SAMPLES], *ptr[NUM_CHANNELS];
-       uint16_t offset, n = 0;
-       int8_t k;
-
-       devc = sdi->priv;
-       offset = devc->sample_packet * PACKET_NUM_SAMPLE_BYTES;
-
-       /*
-        * Array of pointers to the sample data of all channels up to the last
-        * enabled one for an uniform access to them. Note that the currently
-        * received samples always belong to the last enabled channel.
-        */
-       for (i = 0; i < devc->num_enabled_channels - 1; i++)
-               ptr[i] = devc->sample_buffer[devc->channel_map[i]] + offset;
-
-       /*
-        * Skip the first 4 bytes of the buffer because they contain channel
-        * and packet information only.
-        */
-       ptr[i] = devc->xfer_data_in + 4;
-
-       for (i = 0; i < PACKET_NUM_SAMPLE_BYTES; i++) {
-               /* Stop processing if all requested samples are processed. */
-               if (devc->samples_processed == devc->limit_samples)
-                       break;
-
-               k = 7;
-
-               if (devc->samples_processed == 0) {
-                       /*
-                        * Adjust the position of the first sample to be
-                        * processed because possibly more samples than
-                        * necessary might have been acquired. This is because
-                        * the number of acquired samples is always rounded up
-                        * to a multiple of 8.
-                        */
-                       k = k - (devc->pre_trigger_bytes * 8) +
-                               devc->pre_trigger_samples;
-
-                       sr_dbg("Start processing at sample: %d.", 7 - k);
-
-                       /*
-                        * Send the trigger before the first sample is
-                        * processed if no pre trigger samples were calculated
-                        * through the capture ratio.
-                        */
-                       if (devc->trigger_type != TRIGGER_TYPE_NONE &&
-                                       devc->pre_trigger_samples == 0) {
-                               packet.type = SR_DF_TRIGGER;
-                               sr_session_send(devc->cb_data, &packet);
-                       }
-               }
-
-               for (; k >= 0; k--) {
-                       /*
-                        * Stop processing if all requested samples are
-                        * processed.
-                        */
-                       if (devc->samples_processed == devc->limit_samples)
-                               break;
-
-                       buffer[n] = 0;
-
-                       /*
-                        * Extract the current sample for each enabled channel
-                        * and store them in the buffer.
-                        */
-                       for (j = 0; j < devc->num_enabled_channels; j++) {
-                               tmp = (ptr[j][i] & (1 << k)) >> k;
-                               buffer[n] |= tmp << devc->channel_map[j];
-                       }
-
-                       n++;
-                       devc->samples_processed++;
-
-                       /*
-                        * Send all processed samples and the trigger if the
-                        * number of processed samples reaches the calculated
-                        * number of pre trigger samples.
-                        */
-                       if (devc->samples_processed == devc->pre_trigger_samples &&
-                                       devc->trigger_type != TRIGGER_TYPE_NONE) {
-                               packet.type = SR_DF_LOGIC;
-                               packet.payload = &logic;
-                               logic.length = n;
-                               logic.unitsize = 1;
-                               logic.data = buffer;
-                               sr_session_send(devc->cb_data, &packet);
-
-                               packet.type = SR_DF_TRIGGER;
-                               sr_session_send(devc->cb_data, &packet);
-
-                               n = 0;
-                       }
-               }
-       }
-
-       if (n > 0) {
-               packet.type = SR_DF_LOGIC;
-               packet.payload = &logic;
-               logic.length = n;
-               logic.unitsize = 1;
-               logic.data = buffer;
-               sr_session_send(devc->cb_data, &packet);
-       }
-}
-
-SR_PRIV int ikalogic_scanalogic2_receive_data(int fd, int revents, void *cb_data)
-{
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-       struct drv_context *drvc;
-       struct timeval tv;
-       int64_t current_time, time_elapsed;
-       int ret = 0;
-
-       (void)fd;
-       (void)revents;
-
-       if (!(sdi = cb_data))
-               return TRUE;
-
-       if (!(devc = sdi->priv))
-               return TRUE;
-
-       drvc = di->priv;
-       current_time = g_get_monotonic_time();
-
-       if (devc->state == STATE_WAIT_DATA_READY &&
-                       !devc->wait_data_ready_locked) {
-               time_elapsed = current_time - devc->wait_data_ready_time;
-
-               /*
-                * Check here for stopping in addition to the transfer
-                * callback functions to avoid waiting until the
-                * WAIT_DATA_READY_INTERVAL has expired.
-                */
-               if (sdi->status == SR_ST_STOPPING) {
-                       if (!devc->stopping_in_progress) {
-                               devc->next_state = STATE_RESET_AND_IDLE;
-                               devc->stopping_in_progress = TRUE;
-                               ret = libusb_submit_transfer(devc->xfer_in);
-                       }
-               } else if (time_elapsed >= WAIT_DATA_READY_INTERVAL) {
-                       devc->wait_data_ready_locked = TRUE;
-                       ret = libusb_submit_transfer(devc->xfer_in);
-               }
-       }
-
-       if (ret != 0) {
-               sr_err("Submit transfer failed: %s.", libusb_error_name(ret));
-               abort_acquisition(sdi);
-               return TRUE;
-       }
-
-       tv.tv_sec = 0;
-       tv.tv_usec = 0;
-
-       libusb_handle_events_timeout_completed(drvc->sr_ctx->libusb_ctx, &tv,
-               NULL);
-
-       /* Check if an error occurred on a transfer. */
-       if (devc->transfer_error)
-               abort_acquisition(sdi);
-
-       return TRUE;
-}
-
-SR_PRIV void sl2_receive_transfer_in( struct libusb_transfer *transfer)
-{
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-       uint8_t last_channel;
-       int ret = 0;
-
-       sdi = transfer->user_data;
-       devc = sdi->priv;
-
-       if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
-               sr_err("Transfer to device failed: %i.", transfer->status);
-               devc->transfer_error = TRUE;
-               return;
-       }
-
-       if (sdi->status == SR_ST_STOPPING && !devc->stopping_in_progress) {
-               devc->next_state = STATE_RESET_AND_IDLE;
-               devc->stopping_in_progress = TRUE;
-
-               if (libusb_submit_transfer(devc->xfer_in) != 0) {
-                       sr_err("Submit transfer failed: %s.",
-                               libusb_error_name(ret));
-                       devc->transfer_error = TRUE;
-               }
-
-               return;
-       }
-
-       if (devc->state != devc->next_state)
-               sr_spew("State changed from %i to %i.",
-                       devc->state, devc->next_state);
-       devc->state = devc->next_state;
-
-       if (devc->state == STATE_WAIT_DATA_READY) {
-               /* Check if the received data are a valid device status. */
-               if (devc->xfer_data_in[0] == 0x05) {
-                       if (devc->xfer_data_in[1] == STATUS_WAITING_FOR_TRIGGER)
-                               sr_dbg("Waiting for trigger.");
-                       else if (devc->xfer_data_in[1] == STATUS_SAMPLING)
-                               sr_dbg("Sampling in progress.");
-               }
-
-               /*
-                * Check if the received data are a valid device status and the
-                * sample data are ready.
-                */
-               if (devc->xfer_data_in[0] == 0x05 &&
-                               devc->xfer_data_in[1] == STATUS_DATA_READY) {
-                       devc->next_state = STATE_RECEIVE_DATA;
-                       ret = libusb_submit_transfer(transfer);
-               } else {
-                       devc->wait_data_ready_locked = FALSE;
-                       devc->wait_data_ready_time = g_get_monotonic_time();
-               }
-       } else if (devc->state == STATE_RECEIVE_DATA) {
-               last_channel = devc->channel_map[devc->num_enabled_channels - 1];
-
-               if (devc->channel < last_channel) {
-                       buffer_sample_data(sdi);
-               } else if (devc->channel == last_channel) {
-                       process_sample_data(sdi);
-               } else {
-                       /*
-                        * Stop acquisition because all samples of enabled
-                        * channels are processed.
-                        */
-                       devc->next_state = STATE_RESET_AND_IDLE;
-               }
-
-               devc->sample_packet++;
-               devc->sample_packet %= devc->num_sample_packets;
-
-               if (devc->sample_packet == 0)
-                       devc->channel++;
-
-               ret = libusb_submit_transfer(transfer);
-       } else if (devc->state == STATE_RESET_AND_IDLE) {
-               /* Check if the received data are a valid device status. */
-               if (devc->xfer_data_in[0] == 0x05) {
-                       if (devc->xfer_data_in[1] == STATUS_DEVICE_READY) {
-                               devc->next_state = STATE_IDLE;
-                               devc->xfer_data_out[0] = CMD_IDLE;
-                       } else {
-                               devc->next_state = STATE_WAIT_DEVICE_READY;
-                               devc->xfer_data_out[0] = CMD_RESET;
-                       }
-
-                       ret = libusb_submit_transfer(devc->xfer_out);
-               } else {
-                       /*
-                        * The received device status is invalid which
-                        * indicates that the device is not ready to accept
-                        * commands. Request a new device status until a valid
-                        * device status is received.
-                        */
-                       ret = libusb_submit_transfer(transfer);
-               }
-       } else if (devc->state == STATE_WAIT_DEVICE_READY) {
-               /* Check if the received data are a valid device status. */
-               if (devc->xfer_data_in[0] == 0x05) {
-                       if (devc->xfer_data_in[1] == STATUS_DEVICE_READY) {
-                               devc->next_state = STATE_IDLE;
-                               devc->xfer_data_out[0] = CMD_IDLE;
-                       } else {
-                               /*
-                                * The received device status is valid but the
-                                * device is not ready. Probably the device did
-                                * not recognize the last reset. Reset the
-                                * device again.
-                                */
-                               devc->xfer_data_out[0] = CMD_RESET;
-                       }
-
-                       ret = libusb_submit_transfer(devc->xfer_out);
-               } else {
-                       /*
-                        * The device is not ready and therefore not able to
-                        * change to the idle state. Request a new device
-                        * status until the device is ready.
-                        */
-                       ret = libusb_submit_transfer(transfer);
-               }
-       }
-
-       if (ret != 0) {
-               sr_err("Submit transfer failed: %s.", libusb_error_name(ret));
-               devc->transfer_error = TRUE;
-       }
-}
-
-SR_PRIV void sl2_receive_transfer_out( struct libusb_transfer *transfer)
-{
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-       int ret = 0;
-
-       sdi = transfer->user_data;
-       devc = sdi->priv;
-
-       if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
-               sr_err("Transfer to device failed: %i.", transfer->status);
-               devc->transfer_error = TRUE;
-               return;
-       }
-
-       if (sdi->status == SR_ST_STOPPING && !devc->stopping_in_progress) {
-               devc->next_state = STATE_RESET_AND_IDLE;
-               devc->stopping_in_progress = TRUE;
-
-               if (libusb_submit_transfer(devc->xfer_in) != 0) {
-                       sr_err("Submit transfer failed: %s.",
-                               libusb_error_name(ret));
-
-                       devc->transfer_error = TRUE;
-               }
-
-               return;
-       }
-
-       if (devc->state != devc->next_state)
-               sr_spew("State changed from %i to %i.",
-                       devc->state, devc->next_state);
-       devc->state = devc->next_state;
-
-       if (devc->state == STATE_IDLE) {
-               stop_acquisition(sdi);
-       } else if (devc->state == STATE_SAMPLE) {
-               devc->next_state = STATE_WAIT_DATA_READY;
-               ret = libusb_submit_transfer(devc->xfer_in);
-       } else if (devc->state == STATE_WAIT_DEVICE_READY) {
-               ret = libusb_submit_transfer(devc->xfer_in);
-       }
-
-       if (ret != 0) {
-               sr_err("Submit transfer failed: %s.", libusb_error_name(ret));
-               devc->transfer_error = TRUE;
-       }
-}
-
-SR_PRIV int sl2_set_samplerate(const struct sr_dev_inst *sdi,
-               uint64_t samplerate)
-{
-       struct dev_context *devc;
-       unsigned int i;
-
-       devc = sdi->priv;
-
-       for (i = 0; i < NUM_SAMPLERATES; i++) {
-               if (sl2_samplerates[i] == samplerate) {
-                       devc->samplerate = samplerate;
-                       devc->samplerate_id = NUM_SAMPLERATES - i - 1;
-                       return SR_OK;
-               }
-       }
-
-       return SR_ERR_ARG;
-}
-
-SR_PRIV int sl2_set_limit_samples(const struct sr_dev_inst *sdi,
-                                 uint64_t limit_samples)
-{
-       struct dev_context *devc;
-
-       devc = sdi->priv;
-
-       if (limit_samples == 0) {
-               sr_err("Invalid number of limit samples: %" PRIu64 ".",
-                       limit_samples);
-               return SR_ERR_ARG;
-       }
-
-       if (limit_samples > MAX_SAMPLES)
-               limit_samples = MAX_SAMPLES;
-
-       sr_dbg("Limit samples set to %" PRIu64 ".", limit_samples);
-
-       devc->limit_samples = limit_samples;
-
-       return SR_OK;
-}
-
-SR_PRIV int sl2_convert_trigger(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_trigger *trigger;
-       struct sr_trigger_stage *stage;
-       struct sr_trigger_match *match;
-       const GSList *l, *m;
-       int num_triggers_anyedge;
-
-       devc = sdi->priv;
-
-       /* Disable the trigger by default. */
-       devc->trigger_channel = TRIGGER_CHANNEL_0;
-       devc->trigger_type = TRIGGER_TYPE_NONE;
-
-       if (!(trigger = sr_session_trigger_get(sdi->session)))
-               return SR_OK;
-
-       if (g_slist_length(trigger->stages) > 1) {
-               sr_err("This device only supports 1 trigger stage.");
-               return SR_ERR;
-       }
-
-       num_triggers_anyedge = 0;
-       for (l = trigger->stages; l; l = l->next) {
-               stage = l->data;
-               for (m = stage->matches; m; m = m->next) {
-                       match = m->data;
-                       if (!match->channel->enabled)
-                               /* Ignore disabled channels with a trigger. */
-                               continue;
-                       devc->trigger_channel = match->channel->index + 1;
-                       switch (match->match) {
-                       case SR_TRIGGER_RISING:
-                               devc->trigger_type = TRIGGER_TYPE_POSEDGE;
-                               break;
-                       case SR_TRIGGER_FALLING:
-                               devc->trigger_type = TRIGGER_TYPE_NEGEDGE;
-                               break;
-                       case SR_TRIGGER_EDGE:
-                               devc->trigger_type = TRIGGER_TYPE_ANYEDGE;
-                               num_triggers_anyedge++;
-                               break;
-                       }
-               }
-       }
-
-       /*
-        * Set trigger to any edge on all channels if the trigger for each
-        * channel is set to any edge.
-        */
-       if (num_triggers_anyedge == NUM_CHANNELS) {
-               devc->trigger_channel = TRIGGER_CHANNEL_ALL;
-               devc->trigger_type = TRIGGER_TYPE_ANYEDGE;
-       }
-
-       sr_dbg("Trigger set to channel 0x%02x and type 0x%02x.",
-               devc->trigger_channel, devc->trigger_type);
-
-       return SR_OK;
-}
-
-SR_PRIV int sl2_set_capture_ratio(const struct sr_dev_inst *sdi,
-                                 uint64_t capture_ratio)
-{
-       struct dev_context *devc;
-
-       devc = sdi->priv;
-
-       if (capture_ratio > 100) {
-               sr_err("Invalid capture ratio: %" PRIu64 " %%.", capture_ratio);
-               return SR_ERR_ARG;
-       }
-
-       sr_info("Capture ratio set to %" PRIu64 " %%.", capture_ratio);
-
-       devc->capture_ratio = capture_ratio;
-
-       return SR_OK;
-}
-
-SR_PRIV int sl2_set_after_trigger_delay(const struct sr_dev_inst *sdi,
-                                       uint64_t after_trigger_delay)
-{
-       struct dev_context *devc;
-
-       devc = sdi->priv;
-
-       if (after_trigger_delay > MAX_AFTER_TRIGGER_DELAY) {
-               sr_err("Invalid after trigger delay: %" PRIu64 " ms.",
-                       after_trigger_delay);
-               return SR_ERR_ARG;
-       }
-
-       sr_info("After trigger delay set to %" PRIu64 " ms.",
-               after_trigger_delay);
-
-       devc->after_trigger_delay = after_trigger_delay;
-
-       return SR_OK;
-}
-
-SR_PRIV void sl2_calculate_trigger_samples(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       uint64_t pre_trigger_samples, post_trigger_samples;
-       uint16_t pre_trigger_bytes, post_trigger_bytes;
-       uint8_t cr;
-
-       devc = sdi->priv;
-       cr = devc->capture_ratio;
-
-       /* Ignore the capture ratio if no trigger is enabled. */
-       if (devc->trigger_type == TRIGGER_TYPE_NONE)
-               cr = 0;
-
-       pre_trigger_samples = (devc->limit_samples * cr) / 100;
-       post_trigger_samples = (devc->limit_samples * (100 - cr)) / 100;
-
-       /*
-        * Increase the number of post trigger samples by one to compensate the
-        * possible loss of a sample through integer rounding.
-        */
-       if (pre_trigger_samples + post_trigger_samples != devc->limit_samples)
-               post_trigger_samples++;
-
-       /*
-        * The device requires the number of samples in multiples of 8 which
-        * will also be called sample bytes in the following.
-        */
-       pre_trigger_bytes = pre_trigger_samples / 8;
-       post_trigger_bytes = post_trigger_samples / 8;
-
-       /*
-        * Round up the number of sample bytes to ensure that at least the
-        * requested number of samples will be acquired. Note that due to this
-        * rounding the buffer to store these sample bytes needs to be at least
-        * one sample byte larger than the minimal number of sample bytes
-        * needed to store the requested samples.
-        */
-       if (pre_trigger_samples % 8 != 0)
-               pre_trigger_bytes++;
-
-       if (post_trigger_samples % 8 != 0)
-               post_trigger_bytes++;
-
-       sr_info("Pre trigger samples: %" PRIu64 ".", pre_trigger_samples);
-       sr_info("Post trigger samples: %" PRIu64 ".", post_trigger_samples);
-       sr_dbg("Pre trigger sample bytes: %" PRIu16 ".", pre_trigger_bytes);
-       sr_dbg("Post trigger sample bytes: %" PRIu16 ".", post_trigger_bytes);
-
-       devc->pre_trigger_samples = pre_trigger_samples;
-       devc->pre_trigger_bytes = pre_trigger_bytes;
-       devc->post_trigger_bytes = post_trigger_bytes;
-}
-
-SR_PRIV int sl2_get_device_info(struct sr_usb_dev_inst usb,
-               struct device_info *dev_info)
-{
-       struct drv_context *drvc;
-       uint8_t buffer[PACKET_LENGTH];
-       int ret;
-
-       drvc = di->priv;
-
-       if (!dev_info)
-               return SR_ERR_ARG;
-
-       if (sr_usb_open(drvc->sr_ctx->libusb_ctx, &usb) != SR_OK)
-               return SR_ERR;
-
-       /*
-        * Determine if a kernel driver is active on this interface and, if so,
-        * detach it.
-        */
-       if (libusb_kernel_driver_active(usb.devhdl, USB_INTERFACE) == 1) {
-               ret = libusb_detach_kernel_driver(usb.devhdl,
-                       USB_INTERFACE);
-
-               if (ret < 0) {
-                       sr_err("Failed to detach kernel driver: %s.",
-                               libusb_error_name(ret));
-                       libusb_close(usb.devhdl);
-                       return SR_ERR;
-               }
-       }
-
-       ret = libusb_claim_interface(usb.devhdl, USB_INTERFACE);
-
-       if (ret) {
-               sr_err("Failed to claim interface: %s.",
-                       libusb_error_name(ret));
-               libusb_close(usb.devhdl);
-               return SR_ERR;
-       }
-
-       memset(buffer, 0, sizeof(buffer));
-
-       /*
-        * Reset the device to ensure it is in a proper state to request the
-        * device information.
-        */
-       buffer[0] = CMD_RESET;
-       if ((ret = sl2_transfer_out(usb.devhdl, buffer)) != PACKET_LENGTH) {
-               sr_err("Resetting of device failed: %s.",
-                       libusb_error_name(ret));
-               libusb_release_interface(usb.devhdl, USB_INTERFACE);
-               libusb_close(usb.devhdl);
-               return SR_ERR;
-       }
-
-       buffer[0] = CMD_INFO;
-       if ((ret = sl2_transfer_out(usb.devhdl, buffer)) != PACKET_LENGTH) {
-               sr_err("Requesting of device information failed: %s.",
-                       libusb_error_name(ret));
-               libusb_release_interface(usb.devhdl, USB_INTERFACE);
-               libusb_close(usb.devhdl);
-               return SR_ERR;
-       }
-
-       if ((ret = sl2_transfer_in(usb.devhdl, buffer)) != PACKET_LENGTH) {
-               sr_err("Receiving of device information failed: %s.",
-                       libusb_error_name(ret));
-               libusb_release_interface(usb.devhdl, USB_INTERFACE);
-               libusb_close(usb.devhdl);
-               return SR_ERR;
-       }
-
-       memcpy(&(dev_info->serial), buffer + 1, sizeof(uint32_t));
-       dev_info->serial = GUINT32_FROM_LE(dev_info->serial);
-
-       dev_info->fw_ver_major = buffer[5];
-       dev_info->fw_ver_minor = buffer[6];
-
-       buffer[0] = CMD_RESET;
-       if ((ret = sl2_transfer_out(usb.devhdl, buffer)) != PACKET_LENGTH) {
-               sr_err("Device reset failed: %s.", libusb_error_name(ret));
-               libusb_release_interface(usb.devhdl, USB_INTERFACE);
-               libusb_close(usb.devhdl);
-               return SR_ERR;
-       }
-
-       /*
-        * Set the device to idle state. If the device is not in idle state it
-        * possibly will reset itself after a few seconds without being used
-        * and thereby close the connection.
-        */
-       buffer[0] = CMD_IDLE;
-       if ((ret = sl2_transfer_out(usb.devhdl, buffer)) != PACKET_LENGTH) {
-               sr_err("Failed to set device in idle state: %s.",
-                       libusb_error_name(ret));
-               libusb_release_interface(usb.devhdl, USB_INTERFACE);
-               libusb_close(usb.devhdl);
-               return SR_ERR;
-       }
-
-       ret = libusb_release_interface(usb.devhdl, USB_INTERFACE);
-
-       if (ret < 0) {
-               sr_err("Failed to release interface: %s.",
-                       libusb_error_name(ret));
-               libusb_close(usb.devhdl);
-               return SR_ERR;
-       }
-
-       libusb_close(usb.devhdl);
-
-       return SR_OK;
-}
-
-SR_PRIV int sl2_transfer_in(libusb_device_handle *dev_handle, uint8_t *data)
-{
-       return libusb_control_transfer(dev_handle, USB_REQUEST_TYPE_IN,
-               USB_HID_GET_REPORT, USB_HID_REPORT_TYPE_FEATURE, USB_INTERFACE,
-               (unsigned char *)data, PACKET_LENGTH, USB_TIMEOUT);
-}
-
-SR_PRIV int sl2_transfer_out(libusb_device_handle *dev_handle, uint8_t *data)
-{
-       return libusb_control_transfer(dev_handle, USB_REQUEST_TYPE_OUT,
-               USB_HID_SET_REPORT, USB_HID_REPORT_TYPE_FEATURE, USB_INTERFACE,
-               (unsigned char *)data, PACKET_LENGTH, USB_TIMEOUT);
-}
diff --git a/hardware/ikalogic-scanalogic2/protocol.h b/hardware/ikalogic-scanalogic2/protocol.h
deleted file mode 100644 (file)
index 5e7c7b3..0000000
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Marc Schink <sigrok-dev@marcschink.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 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_IKALOGIC_SCANALOGIC2_PROTOCOL_H
-#define LIBSIGROK_HARDWARE_IKALOGIC_SCANALOGIC2_PROTOCOL_H
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "ikalogic-scanalogic2"
-
-#define VENDOR_NAME                    "IKALOGIC"
-#define MODEL_NAME                     "Scanalogic-2"
-
-#define USB_VID_PID                    "20a0.4123"
-#define USB_INTERFACE                  0
-#define USB_TIMEOUT                    5000
-
-#define USB_REQUEST_TYPE_IN            (LIBUSB_REQUEST_TYPE_CLASS | \
-       LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_IN)
-
-#define USB_REQUEST_TYPE_OUT           (LIBUSB_REQUEST_TYPE_CLASS | \
-       LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT)
-
-#define USB_HID_GET_REPORT             0x01
-#define USB_HID_SET_REPORT             0x09
-#define USB_HID_REPORT_TYPE_FEATURE    0x300
-
-#define NUM_SAMPLERATES                        11
-#define NUM_CHANNELS                   4
-
-/*
- * Number of sample bytes and samples the device can acquire. Note that the
- * vendor software can acquire 32736 sample bytes only but the device is capable
- * to acquire up to 32766 sample bytes.
- */
-#define MAX_DEV_SAMPLE_BYTES           32766
-#define MAX_DEV_SAMPLES                        (MAX_INT_SAMPLE_BYTES * 8)
-
-/* Number of sample bytes and samples the driver can acquire. */
-#define MAX_SAMPLE_BYTES               (MAX_DEV_SAMPLE_BYTES - 1)
-#define MAX_SAMPLES                    (MAX_SAMPLE_BYTES * 8)
-
-/* Maximum time that the trigger can be delayed in milliseconds. */
-#define MAX_AFTER_TRIGGER_DELAY                65000
-
-#define PACKET_LENGTH                  128
-
-/* Number of sample bytes per packet where a sample byte contains 8 samples. */
-#define PACKET_NUM_SAMPLE_BYTES                124
-
-/* Number of samples per packet. */
-#define PACKET_NUM_SAMPLES             (PACKET_NUM_SAMPLE_BYTES * 8)
-
-#define DEFAULT_SAMPLERATE             SR_KHZ(1.25)
-
-/*
- * Time interval between the last status of available data received and the
- * moment when the next status request will be sent in microseconds.
- */
-#define WAIT_DATA_READY_INTERVAL       1500000
-
-#define CMD_SAMPLE                     0x01
-#define CMD_RESET                      0x02
-#define CMD_IDLE                       0x07
-#define CMD_INFO                       0x0a
-
-#define TRIGGER_CHANNEL_ALL            0x00
-#define TRIGGER_CHANNEL_0              0x01
-#define TRIGGER_CHANNEL_1              0x02
-#define TRIGGER_CHANNEL_2              0x03
-
-#define TRIGGER_TYPE_NEGEDGE           0x00
-#define TRIGGER_TYPE_POSEDGE           0x01
-#define TRIGGER_TYPE_ANYEDGE           0x02
-#define TRIGGER_TYPE_NONE              0x03
-
-#define STATUS_DATA_READY              0x60
-#define STATUS_WAITING_FOR_TRIGGER     0x61
-#define STATUS_SAMPLING                        0x62
-#define STATUS_DEVICE_READY            0x63
-
-struct device_info {
-       /* Serial number of the device. */
-       uint32_t serial;
-
-       /* Major version of the firmware. */
-       uint8_t fw_ver_major;
-
-       /* Minor version of the firmware. */
-       uint8_t fw_ver_minor;
-};
-
-enum {
-       STATE_IDLE = 0,
-       STATE_SAMPLE,
-       STATE_WAIT_DATA_READY,
-       STATE_RECEIVE_DATA,
-       STATE_RESET_AND_IDLE,
-       STATE_WAIT_DEVICE_READY
-};
-
-/** Private, per-device-instance driver context. */
-struct dev_context {
-       /* Current selected samplerate. */
-       uint64_t samplerate;
-
-       /* Device specific identifier for the current samplerate. */
-       uint8_t samplerate_id;
-
-       /* Current sampling limit. */
-       uint64_t limit_samples;
-
-       /* Calculated number of pre-trigger samples. */
-       uint64_t pre_trigger_samples;
-
-       /* Number of pre- and post-trigger sample bytes to acquire. */
-       uint16_t pre_trigger_bytes;
-       uint16_t post_trigger_bytes;
-
-       /* Device specific settings for the trigger. */
-       uint8_t trigger_channel;
-       uint8_t trigger_type;
-
-       unsigned int capture_ratio;
-
-       /* Time that the trigger will be delayed in milliseconds. */
-       uint16_t after_trigger_delay;
-
-       void *cb_data;
-
-       /* Array to provide an index based access to all channels. */
-       const struct sr_channel *channels[NUM_CHANNELS];
-
-       struct libusb_transfer *xfer_in, *xfer_out;
-
-       /*
-        * Buffer to store setup and payload data for incoming and outgoing
-        * transfers.
-        */
-       uint8_t xfer_buf_in[LIBUSB_CONTROL_SETUP_SIZE + PACKET_LENGTH];
-       uint8_t xfer_buf_out[LIBUSB_CONTROL_SETUP_SIZE + PACKET_LENGTH];
-
-       /* Pointers to the payload of incoming and outgoing transfers. */
-       uint8_t *xfer_data_in, *xfer_data_out;
-
-       /* Current state of the state machine */
-       unsigned int state;
-
-       /* Next state of the state machine. */
-       unsigned int next_state;
-
-       /*
-        * Locking variable to ensure that no status about available data will
-        * be requested until the last status was received.
-        */
-       gboolean wait_data_ready_locked;
-
-       /*
-        * Time when the last response about the status of available data was
-        * received.
-        */
-       int64_t wait_data_ready_time;
-
-       /*
-        * Indicates that stopping of the acquisition is currently in progress.
-        */
-       gboolean stopping_in_progress;
-
-       /*
-        * Buffer which contains the samples received from the device for each
-        * channel except the last one. The samples of the last channel will be
-        * processed directly after they will be received.
-        */
-       uint8_t sample_buffer[NUM_CHANNELS - 1][MAX_DEV_SAMPLE_BYTES];
-
-       /* Expected number of sample packets for each channel. */
-       uint16_t num_sample_packets;
-
-       /* Number of samples already processed. */
-       uint64_t samples_processed;
-
-       /* Sample packet number that is currently processed. */
-       uint16_t sample_packet;
-
-       /* Channel number that is currently processed. */
-       uint8_t channel;
-
-       /* Number of enabled channels. */
-       unsigned int num_enabled_channels;
-
-       /* Array to provide a sequential access to all enabled channel indices. */
-       uint8_t channel_map[NUM_CHANNELS];
-
-       /* Indicates whether a transfer failed. */
-       gboolean transfer_error;
-};
-
-SR_PRIV int ikalogic_scanalogic2_receive_data(int fd, int revents, void *cb_data);
-SR_PRIV void sl2_receive_transfer_in(struct libusb_transfer *transfer);
-SR_PRIV void sl2_receive_transfer_out(struct libusb_transfer *transfer);
-SR_PRIV int sl2_set_samplerate(const struct sr_dev_inst *sdi,
-               uint64_t samplerate);
-SR_PRIV int sl2_set_limit_samples(const struct sr_dev_inst *sdi,
-                                 uint64_t limit_samples);
-SR_PRIV int sl2_convert_trigger(const struct sr_dev_inst *sdi);
-SR_PRIV int sl2_set_capture_ratio(const struct sr_dev_inst *sdi,
-                                 uint64_t capture_ratio);
-SR_PRIV int sl2_set_after_trigger_delay(const struct sr_dev_inst *sdi,
-                                       uint64_t after_trigger_delay);
-SR_PRIV void sl2_calculate_trigger_samples(const struct sr_dev_inst *sdi);
-SR_PRIV int sl2_get_device_info(struct sr_usb_dev_inst usb,
-               struct device_info *dev_info);
-SR_PRIV int sl2_transfer_in(libusb_device_handle *dev_handle, uint8_t *data);
-SR_PRIV int sl2_transfer_out(libusb_device_handle *dev_handle, uint8_t *data);
-
-#endif
diff --git a/hardware/ikalogic-scanaplus/api.c b/hardware/ikalogic-scanaplus/api.c
deleted file mode 100644 (file)
index 3f82763..0000000
+++ /dev/null
@@ -1,438 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include "protocol.h"
-
-#define USB_VENDOR_ID                  0x0403
-#define USB_DEVICE_ID                  0x6014
-#define USB_VENDOR_NAME                        "IKALOGIC"
-#define USB_MODEL_NAME                 "ScanaPLUS"
-#define USB_IPRODUCT                   "SCANAPLUS"
-
-#define SAMPLE_BUF_SIZE                        (8 * 1024 * 1024)
-
-static const int32_t hwcaps[] = {
-       SR_CONF_LOGIC_ANALYZER,
-       SR_CONF_SAMPLERATE,
-       SR_CONF_LIMIT_MSEC,
-       SR_CONF_LIMIT_SAMPLES,
-       SR_CONF_CONTINUOUS, // TODO?
-};
-
-/* Channels are numbered 1-9. */
-static const char *channel_names[] = {
-       "1", "2", "3", "4", "5", "6", "7", "8", "9",
-       NULL,
-};
-
-/* Note: The IKALOGIC ScanaPLUS always samples at 100MHz. */
-static uint64_t samplerates[1] = { SR_MHZ(100) };
-
-SR_PRIV struct sr_dev_driver ikalogic_scanaplus_driver_info;
-static struct sr_dev_driver *di = &ikalogic_scanaplus_driver_info;
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data);
-
-static void clear_helper(void *priv)
-{
-       struct dev_context *devc;
-
-       devc = priv;
-
-       ftdi_free(devc->ftdic);
-       g_free(devc->compressed_buf);
-       g_free(devc->sample_buf);
-}
-
-static int dev_clear(void)
-{
-       return std_dev_clear(di, clear_helper);
-}
-
-static int init(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, di, LOG_PREFIX);
-}
-
-static GSList *scan(GSList *options)
-{
-       struct sr_dev_inst *sdi;
-       struct sr_channel *ch;
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       GSList *devices;
-       unsigned int i;
-       int ret;
-
-       (void)options;
-
-       drvc = di->priv;
-
-       devices = NULL;
-
-       /* Allocate memory for our private device context. */
-       if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
-               sr_err("Device context malloc failed.");
-               goto err_free_nothing;
-       }
-
-       /* Allocate memory for the incoming compressed samples. */
-       if (!(devc->compressed_buf = g_try_malloc0(COMPRESSED_BUF_SIZE))) {
-               sr_err("compressed_buf malloc failed.");
-               goto err_free_devc;
-       }
-
-       /* Allocate memory for the uncompressed samples. */
-       if (!(devc->sample_buf = g_try_malloc0(SAMPLE_BUF_SIZE))) {
-               sr_err("sample_buf malloc failed.");
-               goto err_free_compressed_buf;
-       }
-
-       /* Allocate memory for the FTDI context (ftdic) and initialize it. */
-       if (!(devc->ftdic = ftdi_new())) {
-               sr_err("Failed to initialize libftdi.");
-               goto err_free_sample_buf;
-       }
-
-       /* Check for the device and temporarily open it. */
-       ret = ftdi_usb_open_desc(devc->ftdic, USB_VENDOR_ID, USB_DEVICE_ID,
-                                USB_IPRODUCT, NULL);
-       if (ret < 0) {
-               /* Log errors, except for -3 ("device not found"). */
-               if (ret != -3)
-                       sr_err("Failed to open device (%d): %s", ret,
-                              ftdi_get_error_string(devc->ftdic));
-               goto err_free_ftdic;
-       }
-
-       /* Register the device with libsigrok. */
-       sdi = sr_dev_inst_new(0, SR_ST_INITIALIZING,
-                       USB_VENDOR_NAME, USB_MODEL_NAME, NULL);
-       if (!sdi) {
-               sr_err("Failed to create device instance.");
-               goto err_close_ftdic;
-       }
-       sdi->driver = di;
-       sdi->priv = devc;
-
-       for (i = 0; channel_names[i]; i++) {
-               if (!(ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE,
-                                          channel_names[i])))
-                       return NULL;
-               sdi->channels = g_slist_append(sdi->channels, ch);
-       }
-
-       devices = g_slist_append(devices, sdi);
-       drvc->instances = g_slist_append(drvc->instances, sdi);
-
-       /* Close device. We'll reopen it again when we need it. */
-       scanaplus_close(devc);
-
-       return devices;
-
-err_close_ftdic:
-       scanaplus_close(devc);
-err_free_ftdic:
-       ftdi_free(devc->ftdic); /* NOT free() or g_free()! */
-err_free_sample_buf:
-       g_free(devc->sample_buf);
-err_free_compressed_buf:
-       g_free(devc->compressed_buf);
-err_free_devc:
-       g_free(devc);
-err_free_nothing:
-
-       return NULL;
-}
-
-static GSList *dev_list(void)
-{
-       return ((struct drv_context *)(di->priv))->instances;
-}
-
-static int dev_open(struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       int ret;
-
-       devc = sdi->priv;
-
-       /* Select interface A, otherwise communication will fail. */
-       ret = ftdi_set_interface(devc->ftdic, INTERFACE_A);
-       if (ret < 0) {
-               sr_err("Failed to set FTDI interface A (%d): %s", ret,
-                      ftdi_get_error_string(devc->ftdic));
-               return SR_ERR;
-       }
-       sr_dbg("FTDI chip interface A set successfully.");
-
-       /* Open the device. */
-       ret = ftdi_usb_open_desc(devc->ftdic, USB_VENDOR_ID, USB_DEVICE_ID,
-                                USB_IPRODUCT, NULL);
-       if (ret < 0) {
-               sr_err("Failed to open device (%d): %s", ret,
-                      ftdi_get_error_string(devc->ftdic));
-               return SR_ERR;
-       }
-       sr_dbg("FTDI device opened successfully.");
-
-       /* Purge RX/TX buffers in the FTDI chip. */
-       if ((ret = ftdi_usb_purge_buffers(devc->ftdic)) < 0) {
-               sr_err("Failed to purge FTDI RX/TX buffers (%d): %s.",
-                      ret, ftdi_get_error_string(devc->ftdic));
-               goto err_dev_open_close_ftdic;
-       }
-       sr_dbg("FTDI chip buffers purged successfully.");
-
-       /* Reset the FTDI bitmode. */
-       ret = ftdi_set_bitmode(devc->ftdic, 0xff, BITMODE_RESET);
-       if (ret < 0) {
-               sr_err("Failed to reset the FTDI chip bitmode (%d): %s.",
-                      ret, ftdi_get_error_string(devc->ftdic));
-               goto err_dev_open_close_ftdic;
-       }
-       sr_dbg("FTDI chip bitmode reset successfully.");
-
-       /* Set FTDI bitmode to "sync FIFO". */
-       ret = ftdi_set_bitmode(devc->ftdic, 0xff, BITMODE_SYNCFF);
-       if (ret < 0) {
-               sr_err("Failed to put FTDI chip into sync FIFO mode (%d): %s.",
-                      ret, ftdi_get_error_string(devc->ftdic));
-               goto err_dev_open_close_ftdic;
-       }
-       sr_dbg("FTDI chip sync FIFO mode entered successfully.");
-
-       /* Set the FTDI latency timer to 2. */
-       ret = ftdi_set_latency_timer(devc->ftdic, 2);
-       if (ret < 0) {
-               sr_err("Failed to set FTDI latency timer (%d): %s.",
-                      ret, ftdi_get_error_string(devc->ftdic));
-               goto err_dev_open_close_ftdic;
-       }
-       sr_dbg("FTDI chip latency timer set successfully.");
-
-       /* Set the FTDI read data chunk size to 64kB. */
-       ret = ftdi_read_data_set_chunksize(devc->ftdic, 64 * 1024);
-       if (ret < 0) {
-               sr_err("Failed to set FTDI read data chunk size (%d): %s.",
-                      ret, ftdi_get_error_string(devc->ftdic));
-               goto err_dev_open_close_ftdic;
-       }
-       sr_dbg("FTDI chip read data chunk size set successfully.");
-
-       /* Get the ScanaPLUS device ID from the FTDI EEPROM. */
-       if ((ret = scanaplus_get_device_id(devc)) < 0) {
-               sr_err("Failed to get ScanaPLUS device ID: %d.", ret);
-               goto err_dev_open_close_ftdic;
-       }
-       sr_dbg("Received ScanaPLUS device ID successfully: %02x %02x %02x.",
-              devc->devid[0], devc->devid[1], devc->devid[2]);
-
-       sdi->status = SR_ST_ACTIVE;
-
-       return SR_OK;
-
-err_dev_open_close_ftdic:
-       scanaplus_close(devc);
-       return SR_ERR;
-}
-
-static int dev_close(struct sr_dev_inst *sdi)
-{
-       int ret;
-       struct dev_context *devc;
-
-       ret = SR_OK;
-       devc = sdi->priv;
-
-       if (sdi->status == SR_ST_ACTIVE) {
-               sr_dbg("Status ACTIVE, closing device.");
-               ret = scanaplus_close(devc);
-       } else {
-               sr_spew("Status not ACTIVE, nothing to do.");
-       }
-
-       sdi->status = SR_ST_INACTIVE;
-
-       return ret;
-}
-
-static int cleanup(void)
-{
-       return dev_clear();
-}
-
-static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       (void)sdi;
-       (void)cg;
-
-       switch (id) {
-       case SR_CONF_SAMPLERATE:
-               /* The ScanaPLUS samplerate is 100MHz and can't be changed. */
-               *data = g_variant_new_uint64(SR_MHZ(100));
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-
-       (void)cg;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       devc = sdi->priv;
-
-       switch (id) {
-       case SR_CONF_SAMPLERATE:
-               if (g_variant_get_uint64(data) != SR_MHZ(100)) {
-                       sr_err("ScanaPLUS only supports samplerate = 100MHz.");
-                       return SR_ERR_ARG;
-               }
-               /* Nothing to do, the ScanaPLUS samplerate is always 100MHz. */
-               break;
-       case SR_CONF_LIMIT_MSEC:
-               if (g_variant_get_uint64(data) == 0)
-                       return SR_ERR_ARG;
-               devc->limit_msec = g_variant_get_uint64(data);
-               break;
-       case SR_CONF_LIMIT_SAMPLES:
-               if (g_variant_get_uint64(data) == 0)
-                       return SR_ERR_ARG;
-               devc->limit_samples = g_variant_get_uint64(data);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       GVariant *gvar;
-       GVariantBuilder gvb;
-
-       (void)sdi;
-       (void)cg;
-
-       switch (key) {
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
-               break;
-       case SR_CONF_SAMPLERATE:
-               g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
-               gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"),
-                               samplerates, ARRAY_SIZE(samplerates),
-                               sizeof(uint64_t));
-               g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar);
-               *data = g_variant_builder_end(&gvb);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
-{
-       int ret;
-       struct dev_context *devc;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       if (!(devc = sdi->priv))
-               return SR_ERR_BUG;
-
-       if (!devc->ftdic)
-               return SR_ERR_BUG;
-
-       /* TODO: Configure channels later (thresholds etc.). */
-
-       devc->cb_data = cb_data;
-
-       /* Properly reset internal variables before every new acquisition. */
-       devc->compressed_bytes_ignored = 0;
-       devc->samples_sent = 0;
-       devc->bytes_received = 0;
-
-       if ((ret = scanaplus_init(devc)) < 0)
-               return ret;
-
-       if ((ret = scanaplus_start_acquisition(devc)) < 0)
-               return ret;
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(sdi, LOG_PREFIX);
-
-       /* Hook up a dummy handler to receive data from the device. */
-       sr_session_source_add(sdi->session, -1, G_IO_IN, 0, scanaplus_receive_data, (void *)sdi);
-
-       return SR_OK;
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct sr_datafeed_packet packet;
-
-       (void)cb_data;
-
-       sr_dbg("Stopping acquisition.");
-       sr_session_source_remove(sdi->session, -1);
-
-       /* Send end packet to the session bus. */
-       sr_dbg("Sending SR_DF_END.");
-       packet.type = SR_DF_END;
-       sr_session_send(sdi, &packet);
-
-       return SR_OK;
-}
-
-SR_PRIV struct sr_dev_driver ikalogic_scanaplus_driver_info = {
-       .name = "ikalogic-scanaplus",
-       .longname = "IKALOGIC ScanaPLUS",
-       .api_version = 1,
-       .init = init,
-       .cleanup = cleanup,
-       .scan = scan,
-       .dev_list = dev_list,
-       .dev_clear = dev_clear,
-       .config_get = config_get,
-       .config_set = config_set,
-       .config_list = config_list,
-       .dev_open = dev_open,
-       .dev_close = dev_close,
-       .dev_acquisition_start = dev_acquisition_start,
-       .dev_acquisition_stop = dev_acquisition_stop,
-       .priv = NULL,
-};
diff --git a/hardware/ikalogic-scanaplus/protocol.c b/hardware/ikalogic-scanaplus/protocol.c
deleted file mode 100644 (file)
index 3a834f7..0000000
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include "protocol.h"
-
-/*
- * Logic level thresholds.
- *
- * For each of the two channel groups (1-4 and 5-9), the logic level
- * threshold can be set independently.
- *
- * The threshold can be set to values that are usable for systems with
- * different voltage levels, e.g. for 1.8V or 3.3V systems.
- *
- * The actual threshold value is always the middle of the values below.
- * E.g. for a system voltage level of 1.8V, the threshold is at 0.9V. That
- * means that values <= 0.9V are considered to be a logic 0/low, and
- * values > 0.9V are considered to be a logic 1/high.
- *
- *  - 1.2V system: threshold = 0.6V
- *  - 1.5V system: threshold = 0.75V
- *  - 1.8V system: threshold = 0.9V
- *  - 2.8V system: threshold = 1.4V
- *  - 3.3V system: threshold = 1.65V
- */
-#define THRESHOLD_1_2V_SYSTEM 0x2e
-#define THRESHOLD_1_5V_SYSTEM 0x39
-#define THRESHOLD_1_8V_SYSTEM 0x45
-#define THRESHOLD_2_8V_SYSTEM 0x6c
-#define THRESHOLD_3_3V_SYSTEM 0x7f
-
-static int scanaplus_write(struct dev_context *devc, uint8_t *buf, int size)
-{
-       int i, bytes_written;
-       GString *s;
-
-       /* Note: Caller checks devc, devc->ftdic, buf, size. */
-
-       s = g_string_sized_new(100);
-       g_string_printf(s, "Writing %d bytes: ", size);
-       for (i = 0; i < size; i++)
-               g_string_append_printf(s, "0x%02x ", buf[i]);
-       sr_spew("%s", s->str);
-       g_string_free(s, TRUE);
-
-       bytes_written = ftdi_write_data(devc->ftdic, buf, size);
-       if (bytes_written < 0) {
-               sr_err("Failed to write FTDI data (%d): %s.",
-                      bytes_written, ftdi_get_error_string(devc->ftdic));
-       } else if (bytes_written != size) {
-               sr_err("FTDI write error, only %d/%d bytes written: %s.",
-                      bytes_written, size, ftdi_get_error_string(devc->ftdic));
-       }
-
-       return bytes_written;
-}
-
-SR_PRIV int scanaplus_close(struct dev_context *devc)
-{
-       int ret;
-
-       /* Note: Caller checks devc and devc->ftdic. */
-
-       if ((ret = ftdi_usb_close(devc->ftdic)) < 0) {
-               sr_err("Failed to close FTDI device (%d): %s.",
-                      ret, ftdi_get_error_string(devc->ftdic));
-               return SR_ERR;
-       }
-
-       return SR_OK;
-}
-
-static void scanaplus_uncompress_block(struct dev_context *devc,
-                                      uint64_t num_bytes)
-{
-       uint64_t i, j;
-       uint8_t num_samples, low, high;
-
-       for (i = 0; i < num_bytes; i += 2) {
-               num_samples = devc->compressed_buf[i + 0] >> 1;
-
-               low = devc->compressed_buf[i + 0] & (1 << 0);
-               high = devc->compressed_buf[i + 1];
-
-               for (j = 0; j < num_samples; j++) {
-                       devc->sample_buf[devc->bytes_received++] = high;
-                       devc->sample_buf[devc->bytes_received++] = low;
-               }
-       }
-}
-
-static void send_samples(struct dev_context *devc, uint64_t samples_to_send)
-{
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_logic logic;
-
-       sr_spew("Sending %" PRIu64 " samples.", samples_to_send);
-
-       packet.type = SR_DF_LOGIC;
-       packet.payload = &logic;
-       logic.length = samples_to_send * 2;
-       logic.unitsize = 2; /* We need 2 bytes for 9 channels. */
-       logic.data = devc->sample_buf;
-       sr_session_send(devc->cb_data, &packet);
-
-       devc->samples_sent += samples_to_send;
-       devc->bytes_received -= samples_to_send * 2;
-}
-
-SR_PRIV int scanaplus_get_device_id(struct dev_context *devc)
-{
-       int ret;
-       uint16_t val1, val2;
-
-       /* FTDI EEPROM indices 16+17 contain the 3 device ID bytes. */
-       if ((ret = ftdi_read_eeprom_location(devc->ftdic, 16, &val1)) < 0) {
-               sr_err("Failed to read EEPROM index 16 (%d): %s.",
-                      ret, ftdi_get_error_string(devc->ftdic));
-               return SR_ERR;
-       }
-       if ((ret = ftdi_read_eeprom_location(devc->ftdic, 17, &val2)) < 0) {
-               sr_err("Failed to read EEPROM index 17 (%d): %s.",
-                      ret, ftdi_get_error_string(devc->ftdic));
-               return SR_ERR;
-       }
-
-       /*
-        * Note: Bit 7 of the three bytes must not be used, apparently.
-        *
-        * Even though the three bits can be either 0 or 1 (we've seen both
-        * in actual ScanaPLUS devices), the device ID as sent to the FPGA
-        * has bit 7 of each byte zero'd out.
-        *
-        * It is unknown whether bit 7 of these bytes has any meaning,
-        * whether it's used somewhere, or whether it can be simply ignored.
-        */
-       devc->devid[0] = ((val1 >> 0) & 0xff) & ~(1 << 7);
-       devc->devid[1] = ((val1 >> 8) & 0xff) & ~(1 << 7);
-       devc->devid[2] = ((val2 >> 0) & 0xff) & ~(1 << 7);
-
-       return SR_OK;
-}
-
-static int scanaplus_clear_device_id(struct dev_context *devc)
-{
-       uint8_t buf[2];
-
-       buf[0] = 0x8c;
-       buf[1] = 0x00;
-       if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
-               return SR_ERR;
-
-       buf[0] = 0x8e;
-       buf[1] = 0x00;
-       if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
-               return SR_ERR;
-
-       buf[0] = 0x8f;
-       buf[1] = 0x00;
-       if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
-               return SR_ERR;
-
-       return SR_OK;
-}
-
-static int scanaplus_send_device_id(struct dev_context *devc)
-{
-       uint8_t buf[2];
-
-       buf[0] = 0x8c;
-       buf[1] = devc->devid[0];
-       if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
-               return SR_ERR;
-
-       buf[0] = 0x8e;
-       buf[1] = devc->devid[1];
-       if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
-               return SR_ERR;
-
-       buf[0] = 0x8f;
-       buf[1] = devc->devid[2];
-       if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
-               return SR_ERR;
-
-       return SR_OK;
-}
-
-SR_PRIV int scanaplus_init(struct dev_context *devc)
-{
-       int i;
-       uint8_t buf[8];
-
-       buf[0] = 0x88;
-       buf[1] = 0x41;
-       if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
-               return SR_ERR;
-
-       buf[0] = 0x89;
-       buf[1] = 0x64;
-       buf[2] = 0x8a;
-       buf[3] = 0x64;
-       if (scanaplus_write(devc, (uint8_t *)&buf, 4) < 0)
-               return SR_ERR;
-
-       buf[0] = 0x88;
-       buf[1] = 0x41;
-       if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
-               return SR_ERR;
-
-       buf[0] = 0x88;
-       buf[1] = 0x40;
-       if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
-               return SR_ERR;
-
-       buf[0] = 0x8d;
-       buf[1] = 0x01;
-       buf[2] = 0x8d;
-       buf[3] = 0x05;
-       buf[4] = 0x8d;
-       buf[5] = 0x01;
-       buf[6] = 0x8d;
-       buf[7] = 0x02;
-       if (scanaplus_write(devc, (uint8_t *)&buf, 8) < 0)
-               return SR_ERR;
-
-       for (i = 0; i < 57; i++) {
-               buf[0] = 0x8d;
-               buf[1] = 0x06;
-               if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
-                       return SR_ERR;
-
-               buf[0] = 0x8d;
-               buf[1] = 0x02;
-               if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
-                       return SR_ERR;
-       }
-
-       if (scanaplus_send_device_id(devc) < 0)
-               return SR_ERR;
-
-       buf[0] = 0x88;
-       buf[1] = 0x40;
-       if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
-               return SR_ERR;
-
-       return SR_OK;
-}
-
-SR_PRIV int scanaplus_start_acquisition(struct dev_context *devc)
-{
-       uint8_t buf[4];
-
-       /* Threshold and differential channel settings not yet implemented. */
-
-       buf[0] = 0x89;
-       buf[1] = 0x7f; /* Logic level threshold for channels 1-4. */
-       buf[2] = 0x8a;
-       buf[3] = 0x7f; /* Logic level threshold for channels 5-9. */
-       if (scanaplus_write(devc, (uint8_t *)&buf, 4) < 0)
-               return SR_ERR;
-
-       buf[0] = 0x88;
-       buf[1] = 0x40; /* Special config of channels 5/6 and 7/8. */
-       /* 0x40: normal, 0x50: ch56 diff, 0x48: ch78 diff, 0x58: ch5678 diff */
-       if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
-               return SR_ERR;
-
-       if (scanaplus_clear_device_id(devc) < 0)
-               return SR_ERR;
-
-       if (scanaplus_send_device_id(devc) < 0)
-               return SR_ERR;
-
-       return SR_OK;
-}
-
-SR_PRIV int scanaplus_receive_data(int fd, int revents, void *cb_data)
-{
-       int bytes_read;
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-       uint64_t max, n;
-
-       (void)fd;
-       (void)revents;
-
-       if (!(sdi = cb_data))
-               return TRUE;
-
-       if (!(devc = sdi->priv))
-               return TRUE;
-
-       if (!devc->ftdic)
-               return TRUE;
-
-       /* Get a block of data. */
-       bytes_read = ftdi_read_data(devc->ftdic, devc->compressed_buf,
-                                   COMPRESSED_BUF_SIZE);
-       if (bytes_read < 0) {
-               sr_err("Failed to read FTDI data (%d): %s.",
-                      bytes_read, ftdi_get_error_string(devc->ftdic));
-               sdi->driver->dev_acquisition_stop(sdi, sdi);
-               return FALSE;
-       }
-       if (bytes_read == 0) {
-               sr_spew("Received 0 bytes, nothing to do.");
-               return TRUE;
-       }
-
-       /*
-        * After a ScanaPLUS acquisition starts, a bunch of samples will be
-        * returned as all-zero, no matter which signals are actually present
-        * on the channels. This is probably due to the FPGA reconfiguring some
-        * of its internal state/config during this time.
-        *
-        * As far as we know there is apparently no way for the PC-side to
-        * know when this "reconfiguration" starts or ends. The FTDI chip
-        * will return all-zero "dummy" samples during this time, which is
-        * indistinguishable from actual all-zero samples.
-        *
-        * We currently simply ignore the first 64kB of data after an
-        * acquisition starts. Empirical tests have shown that the
-        * "reconfigure" time is a lot less than that usually.
-        */
-       if (devc->compressed_bytes_ignored < COMPRESSED_BUF_SIZE) {
-               /* Ignore the first 64kB of data of every acquisition. */
-               sr_spew("Ignoring first 64kB chunk of data.");
-               devc->compressed_bytes_ignored += COMPRESSED_BUF_SIZE;
-               return TRUE;
-       }
-
-       /* TODO: Handle bytes_read which is not a multiple of 2? */
-       scanaplus_uncompress_block(devc, bytes_read);
-
-       n = devc->samples_sent + (devc->bytes_received / 2);
-       max = (SR_MHZ(100) / 1000) * devc->limit_msec;
-
-       if (devc->limit_samples && (n >= devc->limit_samples)) {
-               send_samples(devc, devc->limit_samples - devc->samples_sent);
-               sr_info("Requested number of samples reached.");
-               sdi->driver->dev_acquisition_stop(sdi, cb_data);
-               return TRUE;
-       } else if (devc->limit_msec && (n >= max)) {
-               send_samples(devc, max - devc->samples_sent);
-               sr_info("Requested time limit reached.");
-               sdi->driver->dev_acquisition_stop(sdi, cb_data);
-               return TRUE;
-       } else {
-               send_samples(devc, devc->bytes_received / 2);
-       }
-
-       return TRUE;
-}
diff --git a/hardware/ikalogic-scanaplus/protocol.h b/hardware/ikalogic-scanaplus/protocol.h
deleted file mode 100644 (file)
index 1df0517..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#ifndef LIBSIGROK_HARDWARE_IKALOGIC_SCANAPLUS_PROTOCOL_H
-#define LIBSIGROK_HARDWARE_IKALOGIC_SCANAPLUS_PROTOCOL_H
-
-#include <stdint.h>
-#include <string.h>
-#include <glib.h>
-#include <ftdi.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "ikalogic-scanaplus"
-
-#define COMPRESSED_BUF_SIZE            (64 * 1024)
-
-/* Private, per-device-instance driver context. */
-struct dev_context {
-       /** FTDI device context (used by libftdi). */
-       struct ftdi_context *ftdic;
-
-       /** The current sampling limit (in ms). */
-       uint64_t limit_msec;
-
-       /** The current sampling limit (in number of samples). */
-       uint64_t limit_samples;
-
-       void *cb_data;
-
-       uint8_t *compressed_buf;
-       uint64_t compressed_bytes_ignored;
-       uint8_t *sample_buf;
-       uint64_t bytes_received;
-       uint64_t samples_sent;
-
-       /** ScanaPLUS unique device ID (3 bytes). */
-       uint8_t devid[3];
-};
-
-SR_PRIV int scanaplus_close(struct dev_context *devc);
-SR_PRIV int scanaplus_get_device_id(struct dev_context *devc);
-SR_PRIV int scanaplus_init(struct dev_context *devc);
-SR_PRIV int scanaplus_start_acquisition(struct dev_context *devc);
-SR_PRIV int scanaplus_receive_data(int fd, int revents, void *cb_data);
-
-#endif
diff --git a/hardware/kecheng-kc-330b/api.c b/hardware/kecheng-kc-330b/api.c
deleted file mode 100644 (file)
index 71bdc01..0000000
+++ /dev/null
@@ -1,575 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Bert Vermeulen <bert@biot.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 <string.h>
-#include "protocol.h"
-
-#define USB_CONN "1041.8101"
-#define VENDOR "Kecheng"
-#define USB_INTERFACE 0
-
-static const int32_t hwcaps[] = {
-       SR_CONF_SOUNDLEVELMETER,
-       SR_CONF_LIMIT_SAMPLES,
-       SR_CONF_CONTINUOUS,
-       SR_CONF_DATALOG,
-       SR_CONF_SPL_WEIGHT_FREQ,
-       SR_CONF_SPL_WEIGHT_TIME,
-       SR_CONF_DATA_SOURCE,
-};
-
-SR_PRIV const uint64_t kecheng_kc_330b_sample_intervals[][2] = {
-       { 1, 8 },
-       { 1, 2 },
-       { 1, 1 },
-       { 2, 1 },
-       { 5, 1 },
-       { 10, 1 },
-       { 60, 1 },
-};
-
-static const char *weight_freq[] = {
-       "A",
-       "C",
-};
-
-static const char *weight_time[] = {
-       "F",
-       "S",
-};
-
-static const char *data_sources[] = {
-       "Live",
-       "Memory",
-};
-
-SR_PRIV struct sr_dev_driver kecheng_kc_330b_driver_info;
-static struct sr_dev_driver *di = &kecheng_kc_330b_driver_info;
-
-
-static int init(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, di, LOG_PREFIX);
-}
-
-static int scan_kecheng(struct sr_usb_dev_inst *usb, char **model)
-{
-       struct drv_context *drvc;
-       int len, ret;
-       unsigned char cmd, buf[32];
-
-       drvc = di->priv;
-       if (sr_usb_open(drvc->sr_ctx->libusb_ctx, usb) != SR_OK)
-               return SR_ERR;
-
-       cmd = CMD_IDENTIFY;
-       ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, &cmd, 1, &len, 5);
-       if (ret != 0) {
-               libusb_close(usb->devhdl);
-               sr_dbg("Failed to send Identify command: %s", libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-       ret = libusb_bulk_transfer(usb->devhdl, EP_IN, buf, 32, &len, 10);
-       if (ret != 0) {
-               libusb_close(usb->devhdl);
-               sr_dbg("Failed to receive response: %s", libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-       libusb_close(usb->devhdl);
-       usb->devhdl = NULL;
-
-       if (len < 2 || buf[0] != (CMD_IDENTIFY | 0x80) || buf[1] > 30) {
-               sr_dbg("Invalid response to Identify command");
-               return SR_ERR;
-       }
-
-       buf[buf[1] + 2] = '\x0';
-       *model = g_strndup((const gchar *)buf + 2, 30);
-
-       return SR_OK;
-}
-
-static GSList *scan(GSList *options)
-{
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       struct sr_dev_inst *sdi;
-       struct sr_channel *ch;
-       GSList *usb_devices, *devices, *l;
-       char *model;
-
-       (void)options;
-
-       drvc = di->priv;
-       drvc->instances = NULL;
-
-       devices = NULL;
-       if ((usb_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, USB_CONN))) {
-               /* We have a list of sr_usb_dev_inst matching the connection
-                * string. Wrap them in sr_dev_inst and we're done. */
-               for (l = usb_devices; l; l = l->next) {
-                       if (scan_kecheng(l->data, &model) != SR_OK)
-                               continue;
-                       if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, VENDOR,
-                                       model, NULL)))
-                               return NULL;
-                       g_free(model);
-                       sdi->driver = di;
-                       sdi->inst_type = SR_INST_USB;
-                       sdi->conn = l->data;
-                       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "SPL")))
-                               return NULL;
-                       sdi->channels = g_slist_append(sdi->channels, ch);
-
-                       if (!(devc = g_try_malloc(sizeof(struct dev_context)))) {
-                               sr_dbg("Device context malloc failed.");
-                               return NULL;
-                       }
-                       sdi->priv = devc;
-                       devc->limit_samples = 0;
-                       /* The protocol provides no way to read the current
-                        * settings, so we'll enforce these. */
-                       devc->sample_interval = DEFAULT_SAMPLE_INTERVAL;
-                       devc->alarm_low = DEFAULT_ALARM_LOW;
-                       devc->alarm_high = DEFAULT_ALARM_HIGH;
-                       devc->mqflags = DEFAULT_WEIGHT_TIME | DEFAULT_WEIGHT_FREQ;
-                       devc->data_source = DEFAULT_DATA_SOURCE;
-                       devc->config_dirty = FALSE;
-
-                       /* TODO: Set date/time? */
-
-                       drvc->instances = g_slist_append(drvc->instances, sdi);
-                       devices = g_slist_append(devices, sdi);
-               }
-               g_slist_free(usb_devices);
-       } else
-               g_slist_free_full(usb_devices, g_free);
-
-       return devices;
-}
-
-static GSList *dev_list(void)
-{
-       return ((struct drv_context *)(di->priv))->instances;
-}
-
-static int dev_open(struct sr_dev_inst *sdi)
-{
-       struct drv_context *drvc;
-       struct sr_usb_dev_inst *usb;
-       int ret;
-
-       if (!(drvc = di->priv)) {
-               sr_err("Driver was not initialized.");
-               return SR_ERR;
-       }
-
-       usb = sdi->conn;
-
-       if (sr_usb_open(drvc->sr_ctx->libusb_ctx, usb) != SR_OK)
-               return SR_ERR;
-
-       if ((ret = libusb_set_configuration(usb->devhdl, 1))) {
-               sr_err("Failed to set configuration: %s.", libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-       if ((ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE))) {
-               sr_err("Failed to claim interface: %s.", libusb_error_name(ret));
-               return SR_ERR;
-       }
-       sdi->status = SR_ST_ACTIVE;
-
-       return ret;
-}
-
-static int dev_close(struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_usb_dev_inst *usb;
-
-       if (!di->priv) {
-               sr_err("Driver was not initialized.");
-               return SR_ERR;
-       }
-
-       usb = sdi->conn;
-
-       if (!usb->devhdl)
-               /*  Nothing to do. */
-               return SR_OK;
-
-       /* This allows a frontend to configure the device without ever
-        * doing an acquisition step. */
-       devc = sdi->priv;
-       if (!devc->config_dirty)
-               kecheng_kc_330b_configure(sdi);
-
-       libusb_release_interface(usb->devhdl, USB_INTERFACE);
-       libusb_close(usb->devhdl);
-       usb->devhdl = NULL;
-       sdi->status = SR_ST_INACTIVE;
-
-       return SR_OK;
-}
-
-static int cleanup(void)
-{
-       int ret;
-       struct drv_context *drvc;
-
-       if (!(drvc = di->priv))
-               /* Can get called on an unused driver, doesn't matter. */
-               return SR_OK;
-
-
-       ret = std_dev_clear(di, NULL);
-       g_free(drvc);
-       di->priv = NULL;
-
-       return ret;
-}
-
-static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       GVariant *rational[2];
-       const uint64_t *si;
-
-       (void)cg;
-
-       devc = sdi->priv;
-       switch (key) {
-       case SR_CONF_LIMIT_SAMPLES:
-               *data = g_variant_new_uint64(devc->limit_samples);
-               break;
-       case SR_CONF_SAMPLE_INTERVAL:
-               si = kecheng_kc_330b_sample_intervals[devc->sample_interval];
-               rational[0] = g_variant_new_uint64(si[0]);
-               rational[1] = g_variant_new_uint64(si[1]);
-               *data = g_variant_new_tuple(rational, 2);
-               break;
-       case SR_CONF_DATALOG:
-               /* There really isn't a way to be sure the device is logging. */
-               return SR_ERR_NA;
-               break;
-       case SR_CONF_SPL_WEIGHT_FREQ:
-               if (devc->mqflags & SR_MQFLAG_SPL_FREQ_WEIGHT_A)
-                       *data = g_variant_new_string("A");
-               else
-                       *data = g_variant_new_string("C");
-               break;
-       case SR_CONF_SPL_WEIGHT_TIME:
-               if (devc->mqflags & SR_MQFLAG_SPL_TIME_WEIGHT_F)
-                       *data = g_variant_new_string("F");
-               else
-                       *data = g_variant_new_string("S");
-               break;
-       case SR_CONF_DATA_SOURCE:
-               if (devc->data_source == DATA_SOURCE_LIVE)
-                       *data = g_variant_new_string("Live");
-               else
-                       *data = g_variant_new_string("Memory");
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       uint64_t p, q;
-       unsigned int i;
-       int tmp, ret;
-       const char *tmp_str;
-
-       (void)cg;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       if (!di->priv) {
-               sr_err("Driver was not initialized.");
-               return SR_ERR;
-       }
-
-       devc = sdi->priv;
-       ret = SR_OK;
-       switch (key) {
-       case SR_CONF_LIMIT_SAMPLES:
-               devc->limit_samples = g_variant_get_uint64(data);
-               sr_dbg("Setting sample limit to %" PRIu64 ".",
-                      devc->limit_samples);
-               break;
-       case SR_CONF_SAMPLE_INTERVAL:
-               g_variant_get(data, "(tt)", &p, &q);
-               for (i = 0; i < ARRAY_SIZE(kecheng_kc_330b_sample_intervals); i++) {
-                       if (kecheng_kc_330b_sample_intervals[i][0] != p || kecheng_kc_330b_sample_intervals[i][1] != q)
-                               continue;
-                       devc->sample_interval = i;
-                       devc->config_dirty = TRUE;
-                       break;
-               }
-               if (i == ARRAY_SIZE(kecheng_kc_330b_sample_intervals))
-                       ret = SR_ERR_ARG;
-               break;
-       case SR_CONF_SPL_WEIGHT_FREQ:
-               tmp_str = g_variant_get_string(data, NULL);
-               if (!strcmp(tmp_str, "A"))
-                       tmp = SR_MQFLAG_SPL_FREQ_WEIGHT_A;
-               else if (!strcmp(tmp_str, "C"))
-                       tmp = SR_MQFLAG_SPL_FREQ_WEIGHT_C;
-               else
-                       return SR_ERR_ARG;
-               devc->mqflags &= ~(SR_MQFLAG_SPL_FREQ_WEIGHT_A | SR_MQFLAG_SPL_FREQ_WEIGHT_C);
-               devc->mqflags |= tmp;
-               devc->config_dirty = TRUE;
-               break;
-       case SR_CONF_SPL_WEIGHT_TIME:
-               tmp_str = g_variant_get_string(data, NULL);
-               if (!strcmp(tmp_str, "F"))
-                       tmp = SR_MQFLAG_SPL_TIME_WEIGHT_F;
-               else if (!strcmp(tmp_str, "S"))
-                       tmp = SR_MQFLAG_SPL_TIME_WEIGHT_S;
-               else
-                       return SR_ERR_ARG;
-               devc->mqflags &= ~(SR_MQFLAG_SPL_TIME_WEIGHT_F | SR_MQFLAG_SPL_TIME_WEIGHT_S);
-               devc->mqflags |= tmp;
-               devc->config_dirty = TRUE;
-               break;
-       case SR_CONF_DATA_SOURCE:
-               tmp_str = g_variant_get_string(data, NULL);
-               if (!strcmp(tmp_str, "Live"))
-                       devc->data_source = DATA_SOURCE_LIVE;
-               else if (!strcmp(tmp_str, "Memory"))
-                       devc->data_source = DATA_SOURCE_MEMORY;
-               else
-                       return SR_ERR;
-               devc->config_dirty = TRUE;
-               break;
-       default:
-               ret = SR_ERR_NA;
-       }
-
-       return ret;
-}
-
-static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       GVariant *tuple, *rational[2];
-       GVariantBuilder gvb;
-       unsigned int i;
-
-       (void)sdi;
-       (void)cg;
-
-       switch (key) {
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
-               break;
-       case SR_CONF_SAMPLE_INTERVAL:
-               g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
-               for (i = 0; i < ARRAY_SIZE(kecheng_kc_330b_sample_intervals); i++) {
-                       rational[0] = g_variant_new_uint64(kecheng_kc_330b_sample_intervals[i][0]);
-                       rational[1] = g_variant_new_uint64(kecheng_kc_330b_sample_intervals[i][1]);
-                       tuple = g_variant_new_tuple(rational, 2);
-                       g_variant_builder_add_value(&gvb, tuple);
-               }
-               *data = g_variant_builder_end(&gvb);
-               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_DATA_SOURCE:
-               *data = g_variant_new_strv(data_sources, ARRAY_SIZE(data_sources));
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi,
-               void *cb_data)
-{
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_meta meta;
-       struct sr_config *src;
-       struct sr_usb_dev_inst *usb;
-       GVariant *gvar, *rational[2];
-       const uint64_t *si;
-       int stored_mqflags, req_len, buf_len, len, ret;
-       unsigned char buf[9];
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       drvc = di->priv;
-       devc = sdi->priv;
-       usb = sdi->conn;
-
-       devc->cb_data = cb_data;
-       devc->num_samples = 0;
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(cb_data, LOG_PREFIX);
-
-       if (devc->data_source == DATA_SOURCE_LIVE) {
-               /* Force configuration. */
-               kecheng_kc_330b_configure(sdi);
-
-               if (kecheng_kc_330b_status_get(sdi, &ret) != SR_OK)
-                       return SR_ERR;
-               if (ret != DEVICE_ACTIVE) {
-                       sr_err("Device is inactive");
-                       /* Still continue though, since the device will
-                        * just return 30.0 until the user hits the button
-                        * on the device -- and then start feeding good
-                        * samples back. */
-               }
-       } else {
-               if (kecheng_kc_330b_log_info_get(sdi, buf) != SR_OK)
-                       return SR_ERR;
-               stored_mqflags = buf[4] ? SR_MQFLAG_SPL_TIME_WEIGHT_S : SR_MQFLAG_SPL_TIME_WEIGHT_F;
-               stored_mqflags |= buf[5] ? SR_MQFLAG_SPL_FREQ_WEIGHT_C : SR_MQFLAG_SPL_FREQ_WEIGHT_A;
-               devc->stored_samples = (buf[7] << 8) | buf[8];
-               if (devc->stored_samples == 0) {
-                       /* Notify frontend of empty log by sending start/end packets. */
-                       packet.type = SR_DF_END;
-                       sr_session_send(cb_data, &packet);
-                       return SR_OK;
-               }
-
-               if (devc->limit_samples && devc->limit_samples < devc->stored_samples)
-                       devc->stored_samples = devc->limit_samples;
-
-               si = kecheng_kc_330b_sample_intervals[buf[1]];
-               rational[0] = g_variant_new_uint64(si[0]);
-               rational[1] = g_variant_new_uint64(si[1]);
-               gvar = g_variant_new_tuple(rational, 2);
-               src = sr_config_new(SR_CONF_SAMPLE_INTERVAL, gvar);
-               packet.type = SR_DF_META;
-               packet.payload = &meta;
-               meta.config = g_slist_append(NULL, src);
-               sr_session_send(devc->cb_data, &packet);
-               g_free(src);
-       }
-
-       if (!(devc->xfer = libusb_alloc_transfer(0)))
-               return SR_ERR;
-
-       usb_source_add(sdi->session, drvc->sr_ctx, 10,
-               kecheng_kc_330b_handle_events, (void *)sdi);
-
-       if (devc->data_source == DATA_SOURCE_LIVE) {
-               buf[0] = CMD_GET_LIVE_SPL;
-               buf_len = 1;
-               devc->state = LIVE_SPL_WAIT;
-               devc->last_live_request = g_get_monotonic_time() / 1000;
-               req_len = 3;
-       } else {
-               buf[0] = CMD_GET_LOG_DATA;
-               buf[1] = 0;
-               buf[2] = 0;
-               buf_len = 4;
-               devc->state = LOG_DATA_WAIT;
-               if (devc->stored_samples < 63)
-                       buf[3] = devc->stored_samples;
-               else
-                       buf[3] = 63;
-               /* Command ack byte + 2 bytes per sample. */
-               req_len = 1 + buf[3] * 2;
-       }
-
-       ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, buf, buf_len, &len, 5);
-       if (ret != 0 || len != 1) {
-               sr_dbg("Failed to start acquisition: %s", libusb_error_name(ret));
-               libusb_free_transfer(devc->xfer);
-               return SR_ERR;
-       }
-
-       libusb_fill_bulk_transfer(devc->xfer, usb->devhdl, EP_IN, devc->buf,
-                       req_len, kecheng_kc_330b_receive_transfer, (void *)sdi, 15);
-       if (libusb_submit_transfer(devc->xfer) != 0) {
-               libusb_free_transfer(devc->xfer);
-               return SR_ERR;
-       }
-
-       return SR_OK;
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct dev_context *devc;
-
-       (void)cb_data;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       /* Signal USB transfer handler to clean up and stop. */
-       sdi->status = SR_ST_STOPPING;
-
-       devc = sdi->priv;
-       if (devc->data_source == DATA_SOURCE_MEMORY && devc->config_dirty) {
-               /* The protocol doesn't have a command to clear stored data;
-                * it clears it whenever new configuration is set. That means
-                * we can't just configure the device any time we want when
-                * it's in DATA_SOURCE_MEMORY mode. The only safe time to do
-                * it is now, when we're sure we've pulled in all the stored
-                * data. */
-               kecheng_kc_330b_configure(sdi);
-       }
-
-       return SR_OK;
-}
-
-SR_PRIV struct sr_dev_driver kecheng_kc_330b_driver_info = {
-       .name = "kecheng-kc-330b",
-       .longname = "Kecheng KC-330B",
-       .api_version = 1,
-       .init = init,
-       .cleanup = cleanup,
-       .scan = scan,
-       .dev_list = 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,
-       .priv = NULL,
-};
diff --git a/hardware/kecheng-kc-330b/protocol.c b/hardware/kecheng-kc-330b/protocol.c
deleted file mode 100644 (file)
index caf896a..0000000
+++ /dev/null
@@ -1,338 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Bert Vermeulen <bert@biot.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 <string.h>
-#include "protocol.h"
-
-extern struct sr_dev_driver kecheng_kc_330b_driver_info;
-static struct sr_dev_driver *di = &kecheng_kc_330b_driver_info;
-extern const uint64_t kecheng_kc_330b_sample_intervals[][2];
-
-SR_PRIV int kecheng_kc_330b_handle_events(int fd, int revents, void *cb_data)
-{
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       struct sr_datafeed_packet packet;
-       struct sr_dev_inst *sdi;
-       struct sr_usb_dev_inst *usb;
-       struct timeval tv;
-       const uint64_t *intv_entry;
-       gint64 now, interval;
-       int offset, len, ret;
-       unsigned char buf[4];
-
-       (void)fd;
-       (void)revents;
-
-       drvc = di->priv;
-       sdi = cb_data;
-       devc = sdi->priv;
-       usb = sdi->conn;
-
-       memset(&tv, 0, sizeof(struct timeval));
-       libusb_handle_events_timeout_completed(drvc->sr_ctx->libusb_ctx, &tv,
-                                              NULL);
-
-       if (sdi->status == SR_ST_STOPPING) {
-               libusb_free_transfer(devc->xfer);
-               usb_source_remove(sdi->session, drvc->sr_ctx);
-               packet.type = SR_DF_END;
-               sr_session_send(cb_data, &packet);
-               sdi->status = SR_ST_ACTIVE;
-               return TRUE;
-       }
-
-       if (devc->state == LIVE_SPL_IDLE) {
-               /* Request samples at the interval rate. */
-               now = g_get_monotonic_time() / 1000;
-               intv_entry = kecheng_kc_330b_sample_intervals[devc->sample_interval];
-               interval = intv_entry[0] * 1000 / intv_entry[1];
-               if (now - devc->last_live_request > interval) {
-                       buf[0] = CMD_GET_LIVE_SPL;
-                       ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, buf, 1, &len, 5);
-                       if (ret != 0 || len != 1) {
-                               sr_dbg("Failed to request new acquisition: %s",
-                                               libusb_error_name(ret));
-                               sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi,
-                                               devc->cb_data);
-                               return TRUE;
-                       }
-                       libusb_submit_transfer(devc->xfer);
-                       devc->last_live_request = now;
-                       devc->state = LIVE_SPL_WAIT;
-               }
-       } else if (devc->state == LIVE_SPL_IDLE) {
-               buf[0] = CMD_GET_LOG_DATA;
-               offset = devc->num_samples / 63;
-               buf[1] = (offset >> 8) & 0xff;
-               buf[2] = offset & 0xff;
-               if (devc->stored_samples - devc->num_samples > 63)
-                       buf[3] = 63;
-               else
-                       /* Last chunk. */
-                       buf[3] = devc->stored_samples - devc->num_samples;
-               ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, buf, 4, &len, 5);
-               if (ret != 0 || len != 4) {
-                       sr_dbg("Failed to request next chunk: %s",
-                                       libusb_error_name(ret));
-                       sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi,
-                                       devc->cb_data);
-                       return TRUE;
-               }
-               libusb_submit_transfer(devc->xfer);
-               devc->state = LIVE_SPL_WAIT;
-       }
-
-       return TRUE;
-}
-
-static void send_data(const struct sr_dev_inst *sdi, void *buf, unsigned int buf_len)
-{
-       struct dev_context *devc;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_analog analog;
-
-       devc = sdi->priv;
-
-       memset(&analog, 0, sizeof(struct sr_datafeed_analog));
-       analog.mq = SR_MQ_SOUND_PRESSURE_LEVEL;
-       analog.mqflags = devc->mqflags;
-       analog.unit = SR_UNIT_DECIBEL_SPL;
-       analog.channels = sdi->channels;
-       analog.num_samples = buf_len;
-       analog.data = buf;
-       packet.type = SR_DF_ANALOG;
-       packet.payload = &analog;
-       sr_session_send(devc->cb_data, &packet);
-
-}
-
-SR_PRIV void kecheng_kc_330b_receive_transfer(struct libusb_transfer *transfer)
-{
-       struct dev_context *devc;
-       struct sr_dev_inst *sdi;
-       float fvalue[64];
-       int packet_has_error, num_samples, i;
-
-       sdi = transfer->user_data;
-       devc = sdi->priv;
-
-       packet_has_error = FALSE;
-       switch (transfer->status) {
-       case LIBUSB_TRANSFER_NO_DEVICE:
-               /* USB device was unplugged. */
-               sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi,
-                               devc->cb_data);
-               return;
-       case LIBUSB_TRANSFER_COMPLETED:
-       case LIBUSB_TRANSFER_TIMED_OUT: /* We may have received some data though */
-               break;
-       default:
-               packet_has_error = TRUE;
-               break;
-       }
-
-       if (packet_has_error)
-               return;
-
-       if (devc->state == LIVE_SPL_WAIT) {
-               if (transfer->actual_length != 3 || transfer->buffer[0] != 0x88) {
-                       sr_dbg("Received invalid SPL packet.");
-               } else {
-                       fvalue[0] = ((transfer->buffer[1] << 8) + transfer->buffer[2]) / 10.0;
-                       send_data(sdi, fvalue, 1);
-                       devc->num_samples++;
-                       if (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
-                               sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi,
-                                               devc->cb_data);
-                       } else {
-                               /* let USB event handler fire off another
-                                * request when the time is right. */
-                               devc->state = LIVE_SPL_IDLE;
-                       }
-               }
-       } else if (devc->state == LOG_DATA_WAIT) {
-               if (transfer->actual_length < 1 || !(transfer->actual_length & 0x01)) {
-                       sr_dbg("Received invalid stored SPL packet.");
-               } else {
-                       num_samples = (transfer->actual_length - 1) / 2;
-                       for (i = 0; i < num_samples; i++) {
-                               fvalue[i] = transfer->buffer[1 + i * 2] << 8;
-                               fvalue[i] += transfer->buffer[1 + i * 2 + 1];
-                               fvalue[i] /= 10.0;
-                       }
-                       send_data(sdi, fvalue, 1);
-                       devc->num_samples += num_samples;
-                       if (devc->num_samples >= devc->stored_samples) {
-                               sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi,
-                                               devc->cb_data);
-                       } else {
-                               /* let USB event handler fire off another
-                                * request when the time is right. */
-                               devc->state = LOG_DATA_IDLE;
-                       }
-               }
-       }
-
-}
-
-SR_PRIV int kecheng_kc_330b_configure(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_usb_dev_inst *usb;
-       int len, ret;
-       unsigned char buf[7];
-
-       sr_dbg("Configuring device.");
-
-       usb = sdi->conn;
-       devc = sdi->priv;
-
-       buf[0] = CMD_CONFIGURE;
-       buf[1] = devc->sample_interval;
-       buf[2] = devc->alarm_low;
-       buf[3] = devc->alarm_high;
-       buf[4] = devc->mqflags & SR_MQFLAG_SPL_TIME_WEIGHT_F ? 0 : 1;
-       buf[5] = devc->mqflags & SR_MQFLAG_SPL_FREQ_WEIGHT_A ? 0 : 1;
-       buf[6] = devc->data_source;
-       ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, buf, 7, &len, 5);
-       if (ret != 0 || len != 7) {
-               sr_dbg("Failed to configure device: %s", libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-       /* The configure command ack takes about 32ms to come in. */
-       ret = libusb_bulk_transfer(usb->devhdl, EP_IN, buf, 1, &len, 40);
-       if (ret != 0 || len != 1) {
-               sr_dbg("Failed to configure device (no ack): %s", libusb_error_name(ret));
-               return SR_ERR;
-       }
-       if (buf[0] != (CMD_CONFIGURE | 0x80)) {
-               sr_dbg("Failed to configure device: invalid response 0x%2.x", buf[0]);
-               return SR_ERR;
-       }
-
-       devc->config_dirty = FALSE;
-
-       return SR_OK;
-}
-
-SR_PRIV int kecheng_kc_330b_set_date_time(struct sr_dev_inst *sdi)
-{
-       struct sr_usb_dev_inst *usb;
-       GDateTime *dt;
-       int len, ret;
-       unsigned char buf[7];
-
-       sr_dbg("Setting device date/time.");
-
-       usb = sdi->conn;
-
-       dt = g_date_time_new_now_local();
-       buf[0] = CMD_SET_DATE_TIME;
-       buf[1] = g_date_time_get_year(dt) - 2000;
-       buf[2] = g_date_time_get_month(dt);
-       buf[3] = g_date_time_get_day_of_month(dt);
-       buf[4] = g_date_time_get_hour(dt);
-       buf[5] = g_date_time_get_minute(dt);
-       buf[6] = g_date_time_get_second(dt);
-       g_date_time_unref(dt);
-       ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, buf, 7, &len, 5);
-       if (ret != 0 || len != 7) {
-               sr_dbg("Failed to set date/time: %s", libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-       ret = libusb_bulk_transfer(usb->devhdl, EP_IN, buf, 1, &len, 10);
-       if (ret != 0 || len != 1) {
-               sr_dbg("Failed to set date/time (no ack): %s", libusb_error_name(ret));
-               return SR_ERR;
-       }
-       if (buf[0] != (CMD_SET_DATE_TIME | 0x80)) {
-               sr_dbg("Failed to set date/time: invalid response 0x%2.x", buf[0]);
-               return SR_ERR;
-       }
-
-       return SR_OK;
-}
-
-SR_PRIV int kecheng_kc_330b_status_get(const struct sr_dev_inst *sdi,
-               int *status)
-{
-       struct sr_usb_dev_inst *usb;
-       int len, ret;
-       unsigned char buf;
-
-       sr_dbg("Getting device status.");
-
-       usb = sdi->conn;
-       buf = CMD_GET_STATUS;
-       ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, &buf, 1, &len, 5);
-       if (ret != 0 || len != 1) {
-               sr_dbg("Failed to get status: %s", libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-       ret = libusb_bulk_transfer(usb->devhdl, EP_IN, &buf, 1, &len, 10);
-       if (ret != 0 || len != 1) {
-               sr_dbg("Failed to get status (no ack): %s", libusb_error_name(ret));
-               return SR_ERR;
-       }
-       /* Need either 0x84 or 0xa4. */
-       if (buf != (CMD_GET_STATUS | 0x80) && buf != (CMD_GET_STATUS | 0xa0)) {
-               sr_dbg("Failed to get status: invalid response 0x%2.x", buf);
-               return SR_ERR;
-       }
-
-       if (buf & 0x20)
-               *status = DEVICE_INACTIVE;
-       else
-               *status = DEVICE_ACTIVE;
-
-       return SR_OK;
-}
-
-SR_PRIV int kecheng_kc_330b_log_info_get(const struct sr_dev_inst *sdi,
-               unsigned char *buf)
-{
-       struct sr_usb_dev_inst *usb;
-       int len, ret;
-
-       sr_dbg("Getting logging info.");
-
-       usb = sdi->conn;
-       buf[0] = CMD_GET_LOG_INFO;
-       ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, buf, 1, &len, 5);
-       if (ret != 0 || len != 1) {
-               sr_dbg("Failed to get status: %s", libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-       ret = libusb_bulk_transfer(usb->devhdl, EP_IN, buf, 9, &len, 10);
-       if (ret != 0 || len != 9) {
-               sr_dbg("Failed to get status (no ack): %s", libusb_error_name(ret));
-               return SR_ERR;
-       }
-       if (buf[0] != (CMD_GET_LOG_INFO | 0x80) || buf[1] > 6) {
-               sr_dbg("Failed to get log info: invalid response 0x%2.x", buf[0]);
-               return SR_ERR;
-       }
-
-       return SR_OK;
-}
diff --git a/hardware/kecheng-kc-330b/protocol.h b/hardware/kecheng-kc-330b/protocol.h
deleted file mode 100644 (file)
index 09152b9..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Bert Vermeulen <bert@biot.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_KECHENG_KC_330B_PROTOCOL_H
-#define LIBSIGROK_HARDWARE_KECHENG_KC_330B_PROTOCOL_H
-
-#include <stdint.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "kecheng-kc-330b"
-
-#define EP_IN 0x80 | 1
-#define EP_OUT 2
-
-/* 500ms */
-#define DEFAULT_SAMPLE_INTERVAL 0
-#define DEFAULT_ALARM_LOW 40
-#define DEFAULT_ALARM_HIGH 120
-#define DEFAULT_WEIGHT_TIME SR_MQFLAG_SPL_TIME_WEIGHT_F
-#define DEFAULT_WEIGHT_FREQ SR_MQFLAG_SPL_FREQ_WEIGHT_A
-/* Live */
-#define DEFAULT_DATA_SOURCE DATA_SOURCE_LIVE
-
-enum {
-       LIVE_SPL_IDLE,
-       LIVE_SPL_WAIT,
-       LOG_DATA_IDLE,
-       LOG_DATA_WAIT,
-};
-
-enum {
-       CMD_CONFIGURE = 0x01,
-       CMD_IDENTIFY = 0x02,
-       CMD_SET_DATE_TIME = 0x03,
-       CMD_GET_STATUS = 0x04,
-       CMD_GET_LOG_INFO = 0x05,
-       CMD_GET_LOG_DATA = 0x07,
-       CMD_GET_LIVE_SPL = 0x08,
-};
-
-enum {
-       DATA_SOURCE_LIVE,
-       DATA_SOURCE_MEMORY,
-};
-
-enum {
-       DEVICE_ACTIVE,
-       DEVICE_INACTIVE,
-};
-
-/** Private, per-device-instance driver context. */
-struct dev_context {
-       /* Acquisition settings */
-       uint64_t limit_samples;
-       int sample_interval;
-       int alarm_low;
-       int alarm_high;
-       uint64_t mqflags;
-       int data_source;
-
-       /* Operational state */
-       int state;
-       gboolean config_dirty;
-       uint64_t num_samples;
-       uint64_t stored_samples;
-       void *cb_data;
-       struct libusb_transfer *xfer;
-       unsigned char buf[128];
-
-       /* Temporary state across callbacks */
-       gint64 last_live_request;
-
-};
-
-SR_PRIV int kecheng_kc_330b_handle_events(int fd, int revents, void *cb_data);
-SR_PRIV void kecheng_kc_330b_receive_transfer(struct libusb_transfer *transfer);
-SR_PRIV int kecheng_kc_330b_configure(const struct sr_dev_inst *sdi);
-SR_PRIV int kecheng_kc_330b_set_date_time(struct sr_dev_inst *sdi);
-SR_PRIV int kecheng_kc_330b_recording_get(const struct sr_dev_inst *sdi,
-               gboolean *tmp);
-SR_PRIV int kecheng_kc_330b_status_get(const struct sr_dev_inst *sdi,
-               int *status);
-SR_PRIV int kecheng_kc_330b_log_info_get(const struct sr_dev_inst *sdi,
-               unsigned char *buf);
-
-#endif
diff --git a/hardware/lascar-el-usb/api.c b/hardware/lascar-el-usb/api.c
deleted file mode 100644 (file)
index 04f844b..0000000
+++ /dev/null
@@ -1,490 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012 Bert Vermeulen <bert@biot.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 <glib.h>
-#include <libusb.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-#include "protocol.h"
-
-SR_PRIV struct sr_dev_driver lascar_el_usb_driver_info;
-static struct sr_dev_driver *di = &lascar_el_usb_driver_info;
-
-static const int32_t hwopts[] = {
-       SR_CONF_CONN,
-};
-
-static const int32_t hwcaps[] = {
-       SR_CONF_THERMOMETER,
-       SR_CONF_HYGROMETER,
-       SR_CONF_DATALOG,
-       SR_CONF_LIMIT_SAMPLES,
-};
-
-static int init(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, di, LOG_PREFIX);
-}
-
-static GSList *scan(GSList *options)
-{
-       struct drv_context *drvc;
-       struct sr_dev_inst *sdi;
-       struct sr_usb_dev_inst *usb;
-       struct sr_config *src;
-       GSList *usb_devices, *devices, *l;
-       const char *conn;
-
-       drvc = di->priv;
-
-       conn = NULL;
-       for (l = options; l; l = l->next) {
-               src = l->data;
-               switch (src->key) {
-               case SR_CONF_CONN:
-                       conn = g_variant_get_string(src->data, NULL);
-                       break;
-               }
-       }
-       if (!conn)
-               return NULL;
-
-       devices = NULL;
-       if ((usb_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn))) {
-               /* We have a list of sr_usb_dev_inst matching the connection
-                * string. Wrap them in sr_dev_inst and we're done. */
-               for (l = usb_devices; l; l = l->next) {
-                       usb = l->data;
-                       if (!(sdi = lascar_scan(usb->bus, usb->address))) {
-                               /* Not a Lascar EL-USB. */
-                               g_free(usb);
-                               continue;
-                       }
-                       sdi->inst_type = SR_INST_USB;
-                       sdi->conn = usb;
-                       drvc->instances = g_slist_append(drvc->instances, sdi);
-                       devices = g_slist_append(devices, sdi);
-               }
-               g_slist_free(usb_devices);
-       } else
-               g_slist_free_full(usb_devices, g_free);
-
-       return devices;
-}
-
-static GSList *dev_list(void)
-{
-       return ((struct drv_context *)(di->priv))->instances;
-}
-
-static int dev_open(struct sr_dev_inst *sdi)
-{
-       struct drv_context *drvc;
-       struct sr_usb_dev_inst *usb;
-       int ret;
-
-       if (!(drvc = di->priv)) {
-               sr_err("Driver was not initialized.");
-               return SR_ERR;
-       }
-
-       usb = sdi->conn;
-
-       if (sr_usb_open(drvc->sr_ctx->libusb_ctx, usb) != SR_OK)
-               return SR_ERR;
-
-       if ((ret = libusb_claim_interface(usb->devhdl, LASCAR_INTERFACE))) {
-               sr_err("Failed to claim interface: %s.", libusb_error_name(ret));
-               return SR_ERR;
-       }
-       sdi->status = SR_ST_ACTIVE;
-
-       return ret;
-}
-
-static int dev_close(struct sr_dev_inst *sdi)
-{
-       struct sr_usb_dev_inst *usb;
-
-       if (!di->priv) {
-               sr_err("Driver was not initialized.");
-               return SR_ERR;
-       }
-
-       usb = sdi->conn;
-
-       if (!usb->devhdl)
-               /*  Nothing to do. */
-               return SR_OK;
-
-       libusb_release_interface(usb->devhdl, LASCAR_INTERFACE);
-       libusb_close(usb->devhdl);
-       usb->devhdl = NULL;
-       sdi->status = SR_ST_INACTIVE;
-
-       return SR_OK;
-}
-
-static int cleanup(void)
-{
-       int ret;
-       struct drv_context *drvc;
-
-       if (!(drvc = di->priv))
-               /* Can get called on an unused driver, doesn't matter. */
-               return SR_OK;
-
-
-       ret = std_dev_clear(di, NULL);
-       g_free(drvc);
-       di->priv = NULL;
-
-       return ret;
-}
-
-static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       struct sr_usb_dev_inst *usb;
-       int ret;
-       char str[128];
-
-       (void)cg;
-
-       devc = sdi->priv;
-       switch (id) {
-       case SR_CONF_CONN:
-               if (!sdi || !sdi->conn)
-                       return SR_ERR_ARG;
-               usb = sdi->conn;
-               snprintf(str, 128, "%d.%d", usb->bus, usb->address);
-               *data = g_variant_new_string(str);
-               break;
-       case SR_CONF_DATALOG:
-               if (!sdi)
-                       return SR_ERR_ARG;
-               if ((ret = lascar_is_logging(sdi)) == -1)
-                       return SR_ERR;
-               *data = g_variant_new_boolean(ret ? TRUE : FALSE);
-               break;
-       case SR_CONF_LIMIT_SAMPLES:
-               *data = g_variant_new_uint64(devc->limit_samples);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       int ret;
-
-       (void)cg;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       if (!di->priv) {
-               sr_err("Driver was not initialized.");
-               return SR_ERR;
-       }
-
-       devc = sdi->priv;
-       ret = SR_OK;
-       switch (id) {
-       case SR_CONF_DATALOG:
-               if (g_variant_get_boolean(data)) {
-                       /* Start logging. */
-                       ret = lascar_start_logging(sdi);
-               } else {
-                       /* Stop logging. */
-                       ret = lascar_stop_logging(sdi);
-               }
-               break;
-       case SR_CONF_LIMIT_SAMPLES:
-               devc->limit_samples = g_variant_get_uint64(data);
-               sr_dbg("Setting sample limit to %" PRIu64 ".",
-                      devc->limit_samples);
-               break;
-       default:
-               ret = SR_ERR_NA;
-       }
-
-       return ret;
-}
-
-static int config_list(int 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_INT32,
-                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
-               break;
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static void mark_xfer(struct libusb_transfer *xfer)
-{
-
-       if (xfer->status == LIBUSB_TRANSFER_COMPLETED)
-               xfer->user_data = GINT_TO_POINTER(1);
-       else
-               xfer->user_data = GINT_TO_POINTER(-1);
-
-}
-
-/* The Lascar software, in its infinite ignorance, reads a set of four
- * bytes from the device config struct and interprets it as a float.
- * That only works because they only use windows, and only on x86. However
- * we may be running on any architecture, any operating system. So we have
- * to convert these four bytes as the Lascar software would on windows/x86,
- * to the local representation of a float.
- * The source format is little-endian, with IEEE 754-2008 BINARY32 encoding. */
-static float binary32_le_to_float(unsigned char *buf)
-{
-       GFloatIEEE754 f;
-
-       f.v_float = 0;
-       f.mpn.sign = (buf[3] & 0x80) ? 1 : 0;
-       f.mpn.biased_exponent = (buf[3] << 1) | (buf[2] >> 7);
-       f.mpn.mantissa = buf[0] | (buf[1] << 8) | ((buf[2] & 0x7f) << 16);
-
-       return f.v_float;
-}
-
-static int lascar_proc_config(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_usb_dev_inst *usb;
-       int dummy, ret;
-
-       devc = sdi->priv;
-       usb = sdi->conn;
-
-       if (lascar_get_config(usb->devhdl, devc->config, &dummy) != SR_OK)
-               return SR_ERR;
-
-       ret = SR_OK;
-       switch (devc->profile->logformat) {
-       case LOG_TEMP_RH:
-               devc->sample_size = 2;
-               devc->temp_unit = devc->config[0x2e] | (devc->config[0x2f] << 8);
-               if (devc->temp_unit != 0 && devc->temp_unit != 1) {
-                       sr_dbg("invalid temperature unit %d", devc->temp_unit);
-                       /* Default to Celcius, we're all adults here. */
-                       devc->temp_unit = 0;
-               } else
-                       sr_dbg("temperature unit is %s", devc->temp_unit
-                                       ? "Fahrenheit" : "Celcius");
-               break;
-       case LOG_CO:
-               devc->sample_size = 2;
-               devc->co_high = binary32_le_to_float(devc->config + 0x24);
-               devc->co_low = binary32_le_to_float(devc->config + 0x28);
-               sr_dbg("EL-USB-CO calibration high %f low %f", devc->co_high,
-                               devc->co_low);
-               break;
-       default:
-               ret = SR_ERR_ARG;
-       }
-       devc->logged_samples = devc->config[0x1e] | (devc->config[0x1f] << 8);
-       sr_dbg("device log contains %d samples.", devc->logged_samples);
-
-       return ret;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_meta meta;
-       struct sr_config *src;
-       struct dev_context *devc;
-       struct drv_context *drvc;
-       struct sr_usb_dev_inst *usb;
-       struct libusb_transfer *xfer_in, *xfer_out;
-       struct timeval tv;
-       uint64_t interval;
-       int ret;
-       unsigned char cmd[3], resp[4], *buf;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       if (!di->priv) {
-               sr_err("Driver was not initialized.");
-               return SR_ERR;
-       }
-
-       drvc = di->priv;
-       devc = sdi->priv;
-       usb = sdi->conn;
-       devc->cb_data = cb_data;
-
-       if (lascar_proc_config(sdi) != SR_OK)
-               return SR_ERR;
-
-       sr_dbg("Starting log retrieval.");
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(cb_data, LOG_PREFIX);
-
-       interval = (devc->config[0x1c] | (devc->config[0x1d] << 8)) * 1000;
-       packet.type = SR_DF_META;
-       packet.payload = &meta;
-       src = sr_config_new(SR_CONF_SAMPLE_INTERVAL, g_variant_new_uint64(interval));
-       meta.config = g_slist_append(NULL, src);
-       sr_session_send(devc->cb_data, &packet);
-       g_free(src);
-
-       if (devc->logged_samples == 0) {
-               /* This ensures the frontend knows the session is done. */
-               packet.type = SR_DF_END;
-               sr_session_send(devc->cb_data, &packet);
-               return SR_OK;
-       }
-
-       if (!(xfer_in = libusb_alloc_transfer(0)) ||
-                       !(xfer_out = libusb_alloc_transfer(0)))
-               return SR_ERR;
-
-       libusb_control_transfer(usb->devhdl, LIBUSB_REQUEST_TYPE_VENDOR,
-                       0x00, 0xffff, 0x00, NULL, 0, 50);
-       libusb_control_transfer(usb->devhdl, LIBUSB_REQUEST_TYPE_VENDOR,
-                       0x02, 0x0002, 0x00, NULL, 0, 50);
-       libusb_control_transfer(usb->devhdl, LIBUSB_REQUEST_TYPE_VENDOR,
-                       0x02, 0x0001, 0x00, NULL, 0, 50);
-
-
-       /* Flush input. The F321 requires this. */
-       while (libusb_bulk_transfer(usb->devhdl, LASCAR_EP_IN, resp,
-                       256, &ret, 5) == 0 && ret > 0)
-               ;
-
-       libusb_fill_bulk_transfer(xfer_in, usb->devhdl, LASCAR_EP_IN,
-                       resp, sizeof(resp), mark_xfer, 0, 10000);
-       if (libusb_submit_transfer(xfer_in) != 0) {
-               libusb_free_transfer(xfer_in);
-               libusb_free_transfer(xfer_out);
-               return SR_ERR;
-       }
-
-       cmd[0] = 0x03;
-       cmd[1] = 0xff;
-       cmd[2] = 0xff;
-       libusb_fill_bulk_transfer(xfer_out, usb->devhdl, LASCAR_EP_OUT,
-                       cmd, 3, mark_xfer, 0, 100);
-       if (libusb_submit_transfer(xfer_out) != 0) {
-               libusb_free_transfer(xfer_in);
-               libusb_free_transfer(xfer_out);
-               return SR_ERR;
-       }
-
-       tv.tv_sec = 0;
-       tv.tv_usec = 0;
-       while (!xfer_in->user_data || !xfer_out->user_data) {
-               g_usleep(5000);
-               libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
-       }
-       if (xfer_in->user_data != GINT_TO_POINTER(1) ||
-                       xfer_in->user_data != GINT_TO_POINTER(1)) {
-               sr_dbg("no response to log transfer request");
-               libusb_free_transfer(xfer_in);
-               libusb_free_transfer(xfer_out);
-               return SR_ERR;
-       }
-       if (xfer_in->actual_length != 3 || xfer_in->buffer[0] != 2) {
-               sr_dbg("invalid response to log transfer request");
-               libusb_free_transfer(xfer_in);
-               libusb_free_transfer(xfer_out);
-               return SR_ERR;
-       }
-       devc->log_size = xfer_in->buffer[1] + (xfer_in->buffer[2] << 8);
-       libusb_free_transfer(xfer_out);
-
-       usb_source_add(sdi->session, drvc->sr_ctx, 100,
-                       lascar_el_usb_handle_events, (void *)sdi);
-
-       buf = g_try_malloc(4096);
-       libusb_fill_bulk_transfer(xfer_in, usb->devhdl, LASCAR_EP_IN,
-                       buf, 4096, lascar_el_usb_receive_transfer, cb_data, 100);
-       if ((ret = libusb_submit_transfer(xfer_in) != 0)) {
-               sr_err("Unable to submit transfer: %s.", libusb_error_name(ret));
-               libusb_free_transfer(xfer_in);
-               g_free(buf);
-               return SR_ERR;
-       }
-
-       return SR_OK;
-}
-
-SR_PRIV int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       (void)cb_data;
-
-       if (!di->priv) {
-               sr_err("Driver was not initialized.");
-               return SR_ERR;
-       }
-
-       if (sdi->status != SR_ST_ACTIVE) {
-               sr_err("Device inactive, can't stop acquisition.");
-               return SR_ERR;
-       }
-
-       sdi->status = SR_ST_STOPPING;
-       /* TODO: free ongoing transfers? */
-
-       return SR_OK;
-}
-
-SR_PRIV struct sr_dev_driver lascar_el_usb_driver_info = {
-       .name = "lascar-el-usb",
-       .longname = "Lascar EL-USB",
-       .api_version = 1,
-       .init = init,
-       .cleanup = cleanup,
-       .scan = scan,
-       .dev_list = 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,
-       .priv = NULL,
-};
diff --git a/hardware/lascar-el-usb/protocol.c b/hardware/lascar-el-usb/protocol.c
deleted file mode 100644 (file)
index 49c5cd0..0000000
+++ /dev/null
@@ -1,656 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012 Bert Vermeulen <bert@biot.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 <stdlib.h>
-#include <sys/time.h>
-#include <string.h>
-#include <math.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-#include "protocol.h"
-
-extern struct sr_dev_driver lascar_el_usb_driver_info;
-static struct sr_dev_driver *di = &lascar_el_usb_driver_info;
-
-static const struct elusb_profile profiles[] = {
-       { 1, "EL-USB-1", LOG_UNSUPPORTED },
-       { 2, "EL-USB-1", LOG_UNSUPPORTED },
-       { 3, "EL-USB-2", LOG_TEMP_RH },
-       { 4, "EL-USB-3", LOG_UNSUPPORTED },
-       { 5, "EL-USB-4", LOG_UNSUPPORTED },
-       { 6, "EL-USB-3", LOG_UNSUPPORTED },
-       { 7, "EL-USB-4", LOG_UNSUPPORTED },
-       { 8, "EL-USB-LITE", LOG_UNSUPPORTED },
-       { 9, "EL-USB-CO", LOG_CO },
-       { 10, "EL-USB-TC", LOG_UNSUPPORTED },
-       { 11, "EL-USB-CO300", LOG_CO },
-       { 12, "EL-USB-2-LCD", LOG_TEMP_RH },
-       { 13, "EL-USB-2+", LOG_TEMP_RH },
-       { 14, "EL-USB-1-PRO", LOG_UNSUPPORTED },
-       { 15, "EL-USB-TC-LCD", LOG_UNSUPPORTED },
-       { 16, "EL-USB-2-LCD+", LOG_TEMP_RH },
-       { 17, "EL-USB-5", LOG_UNSUPPORTED },
-       { 18, "EL-USB-1-RCG", LOG_UNSUPPORTED },
-       { 19, "EL-USB-1-LCD", LOG_UNSUPPORTED },
-       { 20, "EL-OEM-3", LOG_UNSUPPORTED },
-       { 21, "EL-USB-1-LCD", LOG_UNSUPPORTED },
-       { 0, NULL, 0 }
-};
-
-
-static libusb_device_handle *lascar_open(struct libusb_device *dev)
-{
-       libusb_device_handle *dev_hdl;
-       int ret;
-
-       if ((ret = libusb_open(dev, &dev_hdl)) != 0) {
-               sr_dbg("failed to open device for scan: %s",
-                               libusb_error_name(ret));
-               return NULL;
-       }
-
-       /* Some of these fail, but it needs doing -- some sort of mode
-        * setup for the SILabs F32x. */
-       libusb_control_transfer(dev_hdl, LIBUSB_REQUEST_TYPE_VENDOR,
-                       0x00, 0xffff, 0x00, NULL, 0, 50);
-       libusb_control_transfer(dev_hdl, LIBUSB_REQUEST_TYPE_VENDOR,
-                       0x02, 0x0002, 0x00, NULL, 0, 50);
-       libusb_control_transfer(dev_hdl, LIBUSB_REQUEST_TYPE_VENDOR,
-                       0x02, 0x0001, 0x00, NULL, 0, 50);
-
-       return dev_hdl;
-}
-
-static void mark_xfer(struct libusb_transfer *xfer)
-{
-
-       xfer->user_data = GINT_TO_POINTER(1);
-
-}
-
-SR_PRIV int lascar_get_config(libusb_device_handle *dev_hdl,
-               unsigned char *configblock, int *configlen)
-{
-       struct drv_context *drvc;
-       struct libusb_transfer *xfer_in, *xfer_out;
-       struct timeval tv;
-       int64_t start;
-       int buflen;
-       unsigned char cmd[3], buf[MAX_CONFIGBLOCK_SIZE];
-
-       sr_spew("Reading config block.");
-
-       drvc = di->priv;
-       *configlen = 0;
-
-       if (!(xfer_in = libusb_alloc_transfer(0)) ||
-                       !(xfer_out = libusb_alloc_transfer(0)))
-               return SR_ERR;
-
-       /* Flush anything the F321 still has queued. */
-       while (libusb_bulk_transfer(dev_hdl, LASCAR_EP_IN, buf, 256, &buflen,
-                       5) == 0 && buflen > 0)
-               ;
-
-       /* Keep a read request waiting in the wings, ready to pounce
-        * the moment the device sends something. */
-       libusb_fill_bulk_transfer(xfer_in, dev_hdl, LASCAR_EP_IN,
-                       buf, 256, mark_xfer, 0, 10000);
-       if (libusb_submit_transfer(xfer_in) != 0)
-               goto cleanup;
-
-       /* Request device configuration structure. */
-       cmd[0] = 0x00;
-       cmd[1] = 0xff;
-       cmd[2] = 0xff;
-       libusb_fill_bulk_transfer(xfer_out, dev_hdl, LASCAR_EP_OUT,
-                       cmd, 3, mark_xfer, 0, 100);
-       if (libusb_submit_transfer(xfer_out) != 0)
-               goto cleanup;
-
-       tv.tv_sec = 0;
-       tv.tv_usec = 0;
-       start = g_get_monotonic_time();
-       while (!xfer_in->user_data || !xfer_out->user_data) {
-               if (g_get_monotonic_time() - start > SCAN_TIMEOUT) {
-                       start = 0;
-                       break;
-               }
-               g_usleep(5000);
-               libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
-       }
-       if (!start) {
-               sr_dbg("no response");
-               goto cleanup;
-       }
-       if (xfer_in->actual_length != 3) {
-               sr_dbg("expected 3-byte header, got %d bytes", xfer_in->actual_length);
-               goto cleanup;
-       }
-
-       /* Got configuration structure header. */
-       sr_spew("Response to config request: 0x%.2x 0x%.2x 0x%.2x ",
-                       buf[0], buf[1], buf[2]);
-       buflen = buf[1] | (buf[2] << 8);
-       if (buf[0] != 0x02 || buflen > MAX_CONFIGBLOCK_SIZE) {
-               sr_dbg("Invalid response to config request: "
-                               "0x%.2x 0x%.2x 0x%.2x ", buf[0], buf[1], buf[2]);
-               libusb_close(dev_hdl);
-               goto cleanup;
-       }
-
-       /* Get configuration structure. */
-       xfer_in->length = buflen;
-       xfer_in->user_data = 0;
-       if (libusb_submit_transfer(xfer_in) != 0)
-               goto cleanup;
-       while (!xfer_in->user_data) {
-               if (g_get_monotonic_time() - start > SCAN_TIMEOUT) {
-                       start = 0;
-                       break;
-               }
-               g_usleep(5000);
-               libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
-       }
-       if (!start) {
-               sr_dbg("Timeout waiting for configuration structure.");
-               goto cleanup;
-       }
-       if (xfer_in->actual_length != buflen) {
-               sr_dbg("expected %d-byte structure, got %d bytes", buflen,
-                               xfer_in->actual_length);
-               goto cleanup;
-       }
-
-       memcpy(configblock, buf, buflen);
-       *configlen = buflen;
-
-cleanup:
-       if (!xfer_in->user_data || !xfer_in->user_data) {
-               if (!xfer_in->user_data)
-                       libusb_cancel_transfer(xfer_in);
-               if (!xfer_out->user_data)
-                       libusb_cancel_transfer(xfer_out);
-               start = g_get_monotonic_time();
-               while (!xfer_in->user_data || !xfer_out->user_data) {
-                       if (g_get_monotonic_time() - start > 10000)
-                               break;
-                       g_usleep(1000);
-                       libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
-               }
-       }
-       libusb_free_transfer(xfer_in);
-       libusb_free_transfer(xfer_out);
-
-       return *configlen ? SR_OK : SR_ERR;
-}
-
-static int lascar_save_config(libusb_device_handle *dev_hdl,
-               unsigned char *config, int configlen)
-{
-       struct drv_context *drvc;
-       struct libusb_transfer *xfer_in, *xfer_out;
-       struct timeval tv;
-       int64_t start;
-       int buflen, ret;
-       unsigned char cmd[3], buf[256];
-
-       sr_spew("Writing config block.");
-
-       drvc = di->priv;
-
-       if (!(xfer_in = libusb_alloc_transfer(0)) ||
-                       !(xfer_out = libusb_alloc_transfer(0)))
-               return SR_ERR;
-
-       /* Flush anything the F321 still has queued. */
-       while (libusb_bulk_transfer(dev_hdl, LASCAR_EP_IN, buf, 256, &buflen,
-                       5) == 0 && buflen > 0)
-               ;
-       ret = SR_OK;
-
-       /* Keep a read request waiting in the wings, ready to pounce
-        * the moment the device sends something. */
-       libusb_fill_bulk_transfer(xfer_in, dev_hdl, LASCAR_EP_IN,
-                       buf, 256, mark_xfer, 0, 10000);
-       if (libusb_submit_transfer(xfer_in) != 0) {
-               ret = SR_ERR;
-               goto cleanup;
-       }
-
-       /* Request device configuration structure. */
-       cmd[0] = 0x01;
-       cmd[1] = configlen & 0xff;
-       cmd[2] = (configlen >> 8) & 0xff;
-       libusb_fill_bulk_transfer(xfer_out, dev_hdl, LASCAR_EP_OUT,
-                       cmd, 3, mark_xfer, 0, 100);
-       if (libusb_submit_transfer(xfer_out) != 0) {
-               ret = SR_ERR;
-               goto cleanup;
-       }
-       tv.tv_sec = 0;
-       tv.tv_usec = 0;
-       while (!xfer_out->user_data) {
-               g_usleep(5000);
-               libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
-       }
-
-       libusb_fill_bulk_transfer(xfer_out, dev_hdl, LASCAR_EP_OUT,
-                       config, configlen, mark_xfer, 0, 100);
-       if (libusb_submit_transfer(xfer_out) != 0) {
-               ret = SR_ERR;
-               goto cleanup;
-       }
-       while (!xfer_in->user_data || !xfer_out->user_data) {
-               g_usleep(5000);
-               libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
-       }
-
-       if (xfer_in->actual_length != 1 || buf[0] != 0xff) {
-               sr_dbg("unexpected response after transfer");
-               ret = SR_ERR;
-       }
-
-cleanup:
-       if (!xfer_in->user_data || !xfer_in->user_data) {
-               if (!xfer_in->user_data)
-                       libusb_cancel_transfer(xfer_in);
-               if (!xfer_out->user_data)
-                       libusb_cancel_transfer(xfer_out);
-               start = g_get_monotonic_time();
-               while (!xfer_in->user_data || !xfer_out->user_data) {
-                       if (g_get_monotonic_time() - start > 10000)
-                               break;
-                       g_usleep(1000);
-                       libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
-               }
-       }
-       libusb_free_transfer(xfer_in);
-       libusb_free_transfer(xfer_out);
-
-       return ret;
-}
-
-static struct sr_dev_inst *lascar_identify(unsigned char *config)
-{
-       struct dev_context *devc;
-       const struct elusb_profile *profile;
-       struct sr_dev_inst *sdi;
-       struct sr_channel *ch;
-       int modelid, i;
-       char firmware[5];
-
-       modelid = config[0];
-       sdi = NULL;
-       if (modelid) {
-               profile = NULL;
-               for (i = 0; profiles[i].modelid; i++) {
-                       if (profiles[i].modelid == modelid) {
-                               profile = &profiles[i];
-                               break;
-                       }
-               }
-               if (!profile) {
-                       sr_dbg("unknown EL-USB modelid %d", modelid);
-                       return NULL;
-               }
-
-               i = config[52] | (config[53] << 8);
-               memcpy(firmware, config + 0x30, 4);
-               firmware[4] = '\0';
-               sr_dbg("found %s with firmware version %s serial %d",
-                               profile->modelname, firmware, i);
-
-               if (profile->logformat == LOG_UNSUPPORTED) {
-                       sr_dbg("unsupported EL-USB logformat for %s", profile->modelname);
-                       return NULL;
-               }
-
-               if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, LASCAR_VENDOR,
-                               profile->modelname, firmware)))
-                       return NULL;
-               sdi->driver = di;
-
-               if (profile->logformat == LOG_TEMP_RH) {
-                       /* Model this as two channels: temperature and humidity. */
-                       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "Temp")))
-                               return NULL;
-                       sdi->channels = g_slist_append(NULL, ch);
-                       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "Hum")))
-                               return NULL;
-                       sdi->channels = g_slist_append(sdi->channels, ch);
-               } else if (profile->logformat == LOG_CO) {
-                       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "CO")))
-                               return NULL;
-                       sdi->channels = g_slist_append(NULL, ch);
-               } else {
-                       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1")))
-                               return NULL;
-                       sdi->channels = g_slist_append(NULL, ch);
-               }
-
-               if (!(devc = g_try_malloc0(sizeof(struct dev_context))))
-                       return NULL;
-               sdi->priv = devc;
-               devc->profile = profile;
-       }
-
-       return sdi;
-}
-
-SR_PRIV struct sr_dev_inst *lascar_scan(int bus, int address)
-{
-       struct drv_context *drvc;
-       struct sr_dev_inst *sdi;
-       struct libusb_device **devlist;
-       struct libusb_device_descriptor des;
-       libusb_device_handle *dev_hdl;
-       int dummy, ret, i;
-       unsigned char config[MAX_CONFIGBLOCK_SIZE];
-
-       drvc = di->priv;
-       sdi = NULL;
-
-       libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
-       for (i = 0; devlist[i]; i++) {
-               if ((ret = libusb_get_device_descriptor(devlist[i], &des))) {
-                       sr_err("Failed to get device descriptor: %d.", ret);
-                       continue;
-               }
-
-               if (libusb_get_bus_number(devlist[i]) != bus ||
-                               libusb_get_device_address(devlist[i]) != address)
-                       continue;
-
-               if (!(dev_hdl = lascar_open(devlist[i])))
-                       continue;
-
-               if (lascar_get_config(dev_hdl, config, &dummy) != SR_OK)
-                       continue;
-
-               libusb_close(dev_hdl);
-               sdi = lascar_identify(config);
-       }
-
-       return sdi;
-}
-
-static void lascar_el_usb_dispatch(struct sr_dev_inst *sdi, unsigned char *buf,
-               int buflen)
-{
-       struct dev_context *devc;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_analog analog;
-       struct sr_channel *ch;
-       float *temp, *rh;
-       uint16_t s;
-       int samples, samples_left, i, j;
-
-       devc = sdi->priv;
-
-       samples = buflen / devc->sample_size;
-       samples_left = devc->logged_samples - devc->rcvd_samples;
-       if (samples_left < samples)
-               samples = samples_left;
-       switch (devc->profile->logformat) {
-       case LOG_TEMP_RH:
-               packet.type = SR_DF_ANALOG;
-               packet.payload = &analog;
-               analog.mqflags = 0;
-               if (!(temp = g_try_malloc(sizeof(float) * samples)))
-                       break;
-               if (!(rh = g_try_malloc(sizeof(float) * samples)))
-                       break;
-               for (i = 0, j = 0; i < samples; i++) {
-                       /* Both Celcius and Fahrenheit stored at base -40. */
-                       if (devc->temp_unit == 0)
-                               /* Celcius is stored in half-degree increments. */
-                               temp[j] = buf[i * 2] / 2 - 40;
-                       else
-                               temp[j] = buf[i * 2] - 40;
-
-                       rh[j] = buf[i * 2 + 1] / 2;
-
-                       if (temp[j] == 0.0 && rh[j] == 0.0)
-                               /* Skip invalid measurement. */
-                               continue;
-                       j++;
-               }
-               analog.num_samples = j;
-
-               ch = sdi->channels->data;
-               if (ch->enabled) {
-                       analog.channels = g_slist_append(NULL, ch);
-                       analog.mq = SR_MQ_TEMPERATURE;
-                       if (devc->temp_unit == 1)
-                               analog.unit = SR_UNIT_FAHRENHEIT;
-                       else
-                               analog.unit = SR_UNIT_CELSIUS;
-                       analog.data = temp;
-                       sr_session_send(devc->cb_data, &packet);
-               }
-
-               ch = sdi->channels->next->data;
-               if (ch->enabled) {
-                       analog.channels = g_slist_append(NULL, ch);
-                       analog.mq = SR_MQ_RELATIVE_HUMIDITY;
-                       analog.unit = SR_UNIT_PERCENTAGE;
-                       analog.data = rh;
-                       sr_session_send(devc->cb_data, &packet);
-               }
-
-               g_free(temp);
-               g_free(rh);
-               break;
-       case LOG_CO:
-               packet.type = SR_DF_ANALOG;
-               packet.payload = &analog;
-               analog.channels = sdi->channels;
-               analog.num_samples = samples;
-               analog.mq = SR_MQ_CARBON_MONOXIDE;
-               analog.unit = SR_UNIT_CONCENTRATION;
-               analog.mqflags = 0;
-               if (!(analog.data = g_try_malloc(sizeof(float) * samples)))
-                       break;
-               for (i = 0; i < samples; i++) {
-                       s = (buf[i * 2] << 8) | buf[i * 2 + 1];
-                       analog.data[i] = (s * devc->co_high + devc->co_low) / 1000000;
-                       if (analog.data[i] < 0.0)
-                               analog.data[i] = 0.0;
-               }
-               sr_session_send(devc->cb_data, &packet);
-               g_free(analog.data);
-               break;
-       default:
-               /* How did we even get this far? */
-               break;
-       }
-       devc->rcvd_samples += samples;
-
-}
-
-SR_PRIV int lascar_el_usb_handle_events(int fd, int revents, void *cb_data)
-{
-       struct drv_context *drvc = di->priv;
-       struct sr_datafeed_packet packet;
-       struct sr_dev_inst *sdi;
-       struct timeval tv;
-
-       (void)fd;
-       (void)revents;
-
-       sdi = cb_data;
-
-       if (sdi->status == SR_ST_STOPPING) {
-               usb_source_remove(sdi->session, drvc->sr_ctx);
-
-               packet.type = SR_DF_END;
-               sr_session_send(cb_data, &packet);
-       }
-
-       memset(&tv, 0, sizeof(struct timeval));
-       libusb_handle_events_timeout_completed(drvc->sr_ctx->libusb_ctx, &tv,
-                                              NULL);
-
-       return TRUE;
-}
-
-SR_PRIV void lascar_el_usb_receive_transfer(struct libusb_transfer *transfer)
-{
-       struct dev_context *devc;
-       struct sr_dev_inst *sdi;
-       int ret;
-       gboolean packet_has_error;
-
-       sdi = transfer->user_data;
-       devc = sdi->priv;
-
-       packet_has_error = FALSE;
-       switch (transfer->status) {
-       case LIBUSB_TRANSFER_NO_DEVICE:
-               /* USB device was unplugged. */
-               dev_acquisition_stop(sdi, sdi);
-               return;
-       case LIBUSB_TRANSFER_COMPLETED:
-       case LIBUSB_TRANSFER_TIMED_OUT: /* We may have received some data though */
-               break;
-       default:
-               packet_has_error = TRUE;
-               break;
-       }
-
-       if (!packet_has_error) {
-               if (devc->rcvd_samples < devc->logged_samples)
-                       lascar_el_usb_dispatch(sdi, transfer->buffer,
-                                       transfer->actual_length);
-               devc->rcvd_bytes += transfer->actual_length;
-               sr_spew("received %d/%d bytes (%d/%d samples)",
-                               devc->rcvd_bytes, devc->log_size,
-                               devc->rcvd_samples, devc->logged_samples);
-               if (devc->rcvd_bytes >= devc->log_size)
-                       dev_acquisition_stop(sdi, sdi);
-       }
-
-       if (sdi->status == SR_ST_ACTIVE) {
-               /* Send the same request again. */
-               if ((ret = libusb_submit_transfer(transfer) != 0)) {
-                       sr_err("Unable to resubmit transfer: %s.",
-                              libusb_error_name(ret));
-                       g_free(transfer->buffer);
-                       libusb_free_transfer(transfer);
-                       dev_acquisition_stop(sdi, sdi);
-               }
-       } else {
-               /* This was the last transfer we're going to receive, so
-                * clean up now. */
-               g_free(transfer->buffer);
-               libusb_free_transfer(transfer);
-       }
-
-}
-
-static int get_flags(unsigned char *configblock)
-{
-       int flags;
-
-       flags = (configblock[32] | (configblock[33] << 8)) & 0x1fff;
-       sr_spew("Read flags (0x%.4x).", flags);
-
-       return flags;
-}
-
-static int set_flags(unsigned char *configblock, int flags)
-{
-
-       sr_spew("Setting flags to 0x%.4x.", flags);
-       configblock[32] = flags & 0xff;
-       configblock[33] = (flags >> 8) & 0x1f;
-
-       return flags;
-}
-
-SR_PRIV int lascar_is_logging(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_usb_dev_inst *usb;
-       int dummy, flags, ret;
-
-       devc = sdi->priv;
-       usb = sdi->conn;
-
-       if (lascar_get_config(usb->devhdl, devc->config, &dummy) != SR_OK)
-               return -1;
-
-       flags = get_flags(devc->config);
-       if (flags & 0x0100)
-               ret = 1;
-       else
-               ret = 0;
-
-       return ret;
-}
-
-SR_PRIV int lascar_start_logging(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_usb_dev_inst *usb;
-       int len, flags, ret;
-
-       devc = sdi->priv;
-       usb = sdi->conn;
-
-       if (lascar_get_config(usb->devhdl, devc->config, &len) != SR_OK)
-               return SR_ERR;
-
-       /* Turn on logging. */
-       flags = get_flags(devc->config);
-       flags |= 0x0100;
-       set_flags(devc->config, flags);
-
-       /* Start logging in 0 seconds. */
-       memset(devc->config + 24, 0, 4);
-
-       ret = lascar_save_config(usb->devhdl, devc->config, len);
-       sr_info("Started internal logging.");
-
-       return ret;
-}
-
-SR_PRIV int lascar_stop_logging(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_usb_dev_inst *usb;
-       int len, flags, ret;
-
-       devc = sdi->priv;
-       usb = sdi->conn;
-
-       if (lascar_get_config(usb->devhdl, devc->config, &len) != SR_OK)
-               return SR_ERR;
-
-       flags = get_flags(devc->config);
-       flags &= ~0x0100;
-       set_flags(devc->config, flags);
-
-       ret = lascar_save_config(usb->devhdl, devc->config, len);
-       sr_info("Stopped internal logging.");
-
-       return ret;
-}
diff --git a/hardware/lascar-el-usb/protocol.h b/hardware/lascar-el-usb/protocol.h
deleted file mode 100644 (file)
index a94bd8a..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012 Bert Vermeulen <bert@biot.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_LASCAR_EL_USB_PROTOCOL_H
-#define LIBSIGROK_HARDWARE_LASCAR_EL_USB_PROTOCOL_H
-
-#include <stdint.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "lascar-el-usb"
-
-#define LASCAR_VENDOR "Lascar"
-#define LASCAR_INTERFACE 0
-#define LASCAR_EP_IN 0x82
-#define LASCAR_EP_OUT 2
-/* Max 100ms for a device to positively identify. */
-#define SCAN_TIMEOUT 100000
-#define MAX_CONFIGBLOCK_SIZE 256
-
-/** Private, per-device-instance driver context. */
-struct dev_context {
-       void *cb_data;
-       const struct elusb_profile *profile;
-       /* Generic EL-USB */
-       unsigned char config[MAX_CONFIGBLOCK_SIZE];
-       unsigned int log_size;
-       unsigned int rcvd_bytes;
-       unsigned int sample_size;
-       unsigned int logged_samples;
-       unsigned int rcvd_samples;
-       uint64_t limit_samples;
-       /* Model-specific */
-       /* EL-USB-CO: these are something like scaling and calibration values
-        * fixed per device, used to convert the sample values to CO ppm. */
-       float co_high;
-       float co_low;
-       /* Temperature units as stored in the device config. */
-       int temp_unit;
-};
-
-enum {
-       LOG_UNSUPPORTED,
-       LOG_TEMP_RH,
-       LOG_CO,
-};
-
-struct elusb_profile {
-       int modelid;
-       char *modelname;
-       int logformat;
-};
-
-SR_PRIV int lascar_get_config(libusb_device_handle *dev_hdl,
-               unsigned char *configblock, int *configlen);
-SR_PRIV struct sr_dev_inst *lascar_scan(int bus, int address);
-SR_PRIV int lascar_el_usb_handle_events(int fd, int revents, void *cb_data);
-SR_PRIV void lascar_el_usb_receive_transfer(struct libusb_transfer *transfer);
-SR_PRIV int lascar_start_logging(const struct sr_dev_inst *sdi);
-SR_PRIV int lascar_stop_logging(const struct sr_dev_inst *sdi);
-SR_PRIV int lascar_is_logging(const struct sr_dev_inst *sdi);
-SR_PRIV int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data);
-
-#endif
diff --git a/hardware/link-mso19/api.c b/hardware/link-mso19/api.c
deleted file mode 100644 (file)
index 13c2972..0000000
+++ /dev/null
@@ -1,497 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2011 Daniel Ribeiro <drwyrm@gmail.com>
- * Copyright (C) 2012 Renato Caldas <rmsc@fe.up.pt>
- * Copyright (C) 2013 Lior Elazary <lelazary@yahoo.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 "protocol.h"
-
-static const int32_t hwcaps[] = {
-       SR_CONF_OSCILLOSCOPE,
-       SR_CONF_LOGIC_ANALYZER,
-       SR_CONF_SAMPLERATE,
-       SR_CONF_TRIGGER_TYPE,
-       SR_CONF_TRIGGER_SLOPE,
-       SR_CONF_HORIZ_TRIGGERPOS,
-//      SR_CONF_CAPTURE_RATIO,
-       SR_CONF_LIMIT_SAMPLES,
-//      SR_CONF_RLE,
-};
-
-/*
- * Channels are numbered 0 to 7.
- *
- * See also: http://www.linkinstruments.com/images/mso19_1113.gif
- */
-SR_PRIV const char *mso19_channel_names[NUM_CHANNELS + 1] = {
-       /* Note: DSO needs to be first. */
-       "DSO", "0", "1", "2", "3", "4", "5", "6", "7", NULL,
-};
-
-static const uint64_t samplerates[] = {
-       SR_HZ(100),
-       SR_MHZ(200),
-       SR_HZ(100),
-};
-
-SR_PRIV struct sr_dev_driver link_mso19_driver_info;
-static struct sr_dev_driver *di = &link_mso19_driver_info;
-
-/* TODO: Use sr_dev_inst to store connection handle & use std_dev_clear(). */
-static int dev_clear(void)
-{
-       GSList *l;
-       struct sr_dev_inst *sdi;
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       int ret = SR_OK;
-
-       if (!(drvc = di->priv))
-               return SR_OK;
-
-       /* Properly close and free all devices. */
-       for (l = drvc->instances; l; l = l->next) {
-               if (!(sdi = l->data)) {
-                       /* Log error, but continue cleaning up the rest. */
-                       sr_err("%s: sdi was NULL, continuing", __func__);
-                       ret = SR_ERR_BUG;
-                       continue;
-               }
-               if (!(devc = sdi->priv)) {
-                       /* Log error, but continue cleaning up the rest. */
-                       sr_err("%s: sdi->priv was NULL, continuing", __func__);
-                       ret = SR_ERR_BUG;
-                       continue;
-               }
-               std_serial_dev_close(sdi);
-               sr_serial_dev_inst_free(devc->serial);
-               sr_dev_inst_free(sdi);
-       }
-       g_slist_free(drvc->instances);
-       drvc->instances = NULL;
-
-       return ret;
-}
-
-static int init(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, di, LOG_PREFIX);
-}
-
-static GSList *scan(GSList *options)
-{
-       int i;
-       GSList *devices = NULL;
-       const char *conn = NULL;
-       const char *serialcomm = NULL;
-       GSList *l;
-       struct sr_config *src;
-       struct udev *udev;
-       int chtype;
-
-       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)
-               conn = SERIALCONN;
-       if (serialcomm == NULL)
-               serialcomm = SERIALCOMM;
-
-       udev = udev_new();
-       if (!udev) {
-               sr_err("Failed to initialize udev.");
-       }
-
-       struct udev_enumerate *enumerate = udev_enumerate_new(udev);
-       udev_enumerate_add_match_subsystem(enumerate, "usb-serial");
-       udev_enumerate_scan_devices(enumerate);
-       struct udev_list_entry *devs = udev_enumerate_get_list_entry(enumerate);
-       struct udev_list_entry *dev_list_entry;
-       for (dev_list_entry = devs;
-            dev_list_entry != NULL;
-            dev_list_entry = udev_list_entry_get_next(dev_list_entry)) {
-               const char *syspath = udev_list_entry_get_name(dev_list_entry);
-               struct udev_device *dev =
-                   udev_device_new_from_syspath(udev, syspath);
-               const char *sysname = udev_device_get_sysname(dev);
-               struct udev_device *parent =
-                   udev_device_get_parent_with_subsystem_devtype(dev, "usb",
-                                                                 "usb_device");
-
-               if (!parent) {
-                       sr_err("Unable to find parent usb device for %s",
-                              sysname);
-                       continue;
-               }
-
-               const char *idVendor =
-                   udev_device_get_sysattr_value(parent, "idVendor");
-               const char *idProduct =
-                   udev_device_get_sysattr_value(parent, "idProduct");
-               if (strcmp(USB_VENDOR, idVendor)
-                   || strcmp(USB_PRODUCT, idProduct))
-                       continue;
-
-               const char *iSerial =
-                   udev_device_get_sysattr_value(parent, "serial");
-               const char *iProduct =
-                   udev_device_get_sysattr_value(parent, "product");
-
-               char path[32];
-               snprintf(path, sizeof(path), "/dev/%s", sysname);
-               conn = path;
-
-               size_t s = strcspn(iProduct, " ");
-               char product[32];
-               char manufacturer[32];
-               if (s > sizeof(product) ||
-                   strlen(iProduct) - s > sizeof(manufacturer)) {
-                       sr_err("Could not parse iProduct: %s.", iProduct);
-                       continue;
-               }
-               strncpy(product, iProduct, s);
-               product[s] = 0;
-               strcpy(manufacturer, iProduct + s + 1);
-
-               //Create the device context and set its params
-               struct dev_context *devc;
-               if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
-                       sr_err("Device context malloc failed.");
-                       return devices;
-               }
-
-               if (mso_parse_serial(iSerial, iProduct, devc) != SR_OK) {
-                       sr_err("Invalid iSerial: %s.", iSerial);
-                       g_free(devc);
-                       return devices;
-               }
-
-               char hwrev[32];
-               sprintf(hwrev, "r%d", devc->hwrev);
-               devc->ctlbase1 = 0;
-               devc->protocol_trigger.spimode = 0;
-               for (i = 0; i < 4; i++) {
-                       devc->protocol_trigger.word[i] = 0;
-                       devc->protocol_trigger.mask[i] = 0xff;
-               }
-
-               if (!(devc->serial = sr_serial_dev_inst_new(conn, serialcomm))) {
-                       g_free(devc);
-                       return devices;
-               }
-
-               struct sr_dev_inst *sdi = sr_dev_inst_new(0, SR_ST_INACTIVE,
-                                               manufacturer, product, hwrev);
-
-               if (!sdi) {
-                       sr_err("Unable to create device instance for %s",
-                              sysname);
-                       sr_dev_inst_free(sdi);
-                       g_free(devc);
-                       return devices;
-               }
-
-               sdi->driver = di;
-               sdi->priv = devc;
-
-               for (i = 0; i < NUM_CHANNELS; i++) {
-                       struct sr_channel *ch;
-                       chtype = (i == 0) ? SR_CHANNEL_ANALOG : SR_CHANNEL_LOGIC;
-                       if (!(ch = sr_channel_new(i, chtype, TRUE,
-                                                  mso19_channel_names[i])))
-                               return 0;
-                       sdi->channels = g_slist_append(sdi->channels, ch);
-               }
-
-               //Add the driver
-               struct drv_context *drvc = di->priv;
-               drvc->instances = g_slist_append(drvc->instances, sdi);
-               devices = g_slist_append(devices, sdi);
-       }
-
-       return devices;
-}
-
-static GSList *dev_list(void)
-{
-       return ((struct drv_context *)(di->priv))->instances;
-}
-
-static int dev_open(struct sr_dev_inst *sdi)
-{
-       int ret;
-       struct dev_context *devc;
-
-       devc = sdi->priv;
-
-       if (serial_open(devc->serial, SERIAL_RDWR) != SR_OK)
-               return SR_ERR;
-
-       sdi->status = SR_ST_ACTIVE;
-
-       /* FIXME: discard serial buffer */
-       mso_check_trigger(devc->serial, &devc->trigger_state);
-       sr_dbg("Trigger state: 0x%x.", devc->trigger_state);
-
-       ret = mso_reset_adc(sdi);
-       if (ret != SR_OK)
-               return ret;
-
-       mso_check_trigger(devc->serial, &devc->trigger_state);
-       sr_dbg("Trigger state: 0x%x.", devc->trigger_state);
-
-       //    ret = mso_reset_fsm(sdi);
-       //    if (ret != SR_OK)
-       //            return ret;
-       //    return SR_ERR;
-
-       return SR_OK;
-}
-
-static int cleanup(void)
-{
-       return dev_clear();
-}
-
-static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-
-       (void)cg;
-
-       switch (id) {
-       case SR_CONF_SAMPLERATE:
-               if (sdi) {
-                       devc = sdi->priv;
-                       *data = g_variant_new_uint64(devc->cur_rate);
-               } else
-                       return SR_ERR;
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       int ret;
-       struct dev_context *devc;
-       uint64_t num_samples;
-       const char *slope;
-       int trigger_pos;
-       double pos;
-
-       (void)cg;
-       devc = sdi->priv;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       switch (id) {
-       case SR_CONF_SAMPLERATE:
-               // FIXME
-               return mso_configure_rate(sdi, g_variant_get_uint64(data));
-               ret = SR_OK;
-               break;
-       case SR_CONF_LIMIT_SAMPLES:
-               num_samples = g_variant_get_uint64(data);
-               if (num_samples != 1024) {
-                       sr_err("Only 1024 samples are supported.");
-                       ret = SR_ERR_ARG;
-               } else {
-                       devc->limit_samples = num_samples;
-                       sr_dbg("setting limit_samples to %i\n",
-                              num_samples);
-                       ret = SR_OK;
-               }
-               break;
-       case SR_CONF_CAPTURE_RATIO:
-               ret = SR_OK;
-               break;
-       case SR_CONF_TRIGGER_SLOPE:
-               slope = g_variant_get_string(data, NULL);
-
-               if (!slope || !(slope[0] == 'f' || slope[0] == 'r'))
-                       sr_err("Invalid trigger slope");
-                       ret = SR_ERR_ARG;
-               } else {
-                       devc->trigger_slope = (slope[0] == 'r')
-                               ? SLOPE_POSITIVE : SLOPE_NEGATIVE;
-                       ret = SR_OK;
-               }
-               break;
-       case SR_CONF_HORIZ_TRIGGERPOS:
-               pos = g_variant_get_double(data);
-               if (pos < 0 || pos > 255) {
-                       sr_err("Trigger position (%f) should be between 0 and 255.", pos);
-                       ret = SR_ERR_ARG;
-               } else {
-                       trigger_pos = (int)pos;
-                       devc->trigger_holdoff[0] = trigger_pos & 0xff;
-                       ret = SR_OK;
-               }
-               break;
-       case SR_CONF_RLE:
-               ret = SR_OK;
-               break;
-       default:
-               ret = SR_ERR_NA;
-               break;
-       }
-
-       return ret;
-}
-
-static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       GVariant *gvar;
-       GVariantBuilder gvb;
-
-       (void)cg;
-       (void)sdi;
-
-       switch (key) {
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
-               break;
-       case SR_CONF_SAMPLERATE:
-               g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
-               gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), samplerates,
-                               ARRAY_SIZE(samplerates), sizeof(uint64_t));
-               g_variant_builder_add(&gvb, "{sv}", "samplerate-steps", gvar);
-               *data = g_variant_builder_end(&gvb);
-               break;
-       case SR_CONF_TRIGGER_TYPE:
-               *data = g_variant_new_string(TRIGGER_TYPE);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct dev_context *devc;
-       int ret = SR_ERR;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       devc = sdi->priv;
-
-       if (mso_configure_channels(sdi) != SR_OK) {
-               sr_err("Failed to configure channels.");
-               return SR_ERR;
-       }
-
-       /* FIXME: No need to do full reconfigure every time */
-//      ret = mso_reset_fsm(sdi);
-//      if (ret != SR_OK)
-//              return ret;
-
-       /* FIXME: ACDC Mode */
-       devc->ctlbase1 &= 0x7f;
-//      devc->ctlbase1 |= devc->acdcmode;
-
-       ret = mso_configure_rate(sdi, devc->cur_rate);
-       if (ret != SR_OK)
-               return ret;
-
-       /* set dac offset */
-       ret = mso_dac_out(sdi, devc->dac_offset);
-       if (ret != SR_OK)
-               return ret;
-
-       ret = mso_configure_threshold_level(sdi);
-       if (ret != SR_OK)
-               return ret;
-
-       ret = mso_configure_trigger(sdi);
-       if (ret != SR_OK)
-               return ret;
-
-       /* END of config hardware part */
-       ret = mso_arm(sdi);
-       if (ret != SR_OK)
-               return ret;
-
-       /* Start acquisition on the device. */
-       mso_check_trigger(devc->serial, &devc->trigger_state);
-       ret = mso_check_trigger(devc->serial, NULL);
-       if (ret != SR_OK)
-               return ret;
-
-       /* Reset trigger state. */
-       devc->trigger_state = 0x00;
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(cb_data, LOG_PREFIX);
-
-       /* Our first channel is analog, the other 8 are of type 'logic'. */
-       /* TODO. */
-
-       serial_source_add(sdi->session, devc->serial, G_IO_IN, -1,
-                       mso_receive_data, cb_data);
-
-       return SR_OK;
-}
-
-/* This stops acquisition on ALL devices, ignoring dev_index. */
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       (void)cb_data;
-
-       stop_acquisition(sdi);
-
-       return SR_OK;
-}
-
-SR_PRIV struct sr_dev_driver link_mso19_driver_info = {
-       .name = "link-mso19",
-       .longname = "Link Instruments MSO-19",
-       .api_version = 1,
-       .init = init,
-       .cleanup = cleanup,
-       .scan = scan,
-       .dev_list = dev_list,
-       .dev_clear = dev_clear,
-       .config_get = config_get,
-       .config_set = config_set,
-       .config_list = config_list,
-       .dev_open = dev_open,
-       .dev_close = std_serial_dev_close,
-       .dev_acquisition_start = dev_acquisition_start,
-       .dev_acquisition_stop = dev_acquisition_stop,
-       .priv = NULL,
-};
diff --git a/hardware/link-mso19/protocol.c b/hardware/link-mso19/protocol.c
deleted file mode 100644 (file)
index 5f7aa71..0000000
+++ /dev/null
@@ -1,474 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2011 Daniel Ribeiro <drwyrm@gmail.com>
- * Copyright (C) 2012 Renato Caldas <rmsc@fe.up.pt>
- * Copyright (C) 2013 Lior Elazary <lelazary@yahoo.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 "protocol.h"
-
-/* serial protocol */
-#define mso_trans(a, v) \
-       (((v) & 0x3f) | (((v) & 0xc0) << 6) | (((a) & 0xf) << 8) | \
-       ((~(v) & 0x20) << 1) | ((~(v) & 0x80) << 7))
-
-static const char mso_head[] = { 0x40, 0x4c, 0x44, 0x53, 0x7e };
-static const char mso_foot[] = { 0x7e };
-
-extern SR_PRIV struct sr_dev_driver link_mso19_driver_info;
-static struct sr_dev_driver *di = &link_mso19_driver_info;
-
-SR_PRIV int mso_send_control_message(struct sr_serial_dev_inst *serial,
-                                    uint16_t payload[], int n)
-{
-       int i, w, ret, s = n * 2 + sizeof(mso_head) + sizeof(mso_foot);
-       char *p, *buf;
-
-       ret = SR_ERR;
-
-       if (serial->fd < 0)
-               goto ret;
-
-       if (!(buf = g_try_malloc(s))) {
-               sr_err("Failed to malloc message buffer.");
-               ret = SR_ERR_MALLOC;
-               goto ret;
-       }
-
-       p = buf;
-       memcpy(p, mso_head, sizeof(mso_head));
-       p += sizeof(mso_head);
-
-       for (i = 0; i < n; i++) {
-               *(uint16_t *) p = g_htons(payload[i]);
-               p += 2;
-       }
-       memcpy(p, mso_foot, sizeof(mso_foot));
-
-       w = 0;
-       while (w < s) {
-               ret = serial_write(serial, buf + w, s - w);
-               if (ret < 0) {
-                       ret = SR_ERR;
-                       goto free;
-               }
-               w += ret;
-       }
-       ret = SR_OK;
-free:
-       g_free(buf);
-ret:
-       return ret;
-}
-
-SR_PRIV int mso_configure_trigger(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc = sdi->priv;
-       uint16_t threshold_value = mso_calc_raw_from_mv(devc);
-
-       threshold_value = 0x153C;
-       uint8_t trigger_config = 0;
-
-       if (devc->trigger_slope)
-               trigger_config |= 0x04; //Trigger on falling edge
-
-       switch (devc->trigger_outsrc) {
-       case 1:
-               trigger_config |= 0x00; //Trigger pulse output
-               break;
-       case 2:
-               trigger_config |= 0x08; //PWM DAC from the pattern generator buffer
-               break;
-       case 3:
-               trigger_config |= 0x18; //White noise
-               break;
-       }
-
-       switch (devc->trigger_chan) {
-       case 0:
-               trigger_config |= 0x00; //DSO level trigger //b00000000
-               break;
-       case 1:
-               trigger_config |= 0x20; //DSO level trigger & width < trigger_width
-               break;
-       case 2:
-               trigger_config |= 0x40; //DSO level trigger & width >= trigger_width 
-               break;
-       case 3:
-               trigger_config |= 0x60; //LA combination trigger
-               break;
-       }
-
-       //Last bit of trigger config reg 4 needs to be 1 for trigger enable,
-       //otherwise the trigger is not enabled
-       if (devc->use_trigger)
-               trigger_config |= 0x80;
-
-       uint16_t ops[18];
-       ops[0] = mso_trans(3, threshold_value & 0xff);
-       //The trigger_config also holds the 2 MSB bits from the threshold value
-       ops[1] = mso_trans(4, trigger_config | ((threshold_value >> 8) & 0x03));
-       ops[2] = mso_trans(5, devc->la_trigger);
-       ops[3] = mso_trans(6, devc->la_trigger_mask);
-       ops[4] = mso_trans(7, devc->trigger_holdoff[0]);
-       ops[5] = mso_trans(8, devc->trigger_holdoff[1]);
-
-       ops[6] = mso_trans(11,
-                          devc->dso_trigger_width /
-                          SR_HZ_TO_NS(devc->cur_rate));
-
-       /* Select the SPI/I2C trigger config bank */
-       ops[7] = mso_trans(REG_CTL2, (devc->ctlbase2 | BITS_CTL2_BANK(2)));
-       /* Configure the SPI/I2C protocol trigger */
-       ops[8] = mso_trans(REG_PT_WORD(0), devc->protocol_trigger.word[0]);
-       ops[9] = mso_trans(REG_PT_WORD(1), devc->protocol_trigger.word[1]);
-       ops[10] = mso_trans(REG_PT_WORD(2), devc->protocol_trigger.word[2]);
-       ops[11] = mso_trans(REG_PT_WORD(3), devc->protocol_trigger.word[3]);
-       ops[12] = mso_trans(REG_PT_MASK(0), devc->protocol_trigger.mask[0]);
-       ops[13] = mso_trans(REG_PT_MASK(1), devc->protocol_trigger.mask[1]);
-       ops[14] = mso_trans(REG_PT_MASK(2), devc->protocol_trigger.mask[2]);
-       ops[15] = mso_trans(REG_PT_MASK(3), devc->protocol_trigger.mask[3]);
-       ops[16] = mso_trans(REG_PT_SPIMODE, devc->protocol_trigger.spimode);
-       /* Select the default config bank */
-       ops[17] = mso_trans(REG_CTL2, devc->ctlbase2);
-
-       return mso_send_control_message(devc->serial, ARRAY_AND_SIZE(ops));
-}
-
-SR_PRIV int mso_configure_threshold_level(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc = sdi->priv;
-
-       return mso_dac_out(sdi, la_threshold_map[devc->la_threshold]);
-}
-
-SR_PRIV int mso_read_buffer(struct sr_dev_inst *sdi)
-{
-       uint16_t ops[] = { mso_trans(REG_BUFFER, 0) };
-       struct dev_context *devc = sdi->priv;
-
-       sr_dbg("Requesting buffer dump.");
-       return mso_send_control_message(devc->serial, ARRAY_AND_SIZE(ops));
-}
-
-SR_PRIV int mso_arm(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc = sdi->priv;
-       uint16_t ops[] = {
-               mso_trans(REG_CTL1, devc->ctlbase1 | BIT_CTL1_RESETFSM),
-               mso_trans(REG_CTL1, devc->ctlbase1 | BIT_CTL1_ARM),
-               mso_trans(REG_CTL1, devc->ctlbase1),
-       };
-
-       sr_dbg("Requesting trigger arm.");
-       return mso_send_control_message(devc->serial, ARRAY_AND_SIZE(ops));
-}
-
-SR_PRIV int mso_force_capture(struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc = sdi->priv;
-       uint16_t ops[] = {
-               mso_trans(REG_CTL1, devc->ctlbase1 | 8),
-               mso_trans(REG_CTL1, devc->ctlbase1),
-       };
-
-       sr_dbg("Requesting forced capture.");
-       return mso_send_control_message(devc->serial, ARRAY_AND_SIZE(ops));
-}
-
-SR_PRIV int mso_dac_out(const struct sr_dev_inst *sdi, uint16_t val)
-{
-       struct dev_context *devc = sdi->priv;
-       uint16_t ops[] = {
-               mso_trans(REG_DAC1, (val >> 8) & 0xff),
-               mso_trans(REG_DAC2, val & 0xff),
-               mso_trans(REG_CTL1, devc->ctlbase1 | BIT_CTL1_RESETADC),
-       };
-
-       sr_dbg("Setting dac word to 0x%x.", val);
-       return mso_send_control_message(devc->serial, ARRAY_AND_SIZE(ops));
-}
-
-SR_PRIV inline uint16_t mso_calc_raw_from_mv(struct dev_context * devc)
-{
-       return (uint16_t) (0x200 -
-                          ((devc->dso_trigger_voltage / devc->dso_probe_attn) /
-                           devc->vbit));
-}
-
-SR_PRIV int mso_parse_serial(const char *iSerial, const char *iProduct,
-                            struct dev_context *devc)
-{
-       unsigned int u1, u2, u3, u4, u5, u6;
-
-       (void)iProduct;
-
-       /* FIXME: This code is in the original app, but I think its
-        * used only for the GUI */
-       /*    if (strstr(iProduct, "REV_02") || strstr(iProduct, "REV_03"))
-          devc->num_sample_rates = 0x16;
-          else
-          devc->num_sample_rates = 0x10; */
-
-       /* parse iSerial */
-       if (iSerial[0] != '4' || sscanf(iSerial, "%5u%3u%3u%1u%1u%6u",
-                                       &u1, &u2, &u3, &u4, &u5, &u6) != 6)
-               return SR_ERR;
-       devc->hwmodel = u4;
-       devc->hwrev = u5;
-       devc->vbit = u1 / 10000;
-       if (devc->vbit == 0)
-               devc->vbit = 4.19195;
-       devc->dac_offset = u2;
-       if (devc->dac_offset == 0)
-               devc->dac_offset = 0x1ff;
-       devc->offset_range = u3;
-       if (devc->offset_range == 0)
-               devc->offset_range = 0x17d;
-
-       /*
-        * FIXME: There is more code on the original software to handle
-        * bigger iSerial strings, but as I can't test on my device
-        * I will not implement it yet
-        */
-
-       return SR_OK;
-}
-
-SR_PRIV int mso_reset_adc(struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc = sdi->priv;
-       uint16_t ops[2];
-
-       ops[0] = mso_trans(REG_CTL1, (devc->ctlbase1 | BIT_CTL1_RESETADC));
-       ops[1] = mso_trans(REG_CTL1, devc->ctlbase1);
-       devc->ctlbase1 |= BIT_CTL1_ADC_UNKNOWN4;
-
-       sr_dbg("Requesting ADC reset.");
-       return mso_send_control_message(devc->serial, ARRAY_AND_SIZE(ops));
-}
-
-SR_PRIV int mso_reset_fsm(struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc = sdi->priv;
-       uint16_t ops[1];
-
-       devc->ctlbase1 |= BIT_CTL1_RESETFSM;
-       ops[0] = mso_trans(REG_CTL1, devc->ctlbase1);
-
-       sr_dbg("Requesting ADC reset.");
-       return mso_send_control_message(devc->serial, ARRAY_AND_SIZE(ops));
-}
-
-SR_PRIV int mso_toggle_led(struct sr_dev_inst *sdi, int state)
-{
-       struct dev_context *devc = sdi->priv;
-       uint16_t ops[1];
-
-       devc->ctlbase1 &= ~BIT_CTL1_LED;
-       if (state)
-               devc->ctlbase1 |= BIT_CTL1_LED;
-       ops[0] = mso_trans(REG_CTL1, devc->ctlbase1);
-
-       sr_dbg("Requesting LED toggle.");
-       return mso_send_control_message(devc->serial, ARRAY_AND_SIZE(ops));
-}
-
-SR_PRIV void stop_acquisition(const struct sr_dev_inst *sdi)
-{
-       struct sr_datafeed_packet packet;
-       struct dev_context *devc;
-
-       devc = sdi->priv;
-       serial_source_remove(sdi->session, devc->serial);
-
-       /* Terminate session */
-       packet.type = SR_DF_END;
-       sr_session_send(sdi, &packet);
-}
-
-SR_PRIV int mso_clkrate_out(struct sr_serial_dev_inst *serial, uint16_t val)
-{
-       uint16_t ops[] = {
-               mso_trans(REG_CLKRATE1, (val >> 8) & 0xff),
-               mso_trans(REG_CLKRATE2, val & 0xff),
-       };
-
-       sr_dbg("Setting clkrate word to 0x%x.", val);
-       return mso_send_control_message(serial, ARRAY_AND_SIZE(ops));
-}
-
-SR_PRIV int mso_configure_rate(const struct sr_dev_inst *sdi, uint32_t rate)
-{
-       struct dev_context *devc = sdi->priv;
-       unsigned int i;
-       int ret = SR_ERR;
-
-       for (i = 0; i < ARRAY_SIZE(rate_map); i++) {
-               if (rate_map[i].rate == rate) {
-                       devc->ctlbase2 = rate_map[i].slowmode;
-                       ret = mso_clkrate_out(devc->serial, rate_map[i].val);
-                       if (ret == SR_OK)
-                               devc->cur_rate = rate;
-                       return ret;
-               }
-       }
-
-       if (ret != SR_OK)
-               sr_err("Unsupported rate.");
-
-       return ret;
-}
-
-SR_PRIV int mso_check_trigger(struct sr_serial_dev_inst *serial, uint8_t *info)
-{
-       uint16_t ops[] = { mso_trans(REG_TRIGGER, 0) };
-       int ret;
-
-       sr_dbg("Requesting trigger state.");
-       ret = mso_send_control_message(serial, ARRAY_AND_SIZE(ops));
-       if (info == NULL || ret != SR_OK)
-               return ret;
-
-       uint8_t buf = 0;
-       if (serial_read(serial, &buf, 1) != 1)  /* FIXME: Need timeout */
-               ret = SR_ERR;
-       if (!info)
-               *info = buf;
-
-       sr_dbg("Trigger state is: 0x%x.", *info);
-       return ret;
-}
-
-SR_PRIV int mso_receive_data(int fd, int revents, void *cb_data)
-{
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_logic logic;
-       struct sr_dev_inst *sdi;
-       GSList *l;
-       int i;
-
-       struct drv_context *drvc = di->priv;
-
-       /* Find this device's devc struct by its fd. */
-       struct dev_context *devc = NULL;
-       for (l = drvc->instances; l; l = l->next) {
-               sdi = l->data;
-               devc = sdi->priv;
-               if (devc->serial->fd == fd)
-                       break;
-               devc = NULL;
-       }
-       if (!devc)
-               /* Shouldn't happen. */
-               return TRUE;
-
-       (void)revents;
-
-       uint8_t in[1024];
-       size_t s = serial_read(devc->serial, in, sizeof(in));
-
-       if (s <= 0)
-               return FALSE;
-
-       /* Check if we triggered, then send a command that we are ready
-        * to read the data */
-       if (devc->trigger_state != MSO_TRIGGER_DATAREADY) {
-               devc->trigger_state = in[0];
-               if (devc->trigger_state == MSO_TRIGGER_DATAREADY) {
-                       mso_read_buffer(sdi);
-                       devc->buffer_n = 0;
-               } else {
-                       mso_check_trigger(devc->serial, NULL);
-               }
-               return TRUE;
-       }
-
-       /* the hardware always dumps 1024 samples, 24bits each */
-       if (devc->buffer_n < 3072) {
-               memcpy(devc->buffer + devc->buffer_n, in, s);
-               devc->buffer_n += s;
-       }
-       if (devc->buffer_n < 3072)
-               return TRUE;
-
-       /* do the conversion */
-       uint8_t logic_out[1024];
-       double analog_out[1024];
-       for (i = 0; i < 1024; i++) {
-               /* FIXME: Need to do conversion to mV */
-               analog_out[i] = (devc->buffer[i * 3] & 0x3f) |
-                   ((devc->buffer[i * 3 + 1] & 0xf) << 6);
-               (void)analog_out;
-               logic_out[i] = ((devc->buffer[i * 3 + 1] & 0x30) >> 4) |
-                   ((devc->buffer[i * 3 + 2] & 0x3f) << 2);
-       }
-
-       packet.type = SR_DF_LOGIC;
-       packet.payload = &logic;
-       logic.length = 1024;
-       logic.unitsize = 1;
-       logic.data = logic_out;
-       sr_session_send(cb_data, &packet);
-
-       devc->num_samples += 1024;
-
-       if (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
-               sr_info("Requested number of samples reached.");
-               sdi->driver->dev_acquisition_stop(sdi, cb_data);
-       }
-
-       return TRUE;
-}
-
-SR_PRIV int mso_configure_channels(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_channel *ch;
-       GSList *l;
-       char *tc;
-
-       devc = sdi->priv;
-
-       devc->la_trigger_mask = 0xFF;   //the mask for the LA_TRIGGER (bits set to 0 matter, those set to 1 are ignored).
-       devc->la_trigger = 0x00;        //The value of the LA byte that generates a trigger event (in that mode).
-       devc->dso_trigger_voltage = 3;
-       devc->dso_probe_attn = 1;
-       devc->trigger_outsrc = 0;
-       devc->trigger_chan = 3; //LA combination trigger
-       devc->use_trigger = FALSE;
-
-       for (l = sdi->channels; l; l = l->next) {
-               ch = (struct sr_channel *)l->data;
-               if (ch->enabled == FALSE)
-                       continue;
-
-               int channel_bit = 1 << (ch->index);
-               if (!(ch->trigger))
-                       continue;
-
-               devc->use_trigger = TRUE;
-               //Configure trigger mask and value.
-               for (tc = ch->trigger; *tc; tc++) {
-                       devc->la_trigger_mask &= ~channel_bit;
-                       if (*tc == '1')
-                               devc->la_trigger |= channel_bit;
-               }
-       }
-
-       return SR_OK;
-}
diff --git a/hardware/link-mso19/protocol.h b/hardware/link-mso19/protocol.h
deleted file mode 100644 (file)
index 809d7f8..0000000
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2011 Daniel Ribeiro <drwyrm@gmail.com>
- * Copyright (C) 2012 Renato Caldas <rmsc@fe.up.pt>
- * Copyright (C) 2013 Lior Elazary <lelazary@yahoo.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_LINK_MSO19_PROTOCOL_H
-#define LIBSIGROK_HARDWARE_LINK_MSO19_PROTOCOL_H
-
-#include <stdint.h>
-#include <string.h>
-#include <glib.h>
-#include <libudev.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "link-mso19"
-
-#define USB_VENDOR             "3195"
-#define USB_PRODUCT            "f190"
-
-#define NUM_CHANNELS           (1 + 8)
-#define NUM_TRIGGER_STAGES     4
-#define TRIGGER_TYPE           "01"    //the first r/f is used for the whole group
-#define SERIALCOMM             "460800/8n1/flow=2"
-#define SERIALCONN             "/dev/ttyUSB0"
-#define CLOCK_RATE             SR_MHZ(100)
-#define MIN_NUM_SAMPLES                4
-
-#define MSO_TRIGGER_UNKNOWN    '!'
-#define MSO_TRIGGER_UNKNOWN1   '1'
-#define MSO_TRIGGER_UNKNOWN2   '2'
-#define MSO_TRIGGER_UNKNOWN3   '3'
-#define MSO_TRIGGER_WAIT       '4'
-#define MSO_TRIGGER_FIRED      '5'
-#define MSO_TRIGGER_DATAREADY  '6'
-
-enum trigger_slopes {
-       SLOPE_POSITIVE = 0,
-       SLOPE_NEGATIVE,
-};
-
-/* Structure for the pattern generator state */
-struct mso_patgen {
-       /* Pattern generator clock config */
-       uint16_t clock;
-       /* Buffer start address */
-       uint16_t start;
-       /* Buffer end address */
-       uint16_t end;
-       /* Pattern generator config */
-       uint8_t config;
-       /* Samples buffer */
-       uint8_t buffer[1024];
-       /* Input/output configuration for the samples buffer (?) */
-       uint8_t io[1024];
-       /* Number of loops for the pattern generator */
-       uint8_t loops;
-       /* Bit enable mask for the I/O lines */
-       uint8_t mask;
-};
-
-/* Data structure for the protocol trigger state */
-struct mso_prototrig {
-       /* Word match buffer */
-       uint8_t word[4];
-       /* Masks for the wordmatch buffer */
-       uint8_t mask[4];
-       /* SPI mode 0, 1, 2, 3. Set to 0 for I2C */
-       uint8_t spimode;
-};
-
-/* Private, per-device-instance driver context. */
-struct dev_context {
-       /* info */
-       uint8_t hwmodel;
-       uint8_t hwrev;
-       struct sr_serial_dev_inst *serial;
-//      uint8_t num_sample_rates;
-       /* calibration */
-       double vbit;
-       uint16_t dac_offset;
-       uint16_t offset_range;
-       uint64_t limit_samples;
-       uint64_t num_samples;
-       /* register cache */
-       uint8_t ctlbase1;
-       uint8_t ctlbase2;
-       /* state */
-       uint8_t la_threshold;
-       uint64_t cur_rate;
-       uint8_t dso_probe_attn;
-       int8_t use_trigger;
-       uint8_t trigger_chan;
-       uint8_t trigger_slope;
-       uint8_t trigger_outsrc;
-       uint8_t trigger_state;
-       uint8_t trigger_holdoff[2];
-       uint8_t la_trigger;
-       uint8_t la_trigger_mask;
-       double dso_trigger_voltage;
-       uint16_t dso_trigger_width;
-       struct mso_prototrig protocol_trigger;
-       void *cb_data;
-       uint16_t buffer_n;
-       char buffer[4096];
-};
-
-SR_PRIV int mso_parse_serial(const char *iSerial, const char *iProduct,
-                            struct dev_context *ctx);
-SR_PRIV int mso_check_trigger(struct sr_serial_dev_inst *serial,
-                             uint8_t * info);
-SR_PRIV int mso_reset_adc(struct sr_dev_inst *sdi);
-SR_PRIV int mso_clkrate_out(struct sr_serial_dev_inst *serial, uint16_t val);
-SR_PRIV int mso_configure_rate(const struct sr_dev_inst *sdi, uint32_t rate);
-SR_PRIV int mso_receive_data(int fd, int revents, void *cb_data);
-SR_PRIV int mso_configure_trigger(const struct sr_dev_inst *sdi);
-SR_PRIV int mso_configure_threshold_level(const struct sr_dev_inst *sdi);
-SR_PRIV int mso_read_buffer(struct sr_dev_inst *sdi);
-SR_PRIV int mso_arm(const struct sr_dev_inst *sdi);
-SR_PRIV int mso_force_capture(struct sr_dev_inst *sdi);
-SR_PRIV int mso_dac_out(const struct sr_dev_inst *sdi, uint16_t val);
-SR_PRIV inline uint16_t mso_calc_raw_from_mv(struct dev_context *devc);
-SR_PRIV int mso_reset_fsm(struct sr_dev_inst *sdi);
-SR_PRIV int mso_toggle_led(struct sr_dev_inst *sdi, int state);
-
-SR_PRIV int mso_configure_channels(const struct sr_dev_inst *sdi);
-SR_PRIV void stop_acquisition(const struct sr_dev_inst *sdi);
-
-/* bank agnostic registers */
-#define REG_CTL2               15
-
-/* bank 0 registers */
-#define REG_BUFFER             1
-#define REG_TRIGGER            2
-#define REG_CLKRATE1           9
-#define REG_CLKRATE2           10
-#define REG_DAC1               12
-#define REG_DAC2               13
-/* possibly bank agnostic: */
-#define REG_CTL1               14
-
-/* bank 2 registers (SPI/I2C protocol trigger) */
-#define REG_PT_WORD(x)         (x)
-#define REG_PT_MASK(x)         (x + 4)
-#define REG_PT_SPIMODE         8
-
-/* bits - REG_CTL1 */
-#define BIT_CTL1_RESETFSM      (1 << 0)
-#define BIT_CTL1_ARM           (1 << 1)
-#define BIT_CTL1_ADC_UNKNOWN4  (1 << 4)        /* adc enable? */
-#define BIT_CTL1_RESETADC      (1 << 6)
-#define BIT_CTL1_LED           (1 << 7)
-
-/* bits - REG_CTL2 */
-#define BITS_CTL2_BANK(x)      (x & 0x3)
-#define BIT_CTL2_SLOWMODE      (1 << 5)
-
-struct rate_map {
-       uint32_t rate;
-       uint16_t val;
-       uint8_t slowmode;
-};
-
-static const struct rate_map rate_map[] = {
-       { SR_MHZ(200), 0x0205, 0 },
-       { SR_MHZ(100), 0x0105, 0 },
-       { SR_MHZ(50),  0x0005, 0 },
-       { SR_MHZ(20),  0x0303, 0 },
-       { SR_MHZ(10),  0x0308, 0 },
-       { SR_MHZ(5),   0x030c, 0 },
-       { SR_MHZ(2),   0x0330, 0 },
-       { SR_MHZ(1),   0x0362, 0 },
-       { SR_KHZ(500), 0x03c6, 0 },
-       { SR_KHZ(200), 0x07f2, 0 },
-       { SR_KHZ(100), 0x0fe6, 0 },
-       { SR_KHZ(50),  0x1fce, 0 },
-       { SR_KHZ(20),  0x4f86, 0 },
-       { SR_KHZ(10),  0x9f0e, 0 },
-       { SR_KHZ(5),   0x03c7, 0x20 },
-       { SR_KHZ(2),   0x07f3, 0x20 },
-       { SR_KHZ(1),   0x0fe7, 0x20 },
-       { SR_HZ(500),  0x1fcf, 0x20 },
-       { SR_HZ(200),  0x4f87, 0x20 },
-       { SR_HZ(100),  0x9f0f, 0x20 },
-};
-
-/* FIXME: Determine corresponding voltages */
-static const uint16_t la_threshold_map[] = {
-       0x8600,
-       0x8770,
-       0x88ff,
-       0x8c70,
-       0x8eff,
-       0x8fff,
-};
-
-#endif
diff --git a/hardware/manson-hcs-3xxx/api.c b/hardware/manson-hcs-3xxx/api.c
deleted file mode 100644 (file)
index faa093f..0000000
+++ /dev/null
@@ -1,430 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2014 Uwe Hermann <uwe@hermann-uwe.de>
- * Copyright (C) 2014 Matthias Heidbrink <m-sigrok@heidbrink.biz>
- *
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-/** @file
-  *  <em>Manson HCS-3xxx Series</em> power supply driver
-  *  @internal
-  */
-
-#include "protocol.h"
-
-static const int32_t hwopts[] = {
-       SR_CONF_CONN,
-       SR_CONF_SERIALCOMM,
-};
-
-static const int32_t devopts[] = {
-       /* Device class */
-       SR_CONF_POWER_SUPPLY,
-       /* Aquisition modes. */
-       SR_CONF_LIMIT_SAMPLES,
-       SR_CONF_LIMIT_MSEC,
-       SR_CONF_CONTINUOUS,
-       /* Device configuration */
-       SR_CONF_OUTPUT_CURRENT,
-       SR_CONF_OUTPUT_CURRENT_MAX,
-       SR_CONF_OUTPUT_ENABLED,
-       SR_CONF_OUTPUT_VOLTAGE,
-       SR_CONF_OUTPUT_VOLTAGE_MAX,
-};
-
-/* Note: All models have one power supply output only. */
-static struct hcs_model models[] = {
-       { MANSON_HCS_3100, "HCS-3100",     "3100", { 1, 18, 0.1 }, { 0, 10,   0.10 } },
-       { MANSON_HCS_3102, "HCS-3102",     "3102", { 1, 36, 0.1 }, { 0,  5,   0.01 } },
-       { MANSON_HCS_3104, "HCS-3104",     "3104", { 1, 60, 0.1 }, { 0,  2.5, 0.01 } },
-       { MANSON_HCS_3150, "HCS-3150",     "3150", { 1, 18, 0.1 }, { 0, 15,   0.10 } },
-       { MANSON_HCS_3200, "HCS-3200",     "3200", { 1, 18, 0.1 }, { 0, 20,   0.10 } },
-       { MANSON_HCS_3202, "HCS-3202",     "3202", { 1, 36, 0.1 }, { 0, 10,   0.10 } },
-       { MANSON_HCS_3204, "HCS-3204",     "3204", { 1, 60, 0.1 }, { 0,  5,   0.01 } },
-       { MANSON_HCS_3300, "HCS-3300-USB", "3300", { 1, 16, 0.1 }, { 0, 30,   0.10 } },
-       { MANSON_HCS_3302, "HCS-3302-USB", "3302", { 1, 32, 0.1 }, { 0, 15,   0.10 } },
-       { MANSON_HCS_3304, "HCS-3304-USB", "3304", { 1, 60, 0.1 }, { 0,  8,   0.10 } },
-       { MANSON_HCS_3400, "HCS-3400-USB", "3400", { 1, 16, 0.1 }, { 0, 40,   0.10 } },
-       { MANSON_HCS_3402, "HCS-3402-USB", "3402", { 1, 32, 0.1 }, { 0, 20,   0.10 } },
-       { MANSON_HCS_3404, "HCS-3404-USB", "3404", { 1, 60, 0.1 }, { 0, 10,   0.10 } },
-       { MANSON_HCS_3600, "HCS-3600-USB", "3600", { 1, 16, 0.1 }, { 0, 60,   0.10 } },
-       { MANSON_HCS_3602, "HCS-3602-USB", "3602", { 1, 32, 0.1 }, { 0, 30,   0.10 } },
-       { MANSON_HCS_3604, "HCS-3604-USB", "3604", { 1, 60, 0.1 }, { 0, 15,   0.10 } },
-       { 0, NULL, NULL, { 0, 0, 0 }, { 0, 0, 0 }, },
-};
-
-SR_PRIV struct sr_dev_driver manson_hcs_3xxx_driver_info;
-static struct sr_dev_driver *di = &manson_hcs_3xxx_driver_info;
-
-static int dev_clear(void)
-{
-       return std_dev_clear(di, NULL);
-}
-
-static int init(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, di, LOG_PREFIX);
-}
-
-static GSList *scan(GSList *options)
-{
-       int i, model_id;
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       struct sr_dev_inst *sdi;
-       struct sr_config *src;
-       struct sr_channel *ch;
-       GSList *devices, *l;
-       const char *conn, *serialcomm;
-       struct sr_serial_dev_inst *serial;
-       char reply[50], **tokens, *dummy;
-
-       drvc = di->priv;
-       drvc->instances = NULL;
-       devices = NULL;
-       conn = NULL;
-       serialcomm = NULL;
-       devc = 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;
-               default:
-                       sr_err("Unknown option %d, skipping.", src->key);
-                       break;
-               }
-       }
-
-       if (!conn)
-               return NULL;
-       if (!serialcomm)
-               serialcomm = "9600/8n1";
-
-       if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
-               return NULL;
-
-       if (serial_open(serial, SERIAL_RDWR) != SR_OK)
-               return NULL;
-
-       serial_flush(serial);
-
-       sr_info("Probing serial port %s.", conn);
-
-       /* Get the device model. */
-       memset(&reply, 0, sizeof(reply));
-       if ((hcs_send_cmd(serial, "GMOD\r") < 0) ||
-           (hcs_read_reply(serial, 2, reply, sizeof(reply)) < 0))
-               return NULL;
-       tokens = g_strsplit((const gchar *)&reply, "\r", 2);
-
-       model_id = -1;
-       for (i = 0; models[i].id != NULL; i++) {
-               if (!strcmp(models[i].id, tokens[0]))
-                       model_id = i;
-       }
-       g_strfreev(tokens);
-
-       if (model_id < 0) {
-               sr_err("Unknown model id '%s' detected, aborting.", tokens[0]);
-               return NULL;
-       }
-
-       /* Init device instance, etc. */
-       if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "Manson",
-                                   models[model_id].name, NULL))) {
-               sr_err("Failed to create device instance.");
-               return NULL;
-       }
-
-       sdi->inst_type = SR_INST_SERIAL;
-       sdi->conn = serial;
-       sdi->driver = di;
-
-       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "CH1"))) {
-               sr_err("Failed to create channel.");
-               goto exit_err;
-       }
-       sdi->channels = g_slist_append(sdi->channels, ch);
-
-       devc = g_malloc0(sizeof(struct dev_context));
-       devc->model = &models[model_id];
-
-       sdi->priv = devc;
-
-       /* Get current voltage, current, status. */
-       if ((hcs_send_cmd(serial, "GETD\r") < 0) ||
-           (hcs_read_reply(serial, 2, reply, sizeof(reply)) < 0))
-               goto exit_err;
-       tokens = g_strsplit((const gchar *)&reply, "\r", 2);
-       if (hcs_parse_volt_curr_mode(sdi, tokens) < 0)
-               goto exit_err;
-       g_strfreev(tokens);
-
-       /* Get max. voltage and current. */
-       if ((hcs_send_cmd(serial, "GMAX\r") < 0) ||
-           (hcs_read_reply(serial, 2, reply, sizeof(reply)) < 0))
-               goto exit_err;
-       tokens = g_strsplit((const gchar *)&reply, "\r", 2);
-       devc->current_max_device = g_strtod(&tokens[0][3], &dummy) * devc->model->current[2];
-       tokens[0][3] = '\0';
-       devc->voltage_max_device = g_strtod(tokens[0], &dummy) * devc->model->voltage[2];
-       g_strfreev(tokens);
-
-       drvc->instances = g_slist_append(drvc->instances, sdi);
-       devices = g_slist_append(devices, sdi);
-
-       serial_close(serial);
-       if (!devices)
-               sr_serial_dev_inst_free(serial);
-
-       return devices;
-
-exit_err:
-       sr_dev_inst_free(sdi);
-       if (devc)
-               g_free(devc);
-       return NULL;
-}
-
-static GSList *dev_list(void)
-{
-       return ((struct drv_context *)(di->priv))->instances;
-}
-
-static int cleanup(void)
-{
-       return dev_clear();
-}
-
-static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-
-       (void)cg;
-
-       if (!sdi)
-               return SR_ERR_ARG;
-
-       devc = sdi->priv;
-
-       switch (key) {
-       case SR_CONF_LIMIT_SAMPLES:
-               *data = g_variant_new_uint64(devc->limit_samples);
-               break;
-       case SR_CONF_LIMIT_MSEC:
-               *data = g_variant_new_uint64(devc->limit_msec);
-               break;
-       case SR_CONF_OUTPUT_CURRENT:
-               *data = g_variant_new_double(devc->current);
-               break;
-       case SR_CONF_OUTPUT_CURRENT_MAX:
-               *data = g_variant_new_double(devc->current_max);
-               break;
-       case SR_CONF_OUTPUT_ENABLED:
-               *data = g_variant_new_boolean(devc->output_enabled);
-               break;
-       case SR_CONF_OUTPUT_VOLTAGE:
-               *data = g_variant_new_double(devc->voltage);
-               break;
-       case SR_CONF_OUTPUT_VOLTAGE_MAX:
-               *data = g_variant_new_double(devc->voltage_max);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       gboolean bval;
-       gdouble dval;
-
-       (void)cg;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       devc = sdi->priv;
-
-       switch (key) {
-       case SR_CONF_LIMIT_MSEC:
-               if (g_variant_get_uint64(data) == 0)
-                       return SR_ERR_ARG;
-               devc->limit_msec = g_variant_get_uint64(data);
-               break;
-       case SR_CONF_LIMIT_SAMPLES:
-               if (g_variant_get_uint64(data) == 0)
-                       return SR_ERR_ARG;
-               devc->limit_samples = g_variant_get_uint64(data);
-               break;
-       case SR_CONF_OUTPUT_CURRENT_MAX:
-               dval = g_variant_get_double(data);
-               if (dval < devc->model->current[0] || dval > devc->current_max_device)
-                       return SR_ERR_ARG;
-
-               if ((hcs_send_cmd(sdi->conn, "CURR%03.0f\r",
-                       (dval / devc->model->current[2])) < 0) ||
-                   (hcs_read_reply(sdi->conn, 1, devc->buf, sizeof(devc->buf)) < 0))
-                       return SR_ERR;
-               devc->current_max = dval;
-               break;
-       case SR_CONF_OUTPUT_ENABLED:
-               bval = g_variant_get_boolean(data);
-               if (bval == devc->output_enabled) /* Nothing to do. */
-                       break;
-               if ((hcs_send_cmd(sdi->conn, "SOUT%1d\r", !bval) < 0) ||
-                   (hcs_read_reply(sdi->conn, 1, devc->buf, sizeof(devc->buf)) < 0))
-                       return SR_ERR;
-               devc->output_enabled = bval;
-               break;
-       case SR_CONF_OUTPUT_VOLTAGE_MAX:
-               dval = g_variant_get_double(data);
-               if (dval < devc->model->voltage[0] || dval > devc->voltage_max_device)
-                       return SR_ERR_ARG;
-
-               if ((hcs_send_cmd(sdi->conn, "VOLT%03.0f\r",
-                       (dval / devc->model->voltage[2])) < 0) ||
-                   (hcs_read_reply(sdi->conn, 1, devc->buf, sizeof(devc->buf)) < 0))
-                       return SR_ERR;
-               devc->voltage_max = dval;
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       GVariant *gvar;
-       GVariantBuilder gvb;
-       double dval;
-       int idx;
-
-       (void)cg;
-
-       if (!sdi)
-               return SR_ERR_ARG;
-       devc = sdi->priv;
-
-       switch (key) {
-       case SR_CONF_SCAN_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                       hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
-               break;
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                       devopts, ARRAY_SIZE(devopts), sizeof(int32_t));
-               break;
-       case SR_CONF_OUTPUT_CURRENT_MAX:
-               g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
-               /* Min, max, step. */
-               for (idx = 0; idx < 3; idx++) {
-                       if (idx == 1)
-                               dval = devc->current_max_device;
-                       else
-                               dval = devc->model->current[idx];
-                       gvar = g_variant_new_double(dval);
-                       g_variant_builder_add_value(&gvb, gvar);
-               }
-               *data = g_variant_builder_end(&gvb);
-               break;
-       case SR_CONF_OUTPUT_VOLTAGE_MAX:
-               g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
-               /* Min, max, step. */
-               for (idx = 0; idx < 3; idx++) {
-                       if (idx == 1)
-                               dval = devc->voltage_max_device;
-                       else
-                               dval = devc->model->voltage[idx];
-                       gvar = g_variant_new_double(dval);
-                       g_variant_builder_add_value(&gvb, gvar);
-               }
-               *data = g_variant_builder_end(&gvb);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       devc = sdi->priv;
-       devc->cb_data = cb_data;
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(cb_data, LOG_PREFIX);
-
-       devc->starttime = g_get_monotonic_time();
-       devc->num_samples = 0;
-       devc->reply_pending = FALSE;
-       devc->req_sent_at = 0;
-
-       /* Poll every 10ms, or whenever some data comes in. */
-       serial = sdi->conn;
-       serial_source_add(sdi->session, serial, G_IO_IN, 10,
-                       hcs_receive_data, (void *)sdi);
-
-       return SR_OK;
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       return std_serial_dev_acquisition_stop(sdi, cb_data,
-                       std_serial_dev_close, sdi->conn, LOG_PREFIX);
-}
-
-SR_PRIV struct sr_dev_driver manson_hcs_3xxx_driver_info = {
-       .name = "manson-hcs-3xxx",
-       .longname = "Manson HCS-3xxx",
-       .api_version = 1,
-       .init = init,
-       .cleanup = cleanup,
-       .scan = scan,
-       .dev_list = dev_list,
-       .dev_clear = dev_clear,
-       .config_get = config_get,
-       .config_set = config_set,
-       .config_list = config_list,
-       .dev_open = std_serial_dev_open,
-       .dev_close = std_serial_dev_close,
-       .dev_acquisition_start = dev_acquisition_start,
-       .dev_acquisition_stop = dev_acquisition_stop,
-       .priv = NULL,
-};
diff --git a/hardware/manson-hcs-3xxx/protocol.c b/hardware/manson-hcs-3xxx/protocol.c
deleted file mode 100644 (file)
index f5199e7..0000000
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2014 Uwe Hermann <uwe@hermann-uwe.de>
- * Copyright (C) 2014 Matthias Heidbrink <m-sigrok@heidbrink.biz>
- *
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-/** @file
-  *  <em>Manson HCS-3xxx Series</em> power supply driver
-  *  @internal
-  */
-
-#include "protocol.h"
-
-#define REQ_TIMEOUT_MS 500
-
-SR_PRIV int hcs_send_cmd(struct sr_serial_dev_inst *serial, const char *cmd, ...)
-{
-       int ret;
-       char cmdbuf[50];
-       char *cmd_esc;
-       va_list args;
-
-       va_start(args, cmd);
-       vsnprintf(cmdbuf, sizeof(cmdbuf), cmd, args);
-       va_end(args);
-
-       cmd_esc = g_strescape(cmdbuf, NULL);
-       sr_dbg("Sending '%s'.", cmd_esc);
-       g_free(cmd_esc);
-
-       if ((ret = serial_write_blocking(serial, cmdbuf, strlen(cmdbuf))) < 0) {
-               sr_err("Error sending command: %d.", ret);
-               return ret;
-       }
-
-       return ret;
-}
-
-/**
- * Read data from interface into buffer blocking until @a lines number of \\r chars
- * received.
- * @param serial Previously initialized serial port structure.
- * @param[in] lines Number of \\r-terminated lines to read (1-n).
- * @param     buf Buffer for result. Contents is NUL-terminated on success.
- * @param[in] buflen Buffer length (>0).
- * @retval SR_OK Lines received and ending with "OK\r" (success).
- * @retval SR_ERR Error.
- * @retval SR_ERR_ARG Invalid argument.
- */
-SR_PRIV int hcs_read_reply(struct sr_serial_dev_inst *serial, int lines, char* buf, int buflen)
-{
-       int l_recv = 0;
-       int bufpos = 0;
-       int retc;
-
-       if (!serial || (lines <= 0) || !buf || (buflen <= 0))
-               return SR_ERR_ARG;
-
-       while ((l_recv < lines) && (bufpos < (buflen + 1))) {
-               retc = serial_read_blocking(serial, &buf[bufpos], 1);
-               if (retc != 1)
-                       return SR_ERR;
-               if (buf[bufpos] == '\r')
-                       l_recv++;
-               bufpos++;
-       }
-       buf[bufpos] = '\0';
-
-       if ((l_recv == lines) && (g_str_has_suffix(buf, "OK\r")))
-               return SR_OK;
-       else
-               return SR_ERR;
-}
-
-/** Interpret result of GETD command. */
-SR_PRIV int hcs_parse_volt_curr_mode(struct sr_dev_inst *sdi, char **tokens)
-{
-       char *str;
-       double val;
-       struct dev_context *devc;
-
-       devc = sdi->priv;
-
-       /* Bytes 0-3: Voltage. */
-       str = g_strndup(tokens[0], 4);
-       val = g_ascii_strtod(str, NULL) / 100;
-       devc->voltage = val;
-       g_free(str);
-
-       /* Bytes 4-7: Current. */
-       str = g_strndup((tokens[0] + 4), 4);
-       val = g_ascii_strtod(str, NULL) / 100;
-       devc->current = val;
-       g_free(str);
-
-       /* Byte 8: Mode ('0' means CV, '1' means CC). */
-       devc->cc_mode = (tokens[0][8] == '1');
-
-       /* Output enabled? Works because voltage cannot be set to 0.0 directly. */
-       devc->output_enabled = devc->voltage != 0.0;
-
-       return SR_OK;
-}
-
-static void send_sample(struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_analog analog;
-
-       devc = sdi->priv;
-
-       packet.type = SR_DF_ANALOG;
-       packet.payload = &analog;
-       analog.channels = sdi->channels;
-       analog.num_samples = 1;
-
-       analog.mq = SR_MQ_VOLTAGE;
-       analog.unit = SR_UNIT_VOLT;
-       analog.mqflags = SR_MQFLAG_DC;
-       analog.data = &devc->voltage;
-       sr_session_send(sdi, &packet);
-
-       analog.mq = SR_MQ_CURRENT;
-       analog.unit = SR_UNIT_AMPERE;
-       analog.mqflags = 0;
-       analog.data = &devc->current;
-       sr_session_send(sdi, &packet);
-
-       devc->num_samples++;
-}
-
-static int parse_reply(struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       char *reply_esc, **tokens;
-       int retc;
-
-       devc = sdi->priv;
-
-       reply_esc = g_strescape(devc->buf, NULL);
-       sr_dbg("Received '%s'.", reply_esc);
-       g_free(reply_esc);
-
-       tokens = g_strsplit(devc->buf, "\r", 0);
-       retc = hcs_parse_volt_curr_mode(sdi, tokens);
-       g_strfreev(tokens);
-       if (retc < 0)
-               return SR_ERR;
-
-       send_sample(sdi);
-
-       return SR_OK;
-}
-
-static int handle_new_data(struct sr_dev_inst *sdi)
-{
-       int len;
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-
-       devc = sdi->priv;
-       serial = sdi->conn;
-
-       len = serial_read(serial, devc->buf + devc->buflen, 1);
-       if (len < 1)
-               return SR_ERR;
-
-       devc->buflen += len;
-       devc->buf[devc->buflen] = '\0';
-
-       /* Wait until we received an "OK\r" (among other bytes). */
-       if (!g_str_has_suffix(devc->buf, "OK\r"))
-               return SR_OK;
-
-       parse_reply(sdi);
-
-       devc->buf[0] = '\0';
-       devc->buflen = 0;
-
-       devc->reply_pending = FALSE;
-
-       return SR_OK;
-}
-
-/** Driver/serial data reception function. */
-SR_PRIV int hcs_receive_data(int fd, int revents, void *cb_data)
-{
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-       int64_t t, elapsed_us;
-
-       (void)fd;
-
-       if (!(sdi = cb_data))
-               return TRUE;
-
-       if (!(devc = sdi->priv))
-               return TRUE;
-
-       serial = sdi->conn;
-
-       if (revents == G_IO_IN) {
-               /* New data arrived. */
-               handle_new_data(sdi);
-       } else {
-               /* Timeout. */
-       }
-
-       if (devc->limit_samples && (devc->num_samples >= devc->limit_samples)) {
-               sr_info("Requested number of samples reached.");
-               sdi->driver->dev_acquisition_stop(sdi, cb_data);
-               return TRUE;
-       }
-
-       if (devc->limit_msec) {
-               t = (g_get_monotonic_time() - devc->starttime) / 1000;
-               if (t > (int64_t)devc->limit_msec) {
-                       sr_info("Requested time limit reached.");
-                       sdi->driver->dev_acquisition_stop(sdi, cb_data);
-                       return TRUE;
-               }
-       }
-
-       /* Request next packet, if required. */
-       if (sdi->status == SR_ST_ACTIVE) {
-               if (devc->reply_pending) {
-                       elapsed_us = g_get_monotonic_time() - devc->req_sent_at;
-                       if (elapsed_us > (REQ_TIMEOUT_MS * 1000))
-                               devc->reply_pending = FALSE;
-                       return TRUE;
-               }
-
-               /* Send command to get voltage, current, and mode (CC or CV). */
-               if (hcs_send_cmd(serial, "GETD\r") < 0)
-                       return TRUE;
-
-               devc->req_sent_at = g_get_monotonic_time();
-               devc->reply_pending = TRUE;
-       }
-
-       return TRUE;
-}
diff --git a/hardware/manson-hcs-3xxx/protocol.h b/hardware/manson-hcs-3xxx/protocol.h
deleted file mode 100644 (file)
index b4441d0..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2014 Uwe Hermann <uwe@hermann-uwe.de>
- * Copyright (C) 2014 Matthias Heidbrink <m-sigrok@heidbrink.biz>
- *
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-/** @file
-  *  <em>Manson HCS-3xxx Series</em> power supply driver
-  *  @internal
-  */
-
-#ifndef LIBSIGROK_HARDWARE_MANSON_HCS_3XXX_PROTOCOL_H
-#define LIBSIGROK_HARDWARE_MANSON_HCS_3XXX_PROTOCOL_H
-
-#include <stdint.h>
-#include <string.h>
-#include <math.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "manson-hcs-3xxx"
-
-enum {
-       MANSON_HCS_3100,
-       MANSON_HCS_3102,
-       MANSON_HCS_3104,
-       MANSON_HCS_3150,
-       MANSON_HCS_3200,
-       MANSON_HCS_3202,
-       MANSON_HCS_3204,
-       MANSON_HCS_3300,
-       MANSON_HCS_3302,
-       MANSON_HCS_3304,
-       MANSON_HCS_3400,
-       MANSON_HCS_3402,
-       MANSON_HCS_3404,
-       MANSON_HCS_3600,
-       MANSON_HCS_3602,
-       MANSON_HCS_3604,
-};
-
-/** Information on a single model. */
-struct hcs_model {
-       int model_id;      /**< Model info */
-       char *name;        /**< Model name */
-       char *id;          /**< Model ID, like delivered by interface */
-       double voltage[3]; /**< Min, max, step */
-       double current[3]; /**< Min, max, step */
-};
-
-/** Private, per-device-instance driver context. */
-struct dev_context {
-       struct hcs_model *model; /**< Model informaion. */
-
-       uint64_t limit_samples;
-       uint64_t limit_msec;
-       uint64_t num_samples;
-       int64_t starttime;
-       int64_t req_sent_at;
-       gboolean reply_pending;
-
-       void *cb_data;
-
-       float current;          /**< Last current value [A] read from device. */
-       float current_max;      /**< Output current set. */
-       float current_max_device;/**< Device-provided maximum output current. */
-       float voltage;          /**< Last voltage value [V] read from device. */
-       float voltage_max;      /**< Output voltage set. */
-       float voltage_max_device;/**< Device-provided maximum output voltage. */
-       gboolean cc_mode;       /**< Device is in constant current mode (otherwise constant voltage). */
-
-       gboolean output_enabled; /**< Is the output enabled? */
-
-       char buf[50];
-       int buflen;
-};
-
-SR_PRIV int hcs_parse_volt_curr_mode(struct sr_dev_inst *sdi, char **tokens);
-SR_PRIV int hcs_read_reply(struct sr_serial_dev_inst *serial, int lines, char* buf, int buflen);
-SR_PRIV int hcs_send_cmd(struct sr_serial_dev_inst *serial, const char *cmd, ...);
-SR_PRIV int hcs_receive_data(int fd, int revents, void *cb_data);
-
-#endif
diff --git a/hardware/mic-985xx/api.c b/hardware/mic-985xx/api.c
deleted file mode 100644 (file)
index 6cfc5ef..0000000
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include "protocol.h"
-
-static const int32_t hwopts[] = {
-       SR_CONF_CONN,
-       SR_CONF_SERIALCOMM,
-};
-
-static const int32_t hwcaps[] = {
-       SR_CONF_THERMOMETER,
-       SR_CONF_HYGROMETER,
-       SR_CONF_LIMIT_SAMPLES,
-       SR_CONF_LIMIT_MSEC,
-       SR_CONF_CONTINUOUS,
-};
-
-SR_PRIV struct sr_dev_driver mic_98581_driver_info;
-SR_PRIV struct sr_dev_driver mic_98583_driver_info;
-
-SR_PRIV const struct mic_dev_info mic_devs[] = {
-       {
-               "MIC", "98581", "38400/8n2", 32000, TRUE, FALSE, 6,
-               packet_valid_temp,
-               &mic_98581_driver_info, receive_data_MIC_98581,
-       },
-       {
-               "MIC", "98583", "38400/8n2", 32000, TRUE, TRUE, 10,
-               packet_valid_temp_hum,
-               &mic_98583_driver_info, receive_data_MIC_98583,
-       },
-};
-
-static int dev_clear(int idx)
-{
-       return std_dev_clear(mic_devs[idx].di, NULL);
-}
-
-static int init(struct sr_context *sr_ctx, int idx)
-{
-       sr_dbg("Selected '%s' subdriver.", mic_devs[idx].di->name);
-
-       return std_init(sr_ctx, mic_devs[idx].di, LOG_PREFIX);
-}
-
-static GSList *mic_scan(const char *conn, const char *serialcomm, int idx)
-{
-       struct sr_dev_inst *sdi;
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       struct sr_channel *ch;
-       struct sr_serial_dev_inst *serial;
-       GSList *devices;
-
-       if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
-               return NULL;
-
-       if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
-               return NULL;
-
-       drvc = mic_devs[idx].di->priv;
-       devices = NULL;
-       serial_flush(serial);
-
-       /* TODO: Query device type. */
-       // ret = mic_cmd_get_device_info(serial);
-
-       sr_info("Found device on port %s.", conn);
-
-       /* TODO: Fill in version from protocol response. */
-       if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, mic_devs[idx].vendor,
-                                   mic_devs[idx].device, NULL)))
-               goto scan_cleanup;
-
-       if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
-               sr_err("Device context malloc failed.");
-               goto scan_cleanup;
-       }
-
-       sdi->inst_type = SR_INST_SERIAL;
-       sdi->conn = serial;
-
-       sdi->priv = devc;
-       sdi->driver = mic_devs[idx].di;
-
-       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "Temperature")))
-               goto scan_cleanup;
-       sdi->channels = g_slist_append(sdi->channels, ch);
-
-       if (mic_devs[idx].has_humidity) {
-               if (!(ch = sr_channel_new(1, SR_CHANNEL_ANALOG, TRUE, "Humidity")))
-                       goto scan_cleanup;
-               sdi->channels = g_slist_append(sdi->channels, ch);
-       }
-
-       drvc->instances = g_slist_append(drvc->instances, sdi);
-       devices = g_slist_append(devices, sdi);
-
-scan_cleanup:
-       serial_close(serial);
-
-       return devices;
-}
-
-static GSList *scan(GSList *options, int idx)
-{
-       struct sr_config *src;
-       GSList *l, *devices;
-       const char *conn, *serialcomm;
-
-       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 = mic_scan(conn, serialcomm, idx);
-       } else {
-               /* Try the default. */
-               devices = mic_scan(conn, mic_devs[idx].conn, idx);
-       }
-
-       return devices;
-}
-
-static GSList *dev_list(int idx)
-{
-       return ((struct drv_context *)(mic_devs[idx].di->priv))->instances;
-}
-
-static int cleanup(int idx)
-{
-       return dev_clear(idx);
-}
-
-static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-
-       (void)cg;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       devc = sdi->priv;
-
-       switch (id) {
-       case SR_CONF_LIMIT_SAMPLES:
-               devc->limit_samples = g_variant_get_uint64(data);
-               sr_dbg("Setting sample limit to %" PRIu64 ".",
-                      devc->limit_samples);
-               break;
-       case SR_CONF_LIMIT_MSEC:
-               devc->limit_msec = g_variant_get_uint64(data);
-               sr_dbg("Setting time limit to %" PRIu64 "ms.",
-                      devc->limit_msec);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_list(int 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_INT32,
-                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
-               break;
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi,
-                                   void *cb_data, int idx)
-{
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       devc = sdi->priv;
-       devc->cb_data = cb_data;
-       devc->num_samples = 0;
-       devc->starttime = g_get_monotonic_time();
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(cb_data, LOG_PREFIX);
-
-       /* Poll every 100ms, or whenever some data comes in. */
-       serial = sdi->conn;
-       serial_source_add(sdi->session, serial, G_IO_IN, 100,
-                     mic_devs[idx].receive_data, (void *)sdi);
-
-       return SR_OK;
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       return std_serial_dev_acquisition_stop(sdi, cb_data, std_serial_dev_close,
-                       sdi->conn, LOG_PREFIX);
-}
-
-/* Driver-specific API function wrappers */
-#define HW_INIT(X) \
-static int init_##X(struct sr_context *sr_ctx) { return init(sr_ctx, X); }
-#define HW_CLEANUP(X) \
-static int cleanup_##X(void) { return cleanup(X); }
-#define HW_SCAN(X) \
-static GSList *scan_##X(GSList *options) { return scan(options, X); }
-#define HW_DEV_LIST(X) \
-static GSList *dev_list_##X(void) { return dev_list(X); }
-#define HW_DEV_CLEAR(X) \
-static int dev_clear_##X(void) { return dev_clear(X); }
-#define HW_DEV_ACQUISITION_START(X) \
-static int dev_acquisition_start_##X(const struct sr_dev_inst *sdi, \
-void *cb_data) { return dev_acquisition_start(sdi, cb_data, X); }
-
-/* Driver structs and API function wrappers */
-#define DRV(ID, ID_UPPER, NAME, LONGNAME) \
-HW_INIT(ID_UPPER) \
-HW_CLEANUP(ID_UPPER) \
-HW_SCAN(ID_UPPER) \
-HW_DEV_LIST(ID_UPPER) \
-HW_DEV_CLEAR(ID_UPPER) \
-HW_DEV_ACQUISITION_START(ID_UPPER) \
-SR_PRIV struct sr_dev_driver ID##_driver_info = { \
-       .name = NAME, \
-       .longname = LONGNAME, \
-       .api_version = 1, \
-       .init = init_##ID_UPPER, \
-       .cleanup = cleanup_##ID_UPPER, \
-       .scan = scan_##ID_UPPER, \
-       .dev_list = dev_list_##ID_UPPER, \
-       .dev_clear = dev_clear_##ID_UPPER, \
-       .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_##ID_UPPER, \
-       .dev_acquisition_stop = dev_acquisition_stop, \
-       .priv = NULL, \
-};
-
-DRV(mic_98581, MIC_98581, "mic-98581", "MIC 98581")
-DRV(mic_98583, MIC_98583, "mic-98583", "MIC 98583")
diff --git a/hardware/mic-985xx/protocol.c b/hardware/mic-985xx/protocol.c
deleted file mode 100644 (file)
index ce5f020..0000000
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include "protocol.h"
-
-static int mic_send(struct sr_serial_dev_inst *serial, const char *cmd)
-{
-       int ret;
-
-       if ((ret = serial_write(serial, cmd, strlen(cmd))) < 0) {
-               sr_err("Error sending '%s' command: %d.", cmd, ret);
-               return SR_ERR;
-       }
-
-       return SR_OK;
-}
-
-SR_PRIV int mic_cmd_get_device_info(struct sr_serial_dev_inst *serial)
-{
-       return mic_send(serial, "I\r");
-}
-
-static int mic_cmd_set_realtime_mode(struct sr_serial_dev_inst *serial)
-{
-       return mic_send(serial, "S 1 M 2 32 3\r");
-}
-
-SR_PRIV gboolean packet_valid_temp(const uint8_t *buf)
-{
-       if (buf[0] != 'v' || buf[1] != ' ' || buf[5] != '\r')
-               return FALSE;
-
-       if (!isdigit(buf[2]) || !isdigit(buf[3]) || !isdigit(buf[4]))
-               return FALSE;
-
-       return TRUE;
-}
-
-SR_PRIV gboolean packet_valid_temp_hum(const uint8_t *buf)
-{
-       if (buf[0] != 'v' || buf[1] != ' ' || buf[5] != ' ' || buf[9] != '\r')
-               return FALSE;
-
-       if (!isdigit(buf[2]) || !isdigit(buf[3]) || !isdigit(buf[4]))
-               return FALSE;
-
-       if (!isdigit(buf[6]) || !isdigit(buf[7]) || !isdigit(buf[8]))
-               return FALSE;
-
-       return TRUE;
-}
-
-static int packet_parse(const char *buf, int idx, float *temp, float *humidity)
-{
-       char tmp[4];
-
-       /* Packet format MIC98581: "v ttt\r". */
-       /* Packet format MIC98583: "v ttt hhh\r". */
-
-       /* TODO: Sanity check on buf. For now we assume well-formed ASCII. */
-
-       tmp[3] = '\0';
-
-       strncpy((char *)&tmp, &buf[2], 3);
-       *temp = g_ascii_strtoull((const char *)&tmp, NULL, 10) / 10;
-
-       if (mic_devs[idx].has_humidity) {
-               strncpy((char *)&tmp, &buf[6], 3);
-               *humidity = g_ascii_strtoull((const char *)&tmp, NULL, 10) / 10;
-       }
-
-       return SR_OK;
-}
-
-static int handle_packet(const uint8_t *buf, struct sr_dev_inst *sdi, int idx)
-{
-       float temperature, humidity;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_analog analog;
-       struct dev_context *devc;
-       GSList *l;
-       int ret;
-
-       (void)idx;
-
-       devc = sdi->priv;
-
-       ret = packet_parse((const char *)buf, idx, &temperature, &humidity);
-       if (ret < 0) {
-               sr_err("Failed to parse packet.");
-               return SR_ERR;
-       }
-
-       /* Clear 'analog', otherwise it'll contain random garbage. */
-       memset(&analog, 0, sizeof(struct sr_datafeed_analog));
-
-       /* Common values for both channels. */
-       packet.type = SR_DF_ANALOG;
-       packet.payload = &analog;
-       analog.num_samples = 1;
-
-       /* Temperature. */
-       l = g_slist_copy(sdi->channels);
-       l = g_slist_remove_link(l, g_slist_nth(l, 1));
-       analog.channels = l;
-       analog.mq = SR_MQ_TEMPERATURE;
-       analog.unit = SR_UNIT_CELSIUS; /* TODO: Use C/F correctly. */
-       analog.data = &temperature;
-       sr_session_send(devc->cb_data, &packet);
-       g_slist_free(l);
-
-       /* Humidity. */
-       if (mic_devs[idx].has_humidity) {
-               l = g_slist_copy(sdi->channels);
-               l = g_slist_remove_link(l, g_slist_nth(l, 0));
-               analog.channels = l;
-               analog.mq = SR_MQ_RELATIVE_HUMIDITY;
-               analog.unit = SR_UNIT_PERCENTAGE;
-               analog.data = &humidity;
-               sr_session_send(devc->cb_data, &packet);
-               g_slist_free(l);
-       }
-
-       devc->num_samples++;
-
-       return SR_OK;
-}
-
-static void handle_new_data(struct sr_dev_inst *sdi, int idx)
-{
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-       int len, i, offset = 0;
-
-       devc = sdi->priv;
-       serial = sdi->conn;
-
-       /* Try to get as much data as the buffer can hold. */
-       len = SERIAL_BUFSIZE - devc->buflen;
-       len = serial_read(serial, devc->buf + devc->buflen, len);
-       if (len < 1) {
-               sr_err("Serial port read error: %d.", len);
-               return;
-       }
-
-       devc->buflen += len;
-
-       /* Now look for packets in that data. */
-       while ((devc->buflen - offset) >= mic_devs[idx].packet_size) {
-               if (mic_devs[idx].packet_valid(devc->buf + offset)) {
-                       handle_packet(devc->buf + offset, sdi, idx);
-                       offset += mic_devs[idx].packet_size;
-               } else {
-                       offset++;
-               }
-       }
-
-       /* If we have any data left, move it to the beginning of our buffer. */
-       for (i = 0; i < devc->buflen - offset; i++)
-               devc->buf[i] = devc->buf[offset + i];
-       devc->buflen -= offset;
-}
-
-static int receive_data(int fd, int revents, int idx, void *cb_data)
-{
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-       int64_t t;
-       static gboolean first_time = TRUE;
-       struct sr_serial_dev_inst *serial;
-
-       (void)fd;
-
-       if (!(sdi = cb_data))
-               return TRUE;
-
-       if (!(devc = sdi->priv))
-               return TRUE;
-
-       serial = sdi->conn;
-
-       if (revents == G_IO_IN) {
-               /* New data arrived. */
-               handle_new_data(sdi, idx);
-       } else {
-               /* Timeout. */
-               if (first_time) {
-                       mic_cmd_set_realtime_mode(serial);
-                       first_time = FALSE;
-               }
-       }
-
-       if (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
-               sr_info("Requested number of samples reached.");
-               sdi->driver->dev_acquisition_stop(sdi, cb_data);
-               return TRUE;
-       }
-
-       if (devc->limit_msec) {
-               t = (g_get_monotonic_time() - devc->starttime) / 1000;
-               if (t > (int64_t)devc->limit_msec) {
-                       sr_info("Requested time limit reached.");
-                       sdi->driver->dev_acquisition_stop(sdi, cb_data);
-                       return TRUE;
-               }
-       }
-
-       return TRUE;
-}
-
-#define RECEIVE_DATA(ID_UPPER) \
-SR_PRIV int receive_data_##ID_UPPER(int fd, int revents, void *cb_data) { \
-       return receive_data(fd, revents, ID_UPPER, cb_data); }
-
-/* Driver-specific receive_data() wrappers */
-RECEIVE_DATA(MIC_98581)
-RECEIVE_DATA(MIC_98583)
diff --git a/hardware/mic-985xx/protocol.h b/hardware/mic-985xx/protocol.h
deleted file mode 100644 (file)
index 279cca5..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#ifndef LIBSIGROK_HARDWARE_MIC_985XX_PROTOCOL_H
-#define LIBSIGROK_HARDWARE_MIC_985XX_PROTOCOL_H
-
-#include <stdint.h>
-#include <string.h>
-#include <ctype.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "mic-985xx"
-
-/* Note: When adding entries here, don't forget to update MIC_DEV_COUNT. */
-enum {
-       MIC_98581,
-       MIC_98583,
-};
-
-#define MIC_DEV_COUNT 2
-
-struct mic_dev_info {
-       char *vendor;
-       char *device;
-       char *conn;
-       uint32_t max_sample_points;
-       gboolean has_temperature;
-       gboolean has_humidity;
-       uint8_t packet_size;
-       gboolean (*packet_valid)(const uint8_t *);
-       struct sr_dev_driver *di;
-       int (*receive_data)(int, int, void *);
-};
-
-extern SR_PRIV const struct mic_dev_info mic_devs[MIC_DEV_COUNT];
-
-#define SERIAL_BUFSIZE 256
-
-/** Private, per-device-instance driver context. */
-struct dev_context {
-       /** The current sampling limit (in number of samples). */
-       uint64_t limit_samples;
-
-       /** The current sampling limit (in ms). */
-       uint64_t limit_msec;
-
-       /** Opaque pointer passed in by the frontend. */
-       void *cb_data;
-
-       /** The current number of already received samples. */
-       uint64_t num_samples;
-
-       int64_t starttime;
-
-       uint8_t buf[SERIAL_BUFSIZE];
-       int bufoffset;
-       int buflen;
-};
-
-SR_PRIV gboolean packet_valid_temp(const uint8_t *buf);
-SR_PRIV gboolean packet_valid_temp_hum(const uint8_t *buf);
-
-SR_PRIV int receive_data_MIC_98581(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_MIC_98583(int fd, int revents, void *cb_data);
-
-SR_PRIV int mic_cmd_get_device_info(struct sr_serial_dev_inst *serial);
-
-#endif
diff --git a/hardware/motech-lps-30x/api.c b/hardware/motech-lps-30x/api.c
deleted file mode 100644 (file)
index 164a9cc..0000000
+++ /dev/null
@@ -1,860 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2014 Matthias Heidbrink <m-sigrok@heidbrink.biz>
- * Copyright (C) 2014 Bert Vermeulen <bert@biot.com> (code from atten-pps3xxx)
- *
- * 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
- *  <em>Motech LPS-30x series</em> power supply driver
- *  @internal
- */
-
-#include <ctype.h>
-#include <errno.h>
-#include <math.h>
-#include <string.h>
-
-#include "protocol.h"
-
-/* Forward declarations */
-SR_PRIV struct sr_dev_driver motech_lps_301_driver_info;
-SR_PRIV int lps_read_reply(struct sr_serial_dev_inst *serial, char **buf, int *buflen);
-SR_PRIV int lps_send_va(struct sr_serial_dev_inst *serial, const char* fmt, va_list args);
-SR_PRIV int lps_cmd_ok(struct sr_serial_dev_inst *serial, const char* fmt, ...);
-SR_PRIV int lps_cmd_reply(char* reply, struct sr_serial_dev_inst *serial, const char* fmt, ...);
-SR_PRIV int lps_query_status(struct sr_dev_inst* sdi);
-
-/* Serial communication parameters */
-#define SERIALCOMM "2400/8n1/dtr=1/rts=1/flow=0"
-
-#define VENDOR_MOTECH "Motech"
-
-/** Driver scanning options. */
-static const int32_t hwopts[] = {
-       SR_CONF_CONN,
-       SR_CONF_SERIALCOMM,
-};
-
-/** Hardware capabilities generic. */
-static const int32_t hwcaps[] = {
-       /* Device class */
-       SR_CONF_POWER_SUPPLY,
-       /* Aquisition modes. */
-       SR_CONF_LIMIT_SAMPLES,
-       SR_CONF_LIMIT_MSEC,
-       SR_CONF_CONTINUOUS,
-       /* Device configuration */
-       SR_CONF_OUTPUT_CHANNEL,
-};
-
-/** Hardware capabilities channel 1, 2. */
-static const int32_t hwcaps_ch12[] = {
-       SR_CONF_OUTPUT_VOLTAGE,
-       SR_CONF_OUTPUT_VOLTAGE_MAX,
-       SR_CONF_OUTPUT_CURRENT,
-       SR_CONF_OUTPUT_CURRENT_MAX,
-       SR_CONF_OUTPUT_ENABLED,
-};
-
-/** Hardware capabilities channel 3. (LPS-304/305 only). */
-static const int32_t hwcaps_ch3[] = {
-       SR_CONF_OUTPUT_VOLTAGE,
-       SR_CONF_OUTPUT_ENABLED,
-};
-
-static const char *channel_modes[] = {
-       "Independent",
-       "Track1",
-       "Track2",
-};
-
-static struct lps_modelspec models[] = {
-       { LPS_UNKNOWN, "Dummy", 0,
-               {
-
-               }
-       },
-       { LPS_301, "LPS-301", 1,
-               {
-                       /* Channel 1 */
-                       { { 0, 32, 0.01 }, { 0.005, 2, 0.001 } },
-               },
-       },
-       { LPS_302, "LPS-302", 1,
-               {
-                       /* Channel 1 */
-                       { { 0, 32, 0.01 }, { 0.005, 3, 0.001 } },
-               },
-       },
-       { LPS_303, "LPS-303", 1,
-               {
-                       /* Channel 1 */
-                       { { 0, 32, 0.01 }, { 0.005, 3, 0.001 } },
-               },
-       },
-       { LPS_304, "LPS-304", 3,
-               {
-                       /* Channel 1 */
-                       { { 0, 32, 0.01 }, { 0.005, 3, 0.001 } },
-                       /* Channel 2 */
-                       { { 0, 32, 0.01 }, { 0.005, 3, 0.001 } },
-                       /* Channel 3 */
-                       { { 5, 5, 0.0 }, { 0.005, 3, 0.001 } },
-               },
-       },
-       { LPS_305, "LPS-305", 3,
-               {
-                       /* Channel 1 */
-                       { { 0, 32, 0.01 }, { 0.005, 3, 0.001 } },
-                       /* Channel 2 */
-                       { { 0, 32, 0.01 }, { 0.005, 3, 0.001 } },
-                       /* Channel 3 */
-                       { { 3.3, 5, 1.7 }, { 0.005, 3, 0.001 } },
-               },
-       },
-};
-
-static int init_lps301(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, &motech_lps_301_driver_info, LOG_PREFIX);
-}
-
-/** Send command to device with va_list.
- */
-SR_PRIV int lps_send_va(struct sr_serial_dev_inst *serial, const char* fmt, va_list args)
-{
-       int retc;
-       char auxfmt[LINELEN_MAX];
-       char buf[LINELEN_MAX];
-
-       snprintf(auxfmt, sizeof(auxfmt), "%s\r\n", fmt);
-       vsnprintf(buf, sizeof(buf), auxfmt, args);
-
-       sr_spew("lps_send_va: \"%s\"", buf);
-
-       retc = serial_write_nonblocking(serial, buf, strlen(buf));
-
-       if (retc < 0)
-               return SR_ERR;
-
-       return SR_OK;
-}
-
-/** Send command to device.
- */
-SR_PRIV int lps_send_req(struct sr_serial_dev_inst *serial, const char* fmt, ...)
-{
-       int retc;
-       va_list args;
-
-       va_start(args, fmt);
-       retc = lps_send_va(serial, fmt, args);
-       va_end(args);
-
-       return retc;
-}
-
-/** Send command and consume simple OK reply. */
-SR_PRIV int lps_cmd_ok(struct sr_serial_dev_inst *serial, const char* fmt, ...)
-{
-       int retc;
-       va_list args;
-       char buf[LINELEN_MAX];
-       char* bufptr;
-       int  buflen;
-
-       /* Send command */
-       va_start(args, fmt);
-       retc = lps_send_va(serial, fmt, args);
-       va_end(args);
-
-       if (retc != SR_OK)
-               return SR_ERR;
-
-       /* Read reply */
-       buf[0] = '\0';
-       bufptr = buf;
-       buflen = sizeof(buf);
-       retc = lps_read_reply(serial, &bufptr, &buflen);
-       if ((retc == SR_OK) && (buflen == 0))
-               return SR_OK;
-
-       return SR_ERR;
-}
-
-/** Send command and read reply string.
- *  \param reply Pointer to buffer of size LINELEN_MAX. Will be NUL-terminated.
- */
-SR_PRIV int lps_cmd_reply(char* reply, struct sr_serial_dev_inst *serial, const char* fmt, ...)
-{
-       int retc;
-       va_list args;
-       char buf[LINELEN_MAX];
-       char* bufptr;
-       int  buflen;
-
-       reply[0] = '\0';
-
-       /* Send command */
-       va_start(args, fmt);
-       retc = lps_send_va(serial, fmt, args);
-       va_end(args);
-
-       if (retc != SR_OK)
-               return SR_ERR;
-
-       /* Read reply */
-       buf[0] = '\0';
-       bufptr = buf;
-       buflen = sizeof(buf);
-       retc = lps_read_reply(serial, &bufptr, &buflen);
-       if ((retc == SR_OK) && (buflen > 0)) {
-               strcpy(reply, buf);
-               return SR_OK;
-       }
-
-       return SR_ERR;
-}
-
-/** Process integer value returned by STATUS command. */
-SR_PRIV int lps_process_status(struct sr_dev_inst* sdi, int stat)
-{
-       struct dev_context* devc;
-       int tracking_mode;
-
-       devc = (struct dev_context*)sdi->priv;
-
-       sr_spew("Status: %d", stat);
-       devc->channel_status[0].cc_mode = (stat & 0x01) != 0;
-       sr_spew("Channel 1 %s mode", devc->channel_status[0].cc_mode?"CC":"CV");
-       if (devc->model->num_channels > 1) {
-               devc->channel_status[1].cc_mode = (stat & 0x02) != 0;
-               sr_spew("Channel 2 %s mode", devc->channel_status[1].cc_mode?"CC":"CV");
-
-               tracking_mode = (stat & 0x0c) >> 2;
-               switch (tracking_mode) {
-               case 0: devc->tracking_mode = 0;
-                       break;
-               case 2: devc->tracking_mode = 1;
-                       break;
-               case 3: devc->tracking_mode = 2;
-                       break;
-               default:
-                       sr_err("Illegal channel tracking mode %d!", tracking_mode);
-                       devc->tracking_mode = 0;
-                       break;
-               }
-
-               sr_spew("Channel tracking: %d", devc->tracking_mode);
-       }
-       devc->channel_status[0].output_enabled = devc->channel_status[1].output_enabled = stat&0x040?TRUE:FALSE;
-       sr_spew("Channel 1%s output: %s", devc->model->num_channels > 1?"+2":"", devc->channel_status[0].output_enabled?"ON":"OFF");
-       if (devc->model->num_channels > 2) {
-               devc->channel_status[2].output_enabled = stat&0x010?TRUE:FALSE;
-               devc->channel_status[2].output_voltage_last = stat&0x020?3.3:5;
-               sr_spew("Channel 3 output: %s, U=%02f V, overload=%d",
-                       devc->channel_status[2].output_enabled?"ON":"OFF",
-                       devc->channel_status[2].output_voltage_last,
-                       stat&0x080?1:0);
-       }
-       sr_spew("Fan=%d, beep=%d, CC output compensated=%d", stat&0x0100?1:0, stat&0x0200?1:0, stat&0x0400?1:0);
-
-       return SR_OK;
-}
-
-/** Send STATUS commend and process status string. */
-SR_PRIV int lps_query_status(struct sr_dev_inst* sdi)
-{
-       char buf[LINELEN_MAX];
-       int stat;
-       struct dev_context* devc;
-
-       devc = (struct dev_context*)sdi->priv;
-
-       devc->req_sent_at = g_get_real_time();
-
-       if (lps_cmd_reply(buf, sdi->conn, "STATUS") < 0) {
-               sr_err("%s: Failed to read status: %d %s", __func__, errno, strerror(errno));
-               return SR_ERR;
-       }
-
-       if (sr_atoi(buf, &stat) != SR_OK)
-               return SR_ERR;
-
-       return lps_process_status(sdi, stat);
-}
-
-static gint64 calc_timeout_ms(gint64 start_us)
-{
-       gint64 result = REQ_TIMEOUT_MS - ((g_get_real_time() - start_us) / 1000);
-
-       if (result < 0)
-               return 0;
-
-       return result;
-}
-
-/** Read message into buf until "OK" received.
- *  \retval SR_OK Msg received; buf and buflen contain result, if any except OK.
- *  \retval SR_ERR Error, including timeout.
-*/
-SR_PRIV int lps_read_reply(struct sr_serial_dev_inst *serial, char **buf, int *buflen)
-{
-       int retries;
-       char buf2[LINELEN_MAX];
-       char *buf2ptr;
-       int buf2len;
-       gint64 timeout_start;
-
-       *buf[0] = '\0';
-
-       /* Read one line. It is either a data message or "OK". */
-       timeout_start = g_get_real_time();
-       buf2len = *buflen;
-       /* Up to 5 tries because serial_readline() will consume only one CR or LF per
-        * call, but device sends up to 4 in a row. */
-       for (retries = 0; retries < 5; retries++) {
-               *buflen = buf2len;
-               if (serial_readline(serial, buf, buflen, calc_timeout_ms(timeout_start)) != SR_OK)
-                       return SR_ERR;
-               if (!strcmp(*buf, "OK")) { /* We got an OK! */
-                       *buf[0] = '\0';
-                       *buflen = 0;
-                       return SR_OK;
-               }
-               if (*buflen > 0) /* We got a msg! */
-                       break;
-       }
-
-       /* A data msg is in buf (possibly ERROR), need to consume "OK". */
-       buf2[0] = '\0';
-       buf2ptr = buf2;
-       for (retries = 0; retries < 5; retries++) {
-               buf2len = sizeof(buf2);
-               if (serial_readline(serial, &buf2ptr, &buf2len, calc_timeout_ms(timeout_start)) != SR_OK)
-                       return SR_ERR;
-
-               if (!strcmp(buf2ptr, "OK")) { /* We got an OK! */
-                       if (!strcmp(*buf, "ERROR")) { /* OK came after msg ERROR! */
-                               sr_spew("ERROR found!");
-                               *buf[0] = '\0';
-                               *buflen = 0;
-                               return SR_ERR;
-                       }
-                       return SR_OK;
-               }
-       }
-
-       return SR_ERR; /* Timeout! */
-}
-
-/** Scan for LPS-300 series device.
- */
-static GSList *do_scan(lps_modelid modelid, struct sr_dev_driver *drv, GSList *options)
-{
-       struct sr_dev_inst *sdi;
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-       struct sr_channel *ch;
-       struct sr_channel_group *cg;
-       GSList *devices;
-       const char *conn, *serialcomm;
-       int cnt;
-       gchar  buf[LINELEN_MAX];
-       gchar channel[10];
-       char*  verstr;
-
-       sdi = NULL;
-       devc = NULL;
-       conn = serialcomm = NULL;
-       devices = NULL;
-
-       drvc = drv->priv;
-       drvc->instances = NULL;
-
-       sr_spew("scan() called!");
-
-       /* Process and check options. */
-       if (sr_serial_extract_options(options, &conn, &serialcomm) != SR_OK)
-               return NULL;
-       if (!serialcomm)
-               serialcomm = SERIALCOMM;
-
-       /* Init serial port. */
-       if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
-               return NULL;
-
-       if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
-               goto exit_err;
-
-       /* Query and verify model string. */
-       serial_flush(serial);
-       if (lps_cmd_reply(buf, serial, "MODEL") != SR_OK)
-               return NULL;
-
-       /* Check model string. */
-       if (strncmp(buf, "LPS-", 4)) {
-               sr_spew("Unknown model code \"%s\"!", buf);
-               return NULL;
-       }
-
-       /* Bug in device FW 1.17, model number is empty, so this can't work with this FW! */
-       if (modelid == LPS_UNKNOWN) {
-               g_strstrip(buf);
-               for (cnt = LPS_301; cnt <= LPS_305; cnt++) {
-                       if (!strcmp(buf, models[cnt].modelstr)) {
-                               modelid = cnt;
-                               break;
-                       }
-               }
-               if (modelid == LPS_UNKNOWN) {
-                       sr_err("Unable to detect model from model string '%s'!", buf);
-                       return NULL;
-               }
-       }
-
-       /* Query version */
-       verstr = NULL;
-       if (lps_cmd_reply(buf, serial, "VERSION") == SR_OK) {
-               if (strncmp(buf, "Ver-", 4)) {
-                       sr_spew("Version string %s not recognized.", buf);
-                       goto exit_err;
-               }
-
-
-               g_strstrip(buf);
-               verstr = buf + 4;
-       }
-       else  /* Bug in device FW 1.17: Quering version string fails while output is active.
-               Therefore just print an error message, but do not exit with error. */
-               sr_err("Failed to query for hardware version: %d %s", errno, strerror(errno));
-
-       sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, VENDOR_MOTECH, models[modelid].modelstr, verstr);
-       sdi->driver = drv;
-       sdi->inst_type = SR_INST_SERIAL;
-       sdi->conn = serial;
-
-       devc = g_malloc0(sizeof(struct dev_context));
-       devc->model = &models[modelid];
-       devc->limit_samples = 0;
-       devc->limit_msec = 0;
-       devc->num_samples = 0;
-       devc->elapsed_msec = g_timer_new();
-
-       sdi->priv = devc;
-
-       /* Setup channels and channel groups. */
-       for (cnt = 0; cnt < models[modelid].num_channels; cnt++) {
-               snprintf(channel, sizeof(channel), "CH%d", cnt + 1);
-               ch = sr_channel_new(cnt, SR_CHANNEL_ANALOG, TRUE, channel);
-               sdi->channels = g_slist_append(sdi->channels, ch);
-
-               devc->channel_status[cnt].info = g_slist_append(NULL, ch);
-
-               cg = g_malloc(sizeof(struct sr_channel_group));
-               snprintf(channel, sizeof(channel), "CG%d", cnt+1);
-               cg->name = g_strdup(channel);
-               cg->priv = NULL;
-               cg->channels = g_slist_append(NULL, ch);
-
-               sdi->channel_groups = g_slist_append(sdi->channel_groups, cg);
-       }
-
-       drvc->instances = g_slist_append(drvc->instances, sdi);
-       devices = g_slist_append(devices, sdi);
-
-       /* Query status */
-       if (lps_query_status(sdi) != SR_OK)
-               goto exit_err;
-
-       serial_close(serial);
-       if (!devices)
-               sr_serial_dev_inst_free(serial);
-
-       return devices;
-
-exit_err:
-       sr_info("%s: Error!", __func__);
-
-       if (serial) {
-               serial_close(serial);
-               sr_serial_dev_inst_free(serial);
-       }
-       if (devc)
-               g_free(devc);
-       if (sdi)
-               sr_dev_inst_free(sdi);
-
-       return NULL;
-}
-
-/** Scan for LPS-301 device. */
-static GSList *scan_lps301(GSList *options)
-{
-       return do_scan(LPS_301, &motech_lps_301_driver_info, options);
-}
-
-static GSList *doDevList(struct sr_dev_driver *drv)
-{
-       return ((struct drv_context *)(drv->priv))->instances;
-}
-
-static GSList *dev_list_lps301(void)
-{
-       return doDevList(&motech_lps_301_driver_info);
-}
-
-static void dev_clear_private(struct dev_context* devc)
-{
-       int ch_idx;
-
-       /* Free channel_status.info (list only, data owned by sdi). */
-       for (ch_idx = 0; ch_idx < devc->model->num_channels; ch_idx++)
-               g_slist_free(devc->channel_status[ch_idx].info);
-
-       g_timer_destroy(devc->elapsed_msec);
-}
-
-static int dev_clear_lps301(void)
-{
-       return std_dev_clear(&motech_lps_301_driver_info, (std_dev_clear_callback)dev_clear_private);
-}
-
-static int cleanup(void)
-{
-       return dev_clear_lps301();
-}
-
-static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       struct sr_channel *ch;
-       int ch_idx;
-
-       if (!sdi)
-               return SR_ERR_ARG;
-
-       devc = sdi->priv;
-
-       if (!cg) {
-               /* No channel group: global options. */
-               switch (key) {
-               case SR_CONF_LIMIT_SAMPLES:
-                       *data = g_variant_new_uint64(devc->limit_samples);
-                       break;
-               case SR_CONF_LIMIT_MSEC:
-                       *data = g_variant_new_uint64(devc->limit_msec);
-                       break;
-               case SR_CONF_OUTPUT_CHANNEL:
-                       *data = g_variant_new_string(channel_modes[devc->tracking_mode]);
-                       break;
-               default:
-                       return SR_ERR_NA;
-               }
-       } else {
-               /* We only ever have one channel per channel group in this driver. */
-               ch = cg->channels->data;
-               ch_idx = ch->index;
-               switch (key) {
-               case SR_CONF_OUTPUT_VOLTAGE:
-                       *data = g_variant_new_double(devc->channel_status[ch_idx].output_voltage_last);
-                       break;
-               case SR_CONF_OUTPUT_VOLTAGE_MAX:
-                       *data = g_variant_new_double(devc->channel_status[ch_idx].output_voltage_max);
-                       break;
-               case SR_CONF_OUTPUT_CURRENT:
-                       *data = g_variant_new_double(devc->channel_status[ch_idx].output_current_last);
-                       break;
-               case SR_CONF_OUTPUT_CURRENT_MAX:
-                       *data = g_variant_new_double(devc->channel_status[ch_idx].output_current_max);
-                       break;
-               case SR_CONF_OUTPUT_ENABLED:
-                       *data = g_variant_new_boolean(devc->channel_status[ch_idx].output_enabled);
-                       break;
-               default:
-                       return SR_ERR_NA;
-               }
-       }
-
-       return SR_OK;
-}
-
-static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       struct sr_channel *ch;
-       gdouble dval;
-       int ch_idx;
-       const char *sval;
-       gboolean bval;
-       int idx;
-       gboolean found;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       devc = sdi->priv;
-
-       /* Cannot change settings while acquisition active, would cause a mess with commands.
-        * Changing this would be possible, but tricky. */
-       if (devc->acq_running)
-               return SR_ERR_NA;
-
-       if (!cg) {
-               /* No channel group: global options. */
-               switch (key) {
-               case SR_CONF_LIMIT_MSEC:
-                       if (g_variant_get_uint64(data) == 0) {
-                               sr_err("LIMIT_MSEC can't be 0.");
-                               return SR_ERR;
-                       }
-                       devc->limit_msec = g_variant_get_uint64(data);
-                       sr_dbg("Setting time limit to %" PRIu64 "ms.",
-                               devc->limit_msec);
-                       break;
-               case SR_CONF_LIMIT_SAMPLES:
-                       devc->limit_samples = g_variant_get_uint64(data);
-                       sr_dbg("Setting sample limit to %" PRIu64 ".",
-                               devc->limit_samples);
-                       break;
-               case SR_CONF_OUTPUT_CHANNEL:
-                       sval = g_variant_get_string(data, NULL);
-                       found = FALSE;
-                       for (idx = 0; idx < (int)ARRAY_SIZE(channel_modes); idx++)
-                       {
-                               if (!strcmp(sval, channel_modes[idx])) {
-                                       found = TRUE;
-                                       if (devc->tracking_mode == idx)
-                                               break;  /* Nothing to do! */
-                                       devc->tracking_mode = idx;
-                                       if (devc->model->modelid >= LPS_304) /* No use to set anything in the smaller models. */
-                                               return lps_cmd_ok(sdi->conn, "TRACK%1d", devc->tracking_mode);
-                               }
-                               if (devc->model->modelid <= LPS_303) /* Only first setting possible for smaller models. */
-                                       break;
-                       }
-                       if (!found) {
-                               return SR_ERR_ARG;
-                       }
-                       break;
-               default:
-                       return SR_ERR_NA;
-               }
-       } else {
-               /* Channel group specified: per-channel options. */
-               /* We only ever have one channel per channel group in this driver. */
-               ch = cg->channels->data;
-               ch_idx = ch->index;
-
-               switch (key) {
-               case SR_CONF_OUTPUT_VOLTAGE_MAX:
-                       dval = g_variant_get_double(data);
-                       if (dval < 0 || dval > devc->model->channels[ch_idx].voltage[1])
-                               return SR_ERR_ARG;
-                       if (ch_idx == 2) {
-                               if (devc->model->modelid < LPS_304)
-                                       return SR_ERR_ARG;
-
-                               if (fabs(dval - 5.000) <= 0.001)
-                                       dval = 5.0;
-                               else if ((devc->model->modelid >= LPS_305) && (fabs(dval - 3.300) <= 0.001))
-                                       dval = 3.3;
-                               else return SR_ERR_ARG;
-                       }
-
-                       devc->channel_status[ch_idx].output_voltage_max = dval;
-                       if (ch_idx == 2)
-                               return lps_cmd_ok(sdi->conn, "VDD%1.0f", trunc(dval));
-                       else
-                               return lps_cmd_ok(sdi->conn, "VSET%d %05.3f", ch_idx+1, dval);
-                       break;
-               case SR_CONF_OUTPUT_CURRENT_MAX:
-                       dval = g_variant_get_double(data);
-                       if (dval < 0 || dval > devc->model->channels[ch_idx].current[1])
-                               return SR_ERR_ARG;
-                       if (ch_idx == 2) /* No current setting for CH3. */
-                               return SR_ERR_NA;
-                       devc->channel_status[ch_idx].output_current_max = dval;
-                       return lps_cmd_ok(sdi->conn, "ISET%d %05.4f", ch_idx+1, dval);
-                       break;
-               case SR_CONF_OUTPUT_ENABLED:
-                       bval = g_variant_get_boolean(data);
-                       if (bval == devc->channel_status[ch_idx].output_enabled) /* Nothing to do. */
-                               break;
-                       devc->channel_status[ch_idx].output_enabled = bval;
-                       if (ch_idx != 2) { /* Channels 1,2 can be set only together. */
-                               devc->channel_status[ch_idx^1].output_enabled = bval;
-                               return lps_cmd_ok(sdi->conn, "OUT%1d", (int)bval);
-                       } else { /* Channel 3: No command to disable output, set voltage to 0 instead. */
-                               if (bval)
-                                       return lps_cmd_ok(sdi->conn, "VDD%1.0f", devc->channel_status[ch_idx].output_voltage_max);
-                               else
-                                       return lps_cmd_ok(sdi->conn, "VDD0");
-                       }
-                       break;
-               default:
-                       return SR_ERR_NA;
-               }
-       }
-
-       return SR_OK;
-}
-
-static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       struct sr_channel *ch;
-       int ch_idx, i;
-       GVariant *gvar;
-       GVariantBuilder gvb;
-
-       (void)data;
-
-       /* Driver options, no device instance necessary. */
-       switch (key) {
-       case SR_CONF_SCAN_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                                                 hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
-               return SR_OK;
-       default:
-               if (sdi == NULL)
-                       return SR_ERR_ARG;
-
-               devc = sdi->priv;
-       }
-
-       /* Device options, independant from channel groups. */
-       if (cg == NULL) {
-               switch (key) {
-               case SR_CONF_DEVICE_OPTIONS:
-                       *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                                                         hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
-                       return SR_OK;
-               case SR_CONF_OUTPUT_CHANNEL:
-                       if (devc->model->modelid <= LPS_303) {
-                               /* The 1-channel models. */
-                               *data = g_variant_new_strv(channel_modes, 1);
-                       } else {
-                               /* The other models support all modes. */
-                               *data = g_variant_new_strv(channel_modes, ARRAY_SIZE(channel_modes));
-                       }
-                       return SR_OK;
-                       break;
-               default:
-                       return SR_ERR_NA;
-               }
-       }
-
-       /* Device options, depending on channel groups. */
-       ch = cg->channels->data;
-       ch_idx = ch->index;
-       switch (key) {
-       case SR_CONF_DEVICE_OPTIONS:
-               if ((ch_idx == 0) || (ch_idx == 1)) /* CH1, CH2 */
-                       *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                                 hwcaps_ch12, ARRAY_SIZE(hwcaps_ch12), sizeof(int32_t));
-               else /* Must be CH3 */
-                       *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                                 hwcaps_ch3, ARRAY_SIZE(hwcaps_ch3), sizeof(int32_t));
-               break;
-       case SR_CONF_OUTPUT_VOLTAGE_MAX:
-               g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
-               /* Min, max, step. */
-               for (i = 0; i < 3; i++) {
-                       gvar = g_variant_new_double(devc->model->channels[ch_idx].voltage[i]);
-                       g_variant_builder_add_value(&gvb, gvar);
-               }
-               *data = g_variant_builder_end(&gvb);
-               break;
-       case SR_CONF_OUTPUT_CURRENT_MAX:
-               g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
-               /* Min, max, step. */
-               for (i = 0; i < 3; i++) {
-                       gvar = g_variant_new_double(devc->model->channels[ch_idx].current[i]);
-                       g_variant_builder_add_value(&gvb, gvar);
-               }
-               *data = g_variant_builder_end(&gvb);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi,
-                                   void *cb_data)
-{
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       devc = sdi->priv;
-
-       devc->acq_running = TRUE;
-
-       serial = sdi->conn;
-       serial_source_add(sdi->session, serial, G_IO_IN, 50,
-                       motech_lps_30x_receive_data, (void *)sdi);
-       std_session_send_df_header(cb_data, LOG_PREFIX);
-
-       /* Start timer, if required. */
-       if (devc->limit_msec)
-               g_timer_start(devc->elapsed_msec);
-
-       devc->acq_req = AQ_NONE;
-       /* Do not start polling device here, the read function will do it in 50 ms. */
-
-       return SR_OK;
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct dev_context *devc;
-
-       /* Stop timer, if required. */
-       if (sdi && (devc = sdi->priv) && devc->limit_msec)
-               g_timer_stop(devc->elapsed_msec);
-
-       return std_serial_dev_acquisition_stop(sdi, cb_data, std_serial_dev_close,
-                       sdi->conn, LOG_PREFIX);
-}
-
-SR_PRIV struct sr_dev_driver motech_lps_301_driver_info = {
-       .name = "motech-lps-301",
-       .longname = "Motech LPS-301",
-       .api_version = 1,
-       .init = init_lps301,
-       .cleanup = cleanup,
-       .scan = scan_lps301,
-       .dev_list = dev_list_lps301,
-       .dev_clear = dev_clear_lps301,
-       .config_get = config_get,
-       .config_set = config_set,
-       .config_list = config_list,
-       .dev_open = std_serial_dev_open,
-       .dev_close = std_serial_dev_close,
-       .dev_acquisition_start = dev_acquisition_start,
-       .dev_acquisition_stop = dev_acquisition_stop,
-       .priv = NULL,
-};
diff --git a/hardware/motech-lps-30x/protocol.c b/hardware/motech-lps-30x/protocol.c
deleted file mode 100644 (file)
index c4afd65..0000000
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2014 Matthias Heidbrink <m-sigrok@heidbrink.biz>
- * Copyright (C) 2014 Bert Vermeulen <bert@biot.com> (code from atten-pps3xxx)
- *
- * 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
- *  <em>Motech LPS-30x series</em> power supply driver
- *  @internal
- */
-
-#include <errno.h>
-#include <string.h>
-
-#include "protocol.h"
-
-/** Send data packets for current measurements. */
-static void send_data(struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_analog analog;
-       int i;
-       float data[MAX_CHANNELS];
-
-       devc = sdi->priv;
-       packet.type = SR_DF_ANALOG;
-       packet.payload = &analog;
-       analog.channels = sdi->channels;
-       analog.num_samples = 1;
-
-       analog.mq = SR_MQ_VOLTAGE;
-       analog.unit = SR_UNIT_VOLT;
-       analog.mqflags = SR_MQFLAG_DC;
-       analog.data = data;
-       for (i = 0; i < devc->model->num_channels; i++)
-               analog.data[i] = devc->channel_status[i].output_voltage_last; /* Value always 3.3 or 5 for channel 3, if present! */
-       sr_session_send(sdi, &packet);
-
-       analog.mq = SR_MQ_CURRENT;
-       analog.unit = SR_UNIT_AMPERE;
-       analog.mqflags = 0;
-       analog.data = data;
-       for (i = 0; i < devc->model->num_channels; i++)
-               analog.data[i] = devc->channel_status[i].output_current_last; /* Value always 0 for channel 3, if present! */
-       sr_session_send(sdi, &packet);
-
-       devc->num_samples++;
-}
-
-/** Process a complete line (without CR/LF) in buf. */
-static void process_line(struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       double dbl;
-       int auxint;
-
-       devc = sdi->priv;
-
-       switch (devc->acq_req_pending) {
-       case 0: /* Should not happen... */
-               break;
-       case 1: /* Waiting for data reply to request */
-               /* Convert numbers */
-               switch (devc->acq_req) {
-               case AQ_U1:  case AQ_U2:  case AQ_I1:  case AQ_I2:
-                       if (sr_atod(devc->buf, &dbl) != SR_OK) {
-                               sr_err("Failed to convert '%s' to double, errno=%d %s",
-                                       devc->buf, errno, strerror(errno));
-                               dbl = 0.0;
-                       }
-                       break;
-               case AQ_STATUS:
-                       if (sr_atoi(devc->buf, &auxint) != SR_OK) {
-                               sr_err("Failed to convert '%s' to int, errno=%d %s",
-                                       devc->buf, errno, strerror(errno));
-                               auxint = 0;
-                       }
-                       break;
-               default:
-                       break;
-               }
-
-               switch (devc->acq_req) {
-               case AQ_U1:
-                       devc->channel_status[0].output_voltage_last = dbl;
-                       break;
-               case AQ_I1:
-                       devc->channel_status[0].output_current_last = dbl;
-                       break;
-               case AQ_U2:
-                       devc->channel_status[1].output_voltage_last = dbl;
-                       break;
-               case AQ_I2:
-                       devc->channel_status[1].output_current_last = dbl;
-                       break;
-               case AQ_STATUS: /* Process status and generate data. */
-                       if (lps_process_status(sdi, auxint) == SR_OK) {
-                               send_data(sdi);
-                       }
-                       break;
-               default:
-                       break;
-               }
-
-               devc->acq_req_pending = 2;
-               break;
-       case 2: /* Waiting for OK after request */
-               if (strcmp(devc->buf, "OK")) {
-                       sr_err("Unexpected reply while waiting for OK: '%s'", devc->buf);
-               }
-               devc->acq_req_pending = 0;
-               break;
-       }
-
-       devc->buf[0] = '\0';
-       devc->buflen = 0;
-}
-
-
-SR_PRIV int motech_lps_30x_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 len;
-       gdouble elapsed_s;
-
-       (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. */
-               while (LINELEN_MAX - devc->buflen - 2 > 0) {
-                       len = serial_read(serial, devc->buf + devc->buflen, 1);
-                       if (len < 1)
-                               break;
-
-                       /* Eliminate whitespace at beginning of line. */
-                       if (g_ascii_isspace(devc->buf[0])) {
-                               devc->buf[0] = '\0';
-                               devc->buflen = 0;
-                               continue;
-                       }
-
-                       devc->buflen += len;
-                       devc->buf[devc->buflen] = '\0';
-
-                       /* If line complete, process msg. */
-                       if ((devc->buflen > 0) && ((devc->buf[devc->buflen-1] == '\r') || devc->buf[devc->buflen-1] == '\n')) {
-                               devc->buflen--;
-                               devc->buf[devc->buflen] = '\0';
-
-                               sr_spew("Line complete: \"%s\"", devc->buf);
-                               process_line(sdi);
-                       }
-               }
-       }
-
-       /* If number of samples or time limit reached, stop acquisition. */
-       if (devc->limit_samples && (devc->num_samples >= devc->limit_samples))
-               sdi->driver->dev_acquisition_stop(sdi, cb_data);
-
-       if (devc->limit_msec) {
-               elapsed_s = g_timer_elapsed(devc->elapsed_msec, NULL);
-               if ((elapsed_s * 1000) >= devc->limit_msec)
-                       sdi->driver->dev_acquisition_stop(sdi, cb_data);
-       }
-
-       /* Request next packet, if required. */
-       if ((sdi->status == SR_ST_ACTIVE) && (devc->acq_running)){
-               if (devc->acq_req_pending) {
-                       gint64 elapsed_us = g_get_monotonic_time() - devc->req_sent_at;
-                       if (elapsed_us > (REQ_TIMEOUT_MS * 1000)) {
-                               sr_spew("Request timeout: req=%d t=%lldus", (int)devc->acq_req, elapsed_us);
-                               devc->acq_req_pending = 0;
-                       }
-               }
-               if (devc->acq_req_pending == 0) {
-                       switch(devc->acq_req)
-                       {
-                       case AQ_NONE: /* Fall through */
-                       case AQ_STATUS:
-                               devc->acq_req = AQ_U1;
-                               lps_send_req(serial, "VOUT1");
-                               break;
-                       case AQ_U1:
-                               devc->acq_req = AQ_I1;
-                               lps_send_req(serial, "IOUT1");
-                               break;
-                       case AQ_I1:
-                               if (devc->model->num_channels == 1) {
-                                       devc->acq_req = AQ_STATUS;
-                                       lps_send_req(serial, "STATUS");
-                               } else {
-                                       devc->acq_req = AQ_U2;
-                                       lps_send_req(serial, "VOUT2");
-                               }
-                               break;
-                       case AQ_U2:
-                               devc->acq_req = AQ_I2;
-                               lps_send_req(serial, "IOUT2");
-                               break;
-                       case AQ_I2:
-                               devc->acq_req = AQ_STATUS;
-                               lps_send_req(serial, "STATUS");
-                               break;
-                       default:
-                               sr_err("Illegal devc->acq_req=%d", devc->acq_req);
-                               return SR_ERR;
-                       }
-                       devc->req_sent_at = g_get_real_time();
-                       devc->acq_req_pending = 1;
-               }
-       }
-
-       return TRUE;
-}
diff --git a/hardware/motech-lps-30x/protocol.h b/hardware/motech-lps-30x/protocol.h
deleted file mode 100644 (file)
index 76f646d..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2014 Matthias Heidbrink <m-sigrok@heidbrink.biz>
- * Copyright (C) 2014 Bert Vermeulen <bert@biot.com> (code from atten-pps3xxx)
- *
- * 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
- *  <em>Motech LPS-30x series</em> power supply driver
- *  @internal
- */
-
-
-#ifndef LIBSIGROK_HARDWARE_MOTECH_LPS_30X_PROTOCOL_H
-#define LIBSIGROK_HARDWARE_MOTECH_LPS_30X_PROTOCOL_H
-
-#include <stdint.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-
-SR_PRIV int lps_process_status(struct sr_dev_inst* sdi, int stat);
-SR_PRIV int lps_send_req(struct sr_serial_dev_inst *serial, const char* fmt, ...);
-
-#define LOG_PREFIX "motech-lps-30x"
-
-#define LINELEN_MAX 50 /**< Max. line length for requests */
-
-#define REQ_TIMEOUT_MS 250 /**< Timeout [ms] for single request. */
-
-#define MAX_CHANNELS 3
-
-typedef enum {
-       LPS_UNKNOWN = 0,/**< Unknown model (used during detection process) */
-       LPS_301,        /**< Motech/Amrel LPS-301, 1 output */
-       LPS_302,        /**< Motech/Amrel LPS-302, 1 output */
-       LPS_303,        /**< Motech/Amrel LPS-303, 1 output */
-       LPS_304,        /**< Motech/Amrel LPS-304, 3 outputs */
-       LPS_305,        /**< Motech/Amrel LPS-305, 3 outputs */
-} lps_modelid;
-
-/** Channel specification */
-struct channel_spec {
-       /* Min, max, step. */
-       gdouble voltage[3];
-       gdouble current[3];
-};
-
-/** Model properties specification */
-struct lps_modelspec {
-       lps_modelid modelid;
-       const char* modelstr;
-       uint8_t num_channels;
-       struct channel_spec channels[3];
-};
-
-/** Used to implement a little state machine to query all required values in a row. */
-typedef enum {
-       AQ_NONE,
-       AQ_U1,
-       AQ_I1,
-       AQ_I2,
-       AQ_U2,
-       AQ_STATUS,
-} acquisition_req;
-
-/** Status of a single channel. */
-struct channel_status {
-       /* Channel information (struct channel_info*). data (struct) owned by sdi, just a reference to address a single channel. */
-       GSList* info;
-       /* Received from device. */
-       gdouble output_voltage_last;
-       gdouble output_current_last;
-       gboolean output_enabled;        /**< Also used when set. */
-       gboolean cc_mode;               /**< Constant current mode. If false, constant voltage mode. */
-       /* Set by frontend. */
-       gdouble output_voltage_max;
-       gdouble output_current_max;
-};
-
-/** Private, per-device-instance driver context. */
-struct dev_context {
-       /* Model-specific information */
-       struct lps_modelspec* model;
-
-       /* Acquisition status */
-       gboolean acq_running;           /**< Aquisition is running. */
-       uint64_t limit_samples;         /**< Target number of samples */
-       uint64_t limit_msec;            /**< Target sampling time */
-       acquisition_req acq_req;        /**< Current request. */
-       uint8_t acq_req_pending;        /**< Request pending. 0=none, 1=reply, 2=OK */
-
-       /* Operational state */
-       struct channel_status channel_status[MAX_CHANNELS];
-       guint8 tracking_mode;           /**< 0=off, 1=Tracking from CH1, 2=Tracking from CH2. */
-
-       /* Temporary state across callbacks */
-       int64_t req_sent_at;    /**< Request sent. */
-       uint64_t num_samples;   /**< Current #samples for limit_samples */
-       GTimer *elapsed_msec;   /**< Used for sampling with limit_msec  */
-       gchar buf[LINELEN_MAX]; /**< Buffer for read callback */
-       int buflen;             /**< Data len in buf */
-};
-
-SR_PRIV int motech_lps_30x_receive_data(int fd, int revents, void *cb_data);
-
-#endif
diff --git a/hardware/norma-dmm/api.c b/hardware/norma-dmm/api.c
deleted file mode 100644 (file)
index 798b60e..0000000
+++ /dev/null
@@ -1,375 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Matthias Heidbrink <m-sigrok@heidbrink.biz>
- *
- * 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
- *  Norma DM9x0/Siemens B102x DMMs driver.
- *  @internal
- */
-
-#include "protocol.h"
-
-static const int32_t hwopts[] = {
-       SR_CONF_CONN,
-       SR_CONF_SERIALCOMM,
-};
-
-static const int32_t hwcaps[] = {
-       SR_CONF_MULTIMETER,
-       SR_CONF_LIMIT_SAMPLES,
-       SR_CONF_LIMIT_MSEC,
-       SR_CONF_CONTINUOUS,
-};
-
-#define BUF_MAX 50
-
-#define SERIALCOMM "4800/8n1/dtr=1/rts=0/flow=1"
-
-SR_PRIV struct sr_dev_driver norma_dmm_driver_info;
-SR_PRIV struct sr_dev_driver siemens_b102x_driver_info;
-
-static const char* get_brandstr(struct sr_dev_driver* drv)
-{
-       if (drv == &norma_dmm_driver_info)
-               return "Norma";
-       else
-               return "Siemens";
-}
-
-static const char* get_typestr(int type, struct sr_dev_driver* drv)
-{
-       static const char* nameref[5][2] = {
-               {"DM910", "B1024"},
-               {"DM920", "B1025"},
-               {"DM930", "B1026"},
-               {"DM940", "B1027"},
-               {"DM950", "B1028"}};
-
-       if ((type < 1) || (type > 5))
-               return "Unknown type!";
-
-       return nameref[type-1][(drv == &siemens_b102x_driver_info)];
-}
-
-static int init_norma_dmm(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, &norma_dmm_driver_info, LOG_PREFIX);
-}
-
-static int init_siemens_b102x(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, &siemens_b102x_driver_info, LOG_PREFIX);
-}
-
-static GSList *do_scan(struct sr_dev_driver* drv, GSList *options)
-{
-       struct sr_dev_inst *sdi;
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       struct sr_config *src;
-       struct sr_channel *ch;
-       struct sr_serial_dev_inst *serial;
-       GSList *l, *devices;
-       int len, cnt;
-       const char *conn, *serialcomm;
-       char *buf;
-       char req[10];
-       int auxtype;
-
-       devices = NULL;
-       drvc = drv->priv;
-       drvc->instances = NULL;
-       conn = serialcomm = NULL;
-
-       for (l = options; l; l = l->next) {
-               src = l->data;
-               switch (src->key) {
-               case SR_CONF_CONN:
-                       conn = g_variant_get_string(src->data, NULL);
-                       break;
-               case SR_CONF_SERIALCOMM:
-                       serialcomm = g_variant_get_string(src->data, NULL);
-                       break;
-               }
-       }
-       if (!conn)
-               return NULL;
-       if (!serialcomm)
-               serialcomm = SERIALCOMM;
-
-       if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
-               return NULL;
-
-       if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
-               return NULL;
-
-       serial_flush(serial);
-
-       if (!(buf = g_try_malloc(BUF_MAX))) {
-               sr_err("Serial buffer malloc failed.");
-               return NULL;
-       }
-
-       snprintf(req, sizeof(req), "%s\r\n",
-                nmadmm_requests[NMADMM_REQ_IDN].req_str);
-       g_usleep(150 * 1000); /* Wait a little to allow serial port to settle. */
-       for (cnt = 0; cnt < 7; cnt++) {
-               if (serial_write(serial, req, strlen(req)) == -1) {
-                       sr_err("Unable to send identification request: %d %s.",
-                              errno, strerror(errno));
-                       return NULL;
-               }
-               len = BUF_MAX;
-               serial_readline(serial, &buf, &len, NMADMM_TIMEOUT_MS);
-               if (!len)
-                       continue;
-               buf[BUF_MAX - 1] = '\0';
-
-               /* Match ID string, e.g. "1834 065 V1.06,IF V1.02" (DM950) */
-               if (g_regex_match_simple("^1834 [^,]*,IF V*", (char *)buf, 0, 0)) {
-                       auxtype = xgittoint(buf[7]);
-                       sr_spew("%s %s DMM %s detected!", get_brandstr(drv), get_typestr(auxtype, drv), buf + 9);
-
-                       if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE,
-                                               get_brandstr(drv), get_typestr(auxtype, drv), buf + 9)))
-                               return NULL;
-                       if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
-                               sr_err("Device context malloc failed.");
-                               return NULL;
-                       }
-                       devc->type = auxtype;
-                       devc->version = g_strdup(&buf[9]);
-                       devc->elapsed_msec = g_timer_new();
-
-                       sdi->conn = serial;
-                       sdi->priv = devc;
-                       sdi->driver = drv;
-                       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE,
-                               "P1")))
-                               return NULL;
-                       sdi->channels = g_slist_append(sdi->channels, ch);
-                       drvc->instances = g_slist_append(drvc->instances, sdi);
-                       devices = g_slist_append(devices, sdi);
-                       break;
-               }
-
-               /*
-                * The interface of the DM9x0 contains a cap that needs to
-                * charge for up to 10s before the interface works, if not
-                * powered externally. Therefore wait a little to improve
-                * chances.
-                */
-               if (cnt == 3) {
-                       sr_info("Waiting 5s to allow interface to settle.");
-                       g_usleep(5 * 1000 * 1000);
-               }
-       }
-
-       g_free(buf);
-
-       serial_close(serial);
-       if (!devices)
-               sr_serial_dev_inst_free(serial);
-
-       return devices;
-}
-
-static GSList *scan_norma_dmm(GSList *options)
-{
-       return do_scan(&norma_dmm_driver_info, options);
-}
-
-static GSList *scan_siemens_b102x(GSList *options)
-{
-       return do_scan(&siemens_b102x_driver_info, options);
-}
-
-static GSList *dev_list_norma_dmm(void)
-{
-       return ((struct drv_context *)(norma_dmm_driver_info.priv))->instances;
-}
-
-static GSList *dev_list_siemens_b102x(void)
-{
-       return ((struct drv_context *)(siemens_b102x_driver_info.priv))->instances;
-}
-
-static int dev_close(struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-
-       std_serial_dev_close(sdi);
-
-       /* Free dynamically allocated resources. */
-       if ((devc = sdi->priv) && devc->version) {
-               g_free(devc->version);
-               devc->version = NULL;
-               g_timer_destroy(devc->elapsed_msec);
-       }
-
-       return SR_OK;
-}
-
-static int cleanup_norma_dmm(void)
-{
-       return std_dev_clear(&norma_dmm_driver_info, NULL);
-}
-
-static int cleanup_siemens_b102x(void)
-{
-       return std_dev_clear(&siemens_b102x_driver_info, NULL);
-}
-
-static int config_set(int 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;
-
-       if (!(devc = sdi->priv)) {
-               sr_err("sdi->priv was NULL.");
-               return SR_ERR_BUG;
-       }
-
-       switch (key) {
-       case SR_CONF_LIMIT_MSEC:
-               if (g_variant_get_uint64(data) == 0) {
-                       sr_err("LIMIT_MSEC can't be 0.");
-                       return SR_ERR;
-               }
-               devc->limit_msec = g_variant_get_uint64(data);
-               sr_dbg("Setting time limit to %" PRIu64 "ms.",
-                      devc->limit_msec);
-               break;
-       case SR_CONF_LIMIT_SAMPLES:
-               devc->limit_samples = g_variant_get_uint64(data);
-               sr_dbg("Setting sample limit to %" PRIu64 ".",
-                      devc->limit_samples);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_list(int 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_INT32,
-                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
-               break;
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi,
-                                   void *cb_data)
-{
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-
-       if (!sdi || !cb_data || !(devc = sdi->priv))
-               return SR_ERR_BUG;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       devc->cb_data = cb_data;
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(cb_data, LOG_PREFIX);
-
-       /* Start timer, if required. */
-       if (devc->limit_msec)
-               g_timer_start(devc->elapsed_msec);
-
-       /* Poll every 100ms, or whenever some data comes in. */
-       serial = sdi->conn;
-       serial_source_add(sdi->session, serial, G_IO_IN, 100,
-                       norma_dmm_receive_data, (void *)sdi);
-
-       return SR_OK;
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct dev_context *devc;
-
-       /* Stop timer, if required. */
-       if (sdi && (devc = sdi->priv) && devc->limit_msec)
-               g_timer_stop(devc->elapsed_msec);
-
-       return std_serial_dev_acquisition_stop(sdi, cb_data, dev_close,
-                       sdi->conn, LOG_PREFIX);
-}
-
-SR_PRIV struct sr_dev_driver norma_dmm_driver_info = {
-       .name = "norma-dmm",
-       .longname = "Norma DM9x0 DMMs",
-       .api_version = 1,
-       .init = init_norma_dmm,
-       .cleanup = cleanup_norma_dmm,
-       .scan = scan_norma_dmm,
-       .dev_list = dev_list_norma_dmm,
-       .dev_clear = NULL,
-       .config_get = NULL,
-       .config_set = config_set,
-       .config_list = config_list,
-       .dev_open = std_serial_dev_open,
-       .dev_close = dev_close,
-       .dev_acquisition_start = dev_acquisition_start,
-       .dev_acquisition_stop = dev_acquisition_stop,
-       .priv = NULL,
-};
-
-
-SR_PRIV struct sr_dev_driver siemens_b102x_driver_info = {
-       .name = "siemens-b102x",
-       .longname = "Siemens B102x DMMs",
-       .api_version = 1,
-       .init = init_siemens_b102x,
-       .cleanup = cleanup_siemens_b102x,
-       .scan = scan_siemens_b102x,
-       .dev_list = dev_list_siemens_b102x,
-       .dev_clear = NULL,
-       .config_get = NULL,
-       .config_set = config_set,
-       .config_list = config_list,
-       .dev_open = std_serial_dev_open,
-       .dev_close = dev_close,
-       .dev_acquisition_start = dev_acquisition_start,
-       .dev_acquisition_stop = dev_acquisition_stop,
-       .priv = NULL,
-};
diff --git a/hardware/norma-dmm/protocol.c b/hardware/norma-dmm/protocol.c
deleted file mode 100644 (file)
index 717ef15..0000000
+++ /dev/null
@@ -1,442 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Matthias Heidbrink <m-sigrok@heidbrink.biz>
- *
- * 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
- *  Norma DM9x0/Siemens B102x DMMs driver.
- *  @internal
- */
-
-#include "protocol.h"
-
-SR_PRIV const struct nmadmm_req nmadmm_requests[] = {
-       { NMADMM_REQ_IDN, "IDN?" },
-       { NMADMM_REQ_IDN, "STATUS?" },
-       { 0, NULL },
-};
-
-static int nma_send_req(const struct sr_dev_inst *sdi, int req, char *params)
-{
-       struct sr_serial_dev_inst *serial;
-       struct dev_context *devc;
-       char buf[NMADMM_BUFSIZE];
-       int len;
-
-       if (!sdi || !(serial = sdi->conn) || !(devc = sdi->priv))
-               return SR_ERR_BUG;
-
-       len = snprintf(buf, sizeof(buf), "%s%s\r\n",
-               nmadmm_requests[req].req_str, params ? params : "");
-
-       sr_spew("Sending request: '%s'.", buf);
-
-       devc->last_req = req;
-       devc->last_req_pending = TRUE;
-
-       if (serial_write(serial, buf, len) == -1) {
-               sr_err("Unable to send request: %d %s.",
-                       errno, strerror(errno));
-               devc->last_req_pending = FALSE;
-               return SR_ERR;
-       }
-
-       devc->req_sent_at = g_get_monotonic_time();
-
-       return SR_OK;
-}
-
-/**
- * Convert hexadecimal digit to int.
- *
- * @param[in] xgit Hexadecimal digit to convert.
- * @return Int value of xgit (0 on invalid xgit).
- */
-SR_PRIV int xgittoint(char xgit)
-{
-       if ((xgit >= '0') && (xgit <= '9'))
-               return xgit - '0';
-       xgit = tolower(xgit);
-       if ((xgit >= 'a') && (xgit <= 'f'))
-               return xgit - 'a';
-       return 0;
-}
-
-/**
- * Process received line. It consists of 20 hex digits + \\r\\n,
- * e.g. '08100400018100400000'.
- */
-static void nma_process_line(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       int pos, flags;
-       int vt, range;  /* Measurement value type, range in device format */
-       int mmode, devstat;     /* Measuring mode, device status */
-       float value;    /* Measured value */
-       float scale;    /* Scaling factor depending on range and function */
-       struct sr_datafeed_analog analog;
-       struct sr_datafeed_packet packet;
-
-       devc = sdi->priv;
-
-       devc->buf[20] = '\0';
-
-       sr_spew("Received line '%s'.", devc->buf);
-
-       /* Check line. */
-       if (strlen((const char *)devc->buf) != 20) {
-               sr_err("line: Invalid status '%s', must be 20 hex digits.",
-                      devc->buf);
-               devc->buflen = 0;
-               return;
-       }
-
-       for (pos = 0; pos < 20; pos++) {
-               if (!isxdigit(devc->buf[pos])) {
-                       sr_err("line: Expected hex digit in '%s' at pos %d!",
-                               devc->buf, pos);
-                       devc->buflen = 0;
-                       return;
-               }
-       }
-
-       /* Start decoding. */
-       value = 0.0;
-       scale = 1.0;
-       memset(&analog, 0, sizeof(analog));
-
-       /*
-        * The numbers are hex digits, starting from 0.
-        * 0: Keyboard status, currently not interesting.
-        * 1: Central switch status, currently not interesting.
-        * 2: Type of measured value.
-        */
-       vt = xgittoint(devc->buf[2]);
-       switch (vt) {
-       case 0:
-               analog.mq = SR_MQ_VOLTAGE;
-               break;
-       case 1:
-               analog.mq = SR_MQ_CURRENT;      /* 2A */
-               break;
-       case 2:
-               analog.mq = SR_MQ_RESISTANCE;
-               break;
-       case 3:
-               analog.mq = SR_MQ_CAPACITANCE;
-               break;
-       case 4:
-               analog.mq = SR_MQ_TEMPERATURE;
-               break;
-       case 5:
-               analog.mq = SR_MQ_FREQUENCY;
-               break;
-       case 6:
-               analog.mq = SR_MQ_CURRENT;      /* 10A */
-               break;
-       case 7:
-               analog.mq = SR_MQ_GAIN;         /* TODO: Scale factor */
-               break;
-       case 8:
-               analog.mq = SR_MQ_GAIN;         /* Percentage */
-               scale /= 100.0;
-               break;
-       case 9:
-               analog.mq = SR_MQ_GAIN;         /* dB */
-               scale /= 100.0;
-               break;
-       default:
-               sr_err("Unknown value type: 0x%02x.", vt);
-               break;
-       }
-
-       /* 3: Measurement range for measured value */
-       range = xgittoint(devc->buf[3]);
-       switch (vt) {
-       case 0: /* V */
-               scale *= pow(10.0, range - 5);
-               break;
-       case 1: /* A */
-               scale *= pow(10.0, range - 7);
-               break;
-       case 2: /* Î© */
-               scale *= pow(10.0, range - 2);
-               break;
-       case 3: /* F */
-               scale *= pow(10.0, range - 12);
-               break;
-       case 4: /* Â°C */
-               scale *= pow(10.0, range - 1);
-               break;
-       case 5: /* Hz */
-               scale *= pow(10.0, range - 2);
-               break;
-       // No default, other value types have fixed display format.
-       }
-
-       /* 5: Sign and 1st digit */
-       flags = xgittoint(devc->buf[5]);
-       value = (flags & 0x03);
-       if (flags & 0x04)
-               scale *= -1;
-
-       /* 6-9: 2nd-4th digit */
-       for (pos = 6; pos < 10; pos++)
-               value = value * 10 + xgittoint(devc->buf[pos]);
-       value *= scale;
-
-       /* 10: Display counter */
-       mmode = xgittoint(devc->buf[10]);
-       switch (mmode) {
-       case 0: /* Frequency */
-               analog.unit = SR_UNIT_HERTZ;
-               break;
-       case 1: /* V TRMS, only type 5 */
-               analog.unit = SR_UNIT_VOLT;
-               analog.mqflags |= (SR_MQFLAG_AC | SR_MQFLAG_DC | SR_MQFLAG_RMS);
-               break;
-       case 2: /* V AC */
-               analog.unit = SR_UNIT_VOLT;
-               analog.mqflags |= SR_MQFLAG_AC;
-               if (devc->type >= 3)
-                       analog.mqflags |= SR_MQFLAG_RMS;
-               break;
-       case 3: /* V DC */
-               analog.unit = SR_UNIT_VOLT;
-               analog.mqflags |= SR_MQFLAG_DC;
-               break;
-       case 4: /* Ohm */
-               analog.unit = SR_UNIT_OHM;
-               break;
-       case 5: /* Continuity */
-               analog.unit = SR_UNIT_BOOLEAN;
-               analog.mq = SR_MQ_CONTINUITY;
-               /* TODO: Continuity handling is a bit odd in libsigrok. */
-               break;
-       case 6: /* Degree Celsius */
-               analog.unit = SR_UNIT_CELSIUS;
-               break;
-       case 7: /* Capacity */
-               analog.unit = SR_UNIT_FARAD;
-               break;
-       case 8: /* Current DC */
-               analog.unit = SR_UNIT_AMPERE;
-               analog.mqflags |= SR_MQFLAG_DC;
-               break;
-       case 9: /* Current AC */
-               analog.unit = SR_UNIT_AMPERE;
-               analog.mqflags |= SR_MQFLAG_AC;
-               if (devc->type >= 3)
-                       analog.mqflags |= SR_MQFLAG_RMS;
-               break;
-       case 0xa: /* Current TRMS, only type 5 */
-               analog.unit = SR_UNIT_AMPERE;
-               analog.mqflags |= (SR_MQFLAG_AC | SR_MQFLAG_DC | SR_MQFLAG_RMS);
-               break;
-       case 0xb: /* Diode */
-               analog.unit = SR_UNIT_VOLT;
-               analog.mqflags |= (SR_MQFLAG_DIODE | SR_MQFLAG_DC);
-               break;
-       default:
-               sr_err("Unknown mmode: 0x%02x.", mmode);
-               break;
-       }
-
-       /* 11: Device status */
-       devstat = xgittoint(devc->buf[11]);
-
-       switch (devstat) {
-       case 1: /* Normal measurement */
-               break;
-       case 2: /* Input loop (limit, reference values) */
-               break;
-       case 3: /* TRANS/SENS */
-               break;
-       case 4: /* Error */
-               sr_err("Device error. Fuse?"); /* TODO: Really abort? */
-               devc->buflen = 0;
-               return; /* Cannot continue. */
-       default:
-               sr_err("Unknown device status: 0x%02x", devstat);
-               break;
-       }
-
-       /* 12-19: Flags and display symbols */
-       /* 12, 13 */
-       flags = (xgittoint(devc->buf[12]) << 8) | xgittoint(devc->buf[13]);
-       /* 0x80: PRINT TODO: Stop polling when discovered? */
-       /* 0x40: EXTR */
-       if (analog.mq == SR_MQ_CONTINUITY) {
-               if (flags & 0x20)
-                       value = 1.0; /* Beep */
-               else
-                       value = 0.0;
-       }
-       /* 0x10: AVG */
-       /* 0x08: Diode */
-       if (flags & 0x04) /* REL */
-               analog.mqflags |= SR_MQFLAG_RELATIVE;
-       /* 0x02: SHIFT  */
-       if (flags & 0x01) /* % */
-               analog.unit = SR_UNIT_PERCENTAGE;
-
-       /* 14, 15 */
-       flags = (xgittoint(devc->buf[14]) << 8) | xgittoint(devc->buf[15]);
-       if (!(flags & 0x80))    /* MAN: Manual range */
-               analog.mqflags |= SR_MQFLAG_AUTORANGE;
-       if (flags & 0x40) /* LOBATT1: Low battery, measurement still within specs */
-               devc->lowbatt = 1;
-       /* 0x20: PEAK */
-       /* 0x10: COUNT */
-       if (flags & 0x08)       /* HOLD */
-               analog.mqflags |= SR_MQFLAG_HOLD;
-       /* 0x04: LIMIT  */
-       if (flags & 0x02)       /* MAX */
-               analog.mqflags |= SR_MQFLAG_MAX;
-       if (flags & 0x01)       /* MIN */
-               analog.mqflags |= SR_MQFLAG_MIN;
-
-       /* 16, 17 */
-       flags = (xgittoint(devc->buf[16]) << 8) | xgittoint(devc->buf[17]);
-       /* 0xe0: undefined */
-       if (flags & 0x10) { /* LOBATT2: Low battery, measurement inaccurate */
-               devc->lowbatt = 2;
-               sr_warn("Low battery, measurement quality degraded!");
-       }
-       /* 0x08: SCALED */
-       /* 0x04: RATE (=lower resolution, allows higher rata rate up to 10/s. */
-       /* 0x02: Current clamp */
-       if (flags & 0x01) { /* dB */
-               /*
-                * TODO: The Norma has an adjustable dB reference value. If
-                * changed from default, this is not correct.
-                */
-               if (analog.unit == SR_UNIT_VOLT)
-                       analog.unit = SR_UNIT_DECIBEL_VOLT;
-               else
-                       analog.unit = SR_UNIT_UNITLESS;
-       }
-
-       /* 18, 19 */
-       /* flags = (xgittoint(devc->buf[18]) << 8) | xgittoint(devc->buf[19]); */
-       /* 0x80: Undefined. */
-       /* 0x40: Remote mode, keyboard locked */
-       /* 0x38: Undefined. */
-       /* 0x04: MIN > MAX */
-       /* 0x02: Measured value < Min */
-       /* 0x01: Measured value > Max */
-
-       /* 4: Flags. Evaluating this after setting value! */
-       flags = xgittoint(devc->buf[4]);
-       if (flags & 0x04) /* Invalid value */
-           value = NAN;
-       else if (flags & 0x01) /* Overload */
-           value =  INFINITY;
-       if (flags & 0x02) { /* Duplicate value, has been sent before. */
-           sr_spew("Duplicate value, dismissing!");
-           devc->buflen = 0;
-           return;
-       }
-
-       sr_spew("range=%d/scale=%f/value=%f", range,
-               (double)scale, (double)value);
-
-       /* Finish and send packet. */
-       analog.channels = sdi->channels;
-       analog.num_samples = 1;
-       analog.data = &value;
-
-       memset(&packet, 0, sizeof(packet));
-       packet.type = SR_DF_ANALOG;
-       packet.payload = &analog;
-       sr_session_send(devc->cb_data, &packet);
-
-       /* Finish processing. */
-       devc->num_samples++;
-       devc->buflen = 0;
-}
-
-SR_PRIV int norma_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 len;
-       gboolean terminating;
-       gdouble elapsed_s;
-
-       (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. */
-               while (NMADMM_BUFSIZE - devc->buflen - 1 > 0) {
-                       len = serial_read(serial, devc->buf + devc->buflen, 1);
-                       if (len < 1)
-                               break;
-                       devc->buflen += len;
-                       *(devc->buf + devc->buflen) = '\0';
-                       if (*(devc->buf + devc->buflen - 1) == '\n') {
-                               /*
-                                * TODO: According to specs, should be \r, but
-                                * then we'd have to get rid of the \n.
-                                */
-                               devc->last_req_pending = FALSE;
-                               nma_process_line(sdi);
-                               break;
-                       }
-               }
-       }
-
-       /* If number of samples or time limit reached, stop acquisition. */
-       terminating = FALSE;
-       if (devc->limit_samples && (devc->num_samples >= devc->limit_samples)) {
-               sdi->driver->dev_acquisition_stop(sdi, cb_data);
-               terminating = TRUE;
-       }
-
-       if (devc->limit_msec) {
-               elapsed_s = g_timer_elapsed(devc->elapsed_msec, NULL);
-               if ((elapsed_s * 1000) >= devc->limit_msec) {
-                       sdi->driver->dev_acquisition_stop(sdi, cb_data);
-                       terminating = TRUE;
-               }
-       }
-
-       /* Request next package. */
-       if (!terminating) {
-               if (devc->last_req_pending) {
-                       gint64 elapsed_us = g_get_monotonic_time() - devc->req_sent_at;
-                       if (elapsed_us > NMADMM_TIMEOUT_MS * 1000) {/* Timeout! */
-                               sr_spew("Request timeout!");
-                               devc->last_req_pending = FALSE;
-                       }
-               }
-               if (!devc->last_req_pending) {
-                       if (nma_send_req(sdi, NMADMM_REQ_STATUS, NULL) != SR_OK)
-                               return FALSE;
-               }
-       }
-
-       return TRUE;
-}
diff --git a/hardware/norma-dmm/protocol.h b/hardware/norma-dmm/protocol.h
deleted file mode 100644 (file)
index 951734e..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Matthias Heidbrink <m-sigrok@heidbrink.biz>
- *
- * 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_NORMA_DMM_PROTOCOL_H
-#define LIBSIGROK_HARDWARE_NORMA_DMM_PROTOCOL_H
-
-#include <stdint.h>
-#include <string.h>
-#include <ctype.h>
-#include <errno.h>
-#include <math.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-/** @file
- *  Norma DM9x0/Siemens B102x DMMs driver.
- *  @internal
- */
-
-#define LOG_PREFIX "norma-dmm"
-
-#define NMADMM_BUFSIZE  256
-
-#define NMADMM_TIMEOUT_MS 2000 /**< Request timeout. */
-
-/** Norma DMM request types (used ones only, the DMMs support about 50). */
-enum {
-       NMADMM_REQ_IDN = 0,     /**< Request identity */
-       NMADMM_REQ_STATUS,      /**< Request device status (value + ...) */
-};
-
-/** Defines requests used to communicate with device. */
-struct nmadmm_req {
-       int req_type;           /**< Request type. */
-       const char *req_str;    /**< Request string. */
-};
-
-/** Strings for requests. */
-extern const struct nmadmm_req nmadmm_requests[];
-
-/** Private, per-device-instance driver context. */
-struct dev_context {
-       /* Model-specific information */
-       char *version;          /**< Version string */
-       int type;               /**< DM9x0, e.g. 5 = DM950 */
-
-       /* Acquisition settings */
-       uint64_t limit_samples; /**< Target number of samples */
-       uint64_t limit_msec;    /**< Target sampling time */
-
-       /* Opaque pointer passed in by frontend. */
-       void *cb_data;
-
-       /* Operational state */
-       int last_req;                   /**< Last request. */
-       int64_t req_sent_at;            /**< Request sent. */
-       gboolean last_req_pending;      /**< Last request not answered yet. */
-       int lowbatt;                    /**< Low battery. 1=low, 2=critical. */
-
-       /* Temporary state across callbacks */
-       uint64_t num_samples;           /**< Current #samples. */
-       GTimer *elapsed_msec;           /**< Used for limit_msec */
-       uint8_t buf[NMADMM_BUFSIZE];    /**< Buffer for read callback */
-       int buflen;                     /**< Data len in buf */
-};
-
-SR_PRIV int norma_dmm_receive_data(int fd, int revents, void *cb_data);
-SR_PRIV int xgittoint(char xgit);
-
-#endif
diff --git a/hardware/openbench-logic-sniffer/api.c b/hardware/openbench-logic-sniffer/api.c
deleted file mode 100644 (file)
index cd9d817..0000000
+++ /dev/null
@@ -1,600 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Bert Vermeulen <bert@biot.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 "protocol.h"
-#include <libserialport.h>
-
-#define SERIALCOMM "115200/8n1"
-
-static const int32_t hwopts[] = {
-       SR_CONF_CONN,
-       SR_CONF_SERIALCOMM,
-};
-
-static const int32_t hwcaps[] = {
-       SR_CONF_LOGIC_ANALYZER,
-       SR_CONF_SAMPLERATE,
-       SR_CONF_TRIGGER_MATCH,
-       SR_CONF_CAPTURE_RATIO,
-       SR_CONF_LIMIT_SAMPLES,
-       SR_CONF_EXTERNAL_CLOCK,
-       SR_CONF_PATTERN_MODE,
-       SR_CONF_SWAP,
-       SR_CONF_RLE,
-};
-
-static const int32_t trigger_matches[] = {
-       SR_TRIGGER_ZERO,
-       SR_TRIGGER_ONE,
-};
-
-#define STR_PATTERN_NONE     "None"
-#define STR_PATTERN_EXTERNAL "External"
-#define STR_PATTERN_INTERNAL "Internal"
-
-/* Supported methods of test pattern outputs */
-enum {
-       /**
-        * Capture pins 31:16 (unbuffered wing) output a test pattern
-        * that can captured on pins 0:15.
-        */
-       PATTERN_EXTERNAL,
-
-       /** Route test pattern internally to capture buffer. */
-       PATTERN_INTERNAL,
-};
-
-static const char *patterns[] = {
-       STR_PATTERN_NONE,
-       STR_PATTERN_EXTERNAL,
-       STR_PATTERN_INTERNAL,
-};
-
-/* Channels are numbered 0-31 (on the PCB silkscreen). */
-SR_PRIV const char *ols_channel_names[NUM_CHANNELS + 1] = {
-       "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12",
-       "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23",
-       "24", "25", "26", "27", "28", "29", "30", "31",
-       NULL,
-};
-
-/* Default supported samplerates, can be overridden by device metadata. */
-static const uint64_t samplerates[] = {
-       SR_HZ(10),
-       SR_MHZ(200),
-       SR_HZ(1),
-};
-
-SR_PRIV struct sr_dev_driver ols_driver_info;
-static struct sr_dev_driver *di = &ols_driver_info;
-
-static int init(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, di, LOG_PREFIX);
-}
-
-static GSList *scan(GSList *options)
-{
-       struct sr_config *src;
-       struct sr_dev_inst *sdi;
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       struct sr_channel *ch;
-       struct sr_serial_dev_inst *serial;
-       GPollFD probefd;
-       GSList *l, *devices;
-       int ret, i;
-       const char *conn, *serialcomm;
-       char buf[8];
-
-       drvc = di->priv;
-
-       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 == NULL)
-               serialcomm = SERIALCOMM;
-
-       if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
-               return NULL;
-
-       /* The discovery procedure is like this: first send the Reset
-        * command (0x00) 5 times, since the device could be anywhere
-        * in a 5-byte command. Then send the ID command (0x02).
-        * If the device responds with 4 bytes ("OLS1" or "SLA1"), we
-        * have a match.
-        */
-       sr_info("Probing %s.", conn);
-       if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
-               return NULL;
-
-       ret = SR_OK;
-       for (i = 0; i < 5; i++) {
-               if ((ret = send_shortcommand(serial, CMD_RESET)) != SR_OK) {
-                       sr_err("Port %s is not writable.", conn);
-                       break;
-               }
-       }
-       if (ret != SR_OK) {
-               serial_close(serial);
-               sr_err("Could not use port %s. Quitting.", conn);
-               return NULL;
-       }
-       send_shortcommand(serial, CMD_ID);
-
-       /* Wait 10ms for a response. */
-       g_usleep(10000);
-
-       sp_get_port_handle(serial->data, &probefd.fd);
-       probefd.events = G_IO_IN;
-       g_poll(&probefd, 1, 1);
-
-       if (probefd.revents != G_IO_IN)
-               return NULL;
-       if (serial_read_blocking(serial, buf, 4) != 4)
-               return NULL;
-       if (strncmp(buf, "1SLO", 4) && strncmp(buf, "1ALS", 4))
-               return NULL;
-
-       /* Definitely using the OLS protocol, check if it supports
-        * the metadata command.
-        */
-       send_shortcommand(serial, CMD_METADATA);
-       if (g_poll(&probefd, 1, 10) > 0) {
-               /* Got metadata. */
-               sdi = get_metadata(serial);
-               sdi->index = 0;
-               devc = sdi->priv;
-       } else {
-               /* Not an OLS -- some other board that uses the sump protocol. */
-               sr_info("Device does not support metadata.");
-               sdi = sr_dev_inst_new(0, SR_ST_INACTIVE,
-                               "Sump", "Logic Analyzer", "v1.0");
-               sdi->driver = di;
-               for (i = 0; i < 32; i++) {
-                       if (!(ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE,
-                                       ols_channel_names[i])))
-                               return 0;
-                       sdi->channels = g_slist_append(sdi->channels, ch);
-               }
-               devc = ols_dev_new();
-               sdi->priv = devc;
-       }
-       /* Configure samplerate and divider. */
-       if (ols_set_samplerate(sdi, DEFAULT_SAMPLERATE) != SR_OK)
-               sr_dbg("Failed to set default samplerate (%"PRIu64").",
-                               DEFAULT_SAMPLERATE);
-       sdi->inst_type = SR_INST_SERIAL;
-       sdi->conn = serial;
-
-       drvc->instances = g_slist_append(drvc->instances, sdi);
-       devices = g_slist_append(devices, sdi);
-
-       serial_close(serial);
-
-       return devices;
-}
-
-static GSList *dev_list(void)
-{
-       return ((struct drv_context *)(di->priv))->instances;
-}
-
-static int cleanup(void)
-{
-       return std_dev_clear(di, NULL);
-}
-
-static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-
-       (void)cg;
-
-       if (!sdi)
-               return SR_ERR_ARG;
-
-       devc = sdi->priv;
-       switch (id) {
-       case SR_CONF_SAMPLERATE:
-               *data = g_variant_new_uint64(devc->cur_samplerate);
-               break;
-       case SR_CONF_CAPTURE_RATIO:
-               *data = g_variant_new_uint64(devc->capture_ratio);
-               break;
-       case SR_CONF_LIMIT_SAMPLES:
-               *data = g_variant_new_uint64(devc->limit_samples);
-               break;
-       case SR_CONF_PATTERN_MODE:
-               if (devc->flag_reg & FLAG_EXTERNAL_TEST_MODE)
-                       *data = g_variant_new_string(STR_PATTERN_EXTERNAL);
-               else if (devc->flag_reg & FLAG_INTERNAL_TEST_MODE)
-                       *data = g_variant_new_string(STR_PATTERN_INTERNAL);
-               else
-                       *data = g_variant_new_string(STR_PATTERN_NONE);
-               break;
-       case SR_CONF_RLE:
-               *data = g_variant_new_boolean(devc->flag_reg & FLAG_RLE ? TRUE : FALSE);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       uint16_t flag;
-       uint64_t tmp_u64;
-       int ret;
-       const char *stropt;
-
-       (void)cg;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       devc = sdi->priv;
-
-       switch (id) {
-       case SR_CONF_SAMPLERATE:
-               tmp_u64 = g_variant_get_uint64(data);
-               if (tmp_u64 < samplerates[0] || tmp_u64 > samplerates[1])
-                       return SR_ERR_SAMPLERATE;
-               ret = ols_set_samplerate(sdi, g_variant_get_uint64(data));
-               break;
-       case SR_CONF_LIMIT_SAMPLES:
-               tmp_u64 = g_variant_get_uint64(data);
-               if (tmp_u64 < MIN_NUM_SAMPLES)
-                       return SR_ERR;
-               devc->limit_samples = tmp_u64;
-               ret = SR_OK;
-               break;
-       case SR_CONF_CAPTURE_RATIO:
-               devc->capture_ratio = g_variant_get_uint64(data);
-               if (devc->capture_ratio < 0 || devc->capture_ratio > 100) {
-                       devc->capture_ratio = 0;
-                       ret = SR_ERR;
-               } else
-                       ret = SR_OK;
-               break;
-       case SR_CONF_EXTERNAL_CLOCK:
-               if (g_variant_get_boolean(data)) {
-                       sr_info("Enabling external clock.");
-                       devc->flag_reg |= FLAG_CLOCK_EXTERNAL;
-               } else {
-                       sr_info("Disabled external clock.");
-                       devc->flag_reg &= ~FLAG_CLOCK_EXTERNAL;
-               }
-               ret = SR_OK;
-               break;
-       case SR_CONF_PATTERN_MODE:
-               stropt = g_variant_get_string(data, NULL);
-               ret = SR_OK;
-               flag = 0xffff;
-               if (!strcmp(stropt, STR_PATTERN_NONE)) {
-                       sr_info("Disabling test modes.");
-                       flag = 0x0000;
-               }else if (!strcmp(stropt, STR_PATTERN_INTERNAL)) {
-                       sr_info("Enabling internal test mode.");
-                       flag = FLAG_INTERNAL_TEST_MODE;
-               } else if (!strcmp(stropt, STR_PATTERN_EXTERNAL)) {
-                       sr_info("Enabling external test mode.");
-                       flag = FLAG_EXTERNAL_TEST_MODE;
-               } else {
-                       ret = SR_ERR;
-               }
-               if (flag != 0xffff) {
-                       devc->flag_reg &= ~(FLAG_INTERNAL_TEST_MODE | FLAG_EXTERNAL_TEST_MODE);
-                       devc->flag_reg |= flag;
-               }
-               break;
-       case SR_CONF_SWAP:
-               if (g_variant_get_boolean(data)) {
-                       sr_info("Enabling channel swapping.");
-                       devc->flag_reg |= FLAG_SWAP_CHANNELS;
-               } else {
-                       sr_info("Disabling channel swapping.");
-                       devc->flag_reg &= ~FLAG_SWAP_CHANNELS;
-               }
-               ret = SR_OK;
-               break;
-
-       case SR_CONF_RLE:
-               if (g_variant_get_boolean(data)) {
-                       sr_info("Enabling RLE.");
-                       devc->flag_reg |= FLAG_RLE;
-               } else {
-                       sr_info("Disabling RLE.");
-                       devc->flag_reg &= ~FLAG_RLE;
-               }
-               ret = SR_OK;
-               break;
-       default:
-               ret = SR_ERR_NA;
-       }
-
-       return ret;
-}
-
-static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       GVariant *gvar, *grange[2];
-       GVariantBuilder gvb;
-       int num_ols_changrp, i;
-
-       (void)cg;
-
-       switch (key) {
-       case SR_CONF_SCAN_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
-               break;
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
-               break;
-       case SR_CONF_SAMPLERATE:
-               g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
-               gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), samplerates,
-                               ARRAY_SIZE(samplerates), sizeof(uint64_t));
-               g_variant_builder_add(&gvb, "{sv}", "samplerate-steps", gvar);
-               *data = g_variant_builder_end(&gvb);
-               break;
-       case SR_CONF_TRIGGER_MATCH:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               trigger_matches, ARRAY_SIZE(trigger_matches),
-                               sizeof(int32_t));
-               break;
-       case SR_CONF_PATTERN_MODE:
-               *data = g_variant_new_strv(patterns, ARRAY_SIZE(patterns));
-               break;
-       case SR_CONF_LIMIT_SAMPLES:
-               if (!sdi)
-                       return SR_ERR_ARG;
-               devc = sdi->priv;
-               if (devc->flag_reg & FLAG_RLE)
-                       return SR_ERR_NA;
-               if (devc->max_samples == 0)
-                       /* Device didn't specify sample memory size in metadata. */
-                       return SR_ERR_NA;
-               /*
-                * Channel groups are turned off if no channels in that group are
-                * enabled, making more room for samples for the enabled group.
-               */
-               ols_channel_mask(sdi);
-               num_ols_changrp = 0;
-               for (i = 0; i < 4; i++) {
-                       if (devc->channel_mask & (0xff << (i * 8)))
-                               num_ols_changrp++;
-               }
-               grange[0] = g_variant_new_uint64(MIN_NUM_SAMPLES);
-               if (num_ols_changrp)
-                       grange[1] = g_variant_new_uint64(devc->max_samples / num_ols_changrp);
-               else
-                       grange[1] = g_variant_new_uint64(MIN_NUM_SAMPLES);
-               *data = g_variant_new_tuple(grange, 2);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int set_trigger(const struct sr_dev_inst *sdi, int stage)
-{
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-       uint8_t cmd, arg[4];
-
-       devc = sdi->priv;
-       serial = sdi->conn;
-
-       cmd = CMD_SET_TRIGGER_MASK + stage * 4;
-       arg[0] = devc->trigger_mask[stage] & 0xff;
-       arg[1] = (devc->trigger_mask[stage] >> 8) & 0xff;
-       arg[2] = (devc->trigger_mask[stage] >> 16) & 0xff;
-       arg[3] = (devc->trigger_mask[stage] >> 24) & 0xff;
-       if (send_longcommand(serial, cmd, arg) != SR_OK)
-               return SR_ERR;
-
-       cmd = CMD_SET_TRIGGER_VALUE + stage * 4;
-       arg[0] = devc->trigger_value[stage] & 0xff;
-       arg[1] = (devc->trigger_value[stage] >> 8) & 0xff;
-       arg[2] = (devc->trigger_value[stage] >> 16) & 0xff;
-       arg[3] = (devc->trigger_value[stage] >> 24) & 0xff;
-       if (send_longcommand(serial, cmd, arg) != SR_OK)
-               return SR_ERR;
-
-       cmd = CMD_SET_TRIGGER_CONFIG + stage * 4;
-       arg[0] = arg[1] = arg[3] = 0x00;
-       arg[2] = stage;
-       if (stage == devc->num_stages)
-               /* Last stage, fire when this one matches. */
-               arg[3] |= TRIGGER_START;
-       if (send_longcommand(serial, cmd, arg) != SR_OK)
-               return SR_ERR;
-
-       return SR_OK;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi,
-               void *cb_data)
-{
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-       uint16_t samplecount, readcount, delaycount;
-       uint8_t ols_changrp_mask, arg[4];
-       int num_ols_changrp;
-       int ret, i;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       devc = sdi->priv;
-       serial = sdi->conn;
-
-       ols_channel_mask(sdi);
-
-       num_ols_changrp = 0;
-       ols_changrp_mask = 0;
-       for (i = 0; i < 4; i++) {
-               if (devc->channel_mask & (0xff << (i * 8))) {
-                       ols_changrp_mask |= (1 << i);
-                       num_ols_changrp++;
-               }
-       }
-
-       /*
-        * Limit readcount to prevent reading past the end of the hardware
-        * buffer.
-        */
-       samplecount = MIN(devc->max_samples / num_ols_changrp, devc->limit_samples);
-       readcount = samplecount / 4;
-
-       /* Rather read too many samples than too few. */
-       if (samplecount % 4 != 0)
-               readcount++;
-
-       /* Basic triggers. */
-       if (ols_convert_trigger(sdi) != SR_OK) {
-               sr_err("Failed to configure channels.");
-               return SR_ERR;
-       }
-       if (devc->num_stages > 0) {
-               delaycount = readcount * (1 - devc->capture_ratio / 100.0);
-               devc->trigger_at = (readcount - delaycount) * 4 - devc->num_stages;
-               for (i = 0; i <= devc->num_stages; i++) {
-                       sr_dbg("Setting OLS stage %d trigger.", i);
-                       if ((ret = set_trigger(sdi, i)) != SR_OK)
-                               return ret;
-               }
-       } else {
-               /* No triggers configured, force trigger on first stage. */
-               sr_dbg("Forcing trigger at stage 0.");
-               if ((ret = set_trigger(sdi, 0)) != SR_OK)
-                       return ret;
-               delaycount = readcount;
-       }
-
-       /* Samplerate. */
-       sr_dbg("Setting samplerate to %" PRIu64 "Hz (divider %u)",
-                       devc->cur_samplerate, devc->cur_samplerate_divider);
-       arg[0] = devc->cur_samplerate_divider & 0xff;
-       arg[1] = (devc->cur_samplerate_divider & 0xff00) >> 8;
-       arg[2] = (devc->cur_samplerate_divider & 0xff0000) >> 16;
-       arg[3] = 0x00;
-       if (send_longcommand(serial, CMD_SET_DIVIDER, arg) != SR_OK)
-               return SR_ERR;
-
-       /* Send sample limit and pre/post-trigger capture ratio. */
-       sr_dbg("Setting sample limit %d, trigger point at %d",
-                       (readcount - 1) * 4, (delaycount - 1) * 4);
-       arg[0] = ((readcount - 1) & 0xff);
-       arg[1] = ((readcount - 1) & 0xff00) >> 8;
-       arg[2] = ((delaycount - 1) & 0xff);
-       arg[3] = ((delaycount - 1) & 0xff00) >> 8;
-       if (send_longcommand(serial, CMD_CAPTURE_SIZE, arg) != SR_OK)
-               return SR_ERR;
-
-       /* Flag register. */
-       sr_dbg("Setting intpat %s, extpat %s, RLE %s, noise_filter %s, demux %s",
-                       devc->flag_reg & FLAG_INTERNAL_TEST_MODE ? "on": "off",
-                       devc->flag_reg & FLAG_EXTERNAL_TEST_MODE ? "on": "off",
-                       devc->flag_reg & FLAG_RLE ? "on" : "off",
-                       devc->flag_reg & FLAG_FILTER ? "on": "off",
-                       devc->flag_reg & FLAG_DEMUX ? "on" : "off");
-       /*
-        * Enable/disable OLS channel groups in the flag register according
-        * to the channel mask. 1 means "disable channel".
-        */
-       devc->flag_reg |= ~(ols_changrp_mask << 2) & 0x3c;
-       arg[0] = devc->flag_reg & 0xff;
-       arg[1] = devc->flag_reg >> 8;
-       arg[2] = arg[3] = 0x00;
-       if (send_longcommand(serial, CMD_SET_FLAGS, arg) != SR_OK)
-               return SR_ERR;
-
-       /* Start acquisition on the device. */
-       if (send_shortcommand(serial, CMD_RUN) != SR_OK)
-               return SR_ERR;
-
-       /* Reset all operational states. */
-       devc->rle_count = devc->num_transfers = 0;
-       devc->num_samples = devc->num_bytes = 0;
-       devc->cnt_bytes = devc->cnt_samples = devc->cnt_samples_rle = 0;
-       memset(devc->sample, 0, 4);
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(cb_data, LOG_PREFIX);
-
-       serial_source_add(sdi->session, serial, G_IO_IN, -1,
-                       ols_receive_data, cb_data);
-
-       return SR_OK;
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       (void)cb_data;
-
-       abort_acquisition(sdi);
-
-       return SR_OK;
-}
-
-SR_PRIV struct sr_dev_driver ols_driver_info = {
-       .name = "ols",
-       .longname = "Openbench Logic Sniffer",
-       .api_version = 1,
-       .init = init,
-       .cleanup = cleanup,
-       .scan = scan,
-       .dev_list = dev_list,
-       .dev_clear = NULL,
-       .config_get = config_get,
-       .config_set = config_set,
-       .config_list = config_list,
-       .dev_open = std_serial_dev_open,
-       .dev_close = std_serial_dev_close,
-       .dev_acquisition_start = dev_acquisition_start,
-       .dev_acquisition_stop = dev_acquisition_stop,
-       .priv = NULL,
-};
diff --git a/hardware/openbench-logic-sniffer/protocol.c b/hardware/openbench-logic-sniffer/protocol.c
deleted file mode 100644 (file)
index 1c94b7f..0000000
+++ /dev/null
@@ -1,513 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Bert Vermeulen <bert@biot.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 "protocol.h"
-#include <libserialport.h>
-
-extern SR_PRIV struct sr_dev_driver ols_driver_info;
-static struct sr_dev_driver *di = &ols_driver_info;
-
-SR_PRIV int send_shortcommand(struct sr_serial_dev_inst *serial,
-               uint8_t command)
-{
-       char buf[1];
-
-       sr_dbg("Sending cmd 0x%.2x.", command);
-       buf[0] = command;
-       if (serial_write_blocking(serial, buf, 1) != 1)
-               return SR_ERR;
-
-       return SR_OK;
-}
-
-SR_PRIV int send_longcommand(struct sr_serial_dev_inst *serial,
-               uint8_t command, uint8_t *data)
-{
-       char buf[5];
-
-       sr_dbg("Sending cmd 0x%.2x data 0x%.2x%.2x%.2x%.2x.", command,
-                       data[0], data[1], data[2], data[3]);
-       buf[0] = command;
-       buf[1] = data[0];
-       buf[2] = data[1];
-       buf[3] = data[2];
-       buf[4] = data[3];
-       if (serial_write_blocking(serial, buf, 5) != 5)
-               return SR_ERR;
-
-       return SR_OK;
-}
-
-/* Configures the channel mask based on which channels are enabled. */
-SR_PRIV void ols_channel_mask(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_channel *channel;
-       const GSList *l;
-
-       devc = sdi->priv;
-
-       devc->channel_mask = 0;
-       for (l = sdi->channels; l; l = l->next) {
-               channel = l->data;
-               if (channel->enabled)
-                       devc->channel_mask |= 1 << channel->index;
-       }
-}
-
-SR_PRIV int ols_convert_trigger(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_trigger *trigger;
-       struct sr_trigger_stage *stage;
-       struct sr_trigger_match *match;
-       const GSList *l, *m;
-       int i;
-
-       devc = sdi->priv;
-
-       devc->num_stages = 0;
-       for (i = 0; i < NUM_TRIGGER_STAGES; i++) {
-               devc->trigger_mask[i] = 0;
-               devc->trigger_value[i] = 0;
-       }
-
-       if (!(trigger = sr_session_trigger_get(sdi->session)))
-               return SR_OK;
-
-       devc->num_stages = g_slist_length(trigger->stages);
-       if (devc->num_stages > NUM_TRIGGER_STAGES) {
-               sr_err("This device only supports %d trigger stages.",
-                               NUM_TRIGGER_STAGES);
-               return SR_ERR;
-       }
-
-       for (l = trigger->stages; l; l = l->next) {
-               stage = l->data;
-               for (m = stage->matches; m; m = m->next) {
-                       match = m->data;
-                       if (!match->channel->enabled)
-                               /* Ignore disabled channels with a trigger. */
-                               continue;
-                       devc->trigger_mask[stage->stage] |= 1 << match->channel->index;
-                       if (match->match == SR_TRIGGER_ONE)
-                               devc->trigger_value[stage->stage] |= 1 << match->channel->index;
-               }
-       }
-
-       return SR_OK;
-}
-
-SR_PRIV struct dev_context *ols_dev_new(void)
-{
-       struct dev_context *devc;
-
-       if (!(devc = g_try_malloc(sizeof(struct dev_context)))) {
-               sr_err("Device context malloc failed.");
-               return NULL;
-       }
-
-       /* Device-specific settings */
-       devc->max_samples = devc->max_samplerate = devc->protocol_version = 0;
-
-       /* Acquisition settings */
-       devc->limit_samples = devc->capture_ratio = 0;
-       devc->trigger_at = -1;
-       devc->channel_mask = 0xffffffff;
-       devc->flag_reg = 0;
-
-       return devc;
-}
-
-SR_PRIV struct sr_dev_inst *get_metadata(struct sr_serial_dev_inst *serial)
-{
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-       struct sr_channel *ch;
-       uint32_t tmp_int, ui;
-       uint8_t key, type, token;
-       GString *tmp_str, *devname, *version;
-       guchar tmp_c;
-
-       sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, NULL, NULL, NULL);
-       sdi->driver = di;
-       devc = ols_dev_new();
-       sdi->priv = devc;
-
-       devname = g_string_new("");
-       version = g_string_new("");
-
-       key = 0xff;
-       while (key) {
-               if (serial_read_blocking(serial, &key, 1) != 1)
-                       break;
-               if (key == 0x00) {
-                       sr_dbg("Got metadata key 0x00, metadata ends.");
-                       break;
-               }
-               type = key >> 5;
-               token = key & 0x1f;
-               switch (type) {
-               case 0:
-                       /* NULL-terminated string */
-                       tmp_str = g_string_new("");
-                       while (serial_read_blocking(serial, &tmp_c, 1) == 1 && tmp_c != '\0')
-                               g_string_append_c(tmp_str, tmp_c);
-                       sr_dbg("Got metadata key 0x%.2x value '%s'.",
-                              key, tmp_str->str);
-                       switch (token) {
-                       case 0x01:
-                               /* Device name */
-                               devname = g_string_append(devname, tmp_str->str);
-                               break;
-                       case 0x02:
-                               /* FPGA firmware version */
-                               if (version->len)
-                                       g_string_append(version, ", ");
-                               g_string_append(version, "FPGA version ");
-                               g_string_append(version, tmp_str->str);
-                               break;
-                       case 0x03:
-                               /* Ancillary version */
-                               if (version->len)
-                                       g_string_append(version, ", ");
-                               g_string_append(version, "Ancillary version ");
-                               g_string_append(version, tmp_str->str);
-                               break;
-                       default:
-                               sr_info("ols: unknown token 0x%.2x: '%s'",
-                                       token, tmp_str->str);
-                               break;
-                       }
-                       g_string_free(tmp_str, TRUE);
-                       break;
-               case 1:
-                       /* 32-bit unsigned integer */
-                       if (serial_read_blocking(serial, &tmp_int, 4) != 4)
-                               break;
-                       tmp_int = RB32(&tmp_int);
-                       sr_dbg("Got metadata key 0x%.2x value 0x%.8x.",
-                              key, tmp_int);
-                       switch (token) {
-                       case 0x00:
-                               /* Number of usable channels */
-                               for (ui = 0; ui < tmp_int; ui++) {
-                                       if (!(ch = sr_channel_new(ui, SR_CHANNEL_LOGIC, TRUE,
-                                                       ols_channel_names[ui])))
-                                               return 0;
-                                       sdi->channels = g_slist_append(sdi->channels, ch);
-                               }
-                               break;
-                       case 0x01:
-                               /* Amount of sample memory available (bytes) */
-                               devc->max_samples = tmp_int;
-                               break;
-                       case 0x02:
-                               /* Amount of dynamic memory available (bytes) */
-                               /* what is this for? */
-                               break;
-                       case 0x03:
-                               /* Maximum sample rate (hz) */
-                               devc->max_samplerate = tmp_int;
-                               break;
-                       case 0x04:
-                               /* protocol version */
-                               devc->protocol_version = tmp_int;
-                               break;
-                       default:
-                               sr_info("Unknown token 0x%.2x: 0x%.8x.",
-                                       token, tmp_int);
-                               break;
-                       }
-                       break;
-               case 2:
-                       /* 8-bit unsigned integer */
-                       if (serial_read_blocking(serial, &tmp_c, 1) != 1)
-                               break;
-                       sr_dbg("Got metadata key 0x%.2x value 0x%.2x.",
-                              key, tmp_c);
-                       switch (token) {
-                       case 0x00:
-                               /* Number of usable channels */
-                               for (ui = 0; ui < tmp_c; ui++) {
-                                       if (!(ch = sr_channel_new(ui, SR_CHANNEL_LOGIC, TRUE,
-                                                       ols_channel_names[ui])))
-                                               return 0;
-                                       sdi->channels = g_slist_append(sdi->channels, ch);
-                               }
-                               break;
-                       case 0x01:
-                               /* protocol version */
-                               devc->protocol_version = tmp_c;
-                               break;
-                       default:
-                               sr_info("Unknown token 0x%.2x: 0x%.2x.",
-                                       token, tmp_c);
-                               break;
-                       }
-                       break;
-               default:
-                       /* unknown type */
-                       break;
-               }
-       }
-
-       sdi->model = devname->str;
-       sdi->version = version->str;
-       g_string_free(devname, FALSE);
-       g_string_free(version, FALSE);
-
-       return sdi;
-}
-
-SR_PRIV int ols_set_samplerate(const struct sr_dev_inst *sdi,
-               const uint64_t samplerate)
-{
-       struct dev_context *devc;
-
-       devc = sdi->priv;
-       if (devc->max_samplerate && samplerate > devc->max_samplerate)
-               return SR_ERR_SAMPLERATE;
-
-       if (samplerate > CLOCK_RATE) {
-               sr_info("Enabling demux mode.");
-               devc->flag_reg |= FLAG_DEMUX;
-               devc->flag_reg &= ~FLAG_FILTER;
-               devc->max_channels = NUM_CHANNELS / 2;
-               devc->cur_samplerate_divider = (CLOCK_RATE * 2 / samplerate) - 1;
-       } else {
-               sr_info("Disabling demux mode.");
-               devc->flag_reg &= ~FLAG_DEMUX;
-               devc->flag_reg |= FLAG_FILTER;
-               devc->max_channels = NUM_CHANNELS;
-               devc->cur_samplerate_divider = (CLOCK_RATE / samplerate) - 1;
-       }
-
-       /* Calculate actual samplerate used and complain if it is different
-        * from the requested.
-        */
-       devc->cur_samplerate = CLOCK_RATE / (devc->cur_samplerate_divider + 1);
-       if (devc->flag_reg & FLAG_DEMUX)
-               devc->cur_samplerate *= 2;
-       if (devc->cur_samplerate != samplerate)
-               sr_info("Can't match samplerate %" PRIu64 ", using %"
-                      PRIu64 ".", samplerate, devc->cur_samplerate);
-
-       return SR_OK;
-}
-
-SR_PRIV void abort_acquisition(const struct sr_dev_inst *sdi)
-{
-       struct sr_datafeed_packet packet;
-       struct sr_serial_dev_inst *serial;
-
-       serial = sdi->conn;
-       serial_source_remove(sdi->session, serial);
-
-       /* Terminate session */
-       packet.type = SR_DF_END;
-       sr_session_send(sdi, &packet);
-}
-
-SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data)
-{
-       struct dev_context *devc;
-       struct sr_dev_inst *sdi;
-       struct sr_serial_dev_inst *serial;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_logic logic;
-       uint32_t sample;
-       int num_ols_changrp, offset, j;
-       unsigned int i;
-       unsigned char byte;
-
-       (void)fd;
-
-       sdi = cb_data;
-       serial = sdi->conn;
-       devc = sdi->priv;
-
-       if (devc->num_transfers++ == 0) {
-               /*
-                * First time round, means the device started sending data,
-                * and will not stop until done. If it stops sending for
-                * longer than it takes to send a byte, that means it's
-                * finished. We'll double that to 30ms to be sure...
-                */
-               serial_source_remove(sdi->session, serial);
-               serial_source_add(sdi->session, serial, G_IO_IN, 30,
-                               ols_receive_data, cb_data);
-               devc->raw_sample_buf = g_try_malloc(devc->limit_samples * 4);
-               if (!devc->raw_sample_buf) {
-                       sr_err("Sample buffer malloc failed.");
-                       return FALSE;
-               }
-               /* fill with 1010... for debugging */
-               memset(devc->raw_sample_buf, 0x82, devc->limit_samples * 4);
-       }
-
-       num_ols_changrp = 0;
-       for (i = NUM_CHANNELS; i > 0x02; i /= 2) {
-               if ((devc->flag_reg & i) == 0) {
-                       num_ols_changrp++;
-               }
-       }
-
-       if (revents == G_IO_IN && devc->num_samples < devc->limit_samples) {
-               if (serial_read_nonblocking(serial, &byte, 1) != 1)
-                       return FALSE;
-               devc->cnt_bytes++;
-
-               /* Ignore it if we've read enough. */
-               if (devc->num_samples >= devc->limit_samples)
-                       return TRUE;
-
-               devc->sample[devc->num_bytes++] = byte;
-               sr_spew("Received byte 0x%.2x.", byte);
-               if (devc->num_bytes == num_ols_changrp) {
-                       devc->cnt_samples++;
-                       devc->cnt_samples_rle++;
-                       /*
-                        * Got a full sample. Convert from the OLS's little-endian
-                        * sample to the local format.
-                        */
-                       sample = devc->sample[0] | (devc->sample[1] << 8) \
-                                       | (devc->sample[2] << 16) | (devc->sample[3] << 24);
-                       sr_dbg("Received sample 0x%.*x.", devc->num_bytes * 2, sample);
-                       if (devc->flag_reg & FLAG_RLE) {
-                               /*
-                                * In RLE mode the high bit of the sample is the
-                                * "count" flag, meaning this sample is the number
-                                * of times the previous sample occurred.
-                                */
-                               if (devc->sample[devc->num_bytes - 1] & 0x80) {
-                                       /* Clear the high bit. */
-                                       sample &= ~(0x80 << (devc->num_bytes - 1) * 8);
-                                       devc->rle_count = sample;
-                                       devc->cnt_samples_rle += devc->rle_count;
-                                       sr_dbg("RLE count: %u.", devc->rle_count);
-                                       devc->num_bytes = 0;
-                                       return TRUE;
-                               }
-                       }
-                       devc->num_samples += devc->rle_count + 1;
-                       if (devc->num_samples > devc->limit_samples) {
-                               /* Save us from overrunning the buffer. */
-                               devc->rle_count -= devc->num_samples - devc->limit_samples;
-                               devc->num_samples = devc->limit_samples;
-                       }
-
-                       if (num_ols_changrp < 4) {
-                               /*
-                                * Some channel groups may have been turned
-                                * off, to speed up transfer between the
-                                * hardware and the PC. Expand that here before
-                                * submitting it over the session bus --
-                                * whatever is listening on the bus will be
-                                * expecting a full 32-bit sample, based on
-                                * the number of channels.
-                                */
-                               j = 0;
-                               memset(devc->tmp_sample, 0, 4);
-                               for (i = 0; i < 4; i++) {
-                                       if (((devc->flag_reg >> 2) & (1 << i)) == 0) {
-                                               /*
-                                                * This channel group was
-                                                * enabled, copy from received
-                                                * sample.
-                                                */
-                                               devc->tmp_sample[i] = devc->sample[j++];
-                                       } else if (devc->flag_reg & FLAG_DEMUX && (i > 2)) {
-                                               /* group 2 & 3 get added to 0 & 1 */
-                                               devc->tmp_sample[i - 2] = devc->sample[j++];
-                                       }
-                               }
-                               memcpy(devc->sample, devc->tmp_sample, 4);
-                               sr_spew("Expanded sample: 0x%.8x.", sample);
-                       }
-
-                       /*
-                        * the OLS sends its sample buffer backwards.
-                        * store it in reverse order here, so we can dump
-                        * this on the session bus later.
-                        */
-                       offset = (devc->limit_samples - devc->num_samples) * 4;
-                       for (i = 0; i <= devc->rle_count; i++) {
-                               memcpy(devc->raw_sample_buf + offset + (i * 4),
-                                      devc->sample, 4);
-                       }
-                       memset(devc->sample, 0, 4);
-                       devc->num_bytes = 0;
-                       devc->rle_count = 0;
-               }
-       } else {
-               /*
-                * This is the main loop telling us a timeout was reached, or
-                * we've acquired all the samples we asked for -- we're done.
-                * Send the (properly-ordered) buffer to the frontend.
-                */
-               sr_dbg("Received %d bytes, %d samples, %d decompressed samples.",
-                               devc->cnt_bytes, devc->cnt_samples,
-                               devc->cnt_samples_rle);
-               if (devc->trigger_at != -1) {
-                       /*
-                        * A trigger was set up, so we need to tell the frontend
-                        * about it.
-                        */
-                       if (devc->trigger_at > 0) {
-                               /* There are pre-trigger samples, send those first. */
-                               packet.type = SR_DF_LOGIC;
-                               packet.payload = &logic;
-                               logic.length = devc->trigger_at * 4;
-                               logic.unitsize = 4;
-                               logic.data = devc->raw_sample_buf +
-                                       (devc->limit_samples - devc->num_samples) * 4;
-                               sr_session_send(cb_data, &packet);
-                       }
-
-                       /* Send the trigger. */
-                       packet.type = SR_DF_TRIGGER;
-                       sr_session_send(cb_data, &packet);
-
-                       /* Send post-trigger samples. */
-                       packet.type = SR_DF_LOGIC;
-                       packet.payload = &logic;
-                       logic.length = (devc->num_samples * 4) - (devc->trigger_at * 4);
-                       logic.unitsize = 4;
-                       logic.data = devc->raw_sample_buf + devc->trigger_at * 4 +
-                               (devc->limit_samples - devc->num_samples) * 4;
-                       sr_session_send(cb_data, &packet);
-               } else {
-                       /* no trigger was used */
-                       packet.type = SR_DF_LOGIC;
-                       packet.payload = &logic;
-                       logic.length = devc->num_samples * 4;
-                       logic.unitsize = 4;
-                       logic.data = devc->raw_sample_buf +
-                               (devc->limit_samples - devc->num_samples) * 4;
-                       sr_session_send(cb_data, &packet);
-               }
-               g_free(devc->raw_sample_buf);
-
-               serial_flush(serial);
-               abort_acquisition(sdi);
-       }
-
-       return TRUE;
-}
diff --git a/hardware/openbench-logic-sniffer/protocol.h b/hardware/openbench-logic-sniffer/protocol.h
deleted file mode 100644 (file)
index c0f101d..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Bert Vermeulen <bert@biot.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_OPENBENCH_LOGIC_SNIFFER_PROTOCOL_H
-#define LIBSIGROK_HARDWARE_OPENBENCH_LOGIC_SNIFFER_PROTOCOL_H
-
-#include <stdint.h>
-#include <string.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "ols"
-
-#define NUM_CHANNELS             32
-#define NUM_TRIGGER_STAGES     4
-#define SERIAL_SPEED           B115200
-#define CLOCK_RATE             SR_MHZ(100)
-#define MIN_NUM_SAMPLES        4
-#define DEFAULT_SAMPLERATE     SR_KHZ(200)
-
-/* Command opcodes */
-#define CMD_RESET                  0x00
-#define CMD_RUN                    0x01
-#define CMD_TESTMODE               0x03
-#define CMD_ID                     0x02
-#define CMD_METADATA               0x04
-#define CMD_SET_FLAGS              0x82
-#define CMD_SET_DIVIDER            0x80
-#define CMD_CAPTURE_SIZE           0x81
-#define CMD_SET_TRIGGER_MASK       0xc0
-#define CMD_SET_TRIGGER_VALUE      0xc1
-#define CMD_SET_TRIGGER_CONFIG     0xc2
-
-/* Trigger config */
-#define TRIGGER_START              (1 << 3)
-
-/* Bitmasks for CMD_FLAGS */
-/* 12-13 unused, 14-15 RLE mode (we hardcode mode 0). */
-#define FLAG_INTERNAL_TEST_MODE    (1 << 11)
-#define FLAG_EXTERNAL_TEST_MODE    (1 << 10)
-#define FLAG_SWAP_CHANNELS           (1 << 9)
-#define FLAG_RLE                   (1 << 8)
-#define FLAG_SLOPE_FALLING         (1 << 7)
-#define FLAG_CLOCK_EXTERNAL        (1 << 6)
-#define FLAG_CHANNELGROUP_4        (1 << 5)
-#define FLAG_CHANNELGROUP_3        (1 << 4)
-#define FLAG_CHANNELGROUP_2        (1 << 3)
-#define FLAG_CHANNELGROUP_1        (1 << 2)
-#define FLAG_FILTER                (1 << 1)
-#define FLAG_DEMUX                 (1 << 0)
-
-/* Private, per-device-instance driver context. */
-struct dev_context {
-       /* Fixed device settings */
-       int max_channels;
-       uint32_t max_samples;
-       uint32_t max_samplerate;
-       uint32_t protocol_version;
-
-       /* Acquisition settings */
-       uint64_t cur_samplerate;
-       uint32_t cur_samplerate_divider;
-       uint64_t limit_samples;
-       int capture_ratio;
-       int trigger_at;
-       uint32_t channel_mask;
-       uint32_t trigger_mask[NUM_TRIGGER_STAGES];
-       uint32_t trigger_value[NUM_TRIGGER_STAGES];
-       int num_stages;
-       uint16_t flag_reg;
-
-       /* Operational states */
-       unsigned int num_transfers;
-       unsigned int num_samples;
-       int num_bytes;
-       int cnt_bytes;
-       int cnt_samples;
-       int cnt_samples_rle;
-
-       /* Temporary variables */
-       unsigned int rle_count;
-       unsigned char sample[4];
-       unsigned char tmp_sample[4];
-       unsigned char *raw_sample_buf;
-};
-
-
-SR_PRIV extern const char *ols_channel_names[NUM_CHANNELS + 1];
-
-SR_PRIV int send_shortcommand(struct sr_serial_dev_inst *serial,
-               uint8_t command);
-SR_PRIV int send_longcommand(struct sr_serial_dev_inst *serial,
-               uint8_t command, uint8_t *data);
-SR_PRIV void ols_channel_mask(const struct sr_dev_inst *sdi);
-SR_PRIV int ols_convert_trigger(const struct sr_dev_inst *sdi);
-SR_PRIV struct dev_context *ols_dev_new(void);
-SR_PRIV struct sr_dev_inst *get_metadata(struct sr_serial_dev_inst *serial);
-SR_PRIV int ols_set_samplerate(const struct sr_dev_inst *sdi,
-               uint64_t samplerate);
-SR_PRIV void abort_acquisition(const struct sr_dev_inst *sdi);
-SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data);
-
-#endif
diff --git a/hardware/rigol-ds/api.c b/hardware/rigol-ds/api.c
deleted file mode 100644 (file)
index 872531f..0000000
+++ /dev/null
@@ -1,1040 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012 Martin Ling <martin-git@earth.li>
- * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
- * Copyright (C) 2013 Mathias Grimmberger <mgri@zaphod.sax.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 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 <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-#include "protocol.h"
-
-static const int32_t hwopts[] = {
-       SR_CONF_CONN,
-       SR_CONF_SERIALCOMM
-};
-
-static const int32_t hwcaps[] = {
-       SR_CONF_OSCILLOSCOPE,
-       SR_CONF_TIMEBASE,
-       SR_CONF_TRIGGER_SOURCE,
-       SR_CONF_TRIGGER_SLOPE,
-       SR_CONF_HORIZ_TRIGGERPOS,
-       SR_CONF_NUM_TIMEBASE,
-       SR_CONF_LIMIT_FRAMES,
-       SR_CONF_SAMPLERATE,
-};
-
-static const int32_t analog_hwcaps[] = {
-       SR_CONF_NUM_VDIV,
-       SR_CONF_VDIV,
-       SR_CONF_COUPLING,
-       SR_CONF_DATA_SOURCE,
-};
-
-static const uint64_t timebases[][2] = {
-       /* nanoseconds */
-       { 1, 1000000000 },
-       { 2, 1000000000 },
-       { 5, 1000000000 },
-       { 10, 1000000000 },
-       { 20, 1000000000 },
-       { 50, 1000000000 },
-       { 100, 1000000000 },
-       { 500, 1000000000 },
-       /* microseconds */
-       { 1, 1000000 },
-       { 2, 1000000 },
-       { 5, 1000000 },
-       { 10, 1000000 },
-       { 20, 1000000 },
-       { 50, 1000000 },
-       { 100, 1000000 },
-       { 200, 1000000 },
-       { 500, 1000000 },
-       /* milliseconds */
-       { 1, 1000 },
-       { 2, 1000 },
-       { 5, 1000 },
-       { 10, 1000 },
-       { 20, 1000 },
-       { 50, 1000 },
-       { 100, 1000 },
-       { 200, 1000 },
-       { 500, 1000 },
-       /* seconds */
-       { 1, 1 },
-       { 2, 1 },
-       { 5, 1 },
-       { 10, 1 },
-       { 20, 1 },
-       { 50, 1 },
-       { 100, 1 },
-       { 200, 1 },
-       { 500, 1 },
-       { 1000, 1 },
-};
-
-static const uint64_t vdivs[][2] = {
-       /* microvolts */
-       { 500, 1000000 },
-       /* millivolts */
-       { 1, 1000 },
-       { 2, 1000 },
-       { 5, 1000 },
-       { 10, 1000 },
-       { 20, 1000 },
-       { 50, 1000 },
-       { 100, 1000 },
-       { 200, 1000 },
-       { 500, 1000 },
-       /* volts */
-       { 1, 1 },
-       { 2, 1 },
-       { 5, 1 },
-       { 10, 1 },
-};
-
-#define NUM_TIMEBASE  ARRAY_SIZE(timebases)
-#define NUM_VDIV      ARRAY_SIZE(vdivs)
-
-static const char *trigger_sources[] = {
-       "CH1",
-       "CH2",
-       "CH3",
-       "CH4",
-       "EXT",
-       "AC Line",
-       "D0",
-       "D1",
-       "D2",
-       "D3",
-       "D4",
-       "D5",
-       "D6",
-       "D7",
-       "D8",
-       "D9",
-       "D10",
-       "D11",
-       "D12",
-       "D13",
-       "D14",
-       "D15",
-};
-
-static const char *trigger_slopes[] = {
-       "r",
-       "f",
-};
-
-static const char *coupling[] = {
-       "AC",
-       "DC",
-       "GND",
-};
-
-/* Do not change the order of entries */
-static const char *data_sources[] = {
-       "Live",
-       "Memory",
-       "Segmented",
-};
-
-enum vendor {
-       RIGOL,
-       AGILENT,
-};
-
-enum series {
-       VS5000,
-       DS1000,
-       DS2000,
-       DS2000A,
-       DSO1000,
-};
-
-/* short name, full name */
-static const struct rigol_ds_vendor supported_vendors[] = {
-       [RIGOL] = {"Rigol", "Rigol Technologies"},
-       [AGILENT] = {"Agilent", "Rigol Technologies"},
-};
-
-#define VENDOR(x) &supported_vendors[x]
-/* vendor, series, protocol, max timebase, min vdiv, number of horizontal divs,
- * live waveform samples, memory buffer samples */
-static const struct rigol_ds_series supported_series[] = {
-       [VS5000] = {VENDOR(RIGOL), "VS5000", PROTOCOL_V1, FORMAT_RAW,
-               {50, 1}, {2, 1000}, 14, 2048, 0},
-       [DS1000] = {VENDOR(RIGOL), "DS1000", PROTOCOL_V2, FORMAT_IEEE488_2,
-               {50, 1}, {2, 1000}, 12, 600, 1048576},
-       [DS2000] = {VENDOR(RIGOL), "DS2000", PROTOCOL_V3, FORMAT_IEEE488_2,
-               {500, 1}, {2, 1000}, 14, 1400, 14000},
-       [DS2000A] = {VENDOR(RIGOL), "DS2000A", PROTOCOL_V3, FORMAT_IEEE488_2,
-               {1000, 1}, {500, 1000000}, 14, 1400, 14000},
-       [DSO1000] = {VENDOR(AGILENT), "DSO1000", PROTOCOL_V3, FORMAT_IEEE488_2,
-               {50, 1}, {2, 1000}, 12, 600, 20480},
-};
-
-#define SERIES(x) &supported_series[x]
-/* series, model, min timebase, analog channels, digital */
-static const struct rigol_ds_model supported_models[] = {
-       {SERIES(VS5000), "VS5022", {20, 1000000000}, 2, false},
-       {SERIES(VS5000), "VS5042", {10, 1000000000}, 2, false},
-       {SERIES(VS5000), "VS5062", {5, 1000000000}, 2, false},
-       {SERIES(VS5000), "VS5102", {2, 1000000000}, 2, false},
-       {SERIES(VS5000), "VS5202", {2, 1000000000}, 2, false},
-       {SERIES(VS5000), "VS5022D", {20, 1000000000}, 2, true},
-       {SERIES(VS5000), "VS5042D", {10, 1000000000}, 2, true},
-       {SERIES(VS5000), "VS5062D", {5, 1000000000}, 2, true},
-       {SERIES(VS5000), "VS5102D", {2, 1000000000}, 2, true},
-       {SERIES(VS5000), "VS5202D", {2, 1000000000}, 2, true},
-       {SERIES(DS1000), "DS1052E", {5, 1000000000}, 2, false},
-       {SERIES(DS1000), "DS1102E", {2, 1000000000}, 2, false},
-       {SERIES(DS1000), "DS1152E", {2, 1000000000}, 2, false},
-       {SERIES(DS1000), "DS1052D", {5, 1000000000}, 2, true},
-       {SERIES(DS1000), "DS1102D", {2, 1000000000}, 2, true},
-       {SERIES(DS1000), "DS1152D", {2, 1000000000}, 2, true},
-       {SERIES(DS2000), "DS2072", {5, 1000000000}, 2, false},
-       {SERIES(DS2000), "DS2102", {5, 1000000000}, 2, false},
-       {SERIES(DS2000), "DS2202", {2, 1000000000}, 2, false},
-       {SERIES(DS2000), "DS2302", {1, 1000000000}, 2, false},
-       {SERIES(DS2000A), "DS2072A", {5, 1000000000}, 2, false},
-       {SERIES(DS2000A), "DS2102A", {5, 1000000000}, 2, false},
-       {SERIES(DS2000A), "DS2202A", {2, 1000000000}, 2, false},
-       {SERIES(DS2000A), "DS2302A", {1, 1000000000}, 2, false},
-       {SERIES(DSO1000), "DSO1002A", {5, 1000000000}, 2, false},
-       {SERIES(DSO1000), "DSO1004A", {5, 1000000000}, 4, false},
-       {SERIES(DSO1000), "DSO1012A", {2, 1000000000}, 2, false},
-       {SERIES(DSO1000), "DSO1014A", {2, 1000000000}, 4, false},
-       {SERIES(DSO1000), "DSO1022A", {2, 1000000000}, 2, false},
-       {SERIES(DSO1000), "DSO1024A", {2, 1000000000}, 4, false},
-};
-
-SR_PRIV struct sr_dev_driver rigol_ds_driver_info;
-static struct sr_dev_driver *di = &rigol_ds_driver_info;
-
-static void clear_helper(void *priv)
-{
-       struct dev_context *devc;
-
-       devc = priv;
-       g_free(devc->data);
-       g_free(devc->buffer);
-       g_free(devc->coupling[0]);
-       g_free(devc->coupling[1]);
-       g_free(devc->trigger_source);
-       g_free(devc->trigger_slope);
-       g_slist_free(devc->analog_groups[0].channels);
-       g_slist_free(devc->analog_groups[1].channels);
-       g_slist_free(devc->digital_group.channels);
-}
-
-static int dev_clear(void)
-{
-       return std_dev_clear(di, clear_helper);
-}
-
-static int init(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, di, LOG_PREFIX);
-}
-
-static struct sr_dev_inst *probe_device(struct sr_scpi_dev_inst *scpi)
-{
-       struct dev_context *devc;
-       struct sr_dev_inst *sdi;
-       struct sr_scpi_hw_info *hw_info;
-       struct sr_channel *ch;
-       long n[3];
-       unsigned int i;
-       const struct rigol_ds_model *model = NULL;
-       gchar *channel_name, **version;
-
-       if (sr_scpi_get_hw_id(scpi, &hw_info) != SR_OK) {
-               sr_info("Couldn't get IDN response, retrying.");
-               sr_scpi_close(scpi);
-               sr_scpi_open(scpi);
-               if (sr_scpi_get_hw_id(scpi, &hw_info) != SR_OK) {
-                       sr_info("Couldn't get IDN response.");
-                       return NULL;
-               }
-       }
-
-       for (i = 0; i < ARRAY_SIZE(supported_models); i++) {
-               if (!strcasecmp(hw_info->manufacturer,
-                                       supported_models[i].series->vendor->full_name) &&
-                               !strcmp(hw_info->model, supported_models[i].name)) {
-                       model = &supported_models[i];
-                       break;
-               }
-       }
-
-       if (!model || !(sdi = sr_dev_inst_new(0, SR_ST_ACTIVE,
-                                             model->series->vendor->name,
-                                                 model->name,
-                                                 hw_info->firmware_version))) {
-               sr_scpi_hw_info_free(hw_info);
-               return NULL;
-       }
-
-       sdi->conn = scpi;
-
-       sdi->driver = di;
-       sdi->inst_type = SR_INST_SCPI;
-
-       if (!(devc = g_try_malloc0(sizeof(struct dev_context))))
-               return NULL;
-
-       devc->limit_frames = 0;
-       devc->model = model;
-       devc->format = model->series->format;
-
-       /* DS1000 models with firmware before 0.2.4 used the old data format. */
-       if (model->series == SERIES(DS1000)) {
-               version = g_strsplit(hw_info->firmware_version, ".", 0);
-               do {
-                       if (!version[0] || !version[1] || !version[2])
-                               break;
-                       if (version[0][0] == 0 || version[1][0] == 0 || version[2][0] == 0)
-                               break;
-                       for (i = 0; i < 3; i++) {
-                               if (sr_atol(version[i], &n[i]) != SR_OK)
-                                       break;
-                       }
-                       if (i != 3)
-                               break;
-                       if (n[0] != 0 || n[1] > 2)
-                               break;
-                       if (n[1] == 2 && n[2] > 3)
-                               break;
-                       sr_dbg("Found DS1000 firmware < 0.2.4, using raw data format.");
-                       devc->format = FORMAT_RAW;
-               } while(0);
-               g_strfreev(version);
-       }
-
-       sr_scpi_hw_info_free(hw_info);
-
-       for (i = 0; i < model->analog_channels; i++) {
-               if (!(channel_name = g_strdup_printf("CH%d", i + 1)))
-                       return NULL;
-               ch = sr_channel_new(i, SR_CHANNEL_ANALOG, TRUE, channel_name);
-               sdi->channels = g_slist_append(sdi->channels, ch);
-               devc->analog_groups[i].name = channel_name;
-               devc->analog_groups[i].channels = g_slist_append(NULL, ch);
-               sdi->channel_groups = g_slist_append(sdi->channel_groups,
-                               &devc->analog_groups[i]);
-       }
-
-       if (devc->model->has_digital) {
-               for (i = 0; i < 16; i++) {
-                       if (!(channel_name = g_strdup_printf("D%d", i)))
-                               return NULL;
-                       ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE, channel_name);
-                       g_free(channel_name);
-                       if (!ch)
-                               return NULL;
-                       sdi->channels = g_slist_append(sdi->channels, ch);
-                       devc->digital_group.channels = g_slist_append(
-                                       devc->digital_group.channels, ch);
-               }
-               devc->digital_group.name = "LA";
-               sdi->channel_groups = g_slist_append(sdi->channel_groups,
-                               &devc->digital_group);
-       }
-
-       for (i = 0; i < NUM_TIMEBASE; i++) {
-               if (!memcmp(&devc->model->min_timebase, &timebases[i], sizeof(uint64_t[2])))
-                       devc->timebases = &timebases[i];
-               if (!memcmp(&devc->model->series->max_timebase, &timebases[i], sizeof(uint64_t[2])))
-                       devc->num_timebases = &timebases[i] - devc->timebases + 1;
-       }
-
-       for (i = 0; i < NUM_VDIV; i++)
-               if (!memcmp(&devc->model->series->min_vdiv, &vdivs[i], sizeof(uint64_t[2])))
-                       devc->vdivs = &vdivs[i];
-
-       if (!(devc->buffer = g_try_malloc(ACQ_BUFFER_SIZE)))
-               return NULL;
-       if (!(devc->data = g_try_malloc(ACQ_BUFFER_SIZE * sizeof(float))))
-               return NULL;
-
-       devc->data_source = DATA_SOURCE_LIVE;
-
-       sdi->priv = devc;
-
-       return sdi;
-}
-
-static GSList *scan(GSList *options)
-{
-       return sr_scpi_scan(di->priv, options, probe_device);
-}
-
-static GSList *dev_list(void)
-{
-       return ((struct drv_context *)(di->priv))->instances;
-}
-
-static int dev_open(struct sr_dev_inst *sdi)
-{
-       struct sr_scpi_dev_inst *scpi = sdi->conn;
-
-       if (sr_scpi_open(scpi) < 0)
-               return SR_ERR;
-
-       if (rigol_ds_get_dev_cfg(sdi) != SR_OK)
-               return SR_ERR;
-
-       sdi->status = SR_ST_ACTIVE;
-
-       return SR_OK;
-}
-
-static int dev_close(struct sr_dev_inst *sdi)
-{
-       struct sr_scpi_dev_inst *scpi;
-       struct dev_context *devc;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       scpi = sdi->conn;
-       devc = sdi->priv;
-
-       if (devc->model->series->protocol == PROTOCOL_V2)
-               rigol_ds_config_set(sdi, ":KEY:LOCK DISABLE");
-
-       if (scpi) {
-               if (sr_scpi_close(scpi) < 0)
-                       return SR_ERR;
-               sdi->status = SR_ST_INACTIVE;
-       }
-
-       return SR_OK;
-}
-
-static int cleanup(void)
-{
-       return dev_clear();
-}
-
-static int analog_frame_size(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc = sdi->priv;
-       struct sr_channel *ch;
-       int analog_channels = 0;
-       GSList *l;
-
-       for (l = sdi->channels; l; l = l->next) {
-               ch = l->data;
-               if (ch->type == SR_CHANNEL_ANALOG && ch->enabled)
-                       analog_channels++;
-       }
-
-       if (analog_channels == 0)
-               return 0;
-
-       switch (devc->data_source) {
-       case DATA_SOURCE_LIVE:
-               return devc->model->series->live_samples;
-       case DATA_SOURCE_MEMORY:
-               return devc->model->series->buffer_samples / analog_channels;
-       default:
-               return 0;
-       }
-}
-
-static int digital_frame_size(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc = sdi->priv;
-
-       switch (devc->data_source) {
-       case DATA_SOURCE_LIVE:
-               return devc->model->series->live_samples * 2;
-       case DATA_SOURCE_MEMORY:
-               return devc->model->series->buffer_samples * 2;
-       default:
-               return 0;
-       }
-}
-
-static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       struct sr_channel *ch;
-       const char *tmp_str;
-       uint64_t samplerate;
-       int analog_channel = -1;
-       float smallest_diff = 0.0000000001;
-       int idx = -1;
-       unsigned i;
-
-       if (!sdi || !(devc = sdi->priv))
-               return SR_ERR_ARG;
-
-       /* If a channel group is specified, it must be a valid one. */
-       if (cg && !g_slist_find(sdi->channel_groups, cg)) {
-               sr_err("Invalid channel group specified.");
-               return SR_ERR;
-       }
-
-       if (cg) {
-               ch = g_slist_nth_data(cg->channels, 0);
-               if (!ch)
-                       return SR_ERR;
-               if (ch->type == SR_CHANNEL_ANALOG) {
-                       if (ch->name[2] < '1' || ch->name[2] > '4')
-                               return SR_ERR;
-                       analog_channel = ch->name[2] - '1';
-               }
-       }
-
-       switch (id) {
-       case SR_CONF_NUM_TIMEBASE:
-               *data = g_variant_new_int32(devc->model->series->num_horizontal_divs);
-               break;
-       case SR_CONF_NUM_VDIV:
-               *data = g_variant_new_int32(NUM_VDIV);
-       case SR_CONF_DATA_SOURCE:
-               if (devc->data_source == DATA_SOURCE_LIVE)
-                       *data = g_variant_new_string("Live");
-               else if (devc->data_source == DATA_SOURCE_MEMORY)
-                       *data = g_variant_new_string("Memory");
-               else
-                       *data = g_variant_new_string("Segmented");
-               break;
-       case SR_CONF_SAMPLERATE:
-               if (devc->data_source == DATA_SOURCE_LIVE) {
-                       samplerate = analog_frame_size(sdi) /
-                               (devc->timebase * devc->model->series->num_horizontal_divs);
-                       *data = g_variant_new_uint64(samplerate);
-               } else {
-                       return SR_ERR_NA;
-               }
-               break;
-       case SR_CONF_TRIGGER_SOURCE:
-               if (!strcmp(devc->trigger_source, "ACL"))
-                       tmp_str = "AC Line";
-               else if (!strcmp(devc->trigger_source, "CHAN1"))
-                       tmp_str = "CH1";
-               else if (!strcmp(devc->trigger_source, "CHAN2"))
-                       tmp_str = "CH2";
-               else if (!strcmp(devc->trigger_source, "CHAN3"))
-                       tmp_str = "CH3";
-               else if (!strcmp(devc->trigger_source, "CHAN4"))
-                       tmp_str = "CH4";
-               else
-                       tmp_str = devc->trigger_source;
-               *data = g_variant_new_string(tmp_str);
-               break;
-       case SR_CONF_TRIGGER_SLOPE:
-               if (!strcmp(devc->trigger_slope, "POS"))
-                       tmp_str = "r";
-               else if (!strcmp(devc->trigger_slope, "NEG"))
-                       tmp_str = "f";
-               else
-                       return SR_ERR_NA;
-               *data = g_variant_new_string(tmp_str);
-               break;
-       case SR_CONF_TIMEBASE:
-               for (i = 0; i < devc->num_timebases; i++) {
-                       float tb = (float)devc->timebases[i][0] / devc->timebases[i][1];
-                       float diff = fabs(devc->timebase - tb);
-                       if (diff < smallest_diff) {
-                               smallest_diff = diff;
-                               idx = i;
-                       }
-               }
-               if (idx < 0)
-                       return SR_ERR_NA;
-               *data = g_variant_new("(tt)", devc->timebases[idx][0],
-                                             devc->timebases[idx][1]);
-               break;
-       case SR_CONF_VDIV:
-               if (analog_channel < 0)
-                       return SR_ERR_NA;
-               for (i = 0; i < ARRAY_SIZE(vdivs); i++) {
-                       float vdiv = (float)vdivs[i][0] / vdivs[i][1];
-                       float diff = fabs(devc->vdiv[analog_channel] - vdiv);
-                       if (diff < smallest_diff) {
-                               smallest_diff = diff;
-                               idx = i;
-                       }
-               }
-               if (idx < 0)
-                       return SR_ERR_NA;
-               *data = g_variant_new("(tt)", vdivs[idx][0], vdivs[idx][1]);
-               break;
-       case SR_CONF_COUPLING:
-               if (analog_channel < 0)
-                       return SR_ERR_NA;
-               *data = g_variant_new_string(devc->coupling[analog_channel]);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       uint64_t p, q;
-       double t_dbl;
-       unsigned int i, j;
-       int ret;
-       const char *tmp_str;
-       char buffer[16];
-
-       if (!(devc = sdi->priv))
-               return SR_ERR_ARG;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       /* If a channel group is specified, it must be a valid one. */
-       if (cg && !g_slist_find(sdi->channel_groups, cg)) {
-               sr_err("Invalid channel group specified.");
-               return SR_ERR;
-       }
-
-       ret = SR_OK;
-       switch (id) {
-       case SR_CONF_LIMIT_FRAMES:
-               devc->limit_frames = g_variant_get_uint64(data);
-               break;
-       case SR_CONF_TRIGGER_SLOPE:
-               tmp_str = g_variant_get_string(data, NULL);
-
-               if (!tmp_str || !(tmp_str[0] == 'f' || tmp_str[0] == 'r'))
-                       return SR_ERR_ARG;
-
-               g_free(devc->trigger_slope);
-               devc->trigger_slope = g_strdup((tmp_str[0] == 'r') ? "POS" : "NEG");
-               ret = rigol_ds_config_set(sdi, ":TRIG:EDGE:SLOP %s", devc->trigger_slope);
-               break;
-       case SR_CONF_HORIZ_TRIGGERPOS:
-               t_dbl = g_variant_get_double(data);
-               if (t_dbl < 0.0 || t_dbl > 1.0)
-                       return SR_ERR;
-               devc->horiz_triggerpos = t_dbl;
-               /* We have the trigger offset as a percentage of the frame, but
-                * need to express this in seconds. */
-               t_dbl = -(devc->horiz_triggerpos - 0.5) * devc->timebase * devc->num_timebases;
-               g_ascii_formatd(buffer, sizeof(buffer), "%.6f", t_dbl);
-               ret = rigol_ds_config_set(sdi, ":TIM:OFFS %s", buffer);
-               break;
-       case SR_CONF_TIMEBASE:
-               g_variant_get(data, "(tt)", &p, &q);
-               for (i = 0; i < devc->num_timebases; i++) {
-                       if (devc->timebases[i][0] == p && devc->timebases[i][1] == q) {
-                               devc->timebase = (float)p / q;
-                               g_ascii_formatd(buffer, sizeof(buffer), "%.9f",
-                                               devc->timebase);
-                               ret = rigol_ds_config_set(sdi, ":TIM:SCAL %s", buffer);
-                               break;
-                       }
-               }
-               if (i == devc->num_timebases)
-                       ret = SR_ERR_ARG;
-               break;
-       case SR_CONF_TRIGGER_SOURCE:
-               tmp_str = g_variant_get_string(data, NULL);
-               for (i = 0; i < ARRAY_SIZE(trigger_sources); i++) {
-                       if (!strcmp(trigger_sources[i], tmp_str)) {
-                               g_free(devc->trigger_source);
-                               devc->trigger_source = g_strdup(trigger_sources[i]);
-                               if (!strcmp(devc->trigger_source, "AC Line"))
-                                       tmp_str = "ACL";
-                               else if (!strcmp(devc->trigger_source, "CH1"))
-                                       tmp_str = "CHAN1";
-                               else if (!strcmp(devc->trigger_source, "CH2"))
-                                       tmp_str = "CHAN2";
-                               else if (!strcmp(devc->trigger_source, "CH3"))
-                                       tmp_str = "CHAN3";
-                               else if (!strcmp(devc->trigger_source, "CH4"))
-                                       tmp_str = "CHAN4";
-                               else
-                                       tmp_str = (char *)devc->trigger_source;
-                               ret = rigol_ds_config_set(sdi, ":TRIG:EDGE:SOUR %s", tmp_str);
-                               break;
-                       }
-               }
-               if (i == ARRAY_SIZE(trigger_sources))
-                       ret = SR_ERR_ARG;
-               break;
-       case SR_CONF_VDIV:
-               if (!cg) {
-                       sr_err("No channel group specified.");
-                       return SR_ERR_CHANNEL_GROUP;
-               }
-               g_variant_get(data, "(tt)", &p, &q);
-               for (i = 0; i < 2; i++) {
-                       if (cg == &devc->analog_groups[i]) {
-                               for (j = 0; j < ARRAY_SIZE(vdivs); j++) {
-                                       if (vdivs[j][0] != p || vdivs[j][1] != q)
-                                               continue;
-                                       devc->vdiv[i] = (float)p / q;
-                                       g_ascii_formatd(buffer, sizeof(buffer), "%.3f",
-                                                       devc->vdiv[i]);
-                                       return rigol_ds_config_set(sdi, ":CHAN%d:SCAL %s", i + 1,
-                                                       buffer);
-                               }
-                               return SR_ERR_ARG;
-                       }
-               }
-               return SR_ERR_NA;
-       case SR_CONF_COUPLING:
-               if (!cg) {
-                       sr_err("No channel group specified.");
-                       return SR_ERR_CHANNEL_GROUP;
-               }
-               tmp_str = g_variant_get_string(data, NULL);
-               for (i = 0; i < 2; i++) {
-                       if (cg == &devc->analog_groups[i]) {
-                               for (j = 0; j < ARRAY_SIZE(coupling); j++) {
-                                       if (!strcmp(tmp_str, coupling[j])) {
-                                               g_free(devc->coupling[i]);
-                                               devc->coupling[i] = g_strdup(coupling[j]);
-                                               return rigol_ds_config_set(sdi, ":CHAN%d:COUP %s", i + 1,
-                                                               devc->coupling[i]);
-                                       }
-                               }
-                               return SR_ERR_ARG;
-                       }
-               }
-               return SR_ERR_NA;
-       case SR_CONF_DATA_SOURCE:
-               tmp_str = g_variant_get_string(data, NULL);
-               if (!strcmp(tmp_str, "Live"))
-                       devc->data_source = DATA_SOURCE_LIVE;
-               else if (devc->model->series->protocol >= PROTOCOL_V2
-                       && !strcmp(tmp_str, "Memory"))
-                       devc->data_source = DATA_SOURCE_MEMORY;
-               else if (devc->model->series->protocol >= PROTOCOL_V3
-                        && !strcmp(tmp_str, "Segmented"))
-                       devc->data_source = DATA_SOURCE_SEGMENTED;
-               else
-                       return SR_ERR;
-               break;
-       default:
-               ret = SR_ERR_NA;
-               break;
-       }
-
-       return ret;
-}
-
-static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       GVariant *tuple, *rational[2];
-       GVariantBuilder gvb;
-       unsigned int i;
-       struct dev_context *devc = NULL;
-
-       if (sdi)
-               devc = sdi->priv;
-
-       if (key == SR_CONF_SCAN_OPTIONS) {
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
-               return SR_OK;
-       } else if (key == SR_CONF_DEVICE_OPTIONS && cg == NULL) {
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                       hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
-               return SR_OK;
-       }
-
-       /* Every other option requires a valid device instance. */
-       if (!sdi || !(devc = sdi->priv))
-               return SR_ERR_ARG;
-
-       /* If a channel group is specified, it must be a valid one. */
-       if (cg) {
-               if (cg != &devc->analog_groups[0]
-                               && cg != &devc->analog_groups[1]) {
-                       sr_err("Invalid channel group specified.");
-                       return SR_ERR;
-               }
-       }
-
-       switch (key) {
-       case SR_CONF_DEVICE_OPTIONS:
-               if (!cg) {
-                       sr_err("No channel group specified.");
-                       return SR_ERR_CHANNEL_GROUP;
-               }
-               if (cg == &devc->digital_group) {
-                       *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               NULL, 0, sizeof(int32_t));
-                       return SR_OK;
-               } else {
-                       for (i = 0; i < 2; i++) {
-                               if (cg == &devc->analog_groups[i]) {
-                                       *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                                               analog_hwcaps, ARRAY_SIZE(analog_hwcaps), sizeof(int32_t));
-                                       return SR_OK;
-                               }
-                       }
-                       return SR_ERR_NA;
-               }
-               break;
-       case SR_CONF_COUPLING:
-               if (!cg) {
-                       sr_err("No channel group specified.");
-                       return SR_ERR_CHANNEL_GROUP;
-               }
-               *data = g_variant_new_strv(coupling, ARRAY_SIZE(coupling));
-               break;
-       case SR_CONF_VDIV:
-               if (!devc)
-                       /* Can't know this until we have the exact model. */
-                       return SR_ERR_ARG;
-               if (!cg) {
-                       sr_err("No channel group specified.");
-                       return SR_ERR_CHANNEL_GROUP;
-               }
-               g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
-               for (i = 0; i < NUM_VDIV; i++) {
-                       rational[0] = g_variant_new_uint64(devc->vdivs[i][0]);
-                       rational[1] = g_variant_new_uint64(devc->vdivs[i][1]);
-                       tuple = g_variant_new_tuple(rational, 2);
-                       g_variant_builder_add_value(&gvb, tuple);
-               }
-               *data = g_variant_builder_end(&gvb);
-               break;
-       case SR_CONF_TIMEBASE:
-               if (!devc)
-                       /* Can't know this until we have the exact model. */
-                       return SR_ERR_ARG;
-               if (devc->num_timebases <= 0)
-                       return SR_ERR_NA;
-               g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
-               for (i = 0; i < devc->num_timebases; i++) {
-                       rational[0] = g_variant_new_uint64(devc->timebases[i][0]);
-                       rational[1] = g_variant_new_uint64(devc->timebases[i][1]);
-                       tuple = g_variant_new_tuple(rational, 2);
-                       g_variant_builder_add_value(&gvb, tuple);
-               }
-               *data = g_variant_builder_end(&gvb);
-               break;
-       case SR_CONF_TRIGGER_SOURCE:
-               if (!devc)
-                       /* Can't know this until we have the exact model. */
-                       return SR_ERR_ARG;
-               *data = g_variant_new_strv(trigger_sources,
-                               devc->model->has_digital ? ARRAY_SIZE(trigger_sources) : 4);
-               break;
-       case SR_CONF_TRIGGER_SLOPE:
-               *data = g_variant_new_strv(trigger_slopes, ARRAY_SIZE(trigger_slopes));
-               break;
-       case SR_CONF_DATA_SOURCE:
-               if (!devc)
-                       /* Can't know this until we have the exact model. */
-                       return SR_ERR_ARG;
-               switch (devc->model->series->protocol) {
-               case PROTOCOL_V1:
-                       *data = g_variant_new_strv(data_sources, ARRAY_SIZE(data_sources) - 2);
-                       break;
-               case PROTOCOL_V2:
-                       *data = g_variant_new_strv(data_sources, ARRAY_SIZE(data_sources) - 1);
-                       break;
-               default:
-                       *data = g_variant_new_strv(data_sources, ARRAY_SIZE(data_sources));
-                       break;
-               }
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct sr_scpi_dev_inst *scpi;
-       struct dev_context *devc;
-       struct sr_channel *ch;
-       struct sr_datafeed_packet packet;
-       GSList *l;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       scpi = sdi->conn;
-       devc = sdi->priv;
-
-       devc->num_frames = 0;
-
-       for (l = sdi->channels; l; l = l->next) {
-               ch = l->data;
-               sr_dbg("handling channel %s", ch->name);
-               if (ch->type == SR_CHANNEL_ANALOG) {
-                       if (ch->enabled)
-                               devc->enabled_analog_channels = g_slist_append(
-                                               devc->enabled_analog_channels, ch);
-                       if (ch->enabled != devc->analog_channels[ch->index]) {
-                               /* Enabled channel is currently disabled, or vice versa. */
-                               if (rigol_ds_config_set(sdi, ":CHAN%d:DISP %s", ch->index + 1,
-                                               ch->enabled ? "ON" : "OFF") != SR_OK)
-                                       return SR_ERR;
-                               devc->analog_channels[ch->index] = ch->enabled;
-                       }
-               } else if (ch->type == SR_CHANNEL_LOGIC) {
-                       if (ch->enabled) {
-                               devc->enabled_digital_channels = g_slist_append(
-                                               devc->enabled_digital_channels, ch);
-                               /* Turn on LA module if currently off. */
-                               if (!devc->la_enabled) {
-                                       if (rigol_ds_config_set(sdi, ":LA:DISP ON") != SR_OK)
-                                               return SR_ERR;
-                                       devc->la_enabled = TRUE;
-                               }
-                       }
-                       if (ch->enabled != devc->digital_channels[ch->index]) {
-                               /* Enabled channel is currently disabled, or vice versa. */
-                               if (rigol_ds_config_set(sdi, ":DIG%d:TURN %s", ch->index,
-                                               ch->enabled ? "ON" : "OFF") != SR_OK)
-                                       return SR_ERR;
-                               devc->digital_channels[ch->index] = ch->enabled;
-                       }
-               }
-       }
-
-       if (!devc->enabled_analog_channels && !devc->enabled_digital_channels)
-               return SR_ERR;
-
-       /* Turn off LA module if on and no digital channels selected. */
-       if (devc->la_enabled && !devc->enabled_digital_channels)
-               if (rigol_ds_config_set(sdi, ":LA:DISP OFF") != SR_OK)
-                       return SR_ERR;
-
-       /* Set memory mode. */
-       if (devc->data_source == DATA_SOURCE_SEGMENTED) {
-               sr_err("Data source 'Segmented' not yet supported");
-               return SR_ERR;
-       }
-
-       devc->analog_frame_size = analog_frame_size(sdi);
-       devc->digital_frame_size = digital_frame_size(sdi);
-
-       switch (devc->model->series->protocol) {
-       case PROTOCOL_V2:
-               if (rigol_ds_config_set(sdi, ":ACQ:MEMD LONG") != SR_OK)
-                       return SR_ERR;
-               break;
-       case PROTOCOL_V3:
-               /* Apparently for the DS2000 the memory
-                * depth can only be set in Running state -
-                * this matches the behaviour of the UI. */
-               if (rigol_ds_config_set(sdi, ":RUN") != SR_OK)
-                       return SR_ERR;
-               if (rigol_ds_config_set(sdi, ":ACQ:MDEP %d",
-                                       devc->analog_frame_size) != SR_OK)
-                       return SR_ERR;
-               if (rigol_ds_config_set(sdi, ":STOP") != SR_OK)
-                       return SR_ERR;
-               break;
-       default:
-               break;
-       }
-
-       if (devc->data_source == DATA_SOURCE_LIVE)
-               if (rigol_ds_config_set(sdi, ":RUN") != SR_OK)
-                       return SR_ERR;
-
-       sr_scpi_source_add(sdi->session, scpi, G_IO_IN, 50,
-                       rigol_ds_receive, (void *)sdi);
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(cb_data, LOG_PREFIX);
-
-       if (devc->enabled_analog_channels)
-               devc->channel_entry = devc->enabled_analog_channels;
-       else
-               devc->channel_entry = devc->enabled_digital_channels;
-
-       if (rigol_ds_capture_start(sdi) != SR_OK)
-               return SR_ERR;
-
-       /* Start of first frame. */
-       packet.type = SR_DF_FRAME_BEGIN;
-       sr_session_send(cb_data, &packet);
-
-       return SR_OK;
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct dev_context *devc;
-       struct sr_scpi_dev_inst *scpi;
-       struct sr_datafeed_packet packet;
-
-       (void)cb_data;
-
-       devc = sdi->priv;
-
-       if (sdi->status != SR_ST_ACTIVE) {
-               sr_err("Device inactive, can't stop acquisition.");
-               return SR_ERR;
-       }
-
-       /* End of last frame. */
-       packet.type = SR_DF_END;
-       sr_session_send(sdi, &packet);
-
-       g_slist_free(devc->enabled_analog_channels);
-       g_slist_free(devc->enabled_digital_channels);
-       devc->enabled_analog_channels = NULL;
-       devc->enabled_digital_channels = NULL;
-       scpi = sdi->conn;
-       sr_scpi_source_remove(sdi->session, scpi);
-
-       return SR_OK;
-}
-
-SR_PRIV struct sr_dev_driver rigol_ds_driver_info = {
-       .name = "rigol-ds",
-       .longname = "Rigol DS",
-       .api_version = 1,
-       .init = init,
-       .cleanup = cleanup,
-       .scan = scan,
-       .dev_list = dev_list,
-       .dev_clear = dev_clear,
-       .config_get = config_get,
-       .config_set = config_set,
-       .config_list = config_list,
-       .dev_open = dev_open,
-       .dev_close = dev_close,
-       .dev_acquisition_start = dev_acquisition_start,
-       .dev_acquisition_stop = dev_acquisition_stop,
-       .priv = NULL,
-};
diff --git a/hardware/rigol-ds/protocol.c b/hardware/rigol-ds/protocol.c
deleted file mode 100644 (file)
index 97cb353..0000000
+++ /dev/null
@@ -1,812 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012 Martin Ling <martin-git@earth.li>
- * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
- * Copyright (C) 2013 Mathias Grimmberger <mgri@zaphod.sax.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 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 <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <math.h>
-#include <ctype.h>
-#include <time.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-#include "protocol.h"
-
-/*
- * This is a unified protocol driver for the DS1000 and DS2000 series.
- *
- * DS1000 support tested with a Rigol DS1102D.
- *
- * DS2000 support tested with a Rigol DS2072 using firmware version 01.01.00.02.
- *
- * The Rigol DS2000 series scopes try to adhere to the IEEE 488.2 (I think)
- * standard. If you want to read it - it costs real money...
- *
- * Every response from the scope has a linefeed appended because the
- * standard says so. In principle this could be ignored because sending the
- * next command clears the output queue of the scope. This driver tries to
- * avoid doing that because it may cause an error being generated inside the
- * scope and who knows what bugs the firmware has WRT this.
- *
- * Waveform data is transferred in a format called "arbitrary block program
- * data" specified in IEEE 488.2. See Agilents programming manuals for their
- * 2000/3000 series scopes for a nice description.
- *
- * Each data block from the scope has a header, e.g. "#900000001400".
- * The '#' marks the start of a block.
- * Next is one ASCII decimal digit between 1 and 9, this gives the number of
- * ASCII decimal digits following.
- * Last are the ASCII decimal digits giving the number of bytes (not
- * samples!) in the block.
- *
- * After this header as many data bytes as indicated follow.
- *
- * Each data block has a trailing linefeed too.
- */
-
-static int parse_int(const char *str, int *ret)
-{
-       char *e;
-       long tmp;
-
-       errno = 0;
-       tmp = strtol(str, &e, 10);
-       if (e == str || *e != '\0') {
-               sr_dbg("Failed to parse integer: '%s'", str);
-               return SR_ERR;
-       }
-       if (errno) {
-               sr_dbg("Failed to parse integer: '%s', numerical overflow", str);
-               return SR_ERR;
-       }
-       if (tmp > INT_MAX || tmp < INT_MIN) {
-               sr_dbg("Failed to parse integer: '%s', value to large/small", str);
-               return SR_ERR;
-       }
-
-       *ret = (int)tmp;
-       return SR_OK;
-}
-
-/* Set the next event to wait for in rigol_ds_receive */
-static void rigol_ds_set_wait_event(struct dev_context *devc, enum wait_events event)
-{
-       if (event == WAIT_STOP)
-               devc->wait_status = 2;
-       else
-               devc->wait_status = 1;
-       devc->wait_event = event;
-}
-
-/*
- * Waiting for a event will return a timeout after 2 to 3 seconds in order
- * to not block the application.
- */
-static int rigol_ds_event_wait(const struct sr_dev_inst *sdi, char status1, char status2)
-{
-       char *buf;
-       struct dev_context *devc;
-       time_t start;
-
-       if (!(devc = sdi->priv))
-               return SR_ERR;
-
-       start = time(NULL);
-
-       /*
-        * Trigger status may return:
-        * "TD" or "T'D" - triggered
-        * "AUTO"        - autotriggered
-        * "RUN"         - running
-        * "WAIT"        - waiting for trigger
-        * "STOP"        - stopped
-        */
-
-       if (devc->wait_status == 1) {
-               do {
-                       if (time(NULL) - start >= 3) {
-                               sr_dbg("Timeout waiting for trigger");
-                               return SR_ERR_TIMEOUT;
-                       }
-
-                       if (sr_scpi_get_string(sdi->conn, ":TRIG:STAT?", &buf) != SR_OK)
-                               return SR_ERR;
-               } while (buf[0] == status1 || buf[0] == status2);
-
-               devc->wait_status = 2;
-       }
-       if (devc->wait_status == 2) {
-               do {
-                       if (time(NULL) - start >= 3) {
-                               sr_dbg("Timeout waiting for trigger");
-                               return SR_ERR_TIMEOUT;
-                       }
-
-                       if (sr_scpi_get_string(sdi->conn, ":TRIG:STAT?", &buf) != SR_OK)
-                               return SR_ERR;
-               } while (buf[0] != status1 && buf[0] != status2);
-
-               rigol_ds_set_wait_event(devc, WAIT_NONE);
-       }
-
-       return SR_OK;
-}
-
-/*
- * For live capture we need to wait for a new trigger event to ensure that
- * sample data is not returned twice.
- *
- * Unfortunately this will never really work because for sufficiently fast
- * timebases and trigger rates it just can't catch the status changes.
- *
- * What would be needed is a trigger event register with autoreset like the
- * Agilents have. The Rigols don't seem to have anything like this.
- *
- * The workaround is to only wait for the trigger when the timebase is slow
- * enough. Of course this means that for faster timebases sample data can be
- * returned multiple times, this effect is mitigated somewhat by sleeping
- * for about one sweep time in that case.
- */
-static int rigol_ds_trigger_wait(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       long s;
-
-       if (!(devc = sdi->priv))
-               return SR_ERR;
-
-       /* 
-        * If timebase < 50 msecs/DIV just sleep about one sweep time except
-        * for really fast sweeps.
-        */
-       if (devc->timebase < 0.0499) {
-               if (devc->timebase > 0.99e-6) {
-                       /*
-                        * Timebase * num hor. divs * 85(%) * 1e6(usecs) / 100
-                        * -> 85 percent of sweep time
-                        */
-                       s = (devc->timebase * devc->model->series->num_horizontal_divs
-                            * 85e6) / 100L;
-                       sr_spew("Sleeping for %ld usecs instead of trigger-wait", s);
-                       g_usleep(s);
-               }
-               rigol_ds_set_wait_event(devc, WAIT_NONE);
-               return SR_OK;
-       } else {
-               return rigol_ds_event_wait(sdi, 'T', 'A');
-       }
-}
-
-/* Wait for scope to got to "Stop" in single shot mode */
-static int rigol_ds_stop_wait(const struct sr_dev_inst *sdi)
-{
-       return rigol_ds_event_wait(sdi, 'S', 'S');
-}
-
-/* Check that a single shot acquisition actually succeeded on the DS2000 */
-static int rigol_ds_check_stop(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_channel *ch;
-       int tmp;
-
-       if (!(devc = sdi->priv))
-               return SR_ERR;
-
-       ch = devc->channel_entry->data;
-
-       if (devc->model->series->protocol <= PROTOCOL_V2)
-               return SR_OK;
-
-       if (rigol_ds_config_set(sdi, ":WAV:SOUR CHAN%d",
-                         ch->index + 1) != SR_OK)
-               return SR_ERR;
-       /* Check that the number of samples will be accepted */
-       if (rigol_ds_config_set(sdi, ":WAV:POIN %d", devc->analog_frame_size) != SR_OK)
-               return SR_ERR;
-       if (sr_scpi_get_int(sdi->conn, "*ESR?", &tmp) != SR_OK)
-               return SR_ERR;
-       /*
-        * If we get an "Execution error" the scope went from "Single" to
-        * "Stop" without actually triggering. There is no waveform
-        * displayed and trying to download one will fail - the scope thinks
-        * it has 1400 samples (like display memory) and the driver thinks
-        * it has a different number of samples.
-        *
-        * In that case just try to capture something again. Might still
-        * fail in interesting ways.
-        *
-        * Ain't firmware fun?
-        */
-       if (tmp & 0x10) {
-               sr_warn("Single shot acquisition failed, retrying...");
-               /* Sleep a bit, otherwise the single shot will often fail */
-               g_usleep(500000);
-               rigol_ds_config_set(sdi, ":SING");
-               rigol_ds_set_wait_event(devc, WAIT_STOP);
-               return SR_ERR;
-       }
-
-       return SR_OK;
-}
-
-/* Wait for enough data becoming available in scope output buffer */
-static int rigol_ds_block_wait(const struct sr_dev_inst *sdi)
-{
-       char *buf;
-       struct dev_context *devc;
-       time_t start;
-       int len;
-
-       if (!(devc = sdi->priv))
-               return SR_ERR;
-
-       if (devc->model->series->protocol >= PROTOCOL_V3) {
-
-               start = time(NULL);
-
-               do {
-                       if (time(NULL) - start >= 3) {
-                               sr_dbg("Timeout waiting for data block");
-                               return SR_ERR_TIMEOUT;
-                       }
-
-                       /*
-                        * The scope copies data really slowly from sample
-                        * memory to its output buffer, so try not to bother
-                        * it too much with SCPI requests but don't wait too
-                        * long for short sample frame sizes.
-                        */
-                       g_usleep(devc->analog_frame_size < 15000 ? 100000 : 1000000);
-
-                       /* "READ,nnnn" (still working) or "IDLE,nnnn" (finished) */
-                       if (sr_scpi_get_string(sdi->conn, ":WAV:STAT?", &buf) != SR_OK)
-                               return SR_ERR;
-
-                       if (parse_int(buf + 5, &len) != SR_OK)
-                               return SR_ERR;
-               } while (buf[0] == 'R' && len < 1000000);
-       }
-
-       rigol_ds_set_wait_event(devc, WAIT_NONE);
-
-       return SR_OK;
-}
-
-/* Send a configuration setting. */
-SR_PRIV int rigol_ds_config_set(const struct sr_dev_inst *sdi, const char *format, ...)
-{
-       struct dev_context *devc = sdi->priv;
-       va_list args;
-       int ret;
-
-       va_start(args, format);
-       ret = sr_scpi_send_variadic(sdi->conn, format, args);
-       va_end(args);
-
-       if (ret != SR_OK)
-               return SR_ERR;
-
-       if (devc->model->series->protocol == PROTOCOL_V2) {
-               /* The DS1000 series needs this stupid delay, *OPC? doesn't work. */
-               sr_spew("delay %dms", 100);
-               g_usleep(100000);
-               return SR_OK;
-       } else {
-               return sr_scpi_get_opc(sdi->conn);
-       }
-}
-
-/* Start capturing a new frameset */
-SR_PRIV int rigol_ds_capture_start(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       gchar *trig_mode;
-
-       if (!(devc = sdi->priv))
-               return SR_ERR;
-
-       sr_dbg("Starting data capture for frameset %lu of %lu",
-              devc->num_frames + 1, devc->limit_frames);
-
-       switch (devc->model->series->protocol) {
-       case PROTOCOL_V1:
-               rigol_ds_set_wait_event(devc, WAIT_TRIGGER);
-               break;
-       case PROTOCOL_V2:
-               if (devc->data_source == DATA_SOURCE_LIVE) {
-                       if (rigol_ds_config_set(sdi, ":WAV:POIN:MODE NORMAL") != SR_OK)
-                               return SR_ERR;
-                       rigol_ds_set_wait_event(devc, WAIT_TRIGGER);
-               } else {
-                       if (rigol_ds_config_set(sdi, ":STOP") != SR_OK)
-                               return SR_ERR;
-                       if (rigol_ds_config_set(sdi, ":WAV:POIN:MODE RAW") != SR_OK)
-                               return SR_ERR;
-                       if (sr_scpi_get_string(sdi->conn, ":TRIG:MODE?", &trig_mode) != SR_OK)
-                               return SR_ERR;
-                       if (rigol_ds_config_set(sdi, ":TRIG:%s:SWE SING", trig_mode) != SR_OK)
-                               return SR_ERR;
-                       if (rigol_ds_config_set(sdi, ":RUN") != SR_OK)
-                               return SR_ERR;
-                       rigol_ds_set_wait_event(devc, WAIT_STOP);
-               }
-               break;
-       case PROTOCOL_V3:
-               if (rigol_ds_config_set(sdi, ":WAV:FORM BYTE") != SR_OK)
-                       return SR_ERR;
-               if (devc->data_source == DATA_SOURCE_LIVE) {
-                       if (rigol_ds_config_set(sdi, ":WAV:MODE NORM") != SR_OK)
-                               return SR_ERR;
-                       rigol_ds_set_wait_event(devc, WAIT_TRIGGER);
-               } else {
-                       if (rigol_ds_config_set(sdi, ":WAV:MODE RAW") != SR_OK)
-                               return SR_ERR;
-                       if (rigol_ds_config_set(sdi, ":SING") != SR_OK)
-                               return SR_ERR;
-                       rigol_ds_set_wait_event(devc, WAIT_STOP);
-               }
-               break;
-       }
-
-       return SR_OK;
-}
-
-/* Start reading data from the current channel */
-SR_PRIV int rigol_ds_channel_start(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_channel *ch;
-
-       if (!(devc = sdi->priv))
-               return SR_ERR;
-
-       ch = devc->channel_entry->data;
-
-       sr_dbg("Starting reading data from channel %d", ch->index + 1);
-
-       if (devc->model->series->protocol <= PROTOCOL_V2) {
-               if (ch->type == SR_CHANNEL_LOGIC) {
-                       if (sr_scpi_send(sdi->conn, ":WAV:DATA? DIG") != SR_OK)
-                               return SR_ERR;
-               } else {
-                       if (sr_scpi_send(sdi->conn, ":WAV:DATA? CHAN%d",
-                                       ch->index + 1) != SR_OK)
-                               return SR_ERR;
-               }
-               rigol_ds_set_wait_event(devc, WAIT_NONE);
-       } else {
-               if (rigol_ds_config_set(sdi, ":WAV:SOUR CHAN%d",
-                                 ch->index + 1) != SR_OK)
-                       return SR_ERR;
-               if (devc->data_source != DATA_SOURCE_LIVE) {
-                       if (rigol_ds_config_set(sdi, ":WAV:RES") != SR_OK)
-                               return SR_ERR;
-                       if (rigol_ds_config_set(sdi, ":WAV:BEG") != SR_OK)
-                               return SR_ERR;
-               }
-       }
-
-       rigol_ds_set_wait_event(devc, WAIT_BLOCK);
-
-       devc->num_channel_bytes = 0;
-       devc->num_header_bytes = 0;
-       devc->num_block_bytes = 0;
-
-       return SR_OK;
-}
-
-/* Read the header of a data block */
-static int rigol_ds_read_header(struct sr_dev_inst *sdi)
-{
-       struct sr_scpi_dev_inst *scpi = sdi->conn;
-       struct dev_context *devc = sdi->priv;
-       char *buf = (char *) devc->buffer;
-       size_t header_length;
-       int ret;
-
-       /* Try to read the hashsign and length digit. */
-       if (devc->num_header_bytes < 2) {
-               ret = sr_scpi_read_data(scpi, buf + devc->num_header_bytes,
-                               2 - devc->num_header_bytes);
-               if (ret < 0) {
-                       sr_err("Read error while reading data header.");
-                       return SR_ERR;
-               }
-               devc->num_header_bytes += ret;
-       }
-
-       if (devc->num_header_bytes < 2)
-               return 0;
-
-       if (buf[0] != '#' || !isdigit(buf[1]) || buf[1] == '0') {
-               sr_err("Received invalid data block header '%c%c'.", buf[0], buf[1]);
-               return SR_ERR;
-       }
-
-       header_length = 2 + buf[1] - '0';
-
-       /* Try to read the length. */
-       if (devc->num_header_bytes < header_length) {
-               ret = sr_scpi_read_data(scpi, buf + devc->num_header_bytes,
-                               header_length - devc->num_header_bytes);
-               if (ret < 0) {
-                       sr_err("Read error while reading data header.");
-                       return SR_ERR;
-               }
-               devc->num_header_bytes += ret;
-       }
-
-       if (devc->num_header_bytes < header_length)
-               return 0;
-
-       /* Read the data length. */
-       buf[header_length] = '\0';
-
-       if (parse_int(buf + 2, &ret) != SR_OK) {
-               sr_err("Received invalid data block length '%s'.", buf + 2);
-               return -1;
-       }
-
-       sr_dbg("Received data block header: '%s' -> block length %d", buf, ret);
-
-       return ret;
-}
-
-SR_PRIV int rigol_ds_receive(int fd, int revents, void *cb_data)
-{
-       struct sr_dev_inst *sdi;
-       struct sr_scpi_dev_inst *scpi;
-       struct dev_context *devc;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_analog analog;
-       struct sr_datafeed_logic logic;
-       double vdiv, offset;
-       int len, i, vref;
-       struct sr_channel *ch;
-       gsize expected_data_bytes;
-
-       (void)fd;
-
-       if (!(sdi = cb_data))
-               return TRUE;
-
-       if (!(devc = sdi->priv))
-               return TRUE;
-
-       scpi = sdi->conn;
-
-       if (revents == G_IO_IN || revents == 0) {
-               switch(devc->wait_event) {
-               case WAIT_NONE:
-                       break;
-               case WAIT_TRIGGER:
-                       if (rigol_ds_trigger_wait(sdi) != SR_OK)
-                               return TRUE;
-                       if (rigol_ds_channel_start(sdi) != SR_OK)
-                               return TRUE;
-                       return TRUE;
-               case WAIT_BLOCK:
-                       if (rigol_ds_block_wait(sdi) != SR_OK)
-                               return TRUE;
-                       break;
-               case WAIT_STOP:
-                       if (rigol_ds_stop_wait(sdi) != SR_OK)
-                               return TRUE;
-                       if (rigol_ds_check_stop(sdi) != SR_OK)
-                               return TRUE;
-                       if (rigol_ds_channel_start(sdi) != SR_OK)
-                               return TRUE;
-                       return TRUE;
-               default:
-                       sr_err("BUG: Unknown event target encountered");
-               }
-
-               ch = devc->channel_entry->data;
-
-               expected_data_bytes = ch->type == SR_CHANNEL_ANALOG ?
-                               devc->analog_frame_size : devc->digital_frame_size;
-
-               if (devc->num_block_bytes == 0) {
-                       if (devc->model->series->protocol >= PROTOCOL_V3)
-                               if (sr_scpi_send(sdi->conn, ":WAV:DATA?") != SR_OK)
-                                       return TRUE;
-
-                       if (sr_scpi_read_begin(scpi) != SR_OK)
-                               return TRUE;
-
-                       if (devc->format == FORMAT_IEEE488_2) {
-                               sr_dbg("New block header expected");
-                               len = rigol_ds_read_header(sdi);
-                               if (len == 0)
-                                       /* Still reading the header. */
-                                       return TRUE;
-                               if (len == -1) {
-                                       sr_err("Read error, aborting capture.");
-                                       packet.type = SR_DF_FRAME_END;
-                                       sr_session_send(cb_data, &packet);
-                                       sdi->driver->dev_acquisition_stop(sdi, cb_data);
-                                       return TRUE;
-                               }
-                               /* At slow timebases in live capture the DS2072
-                                * sometimes returns "short" data blocks, with
-                                * apparently no way to get the rest of the data.
-                                * Discard these, the complete data block will
-                                * appear eventually.
-                                */
-                               if (devc->data_source == DATA_SOURCE_LIVE
-                                               && (unsigned)len < expected_data_bytes) {
-                                       sr_dbg("Discarding short data block");
-                                       sr_scpi_read_data(scpi, (char *)devc->buffer, len + 1);
-                                       return TRUE;
-                               }
-                               devc->num_block_bytes = len;
-                       } else {
-                               devc->num_block_bytes = expected_data_bytes;
-                       }
-                       devc->num_block_read = 0;
-               }
-
-               len = devc->num_block_bytes - devc->num_block_read;
-               if (len > ACQ_BUFFER_SIZE)
-                       len = ACQ_BUFFER_SIZE;
-               sr_dbg("Requesting read of %d bytes", len);
-
-               len = sr_scpi_read_data(scpi, (char *)devc->buffer, len);
-
-               if (len == -1) {
-                       sr_err("Read error, aborting capture.");
-                       packet.type = SR_DF_FRAME_END;
-                       sr_session_send(cb_data, &packet);
-                       sdi->driver->dev_acquisition_stop(sdi, cb_data);
-                       return TRUE;
-               }
-
-               sr_dbg("Received %d bytes.", len);
-
-               devc->num_block_read += len;
-
-               if (ch->type == SR_CHANNEL_ANALOG) {
-                       vref = devc->vert_reference[ch->index];
-                       vdiv = devc->vdiv[ch->index] / 25.6;
-                       offset = devc->vert_offset[ch->index];
-                       if (devc->model->series->protocol >= PROTOCOL_V3)
-                               for (i = 0; i < len; i++)
-                                       devc->data[i] = ((int)devc->buffer[i] - vref) * vdiv - offset;
-                       else
-                               for (i = 0; i < len; i++)
-                                       devc->data[i] = (128 - devc->buffer[i]) * vdiv - offset;
-                       analog.channels = g_slist_append(NULL, ch);
-                       analog.num_samples = len;
-                       analog.data = devc->data;
-                       analog.mq = SR_MQ_VOLTAGE;
-                       analog.unit = SR_UNIT_VOLT;
-                       analog.mqflags = 0;
-                       packet.type = SR_DF_ANALOG;
-                       packet.payload = &analog;
-                       sr_session_send(cb_data, &packet);
-                       g_slist_free(analog.channels);
-               } else {
-                       logic.length = len;
-                       logic.unitsize = 2;
-                       logic.data = devc->buffer;
-                       packet.type = SR_DF_LOGIC;
-                       packet.payload = &logic;
-                       sr_session_send(cb_data, &packet);
-               }
-
-               if (devc->num_block_read == devc->num_block_bytes) {
-                       sr_dbg("Block has been completed");
-                       if (devc->model->series->protocol >= PROTOCOL_V3) {
-                               /* Discard the terminating linefeed */
-                               sr_scpi_read_data(scpi, (char *)devc->buffer, 1);
-                       }
-                       if (devc->format == FORMAT_IEEE488_2) {
-                               /* Prepare for possible next block */
-                               devc->num_header_bytes = 0;
-                               devc->num_block_bytes = 0;
-                               if (devc->data_source != DATA_SOURCE_LIVE)
-                                       rigol_ds_set_wait_event(devc, WAIT_BLOCK);
-                       }
-                       if (!sr_scpi_read_complete(scpi)) {
-                               sr_err("Read should have been completed");
-                               packet.type = SR_DF_FRAME_END;
-                               sr_session_send(cb_data, &packet);
-                               sdi->driver->dev_acquisition_stop(sdi, cb_data);
-                               return TRUE;
-                       }
-                       devc->num_block_read = 0;
-               } else {
-                       sr_dbg("%d of %d block bytes read", devc->num_block_read, devc->num_block_bytes);
-               }
-
-               devc->num_channel_bytes += len;
-
-               if (devc->num_channel_bytes < expected_data_bytes)
-                       /* Don't have the full data for this channel yet, re-run. */
-                       return TRUE;
-
-               /* End of data for this channel. */
-               if (devc->model->series->protocol >= PROTOCOL_V3) {
-                       /* Signal end of data download to scope */
-                       if (devc->data_source != DATA_SOURCE_LIVE)
-                               /*
-                                * This causes a query error, without it switching
-                                * to the next channel causes an error. Fun with
-                                * firmware...
-                                */
-                               rigol_ds_config_set(sdi, ":WAV:END");
-               }
-
-               if (ch->type == SR_CHANNEL_ANALOG
-                               && devc->channel_entry->next != NULL) {
-                       /* We got the frame for this analog channel, but
-                        * there's another analog channel. */
-                       devc->channel_entry = devc->channel_entry->next;
-                       rigol_ds_channel_start(sdi);
-               } else {
-                       /* Done with all analog channels in this frame. */
-                       if (devc->enabled_digital_channels
-                                       && devc->channel_entry != devc->enabled_digital_channels) {
-                               /* Now we need to get the digital data. */
-                               devc->channel_entry = devc->enabled_digital_channels;
-                               rigol_ds_channel_start(sdi);
-                       } else {
-                               /* Done with this frame. */
-                               packet.type = SR_DF_FRAME_END;
-                               sr_session_send(cb_data, &packet);
-
-                               if (++devc->num_frames == devc->limit_frames) {
-                                       /* Last frame, stop capture. */
-                                       sdi->driver->dev_acquisition_stop(sdi, cb_data);
-                               } else {
-                                       /* Get the next frame, starting with the first analog channel. */
-                                       if (devc->enabled_analog_channels)
-                                               devc->channel_entry = devc->enabled_analog_channels;
-                                       else
-                                               devc->channel_entry = devc->enabled_digital_channels;
-
-                                       rigol_ds_capture_start(sdi);
-
-                                       /* Start of next frame. */
-                                       packet.type = SR_DF_FRAME_BEGIN;
-                                       sr_session_send(cb_data, &packet);
-                               }
-                       }
-               }
-       }
-
-       return TRUE;
-}
-
-SR_PRIV int rigol_ds_get_dev_cfg(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       char *t_s, *cmd;
-       unsigned int i;
-       int res;
-
-       devc = sdi->priv;
-
-       /* Analog channel state. */
-       for (i = 0; i < devc->model->analog_channels; i++) {
-               cmd = g_strdup_printf(":CHAN%d:DISP?", i + 1);
-               res = sr_scpi_get_string(sdi->conn, cmd, &t_s);
-               g_free(cmd);
-               if (res != SR_OK)
-                       return SR_ERR;
-               devc->analog_channels[i] = !strcmp(t_s, "ON") || !strcmp(t_s, "1");
-       }
-       sr_dbg("Current analog channel state:");
-       for (i = 0; i < devc->model->analog_channels; i++)
-               sr_dbg("CH%d %s", i + 1, devc->analog_channels[i] ? "on" : "off");
-
-       /* Digital channel state. */
-       if (devc->model->has_digital) {
-               if (sr_scpi_get_string(sdi->conn, ":LA:DISP?", &t_s) != SR_OK)
-                       return SR_ERR;
-               devc->la_enabled = !strcmp(t_s, "ON") ? TRUE : FALSE;
-               sr_dbg("Logic analyzer %s, current digital channel state:",
-                               devc->la_enabled ? "enabled" : "disabled");
-               for (i = 0; i < 16; i++) {
-                       cmd = g_strdup_printf(":DIG%d:TURN?", i);
-                       res = sr_scpi_get_string(sdi->conn, cmd, &t_s);
-                       g_free(cmd);
-                       if (res != SR_OK)
-                               return SR_ERR;
-                       devc->digital_channels[i] = !strcmp(t_s, "ON") ? TRUE : FALSE;
-                       g_free(t_s);
-                       sr_dbg("D%d: %s", i, devc->digital_channels[i] ? "on" : "off");
-               }
-       }
-
-       /* Timebase. */
-       if (sr_scpi_get_float(sdi->conn, ":TIM:SCAL?", &devc->timebase) != SR_OK)
-               return SR_ERR;
-       sr_dbg("Current timebase %g", devc->timebase);
-
-       /* Vertical gain. */
-       for (i = 0; i < devc->model->analog_channels; i++) {
-               cmd = g_strdup_printf(":CHAN%d:SCAL?", i + 1);
-               res = sr_scpi_get_float(sdi->conn, cmd, &devc->vdiv[i]);
-               g_free(cmd);
-               if (res != SR_OK)
-                       return SR_ERR;
-       }
-       sr_dbg("Current vertical gain:");
-       for (i = 0; i < devc->model->analog_channels; i++)
-               sr_dbg("CH%d %g", i + 1, devc->vdiv[i]);
-
-       sr_dbg("Current vertical reference:");
-       if (devc->model->series->protocol >= PROTOCOL_V3) {
-               /* Vertical reference - not certain if this is the place to read it. */
-               for (i = 0; i < devc->model->analog_channels; i++) {
-                       if (rigol_ds_config_set(sdi, ":WAV:SOUR CHAN%d", i + 1) != SR_OK)
-                               return SR_ERR;
-                       if (sr_scpi_get_int(sdi->conn, ":WAV:YREF?", &devc->vert_reference[i]) != SR_OK)
-                               return SR_ERR;
-                       sr_dbg("CH%d %d", i + 1, devc->vert_reference[i]);
-               }
-       }
-
-       /* Vertical offset. */
-       for (i = 0; i < devc->model->analog_channels; i++) {
-               cmd = g_strdup_printf(":CHAN%d:OFFS?", i + 1);
-               res = sr_scpi_get_float(sdi->conn, cmd, &devc->vert_offset[i]);
-               g_free(cmd);
-               if (res != SR_OK)
-                       return SR_ERR;
-       }
-       sr_dbg("Current vertical offset:");
-       for (i = 0; i < devc->model->analog_channels; i++)
-               sr_dbg("CH%d %g", i + 1, devc->vert_offset[i]);
-
-       /* Coupling. */
-       for (i = 0; i < devc->model->analog_channels; i++) {
-               cmd = g_strdup_printf(":CHAN%d:COUP?", i + 1);
-               res = sr_scpi_get_string(sdi->conn, cmd, &devc->coupling[i]);
-               g_free(cmd);
-               if (res != SR_OK)
-                       return SR_ERR;
-       }
-       sr_dbg("Current coupling:");
-       for (i = 0; i < devc->model->analog_channels; i++)
-               sr_dbg("CH%d %s", i + 1, devc->coupling[i]);
-
-       /* Trigger source. */
-       if (sr_scpi_get_string(sdi->conn, ":TRIG:EDGE:SOUR?", &devc->trigger_source) != SR_OK)
-               return SR_ERR;
-       sr_dbg("Current trigger source %s", devc->trigger_source);
-
-       /* Horizontal trigger position. */
-       if (sr_scpi_get_float(sdi->conn, ":TIM:OFFS?", &devc->horiz_triggerpos) != SR_OK)
-               return SR_ERR;
-       sr_dbg("Current horizontal trigger position %g", devc->horiz_triggerpos);
-
-       /* Trigger slope. */
-       if (sr_scpi_get_string(sdi->conn, ":TRIG:EDGE:SLOP?", &devc->trigger_slope) != SR_OK)
-               return SR_ERR;
-       sr_dbg("Current trigger slope %s", devc->trigger_slope);
-
-       return SR_OK;
-}
diff --git a/hardware/rigol-ds/protocol.h b/hardware/rigol-ds/protocol.h
deleted file mode 100644 (file)
index 0117628..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012 Martin Ling <martin-git@earth.li>
- * Copyright (C) 2013 Bert Vermeulen <bert@biot.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_RIGOL_DS_PROTOCOL_H
-#define LIBSIGROK_HARDWARE_RIGOL_DS_PROTOCOL_H
-
-#include <stdint.h>
-#include <stdbool.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "rigol-ds"
-
-/* Size of acquisition buffers */
-#define ACQ_BUFFER_SIZE 32768
-
-#define MAX_ANALOG_CHANNELS 4
-#define MAX_DIGITAL_CHANNELS 16
-
-enum protocol_version {
-       PROTOCOL_V1, /* VS5000 */
-       PROTOCOL_V2, /* DS1000 */
-       PROTOCOL_V3, /* DS2000, DSO1000 */
-};
-
-enum data_format {
-       /* Used by DS1000 versions up to 2.02, and VS5000 series */
-       FORMAT_RAW,
-       /* Used by DS1000 versions from 2.04 onwards and all later series */
-       FORMAT_IEEE488_2,
-};
-
-enum data_source {
-       DATA_SOURCE_LIVE,
-       DATA_SOURCE_MEMORY,
-       DATA_SOURCE_SEGMENTED,
-};
-
-struct rigol_ds_vendor {
-       const char *name;
-       const char *full_name;
-};
-
-struct rigol_ds_series {
-       const struct rigol_ds_vendor *vendor;
-       const char *name;
-       enum protocol_version protocol;
-       enum data_format format;
-       uint64_t max_timebase[2];
-       uint64_t min_vdiv[2];
-       int num_horizontal_divs;
-       int live_samples;
-       int buffer_samples;
-};
-
-struct rigol_ds_model {
-       const struct rigol_ds_series *series;
-       const char *name;
-       uint64_t min_timebase[2];
-       unsigned int analog_channels;
-       bool has_digital;
-};
-
-enum wait_events {
-       WAIT_NONE,    /* Don't wait */
-       WAIT_TRIGGER, /* Wait for trigger (only live capture) */
-       WAIT_BLOCK,   /* Wait for block data (only when reading sample mem) */
-       WAIT_STOP,    /* Wait for scope stopping (only single shots) */
-};
-
-/** Private, per-device-instance driver context. */
-struct dev_context {
-       /* Device model */
-       const struct rigol_ds_model *model;
-       enum data_format format;
-
-       /* Device properties */
-       const uint64_t (*timebases)[2];
-       uint64_t num_timebases;
-       const uint64_t (*vdivs)[2];
-       uint64_t num_vdivs;
-
-       /* Channel groups */
-       struct sr_channel_group analog_groups[MAX_ANALOG_CHANNELS];
-       struct sr_channel_group digital_group;
-
-       /* Acquisition settings */
-       GSList *enabled_analog_channels;
-       GSList *enabled_digital_channels;
-       uint64_t limit_frames;
-       void *cb_data;
-       enum data_source data_source;
-       uint64_t analog_frame_size;
-       uint64_t digital_frame_size;
-
-       /* Device settings */
-       gboolean analog_channels[MAX_ANALOG_CHANNELS];
-       gboolean digital_channels[MAX_DIGITAL_CHANNELS];
-       gboolean la_enabled;
-       float timebase;
-       float vdiv[MAX_ANALOG_CHANNELS];
-       int vert_reference[MAX_ANALOG_CHANNELS];
-       float vert_offset[MAX_ANALOG_CHANNELS];
-       char *trigger_source;
-       float horiz_triggerpos;
-       char *trigger_slope;
-       char *coupling[MAX_ANALOG_CHANNELS];
-
-       /* Operational state */
-
-       /* Number of frames received in total. */
-       uint64_t num_frames;
-       /* GSList entry for the current channel. */
-       GSList *channel_entry;
-       /* Number of bytes received for current channel. */
-       uint64_t num_channel_bytes;
-       /* Number of bytes of block header read */
-       uint64_t num_header_bytes;
-       /* Number of bytes in current data block, if 0 block header expected */
-       uint64_t num_block_bytes;
-       /* Number of data block bytes already read */
-       uint64_t num_block_read;
-       /* What to wait for in *_receive */
-       enum wait_events wait_event;
-       /* Trigger/block copying/stop waiting status */
-       int wait_status;
-       /* Acq buffers used for reading from the scope and sending data to app */
-       unsigned char *buffer;
-       float *data;
-};
-
-SR_PRIV int rigol_ds_config_set(const struct sr_dev_inst *sdi, const char *format, ...);
-SR_PRIV int rigol_ds_capture_start(const struct sr_dev_inst *sdi);
-SR_PRIV int rigol_ds_channel_start(const struct sr_dev_inst *sdi);
-SR_PRIV int rigol_ds_receive(int fd, int revents, void *cb_data);
-SR_PRIV int rigol_ds_get_dev_cfg(const struct sr_dev_inst *sdi);
-
-#endif
diff --git a/hardware/saleae-logic16/api.c b/hardware/saleae-logic16/api.c
deleted file mode 100644 (file)
index 6bd539c..0000000
+++ /dev/null
@@ -1,837 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Marcus Comstedt <marcus@mc.pp.se>
- * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
- * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <glib.h>
-#include <libusb.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-#include "protocol.h"
-
-#define LOGIC16_VID            0x21a9
-#define LOGIC16_PID            0x1001
-
-#define USB_INTERFACE          0
-#define USB_CONFIGURATION      1
-#define FX2_FIRMWARE           FIRMWARE_DIR "/saleae-logic16-fx2.fw"
-
-#define MAX_RENUM_DELAY_MS     3000
-#define NUM_SIMUL_TRANSFERS    32
-
-SR_PRIV struct sr_dev_driver saleae_logic16_driver_info;
-static struct sr_dev_driver *di = &saleae_logic16_driver_info;
-
-static const int32_t hwopts[] = {
-       SR_CONF_CONN,
-};
-
-static const int32_t hwcaps[] = {
-       SR_CONF_LOGIC_ANALYZER,
-       SR_CONF_SAMPLERATE,
-       SR_CONF_VOLTAGE_THRESHOLD,
-       SR_CONF_TRIGGER_MATCH,
-
-       /* These are really implemented in the driver, not the hardware. */
-       SR_CONF_LIMIT_SAMPLES,
-       SR_CONF_CONTINUOUS,
-};
-
-static const int32_t soft_trigger_matches[] = {
-       SR_TRIGGER_ZERO,
-       SR_TRIGGER_ONE,
-       SR_TRIGGER_RISING,
-       SR_TRIGGER_FALLING,
-       SR_TRIGGER_EDGE,
-};
-
-static const char *channel_names[] = {
-       "0", "1", "2", "3", "4", "5", "6", "7", "8",
-       "9", "10", "11", "12", "13", "14", "15",
-       NULL,
-};
-
-static const struct {
-       enum voltage_range range;
-       gdouble low;
-       gdouble high;
-} volt_thresholds[] = {
-       { VOLTAGE_RANGE_18_33_V, 0.7, 1.4 },
-       { VOLTAGE_RANGE_5_V,     1.4, 3.6 },
-};
-
-static const uint64_t samplerates[] = {
-       SR_KHZ(500),
-       SR_MHZ(1),
-       SR_MHZ(2),
-       SR_MHZ(4),
-       SR_MHZ(5),
-       SR_MHZ(8),
-       SR_MHZ(10),
-       SR_KHZ(12500),
-       SR_MHZ(16),
-       SR_MHZ(25),
-       SR_MHZ(32),
-       SR_MHZ(40),
-       SR_MHZ(80),
-       SR_MHZ(100),
-};
-
-static int init(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, di, LOG_PREFIX);
-}
-
-static gboolean check_conf_profile(libusb_device *dev)
-{
-       struct libusb_device_descriptor des;
-       struct libusb_device_handle *hdl;
-       gboolean ret;
-       unsigned char strdesc[64];
-
-       hdl = NULL;
-       ret = FALSE;
-       while (!ret) {
-               /* Assume the FW has not been loaded, unless proven wrong. */
-               if (libusb_get_device_descriptor(dev, &des) != 0)
-                       break;
-
-               if (libusb_open(dev, &hdl) != 0)
-                       break;
-
-               if (libusb_get_string_descriptor_ascii(hdl,
-                   des.iManufacturer, strdesc, sizeof(strdesc)) < 0)
-                       break;
-               if (strcmp((const char *)strdesc, "Saleae LLC"))
-                       break;
-
-               if (libusb_get_string_descriptor_ascii(hdl,
-                   des.iProduct, strdesc, sizeof(strdesc)) < 0)
-                       break;
-               if (strcmp((const char *)strdesc, "Logic S/16"))
-                       break;
-
-               /* If we made it here, it must be a configured Logic16. */
-               ret = TRUE;
-       }
-       if (hdl)
-               libusb_close(hdl);
-
-       return ret;
-}
-
-static GSList *scan(GSList *options)
-{
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       struct sr_dev_inst *sdi;
-       struct sr_usb_dev_inst *usb;
-       struct sr_channel *ch;
-       struct sr_config *src;
-       GSList *l, *devices, *conn_devices;
-       struct libusb_device_descriptor des;
-       libusb_device **devlist;
-       int devcnt, ret, i, j;
-       const char *conn;
-
-       drvc = di->priv;
-
-       conn = NULL;
-       for (l = options; l; l = l->next) {
-               src = l->data;
-               switch (src->key) {
-               case SR_CONF_CONN:
-                       conn = g_variant_get_string(src->data, NULL);
-                       break;
-               }
-       }
-       if (conn)
-               conn_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn);
-       else
-               conn_devices = NULL;
-
-       /* Find all Logic16 devices and upload firmware to them. */
-       devices = NULL;
-       libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
-       for (i = 0; devlist[i]; i++) {
-               if (conn) {
-                       usb = NULL;
-                       for (l = conn_devices; l; l = l->next) {
-                               usb = l->data;
-                               if (usb->bus == libusb_get_bus_number(devlist[i])
-                                   && usb->address == libusb_get_device_address(devlist[i]))
-                                       break;
-                       }
-                       if (!l)
-                               /* This device matched none of the ones that
-                                * matched the conn specification. */
-                               continue;
-               }
-
-               if ((ret = libusb_get_device_descriptor(devlist[i], &des)) != 0) {
-                       sr_warn("Failed to get device descriptor: %s.",
-                               libusb_error_name(ret));
-                       continue;
-               }
-
-               if (des.idVendor != LOGIC16_VID || des.idProduct != LOGIC16_PID)
-                       continue;
-
-               devcnt = g_slist_length(drvc->instances);
-               sdi = sr_dev_inst_new(devcnt, SR_ST_INITIALIZING,
-                                     "Saleae", "Logic16", NULL);
-               if (!sdi)
-                       return NULL;
-               sdi->driver = di;
-
-               for (j = 0; channel_names[j]; j++) {
-                       if (!(ch = sr_channel_new(j, SR_CHANNEL_LOGIC, TRUE,
-                                                  channel_names[j])))
-                               return NULL;
-                       sdi->channels = g_slist_append(sdi->channels, ch);
-               }
-
-               if (!(devc = g_try_malloc0(sizeof(struct dev_context))))
-                       return NULL;
-               devc->selected_voltage_range = VOLTAGE_RANGE_18_33_V;
-               sdi->priv = devc;
-               drvc->instances = g_slist_append(drvc->instances, sdi);
-               devices = g_slist_append(devices, sdi);
-
-               if (check_conf_profile(devlist[i])) {
-                       /* Already has the firmware, so fix the new address. */
-                       sr_dbg("Found a Logic16 device.");
-                       sdi->status = SR_ST_INACTIVE;
-                       sdi->inst_type = SR_INST_USB;
-                       sdi->conn = sr_usb_dev_inst_new(
-                               libusb_get_bus_number(devlist[i]),
-                               libusb_get_device_address(devlist[i]), NULL);
-               } else {
-                       if (ezusb_upload_firmware(devlist[i], USB_CONFIGURATION,
-                                                 FX2_FIRMWARE) == SR_OK)
-                               /* Store when this device's FW was updated. */
-                               devc->fw_updated = g_get_monotonic_time();
-                       else
-                               sr_err("Firmware upload failed for "
-                                      "device %d.", devcnt);
-                       sdi->inst_type = SR_INST_USB;
-                       sdi->conn = sr_usb_dev_inst_new(
-                               libusb_get_bus_number(devlist[i]), 0xff, NULL);
-               }
-       }
-       libusb_free_device_list(devlist, 1);
-       g_slist_free_full(conn_devices, (GDestroyNotify)sr_usb_dev_inst_free);
-
-       return devices;
-}
-
-static GSList *dev_list(void)
-{
-       return ((struct drv_context *)(di->priv))->instances;
-}
-
-static int logic16_dev_open(struct sr_dev_inst *sdi)
-{
-       libusb_device **devlist;
-       struct sr_usb_dev_inst *usb;
-       struct libusb_device_descriptor des;
-       struct drv_context *drvc;
-       int ret, skip, i, device_count;
-
-       drvc = di->priv;
-       usb = sdi->conn;
-
-       if (sdi->status == SR_ST_ACTIVE)
-               /* Device is already in use. */
-               return SR_ERR;
-
-       skip = 0;
-       device_count = libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
-       if (device_count < 0) {
-               sr_err("Failed to get device list: %s.",
-                      libusb_error_name(device_count));
-               return SR_ERR;
-       }
-
-       for (i = 0; i < device_count; i++) {
-               if ((ret = libusb_get_device_descriptor(devlist[i], &des))) {
-                       sr_err("Failed to get device descriptor: %s.",
-                              libusb_error_name(ret));
-                       continue;
-               }
-
-               if (des.idVendor != LOGIC16_VID || des.idProduct != LOGIC16_PID)
-                       continue;
-
-               if (sdi->status == SR_ST_INITIALIZING) {
-                       if (skip != sdi->index) {
-                               /* Skip devices of this type that aren't the one we want. */
-                               skip += 1;
-                               continue;
-                       }
-               } else if (sdi->status == SR_ST_INACTIVE) {
-                       /*
-                        * This device is fully enumerated, so we need to find
-                        * this device by vendor, product, bus and address.
-                        */
-                       if (libusb_get_bus_number(devlist[i]) != usb->bus
-                           || libusb_get_device_address(devlist[i]) != usb->address)
-                               /* This is not the one. */
-                               continue;
-               }
-
-               if (!(ret = libusb_open(devlist[i], &usb->devhdl))) {
-                       if (usb->address == 0xff)
-                               /*
-                                * First time we touch this device after FW
-                                * upload, so we don't know the address yet.
-                                */
-                               usb->address = libusb_get_device_address(devlist[i]);
-               } else {
-                       sr_err("Failed to open device: %s.",
-                              libusb_error_name(ret));
-                       break;
-               }
-
-               ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE);
-               if (ret == LIBUSB_ERROR_BUSY) {
-                       sr_err("Unable to claim USB interface. Another "
-                              "program or driver has already claimed it.");
-                       break;
-               } else if (ret == LIBUSB_ERROR_NO_DEVICE) {
-                       sr_err("Device has been disconnected.");
-                       break;
-               } else if (ret != 0) {
-                       sr_err("Unable to claim interface: %s.",
-                              libusb_error_name(ret));
-                       break;
-               }
-
-               if ((ret = logic16_init_device(sdi)) != SR_OK) {
-                       sr_err("Failed to init device.");
-                       break;
-               }
-
-               sdi->status = SR_ST_ACTIVE;
-               sr_info("Opened device %d on %d.%d, interface %d.",
-                       sdi->index, usb->bus, usb->address, USB_INTERFACE);
-
-               break;
-       }
-       libusb_free_device_list(devlist, 1);
-
-       if (sdi->status != SR_ST_ACTIVE) {
-               if (usb->devhdl) {
-                       libusb_release_interface(usb->devhdl, USB_INTERFACE);
-                       libusb_close(usb->devhdl);
-                       usb->devhdl = NULL;
-               }
-               return SR_ERR;
-       }
-
-       return SR_OK;
-}
-
-static int dev_open(struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       int ret;
-       int64_t timediff_us, timediff_ms;
-
-       devc = sdi->priv;
-
-       /*
-        * If the firmware was recently uploaded, wait up to MAX_RENUM_DELAY_MS
-        * milliseconds for the FX2 to renumerate.
-        */
-       ret = SR_ERR;
-       if (devc->fw_updated > 0) {
-               sr_info("Waiting for device to reset.");
-               /* Takes >= 300ms for the FX2 to be gone from the USB bus. */
-               g_usleep(300 * 1000);
-               timediff_ms = 0;
-               while (timediff_ms < MAX_RENUM_DELAY_MS) {
-                       if ((ret = logic16_dev_open(sdi)) == SR_OK)
-                               break;
-                       g_usleep(100 * 1000);
-
-                       timediff_us = g_get_monotonic_time() - devc->fw_updated;
-                       timediff_ms = timediff_us / 1000;
-                       sr_spew("Waited %" PRIi64 "ms.", timediff_ms);
-               }
-               if (ret != SR_OK) {
-                       sr_err("Device failed to renumerate.");
-                       return SR_ERR;
-               }
-               sr_info("Device came back after %" PRIi64 "ms.", timediff_ms);
-       } else {
-               sr_info("Firmware upload was not needed.");
-               ret = logic16_dev_open(sdi);
-       }
-
-       if (ret != SR_OK) {
-               sr_err("Unable to open device.");
-               return SR_ERR;
-       }
-
-       if (devc->cur_samplerate == 0) {
-               /* Samplerate hasn't been set; default to the slowest one. */
-               devc->cur_samplerate = samplerates[0];
-       }
-
-       return SR_OK;
-}
-
-static int dev_close(struct sr_dev_inst *sdi)
-{
-       struct sr_usb_dev_inst *usb;
-
-       usb = sdi->conn;
-       if (usb->devhdl == NULL)
-               return SR_ERR;
-
-       sr_info("Closing device %d on %d.%d interface %d.",
-               sdi->index, usb->bus, usb->address, USB_INTERFACE);
-       libusb_release_interface(usb->devhdl, USB_INTERFACE);
-       libusb_close(usb->devhdl);
-       usb->devhdl = NULL;
-       sdi->status = SR_ST_INACTIVE;
-
-       return SR_OK;
-}
-
-static int cleanup(void)
-{
-       int ret;
-       struct drv_context *drvc;
-
-       if (!(drvc = di->priv))
-               /* Can get called on an unused driver, doesn't matter. */
-               return SR_OK;
-
-
-       ret = std_dev_clear(di, NULL);
-       g_free(drvc);
-       di->priv = NULL;
-
-       return ret;
-}
-
-static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       struct sr_usb_dev_inst *usb;
-       GVariant *range[2];
-       char str[128];
-       int ret;
-       unsigned int i;
-
-       (void)cg;
-
-       ret = SR_OK;
-       switch (key) {
-       case SR_CONF_CONN:
-               if (!sdi || !sdi->conn)
-                       return SR_ERR_ARG;
-               usb = sdi->conn;
-               if (usb->address == 255)
-                       /* Device still needs to re-enumerate after firmware
-                        * upload, so we don't know its (future) address. */
-                       return SR_ERR;
-               snprintf(str, 128, "%d.%d", usb->bus, usb->address);
-               *data = g_variant_new_string(str);
-               break;
-       case SR_CONF_SAMPLERATE:
-               if (!sdi)
-                       return SR_ERR;
-               devc = sdi->priv;
-               *data = g_variant_new_uint64(devc->cur_samplerate);
-               break;
-       case SR_CONF_VOLTAGE_THRESHOLD:
-               if (!sdi)
-                       return SR_ERR;
-               devc = sdi->priv;
-               ret = SR_ERR;
-               for (i = 0; i < ARRAY_SIZE(volt_thresholds); i++) {
-                       if (devc->selected_voltage_range !=
-                           volt_thresholds[i].range)
-                               continue;
-                       range[0] = g_variant_new_double(volt_thresholds[i].low);
-                       range[1] = g_variant_new_double(volt_thresholds[i].high);
-                       *data = g_variant_new_tuple(range, 2);
-                       ret = SR_OK;
-                       break;
-               }
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return ret;
-}
-
-static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       gdouble low, high;
-       int ret;
-       unsigned int i;
-
-       (void)cg;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       devc = sdi->priv;
-
-       ret = SR_OK;
-       switch (key) {
-       case SR_CONF_SAMPLERATE:
-               devc->cur_samplerate = g_variant_get_uint64(data);
-               break;
-       case SR_CONF_LIMIT_SAMPLES:
-               devc->limit_samples = g_variant_get_uint64(data);
-               break;
-       case SR_CONF_VOLTAGE_THRESHOLD:
-               g_variant_get(data, "(dd)", &low, &high);
-               ret = SR_ERR_ARG;
-               for (i = 0; i < ARRAY_SIZE(volt_thresholds); i++) {
-                       if (fabs(volt_thresholds[i].low - low) < 0.1 &&
-                           fabs(volt_thresholds[i].high - high) < 0.1) {
-                               devc->selected_voltage_range =
-                                       volt_thresholds[i].range;
-                               ret = SR_OK;
-                               break;
-                       }
-               }
-               break;
-       default:
-               ret = SR_ERR_NA;
-       }
-
-       return ret;
-}
-
-static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       GVariant *gvar, *range[2];
-       GVariantBuilder gvb;
-       int ret;
-       unsigned int i;
-
-       (void)sdi;
-       (void)cg;
-
-       ret = SR_OK;
-       switch (key) {
-       case SR_CONF_SCAN_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
-               break;
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
-               break;
-       case SR_CONF_SAMPLERATE:
-               g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
-               gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"),
-                       samplerates, ARRAY_SIZE(samplerates), sizeof(uint64_t));
-               g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar);
-               *data = g_variant_builder_end(&gvb);
-               break;
-       case SR_CONF_VOLTAGE_THRESHOLD:
-               g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
-               for (i = 0; i < ARRAY_SIZE(volt_thresholds); i++) {
-                       range[0] = g_variant_new_double(volt_thresholds[i].low);
-                       range[1] = g_variant_new_double(volt_thresholds[i].high);
-                       gvar = g_variant_new_tuple(range, 2);
-                       g_variant_builder_add_value(&gvb, gvar);
-               }
-               *data = g_variant_builder_end(&gvb);
-               break;
-       case SR_CONF_TRIGGER_MATCH:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               soft_trigger_matches, ARRAY_SIZE(soft_trigger_matches),
-                               sizeof(int32_t));
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return ret;
-}
-
-static void abort_acquisition(struct dev_context *devc)
-{
-       int i;
-
-       devc->sent_samples = -1;
-
-       for (i = devc->num_transfers - 1; i >= 0; i--) {
-               if (devc->transfers[i])
-                       libusb_cancel_transfer(devc->transfers[i]);
-       }
-}
-
-static unsigned int bytes_per_ms(struct dev_context *devc)
-{
-       return devc->cur_samplerate * devc->num_channels / 8000;
-}
-
-static size_t get_buffer_size(struct dev_context *devc)
-{
-       size_t s;
-
-       /*
-        * The buffer should be large enough to hold 10ms of data and
-        * a multiple of 512.
-        */
-       s = 10 * bytes_per_ms(devc);
-       return (s + 511) & ~511;
-}
-
-static unsigned int get_number_of_transfers(struct dev_context *devc)
-{
-       unsigned int n;
-
-       /* Total buffer size should be able to hold about 500ms of data. */
-       n = 500 * bytes_per_ms(devc) / get_buffer_size(devc);
-
-       if (n > NUM_SIMUL_TRANSFERS)
-               return NUM_SIMUL_TRANSFERS;
-
-       return n;
-}
-
-static unsigned int get_timeout(struct dev_context *devc)
-{
-       size_t total_size;
-       unsigned int timeout;
-
-       total_size = get_buffer_size(devc) * get_number_of_transfers(devc);
-       timeout = total_size / bytes_per_ms(devc);
-       return timeout + timeout / 4; /* Leave a headroom of 25% percent. */
-}
-
-static int configure_channels(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_channel *ch;
-       GSList *l;
-       uint16_t channel_bit;
-
-       devc = sdi->priv;
-
-       devc->cur_channels = 0;
-       devc->num_channels = 0;
-       for (l = sdi->channels; l; l = l->next) {
-               ch = (struct sr_channel *)l->data;
-               if (ch->enabled == FALSE)
-                       continue;
-
-               channel_bit = 1 << (ch->index);
-
-               devc->cur_channels |= channel_bit;
-
-#ifdef WORDS_BIGENDIAN
-               /*
-                * Output logic data should be stored in little endian format.
-                * To speed things up during conversion, do the switcharoo
-                * here instead.
-                */
-               channel_bit = 1 << (ch->index ^ 8);
-#endif
-
-               devc->channel_masks[devc->num_channels++] = channel_bit;
-       }
-
-       return SR_OK;
-}
-
-static int receive_data(int fd, int revents, void *cb_data)
-{
-       struct timeval tv;
-       struct dev_context *devc;
-       struct drv_context *drvc;
-       const struct sr_dev_inst *sdi;
-
-       (void)fd;
-       (void)revents;
-
-       sdi = cb_data;
-       drvc = di->priv;
-       devc = sdi->priv;
-
-       tv.tv_sec = tv.tv_usec = 0;
-       libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
-
-       if (devc->sent_samples == -2) {
-               logic16_abort_acquisition(sdi);
-               abort_acquisition(devc);
-       }
-
-       return TRUE;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct dev_context *devc;
-       struct drv_context *drvc;
-       struct sr_usb_dev_inst *usb;
-       struct sr_trigger *trigger;
-       struct libusb_transfer *transfer;
-       unsigned int i, timeout, num_transfers;
-       int ret;
-       unsigned char *buf;
-       size_t size, convsize;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       drvc = di->priv;
-       devc = sdi->priv;
-       usb = sdi->conn;
-
-       /* Configures devc->cur_channels. */
-       if (configure_channels(sdi) != SR_OK) {
-               sr_err("Failed to configure channels.");
-               return SR_ERR;
-       }
-
-       devc->cb_data = cb_data;
-       devc->sent_samples = 0;
-       devc->empty_transfer_count = 0;
-       devc->cur_channel = 0;
-       memset(devc->channel_data, 0, sizeof(devc->channel_data));
-
-       if ((trigger = sr_session_trigger_get(sdi->session))) {
-               devc->stl = soft_trigger_logic_new(sdi, trigger);
-               devc->trigger_fired = FALSE;
-       } else
-               devc->trigger_fired = TRUE;
-
-       timeout = get_timeout(devc);
-       num_transfers = get_number_of_transfers(devc);
-       size = get_buffer_size(devc);
-       convsize = (size / devc->num_channels + 2) * 16;
-       devc->submitted_transfers = 0;
-
-       devc->convbuffer_size = convsize;
-       if (!(devc->convbuffer = g_try_malloc(convsize))) {
-               sr_err("Conversion buffer malloc failed.");
-               return SR_ERR_MALLOC;
-       }
-
-       devc->transfers = g_try_malloc0(sizeof(*devc->transfers) * num_transfers);
-       if (!devc->transfers) {
-               sr_err("USB transfers malloc failed.");
-               g_free(devc->convbuffer);
-               return SR_ERR_MALLOC;
-       }
-
-       if ((ret = logic16_setup_acquisition(sdi, devc->cur_samplerate,
-                                            devc->cur_channels)) != SR_OK) {
-               g_free(devc->transfers);
-               g_free(devc->convbuffer);
-               return ret;
-       }
-
-       devc->num_transfers = num_transfers;
-       for (i = 0; i < num_transfers; i++) {
-               if (!(buf = g_try_malloc(size))) {
-                       sr_err("USB transfer buffer malloc failed.");
-                       if (devc->submitted_transfers)
-                               abort_acquisition(devc);
-                       else {
-                               g_free(devc->transfers);
-                               g_free(devc->convbuffer);
-                       }
-                       return SR_ERR_MALLOC;
-               }
-               transfer = libusb_alloc_transfer(0);
-               libusb_fill_bulk_transfer(transfer, usb->devhdl,
-                               2 | LIBUSB_ENDPOINT_IN, buf, size,
-                               logic16_receive_transfer, (void *)sdi, timeout);
-               if ((ret = libusb_submit_transfer(transfer)) != 0) {
-                       sr_err("Failed to submit transfer: %s.",
-                              libusb_error_name(ret));
-                       libusb_free_transfer(transfer);
-                       g_free(buf);
-                       abort_acquisition(devc);
-                       return SR_ERR;
-               }
-               devc->transfers[i] = transfer;
-               devc->submitted_transfers++;
-       }
-
-       devc->ctx = drvc->sr_ctx;
-
-       usb_source_add(sdi->session, devc->ctx, timeout, receive_data, (void *)sdi);
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(cb_data, LOG_PREFIX);
-
-       if ((ret = logic16_start_acquisition(sdi)) != SR_OK) {
-               abort_acquisition(devc);
-               return ret;
-       }
-
-       return SR_OK;
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       int ret;
-
-       (void)cb_data;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       ret = logic16_abort_acquisition(sdi);
-
-       abort_acquisition(sdi->priv);
-
-       return ret;
-}
-
-SR_PRIV struct sr_dev_driver saleae_logic16_driver_info = {
-       .name = "saleae-logic16",
-       .longname = "Saleae Logic16",
-       .api_version = 1,
-       .init = init,
-       .cleanup = cleanup,
-       .scan = scan,
-       .dev_list = 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,
-       .priv = NULL,
-};
diff --git a/hardware/saleae-logic16/protocol.c b/hardware/saleae-logic16/protocol.c
deleted file mode 100644 (file)
index 7858334..0000000
+++ /dev/null
@@ -1,790 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Marcus Comstedt <marcus@mc.pp.se>
- * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
- * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "protocol.h"
-
-#include <stdint.h>
-#include <string.h>
-#include <glib.h>
-#include <glib/gstdio.h>
-#include <stdio.h>
-#include <errno.h>
-#include <math.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define FPGA_FIRMWARE_18       FIRMWARE_DIR"/saleae-logic16-fpga-18.bitstream"
-#define FPGA_FIRMWARE_33       FIRMWARE_DIR"/saleae-logic16-fpga-33.bitstream"
-
-#define MAX_SAMPLE_RATE                SR_MHZ(100)
-#define MAX_4CH_SAMPLE_RATE    SR_MHZ(50)
-#define MAX_7CH_SAMPLE_RATE    SR_MHZ(40)
-#define MAX_8CH_SAMPLE_RATE    SR_MHZ(32)
-#define MAX_10CH_SAMPLE_RATE   SR_MHZ(25)
-#define MAX_13CH_SAMPLE_RATE   SR_MHZ(16)
-
-#define BASE_CLOCK_0_FREQ      SR_MHZ(100)
-#define BASE_CLOCK_1_FREQ      SR_MHZ(160)
-
-#define COMMAND_START_ACQUISITION      1
-#define COMMAND_ABORT_ACQUISITION_ASYNC        2
-#define COMMAND_WRITE_EEPROM           6
-#define COMMAND_READ_EEPROM            7
-#define COMMAND_WRITE_LED_TABLE                0x7a
-#define COMMAND_SET_LED_MODE           0x7b
-#define COMMAND_RETURN_TO_BOOTLOADER   0x7c
-#define COMMAND_ABORT_ACQUISITION_SYNC 0x7d
-#define COMMAND_FPGA_UPLOAD_INIT       0x7e
-#define COMMAND_FPGA_UPLOAD_SEND_DATA  0x7f
-#define COMMAND_FPGA_WRITE_REGISTER    0x80
-#define COMMAND_FPGA_READ_REGISTER     0x81
-#define COMMAND_GET_REVID              0x82
-
-#define WRITE_EEPROM_COOKIE1           0x42
-#define WRITE_EEPROM_COOKIE2           0x55
-#define READ_EEPROM_COOKIE1            0x33
-#define READ_EEPROM_COOKIE2            0x81
-#define ABORT_ACQUISITION_SYNC_PATTERN 0x55
-
-#define MAX_EMPTY_TRANSFERS            64
-
-static void encrypt(uint8_t *dest, const uint8_t *src, uint8_t cnt)
-{
-       uint8_t state1 = 0x9b, state2 = 0x54;
-       uint8_t t, v;
-       int i;
-
-       for (i = 0; i < cnt; i++) {
-               v = src[i];
-               t = (((v ^ state2 ^ 0x2b) - 0x05) ^ 0x35) - 0x39;
-               t = (((t ^ state1 ^ 0x5a) - 0xb0) ^ 0x38) - 0x45;
-               dest[i] = state2 = t;
-               state1 = v;
-       }
-}
-
-static void decrypt(uint8_t *dest, const uint8_t *src, uint8_t cnt)
-{
-       uint8_t state1 = 0x9b, state2 = 0x54;
-       uint8_t t, v;
-       int i;
-
-       for (i = 0; i < cnt; i++) {
-               v = src[i];
-               t = (((v + 0x45) ^ 0x38) + 0xb0) ^ 0x5a ^ state1;
-               t = (((t + 0x39) ^ 0x35) + 0x05) ^ 0x2b ^ state2;
-               dest[i] = state1 = t;
-               state2 = v;
-       }
-}
-
-static int do_ep1_command(const struct sr_dev_inst *sdi,
-                         const uint8_t *command, uint8_t cmd_len,
-                         uint8_t *reply, uint8_t reply_len)
-{
-       uint8_t buf[64];
-       struct sr_usb_dev_inst *usb;
-       int ret, xfer;
-
-       usb = sdi->conn;
-
-       if (cmd_len < 1 || cmd_len > 64 || reply_len > 64 ||
-           command == NULL || (reply_len > 0 && reply == NULL))
-               return SR_ERR_ARG;
-
-       encrypt(buf, command, cmd_len);
-
-       ret = libusb_bulk_transfer(usb->devhdl, 1, buf, cmd_len, &xfer, 1000);
-       if (ret != 0) {
-               sr_dbg("Failed to send EP1 command 0x%02x: %s.",
-                      command[0], libusb_error_name(ret));
-               return SR_ERR;
-       }
-       if (xfer != cmd_len) {
-               sr_dbg("Failed to send EP1 command 0x%02x: incorrect length "
-                      "%d != %d.", xfer, cmd_len);
-               return SR_ERR;
-       }
-
-       if (reply_len == 0)
-               return SR_OK;
-
-       ret = libusb_bulk_transfer(usb->devhdl, 0x80 | 1, buf, reply_len,
-                                  &xfer, 1000);
-       if (ret != 0) {
-               sr_dbg("Failed to receive reply to EP1 command 0x%02x: %s.",
-                      command[0], libusb_error_name(ret));
-               return SR_ERR;
-       }
-       if (xfer != reply_len) {
-               sr_dbg("Failed to receive reply to EP1 command 0x%02x: "
-                      "incorrect length %d != %d.", xfer, reply_len);
-               return SR_ERR;
-       }
-
-       decrypt(reply, buf, reply_len);
-
-       return SR_OK;
-}
-
-static int read_eeprom(const struct sr_dev_inst *sdi,
-                      uint8_t address, uint8_t length, uint8_t *buf)
-{
-       uint8_t command[5] = {
-               COMMAND_READ_EEPROM,
-               READ_EEPROM_COOKIE1,
-               READ_EEPROM_COOKIE2,
-               address,
-               length,
-       };
-
-       return do_ep1_command(sdi, command, 5, buf, length);
-}
-
-static int upload_led_table(const struct sr_dev_inst *sdi,
-                           const uint8_t *table, uint8_t offset, uint8_t cnt)
-{
-       uint8_t chunk, command[64];
-       int ret;
-
-       if (cnt < 1 || cnt + offset > 64 || table == NULL)
-               return SR_ERR_ARG;
-
-       while (cnt > 0) {
-               chunk = (cnt > 32 ? 32 : cnt);
-
-               command[0] = COMMAND_WRITE_LED_TABLE;
-               command[1] = offset;
-               command[2] = chunk;
-               memcpy(command + 3, table, chunk);
-
-               ret = do_ep1_command(sdi, command, 3 + chunk, NULL, 0);
-               if (ret != SR_OK)
-                       return ret;
-
-               table += chunk;
-               offset += chunk;
-               cnt -= chunk;
-       }
-
-       return SR_OK;
-}
-
-static int set_led_mode(const struct sr_dev_inst *sdi,
-                       uint8_t animate, uint16_t t2reload, uint8_t div,
-                       uint8_t repeat)
-{
-       uint8_t command[6] = {
-               COMMAND_SET_LED_MODE,
-               animate,
-               t2reload & 0xff,
-               t2reload >> 8,
-               div,
-               repeat,
-       };
-
-       return do_ep1_command(sdi, command, 6, NULL, 0);
-}
-
-static int read_fpga_register(const struct sr_dev_inst *sdi,
-                             uint8_t address, uint8_t *value)
-{
-       uint8_t command[3] = {
-               COMMAND_FPGA_READ_REGISTER,
-               1,
-               address,
-       };
-
-       return do_ep1_command(sdi, command, 3, value, 1);
-}
-
-static int write_fpga_registers(const struct sr_dev_inst *sdi,
-                               uint8_t (*regs)[2], uint8_t cnt)
-{
-       uint8_t command[64];
-       int i;
-
-       if (cnt < 1 || cnt > 31)
-               return SR_ERR_ARG;
-
-       command[0] = COMMAND_FPGA_WRITE_REGISTER;
-       command[1] = cnt;
-       for (i = 0; i < cnt; i++) {
-               command[2 + 2 * i] = regs[i][0];
-               command[3 + 2 * i] = regs[i][1];
-       }
-
-       return do_ep1_command(sdi, command, 2 * (cnt + 1), NULL, 0);
-}
-
-static int write_fpga_register(const struct sr_dev_inst *sdi,
-                              uint8_t address, uint8_t value)
-{
-       uint8_t regs[2] = { address, value };
-
-       return write_fpga_registers(sdi, &regs, 1);
-}
-
-static uint8_t map_eeprom_data(uint8_t v)
-{
-       return (((v ^ 0x80) + 0x44) ^ 0xd5) + 0x69;
-}
-
-static int prime_fpga(const struct sr_dev_inst *sdi)
-{
-       uint8_t eeprom_data[16];
-       uint8_t old_reg_10, version;
-       uint8_t regs[8][2] = {
-               {10, 0x00},
-               {10, 0x40},
-               {12, 0},
-               {10, 0xc0},
-               {10, 0x40},
-               {6, 0},
-               {7, 1},
-               {7, 0}
-       };
-       int i, ret;
-
-       if ((ret = read_eeprom(sdi, 16, 16, eeprom_data)) != SR_OK)
-               return ret;
-
-       if ((ret = read_fpga_register(sdi, 10, &old_reg_10)) != SR_OK)
-               return ret;
-
-       regs[0][1] = (old_reg_10 &= 0x7f);
-       regs[1][1] |= old_reg_10;
-       regs[3][1] |= old_reg_10;
-       regs[4][1] |= old_reg_10;
-
-       for (i = 0; i < 16; i++) {
-               regs[2][1] = eeprom_data[i];
-               regs[5][1] = map_eeprom_data(eeprom_data[i]);
-               if (i)
-                       ret = write_fpga_registers(sdi, &regs[2], 6);
-               else
-                       ret = write_fpga_registers(sdi, &regs[0], 8);
-               if (ret != SR_OK)
-                       return ret;
-       }
-
-       if ((ret = write_fpga_register(sdi, 10, old_reg_10)) != SR_OK)
-               return ret;
-
-       if ((ret = read_fpga_register(sdi, 0, &version)) != SR_OK)
-               return ret;
-
-       if (version != 0x10) {
-               sr_err("Invalid FPGA bitstream version: 0x%02x != 0x10.", version);
-               return SR_ERR;
-       }
-
-       return SR_OK;
-}
-
-static void make_heartbeat(uint8_t *table, int len)
-{
-       int i, j;
-
-       memset(table, 0, len);
-       len >>= 3;
-       for (i = 0; i < 2; i++)
-               for (j = 0; j < len; j++)
-                       *table++ = sin(j * M_PI / len) * 255;
-}
-
-static int configure_led(const struct sr_dev_inst *sdi)
-{
-       uint8_t table[64];
-       int ret;
-
-       make_heartbeat(table, 64);
-       if ((ret = upload_led_table(sdi, table, 0, 64)) != SR_OK)
-               return ret;
-
-       return set_led_mode(sdi, 1, 6250, 0, 1);
-}
-
-static int upload_fpga_bitstream(const struct sr_dev_inst *sdi,
-                                enum voltage_range vrange)
-{
-       struct dev_context *devc;
-       int offset, chunksize, ret;
-       const char *filename;
-       uint8_t len, buf[256 * 62], command[64];
-       FILE *fw;
-
-       devc = sdi->priv;
-
-       if (devc->cur_voltage_range == vrange)
-               return SR_OK;
-
-       switch (vrange) {
-       case VOLTAGE_RANGE_18_33_V:
-               filename = FPGA_FIRMWARE_18;
-               break;
-       case VOLTAGE_RANGE_5_V:
-               filename = FPGA_FIRMWARE_33;
-               break;
-       default:
-               sr_err("Unsupported voltage range.");
-               return SR_ERR;
-       }
-
-       sr_info("Uploading FPGA bitstream at %s.", filename);
-       if ((fw = g_fopen(filename, "rb")) == NULL) {
-               sr_err("Unable to open bitstream file %s for reading: %s.",
-                      filename, strerror(errno));
-               return SR_ERR;
-       }
-
-       buf[0] = COMMAND_FPGA_UPLOAD_INIT;
-       if ((ret = do_ep1_command(sdi, buf, 1, NULL, 0)) != SR_OK) {
-               fclose(fw);
-               return ret;
-       }
-
-       while (1) {
-               chunksize = fread(buf, 1, sizeof(buf), fw);
-               if (chunksize == 0)
-                       break;
-
-               for (offset = 0; offset < chunksize; offset += 62) {
-                       len = (offset + 62 > chunksize ?
-                               chunksize - offset : 62);
-                       command[0] = COMMAND_FPGA_UPLOAD_SEND_DATA;
-                       command[1] = len;
-                       memcpy(command + 2, buf + offset, len);
-                       ret = do_ep1_command(sdi, command, len + 2, NULL, 0);
-                       if (ret != SR_OK) {
-                               fclose(fw);
-                               return ret;
-                       }
-               }
-
-               sr_info("Uploaded %d bytes.", chunksize);
-       }
-       fclose(fw);
-       sr_info("FPGA bitstream upload done.");
-
-       if ((ret = prime_fpga(sdi)) != SR_OK)
-               return ret;
-
-       if ((ret = configure_led(sdi)) != SR_OK)
-               return ret;
-
-       devc->cur_voltage_range = vrange;
-       return SR_OK;
-}
-
-static int abort_acquisition_sync(const struct sr_dev_inst *sdi)
-{
-       static const uint8_t command[2] = {
-               COMMAND_ABORT_ACQUISITION_SYNC,
-               ABORT_ACQUISITION_SYNC_PATTERN,
-       };
-       uint8_t reply, expected_reply;
-       int ret;
-
-       if ((ret = do_ep1_command(sdi, command, 2, &reply, 1)) != SR_OK)
-               return ret;
-
-       expected_reply = ~command[1];
-       if (reply != expected_reply) {
-               sr_err("Invalid response for abort acquisition command: "
-                      "0x%02x != 0x%02x.", reply, expected_reply);
-               return SR_ERR;
-       }
-
-       return SR_OK;
-}
-
-SR_PRIV int logic16_setup_acquisition(const struct sr_dev_inst *sdi,
-                            uint64_t samplerate, uint16_t channels)
-{
-       uint8_t clock_select, reg1, reg10;
-       uint64_t div;
-       int i, ret, nchan = 0;
-       struct dev_context *devc;
-
-       devc = sdi->priv;
-
-       if (samplerate == 0 || samplerate > MAX_SAMPLE_RATE) {
-               sr_err("Unable to sample at %" PRIu64 "Hz.", samplerate);
-               return SR_ERR;
-       }
-
-       if (BASE_CLOCK_0_FREQ % samplerate == 0 &&
-           (div = BASE_CLOCK_0_FREQ / samplerate) <= 256) {
-               clock_select = 0;
-       } else if (BASE_CLOCK_1_FREQ % samplerate == 0 &&
-                  (div = BASE_CLOCK_1_FREQ / samplerate) <= 256) {
-               clock_select = 1;
-       } else {
-               sr_err("Unable to sample at %" PRIu64 "Hz.", samplerate);
-               return SR_ERR;
-       }
-
-       for (i = 0; i < 16; i++)
-               if (channels & (1U << i))
-                       nchan++;
-
-       if ((nchan >= 13 && samplerate > MAX_13CH_SAMPLE_RATE) ||
-           (nchan >= 10 && samplerate > MAX_10CH_SAMPLE_RATE) ||
-           (nchan >= 8  && samplerate > MAX_8CH_SAMPLE_RATE) ||
-           (nchan >= 7  && samplerate > MAX_7CH_SAMPLE_RATE) ||
-           (nchan >= 4  && samplerate > MAX_4CH_SAMPLE_RATE)) {
-               sr_err("Unable to sample at %" PRIu64 "Hz "
-                      "with this many channels.", samplerate);
-               return SR_ERR;
-       }
-
-       ret = upload_fpga_bitstream(sdi, devc->selected_voltage_range);
-       if (ret != SR_OK)
-               return ret;
-
-       if ((ret = read_fpga_register(sdi, 1, &reg1)) != SR_OK)
-               return ret;
-
-       if (reg1 != 0x08) {
-               sr_dbg("Invalid state at acquisition setup: 0x%02x != 0x08.", reg1);
-               return SR_ERR;
-       }
-
-       if ((ret = write_fpga_register(sdi, 1, 0x40)) != SR_OK)
-               return ret;
-
-       if ((ret = write_fpga_register(sdi, 10, clock_select)) != SR_OK)
-               return ret;
-
-       if ((ret = write_fpga_register(sdi, 4, (uint8_t)(div - 1))) != SR_OK)
-               return ret;
-
-       if ((ret = write_fpga_register(sdi, 2, (uint8_t)(channels & 0xff))) != SR_OK)
-               return ret;
-
-       if ((ret = write_fpga_register(sdi, 3, (uint8_t)(channels >> 8))) != SR_OK)
-               return ret;
-
-       if ((ret = write_fpga_register(sdi, 1, 0x42)) != SR_OK)
-               return ret;
-
-       if ((ret = write_fpga_register(sdi, 1, 0x40)) != SR_OK)
-               return ret;
-
-       if ((ret = read_fpga_register(sdi, 1, &reg1)) != SR_OK)
-               return ret;
-
-       if (reg1 != 0x48) {
-               sr_dbg("Invalid state at acquisition setup: 0x%02x != 0x48.", reg1);
-               return SR_ERR;
-       }
-
-       if ((ret = read_fpga_register(sdi, 10, &reg10)) != SR_OK)
-               return ret;
-
-       if (reg10 != clock_select) {
-               sr_dbg("Invalid state at acquisition setup: 0x%02x != 0x%02x.",
-                      reg10, clock_select);
-               return SR_ERR;
-       }
-
-       return SR_OK;
-}
-
-SR_PRIV int logic16_start_acquisition(const struct sr_dev_inst *sdi)
-{
-       static const uint8_t command[1] = {
-               COMMAND_START_ACQUISITION,
-       };
-       int ret;
-
-       if ((ret = do_ep1_command(sdi, command, 1, NULL, 0)) != SR_OK)
-               return ret;
-
-       return write_fpga_register(sdi, 1, 0x41);
-}
-
-SR_PRIV int logic16_abort_acquisition(const struct sr_dev_inst *sdi)
-{
-       static const uint8_t command[1] = {
-               COMMAND_ABORT_ACQUISITION_ASYNC,
-       };
-       int ret;
-       uint8_t reg1, reg8, reg9;
-
-       if ((ret = do_ep1_command(sdi, command, 1, NULL, 0)) != SR_OK)
-               return ret;
-
-       if ((ret = write_fpga_register(sdi, 1, 0x00)) != SR_OK)
-               return ret;
-
-       if ((ret = read_fpga_register(sdi, 1, &reg1)) != SR_OK)
-               return ret;
-
-       if (reg1 != 0x08) {
-               sr_dbg("Invalid state at acquisition stop: 0x%02x != 0x08.", reg1);
-               return SR_ERR;
-       }
-
-       if ((ret = read_fpga_register(sdi, 8, &reg8)) != SR_OK)
-               return ret;
-
-       if ((ret = read_fpga_register(sdi, 9, &reg9)) != SR_OK)
-               return ret;
-
-       return SR_OK;
-}
-
-SR_PRIV int logic16_init_device(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       int ret;
-
-       devc = sdi->priv;
-
-       devc->cur_voltage_range = VOLTAGE_RANGE_UNKNOWN;
-
-       if ((ret = abort_acquisition_sync(sdi)) != SR_OK)
-               return ret;
-
-       if ((ret = read_eeprom(sdi, 8, 8, devc->eeprom_data)) != SR_OK)
-               return ret;
-
-       ret = upload_fpga_bitstream(sdi, devc->selected_voltage_range);
-       if (ret != SR_OK)
-               return ret;
-
-       return SR_OK;
-}
-
-static void finish_acquisition(struct sr_dev_inst *sdi)
-{
-       struct sr_datafeed_packet packet;
-       struct dev_context *devc;
-
-       devc = sdi->priv;
-
-       /* Terminate session. */
-       packet.type = SR_DF_END;
-       sr_session_send(devc->cb_data, &packet);
-
-       /* Remove fds from polling. */
-       usb_source_remove(sdi->session, devc->ctx);
-
-       devc->num_transfers = 0;
-       g_free(devc->transfers);
-       g_free(devc->convbuffer);
-       if (devc->stl) {
-               soft_trigger_logic_free(devc->stl);
-               devc->stl = NULL;
-       }
-}
-
-static void free_transfer(struct libusb_transfer *transfer)
-{
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-       unsigned int i;
-
-       sdi = transfer->user_data;
-       devc = sdi->priv;
-
-       g_free(transfer->buffer);
-       transfer->buffer = NULL;
-       libusb_free_transfer(transfer);
-
-       for (i = 0; i < devc->num_transfers; i++) {
-               if (devc->transfers[i] == transfer) {
-                       devc->transfers[i] = NULL;
-                       break;
-               }
-       }
-
-       devc->submitted_transfers--;
-       if (devc->submitted_transfers == 0)
-               finish_acquisition(sdi);
-}
-
-static void resubmit_transfer(struct libusb_transfer *transfer)
-{
-       int ret;
-
-       if ((ret = libusb_submit_transfer(transfer)) == LIBUSB_SUCCESS)
-               return;
-
-       free_transfer(transfer);
-       /* TODO: Stop session? */
-
-       sr_err("%s: %s", __func__, libusb_error_name(ret));
-}
-
-static size_t convert_sample_data(struct dev_context *devc,
-               uint8_t *dest, size_t destcnt, const uint8_t *src, size_t srccnt)
-{
-       uint16_t *channel_data;
-       int i, cur_channel;
-       size_t ret = 0;
-       uint16_t sample, channel_mask;
-
-       srccnt /= 2;
-
-       channel_data = devc->channel_data;
-       cur_channel = devc->cur_channel;
-
-       while (srccnt--) {
-               sample = src[0] | (src[1] << 8);
-               src += 2;
-
-               channel_mask = devc->channel_masks[cur_channel];
-
-               for (i = 15; i >= 0; --i, sample >>= 1)
-                       if (sample & 1)
-                               channel_data[i] |= channel_mask;
-
-               if (++cur_channel == devc->num_channels) {
-                       cur_channel = 0;
-                       if (destcnt < 16 * 2) {
-                               sr_err("Conversion buffer too small!");
-                               break;
-                       }
-                       memcpy(dest, channel_data, 16 * 2);
-                       memset(channel_data, 0, 16 * 2);
-                       dest += 16 * 2;
-                       ret += 16;
-                       destcnt -= 16 * 2;
-               }
-       }
-
-       devc->cur_channel = cur_channel;
-
-       return ret;
-}
-
-SR_PRIV void logic16_receive_transfer(struct libusb_transfer *transfer)
-{
-       gboolean packet_has_error = FALSE;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_logic logic;
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-       size_t new_samples, num_samples;
-       int trigger_offset;
-
-       sdi = transfer->user_data;
-       devc = sdi->priv;
-
-       /*
-        * If acquisition has already ended, just free any queued up
-        * transfer that come in.
-        */
-       if (devc->sent_samples < 0) {
-               free_transfer(transfer);
-               return;
-       }
-
-       sr_info("receive_transfer(): status %d received %d bytes.",
-               transfer->status, transfer->actual_length);
-
-       switch (transfer->status) {
-       case LIBUSB_TRANSFER_NO_DEVICE:
-               devc->sent_samples = -2;
-               free_transfer(transfer);
-               return;
-       case LIBUSB_TRANSFER_COMPLETED:
-       case LIBUSB_TRANSFER_TIMED_OUT: /* We may have received some data though. */
-               break;
-       default:
-               packet_has_error = TRUE;
-               break;
-       }
-
-       if (transfer->actual_length & 1) {
-               sr_err("Got an odd number of bytes from the device. "
-                      "This should not happen.");
-               /* Bail out right away. */
-               packet_has_error = TRUE;
-               devc->empty_transfer_count = MAX_EMPTY_TRANSFERS;
-       }
-
-       if (transfer->actual_length == 0 || packet_has_error) {
-               devc->empty_transfer_count++;
-               if (devc->empty_transfer_count > MAX_EMPTY_TRANSFERS) {
-                       /*
-                        * The FX2 gave up. End the acquisition, the frontend
-                        * will work out that the samplecount is short.
-                        */
-                       devc->sent_samples = -2;
-                       free_transfer(transfer);
-               } else {
-                       resubmit_transfer(transfer);
-               }
-               return;
-       } else {
-               devc->empty_transfer_count = 0;
-       }
-
-       new_samples = convert_sample_data(devc, devc->convbuffer,
-                       devc->convbuffer_size, transfer->buffer, transfer->actual_length);
-
-       if (new_samples > 0) {
-               if (devc->trigger_fired) {
-                       /* Send the incoming transfer to the session bus. */
-                       packet.type = SR_DF_LOGIC;
-                       packet.payload = &logic;
-                       if (devc->limit_samples &&
-                                       new_samples > devc->limit_samples - devc->sent_samples)
-                               new_samples = devc->limit_samples - devc->sent_samples;
-                       logic.length = new_samples * 2;
-                       logic.unitsize = 2;
-                       logic.data = devc->convbuffer;
-                       sr_session_send(devc->cb_data, &packet);
-                       devc->sent_samples += new_samples;
-               } else {
-                       trigger_offset = soft_trigger_logic_check(devc->stl,
-                                       devc->convbuffer, new_samples * 2);
-                       if (trigger_offset > -1) {
-                               packet.type = SR_DF_LOGIC;
-                               packet.payload = &logic;
-                               num_samples = new_samples - trigger_offset;
-                               if (devc->limit_samples &&
-                                               num_samples > devc->limit_samples - devc->sent_samples)
-                                       num_samples = devc->limit_samples - devc->sent_samples;
-                               logic.length = num_samples * 2;
-                               logic.unitsize = 2;
-                               logic.data = devc->convbuffer + trigger_offset * 2;
-                               sr_session_send(devc->cb_data, &packet);
-                               devc->sent_samples += num_samples;
-
-                               devc->trigger_fired = TRUE;
-                       }
-               }
-
-               if (devc->limit_samples &&
-                               (uint64_t)devc->sent_samples >= devc->limit_samples) {
-                       devc->sent_samples = -2;
-                       free_transfer(transfer);
-                       return;
-               }
-       }
-
-       resubmit_transfer(transfer);
-}
diff --git a/hardware/saleae-logic16/protocol.h b/hardware/saleae-logic16/protocol.h
deleted file mode 100644 (file)
index 8a1ded8..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Marcus Comstedt <marcus@mc.pp.se>
- * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
- * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef LIBSIGROK_HARDWARE_SALEAE_LOGIC16_PROTOCOL_H
-#define LIBSIGROK_HARDWARE_SALEAE_LOGIC16_PROTOCOL_H
-
-#include <stdint.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "saleae-logic16"
-
-enum voltage_range {
-       VOLTAGE_RANGE_UNKNOWN,
-       VOLTAGE_RANGE_18_33_V,  /* 1.8V and 3.3V logic */
-       VOLTAGE_RANGE_5_V,      /* 5V logic */
-};
-
-/** Private, per-device-instance driver context. */
-struct dev_context {
-       /*
-        * Since we can't keep track of a Logic16 device after upgrading
-        * the firmware (it renumerates into a different device address
-        * after the upgrade) this is like a global lock. No device will open
-        * until a proper delay after the last device was upgraded.
-        */
-       int64_t fw_updated;
-
-       /** The currently configured samplerate of the device. */
-       uint64_t cur_samplerate;
-
-       /** Maximum number of samples to capture, if nonzero. */
-       uint64_t limit_samples;
-
-       /** The currently configured input voltage of the device. */
-       enum voltage_range cur_voltage_range;
-
-       /** The input voltage selected by the user. */
-       enum voltage_range selected_voltage_range;
-
-       /** Channels to use. */
-       uint16_t cur_channels;
-
-       /* EEPROM data from address 8. */
-       uint8_t eeprom_data[8];
-
-       int64_t sent_samples;
-       int submitted_transfers;
-       int empty_transfer_count;
-       int num_channels;
-       int cur_channel;
-       uint16_t channel_masks[16];
-       uint16_t channel_data[16];
-       uint8_t *convbuffer;
-       size_t convbuffer_size;
-       struct soft_trigger_logic *stl;
-       gboolean trigger_fired;
-
-       void *cb_data;
-       unsigned int num_transfers;
-       struct libusb_transfer **transfers;
-       struct sr_context *ctx;
-};
-
-SR_PRIV int logic16_setup_acquisition(const struct sr_dev_inst *sdi,
-                       uint64_t samplerate, uint16_t channels);
-SR_PRIV int logic16_start_acquisition(const struct sr_dev_inst *sdi);
-SR_PRIV int logic16_abort_acquisition(const struct sr_dev_inst *sdi);
-SR_PRIV int logic16_init_device(const struct sr_dev_inst *sdi);
-SR_PRIV void logic16_receive_transfer(struct libusb_transfer *transfer);
-
-#endif
diff --git a/hardware/serial-dmm/api.c b/hardware/serial-dmm/api.c
deleted file mode 100644 (file)
index b96c7a0..0000000
+++ /dev/null
@@ -1,632 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012 Bert Vermeulen <bert@biot.com>
- * Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@gmail.com>
- * Copyright (C) 2012 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 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 <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <string.h>
-#include <errno.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-#include "protocol.h"
-
-static const int32_t hwopts[] = {
-       SR_CONF_CONN,
-       SR_CONF_SERIALCOMM,
-};
-
-static const int32_t hwcaps[] = {
-       SR_CONF_MULTIMETER,
-       SR_CONF_LIMIT_SAMPLES,
-       SR_CONF_LIMIT_MSEC,
-       SR_CONF_CONTINUOUS,
-};
-
-SR_PRIV struct sr_dev_driver bbcgm_m2110_driver_info;
-SR_PRIV struct sr_dev_driver digitek_dt4000zc_driver_info;
-SR_PRIV struct sr_dev_driver tekpower_tp4000zc_driver_info;
-SR_PRIV struct sr_dev_driver metex_me31_driver_info;
-SR_PRIV struct sr_dev_driver peaktech_3410_driver_info;
-SR_PRIV struct sr_dev_driver mastech_mas345_driver_info;
-SR_PRIV struct sr_dev_driver va_va18b_driver_info;
-SR_PRIV struct sr_dev_driver va_va40b_driver_info;
-SR_PRIV struct sr_dev_driver metex_m3640d_driver_info;
-SR_PRIV struct sr_dev_driver metex_m4650cr_driver_info;
-SR_PRIV struct sr_dev_driver peaktech_4370_driver_info;
-SR_PRIV struct sr_dev_driver pce_pce_dm32_driver_info;
-SR_PRIV struct sr_dev_driver radioshack_22_168_driver_info;
-SR_PRIV struct sr_dev_driver radioshack_22_805_driver_info;
-SR_PRIV struct sr_dev_driver radioshack_22_812_driver_info;
-SR_PRIV struct sr_dev_driver tecpel_dmm_8061_ser_driver_info;
-SR_PRIV struct sr_dev_driver voltcraft_m3650cr_driver_info;
-SR_PRIV struct sr_dev_driver voltcraft_m3650d_driver_info;
-SR_PRIV struct sr_dev_driver voltcraft_m4650cr_driver_info;
-SR_PRIV struct sr_dev_driver voltcraft_me42_driver_info;
-SR_PRIV struct sr_dev_driver voltcraft_vc820_ser_driver_info;
-SR_PRIV struct sr_dev_driver voltcraft_vc830_ser_driver_info;
-SR_PRIV struct sr_dev_driver voltcraft_vc840_ser_driver_info;
-SR_PRIV struct sr_dev_driver uni_t_ut60a_ser_driver_info;
-SR_PRIV struct sr_dev_driver uni_t_ut60e_ser_driver_info;
-SR_PRIV struct sr_dev_driver uni_t_ut60g_ser_driver_info;
-SR_PRIV struct sr_dev_driver uni_t_ut61b_ser_driver_info;
-SR_PRIV struct sr_dev_driver uni_t_ut61c_ser_driver_info;
-SR_PRIV struct sr_dev_driver uni_t_ut61d_ser_driver_info;
-SR_PRIV struct sr_dev_driver uni_t_ut61e_ser_driver_info;
-SR_PRIV struct sr_dev_driver iso_tech_idm103n_driver_info;
-SR_PRIV struct sr_dev_driver tenma_72_7745_ser_driver_info;
-SR_PRIV struct sr_dev_driver tenma_72_7750_ser_driver_info;
-
-SR_PRIV struct dmm_info dmms[] = {
-       {
-               "BBC Goertz Metrawatt", "M2110", "1200/7n2", 1200,
-               BBCGM_M2110_PACKET_SIZE, 0, 0, NULL,
-               sr_m2110_packet_valid, sr_m2110_parse,
-               NULL,
-               &bbcgm_m2110_driver_info, receive_data_BBCGM_M2110,
-       },
-       {
-               "Digitek", "DT4000ZC", "2400/8n1/dtr=1", 2400,
-               FS9721_PACKET_SIZE, 0, 0, NULL,
-               sr_fs9721_packet_valid, sr_fs9721_parse,
-               sr_fs9721_10_temp_c,
-               &digitek_dt4000zc_driver_info, receive_data_DIGITEK_DT4000ZC,
-       },
-       {
-               "TekPower", "TP4000ZC", "2400/8n1/dtr=1", 2400,
-               FS9721_PACKET_SIZE, 0, 0, NULL,
-               sr_fs9721_packet_valid, sr_fs9721_parse,
-               sr_fs9721_10_temp_c,
-               &tekpower_tp4000zc_driver_info, receive_data_TEKPOWER_TP4000ZC,
-       },
-       {
-               "Metex", "ME-31", "600/7n2/rts=0/dtr=1", 600,
-               METEX14_PACKET_SIZE, 0, 0, sr_metex14_packet_request,
-               sr_metex14_packet_valid, sr_metex14_parse,
-               NULL,
-               &metex_me31_driver_info, receive_data_METEX_ME31,
-       },
-       {
-               "Peaktech", "3410", "600/7n2/rts=0/dtr=1", 600,
-               METEX14_PACKET_SIZE, 0, 0, sr_metex14_packet_request,
-               sr_metex14_packet_valid, sr_metex14_parse,
-               NULL,
-               &peaktech_3410_driver_info, receive_data_PEAKTECH_3410,
-       },
-       {
-               "MASTECH", "MAS345", "600/7n2/rts=0/dtr=1", 600,
-               METEX14_PACKET_SIZE, 0, 0, sr_metex14_packet_request,
-               sr_metex14_packet_valid, sr_metex14_parse,
-               NULL,
-               &mastech_mas345_driver_info, receive_data_MASTECH_MAS345,
-       },
-       {
-               "V&A", "VA18B", "2400/8n1", 2400,
-               FS9721_PACKET_SIZE, 0, 0, NULL,
-               sr_fs9721_packet_valid, sr_fs9721_parse,
-               sr_fs9721_01_temp_c,
-               &va_va18b_driver_info, receive_data_VA_VA18B,
-       },
-       {
-               "V&A", "VA40B", "2400/8n1", 2400,
-               FS9721_PACKET_SIZE, 0, 0, NULL,
-               sr_fs9721_packet_valid, sr_fs9721_parse,
-               sr_fs9721_max_c_min,
-               &va_va40b_driver_info, receive_data_VA_VA40B,
-       },
-       {
-               "Metex", "M-3640D", "1200/7n2/rts=0/dtr=1", 1200,
-               METEX14_PACKET_SIZE, 0, 0, sr_metex14_packet_request,
-               sr_metex14_packet_valid, sr_metex14_parse,
-               NULL,
-               &metex_m3640d_driver_info, receive_data_METEX_M3640D,
-       },
-       {
-               "Metex", "M-4650CR", "1200/7n2/rts=0/dtr=1", 1200,
-               METEX14_PACKET_SIZE, 0, 0, sr_metex14_packet_request,
-               sr_metex14_packet_valid, sr_metex14_parse,
-               NULL,
-               &metex_m4650cr_driver_info, receive_data_METEX_M4650CR,
-       },
-       {
-               "PeakTech", "4370", "1200/7n2/rts=0/dtr=1", 1200,
-               METEX14_PACKET_SIZE, 0, 0, sr_metex14_packet_request,
-               sr_metex14_packet_valid, sr_metex14_parse,
-               NULL,
-               &peaktech_4370_driver_info, receive_data_PEAKTECH_4370,
-       },
-       {
-               "PCE", "PCE-DM32", "2400/8n1", 2400,
-               FS9721_PACKET_SIZE, 0, 0, NULL,
-               sr_fs9721_packet_valid, sr_fs9721_parse,
-               sr_fs9721_01_10_temp_f_c,
-               &pce_pce_dm32_driver_info, receive_data_PCE_PCE_DM32,
-       },
-       {
-               "RadioShack", "22-168", "1200/7n2/rts=0/dtr=1", 1200,
-               METEX14_PACKET_SIZE, 0, 0, sr_metex14_packet_request,
-               sr_metex14_packet_valid, sr_metex14_parse,
-               NULL,
-               &radioshack_22_168_driver_info, receive_data_RADIOSHACK_22_168,
-       },
-       {
-               "RadioShack", "22-805", "600/7n2/rts=0/dtr=1", 600,
-               METEX14_PACKET_SIZE, 0, 0, sr_metex14_packet_request,
-               sr_metex14_packet_valid, sr_metex14_parse,
-               NULL,
-               &radioshack_22_805_driver_info, receive_data_RADIOSHACK_22_805,
-       },
-       {
-               "RadioShack", "22-812", "4800/8n1/rts=0/dtr=1", 4800,
-               RS9LCD_PACKET_SIZE, 0, 0, NULL,
-               sr_rs9lcd_packet_valid, sr_rs9lcd_parse,
-               NULL,
-               &radioshack_22_812_driver_info, receive_data_RADIOSHACK_22_812,
-       },
-       {
-               "Tecpel", "DMM-8061 (UT-D02 cable)", "2400/8n1/rts=0/dtr=1",
-               2400, FS9721_PACKET_SIZE, 0, 0, NULL,
-               sr_fs9721_packet_valid, sr_fs9721_parse,
-               sr_fs9721_00_temp_c,
-               &tecpel_dmm_8061_ser_driver_info,
-               receive_data_TECPEL_DMM_8061_SER,
-       },
-       {
-               "Voltcraft", "M-3650CR", "1200/7n2/rts=0/dtr=1", 1200,
-               METEX14_PACKET_SIZE, 150, 20, sr_metex14_packet_request,
-               sr_metex14_packet_valid, sr_metex14_parse,
-               NULL,
-               &voltcraft_m3650cr_driver_info, receive_data_VOLTCRAFT_M3650CR,
-       },
-       {
-               "Voltcraft", "M-3650D", "1200/7n2/rts=0/dtr=1", 1200,
-               METEX14_PACKET_SIZE, 0, 0, sr_metex14_packet_request,
-               sr_metex14_packet_valid, sr_metex14_parse,
-               NULL,
-               &voltcraft_m3650d_driver_info, receive_data_VOLTCRAFT_M3650D,
-       },
-       {
-               "Voltcraft", "M-4650CR", "1200/7n2/rts=0/dtr=1", 1200,
-               METEX14_PACKET_SIZE, 0, 0, sr_metex14_packet_request,
-               sr_metex14_packet_valid, sr_metex14_parse,
-               NULL,
-               &voltcraft_m4650cr_driver_info, receive_data_VOLTCRAFT_M4650CR,
-       },
-       {
-               "Voltcraft", "ME-42", "600/7n2/rts=0/dtr=1", 600,
-               METEX14_PACKET_SIZE, 250, 60, sr_metex14_packet_request,
-               sr_metex14_packet_valid, sr_metex14_parse,
-               NULL,
-               &voltcraft_me42_driver_info, receive_data_VOLTCRAFT_ME42,
-       },
-       {
-               "Voltcraft", "VC-820 (UT-D02 cable)", "2400/8n1/rts=0/dtr=1",
-               2400, FS9721_PACKET_SIZE, 0, 0, NULL,
-               sr_fs9721_packet_valid, sr_fs9721_parse,
-               NULL,
-               &voltcraft_vc820_ser_driver_info,
-               receive_data_VOLTCRAFT_VC820_SER,
-       },
-       {
-               /*
-                * Note: The VC830 doesn't set the 'volt' and 'diode' bits of
-                * the FS9922 protocol. Instead, it only sets the user-defined
-                * bit "z1" to indicate "diode mode" and "voltage".
-                */
-               "Voltcraft", "VC-830 (UT-D02 cable)", "2400/8n1/rts=0/dtr=1",
-               2400, FS9922_PACKET_SIZE, 0, 0, NULL,
-               sr_fs9922_packet_valid, sr_fs9922_parse,
-               &sr_fs9922_z1_diode,
-               &voltcraft_vc830_ser_driver_info,
-               receive_data_VOLTCRAFT_VC830_SER,
-       },
-       {
-               "Voltcraft", "VC-840 (UT-D02 cable)", "2400/8n1/rts=0/dtr=1",
-               2400, FS9721_PACKET_SIZE, 0, 0, NULL,
-               sr_fs9721_packet_valid, sr_fs9721_parse,
-               sr_fs9721_00_temp_c,
-               &voltcraft_vc840_ser_driver_info,
-               receive_data_VOLTCRAFT_VC840_SER,
-       },
-       {
-               "UNI-T", "UT60A (UT-D02 cable)", "2400/8n1/rts=0/dtr=1",
-               2400, FS9721_PACKET_SIZE, 0, 0, NULL,
-               sr_fs9721_packet_valid, sr_fs9721_parse,
-               NULL,
-               &uni_t_ut60a_ser_driver_info,
-               receive_data_UNI_T_UT60A_SER,
-       },
-       {
-               "UNI-T", "UT60E (UT-D02 cable)", "2400/8n1/rts=0/dtr=1",
-               2400, FS9721_PACKET_SIZE, 0, 0, NULL,
-               sr_fs9721_packet_valid, sr_fs9721_parse,
-               sr_fs9721_00_temp_c,
-               &uni_t_ut60e_ser_driver_info,
-               receive_data_UNI_T_UT60E_SER,
-       },
-       {
-               /* Note: ES51986 baudrate is actually 19230! */
-               "UNI-T", "UT60G (UT-D02 cable)", "19200/7o1/rts=0/dtr=1",
-               19200, ES519XX_11B_PACKET_SIZE, 0, 0, NULL,
-               sr_es519xx_19200_11b_packet_valid, sr_es519xx_19200_11b_parse,
-               NULL,
-               &uni_t_ut60g_ser_driver_info, receive_data_UNI_T_UT60G_SER,
-       },
-       {
-               "UNI-T", "UT61B (UT-D02 cable)", "2400/8n1/rts=0/dtr=1",
-               2400, FS9922_PACKET_SIZE, 0, 0, NULL,
-               sr_fs9922_packet_valid, sr_fs9922_parse, NULL,
-               &uni_t_ut61b_ser_driver_info, receive_data_UNI_T_UT61B_SER,
-       },
-       {
-               "UNI-T", "UT61C (UT-D02 cable)", "2400/8n1/rts=0/dtr=1",
-               2400, FS9922_PACKET_SIZE, 0, 0, NULL,
-               sr_fs9922_packet_valid, sr_fs9922_parse, NULL,
-               &uni_t_ut61c_ser_driver_info, receive_data_UNI_T_UT61C_SER,
-       },
-       {
-               "UNI-T", "UT61D (UT-D02 cable)", "2400/8n1/rts=0/dtr=1",
-               2400, FS9922_PACKET_SIZE, 0, 0, NULL,
-               sr_fs9922_packet_valid, sr_fs9922_parse, NULL,
-               &uni_t_ut61d_ser_driver_info, receive_data_UNI_T_UT61D_SER,
-       },
-       {
-               /* Note: ES51922 baudrate is actually 19230! */
-               "UNI-T", "UT61E (UT-D02 cable)", "19200/7o1/rts=0/dtr=1",
-               19200, ES519XX_14B_PACKET_SIZE, 0, 0, NULL,
-               sr_es519xx_19200_14b_packet_valid, sr_es519xx_19200_14b_parse,
-               NULL,
-               &uni_t_ut61e_ser_driver_info, receive_data_UNI_T_UT61E_SER,
-       },
-       {
-               "ISO-TECH", "IDM103N", "2400/7o1/rts=0/dtr=1",
-               2400, ES519XX_11B_PACKET_SIZE, 0, 0, NULL,
-               sr_es519xx_2400_11b_packet_valid, sr_es519xx_2400_11b_parse,
-               NULL,
-               &iso_tech_idm103n_driver_info, receive_data_ISO_TECH_IDM103N,
-       },
-       {
-               "Tenma", "72-7745 (UT-D02 cable)", "2400/8n1/rts=0/dtr=1",
-               2400, FS9721_PACKET_SIZE, 0, 0, NULL,
-               sr_fs9721_packet_valid, sr_fs9721_parse,
-               sr_fs9721_00_temp_c,
-               &tenma_72_7745_ser_driver_info, receive_data_TENMA_72_7745_SER,
-       },
-       {
-               /* Note: ES51986 baudrate is actually 19230! */
-               "Tenma", "72-7750 (UT-D02 cable)", "19200/7o1/rts=0/dtr=1",
-               19200, ES519XX_11B_PACKET_SIZE, 0, 0, NULL,
-               sr_es519xx_19200_11b_packet_valid, sr_es519xx_19200_11b_parse,
-               NULL,
-               &tenma_72_7750_ser_driver_info, receive_data_TENMA_72_7750_SER,
-       },
-};
-
-static int dev_clear(int dmm)
-{
-       return std_dev_clear(dmms[dmm].di, NULL);
-}
-
-static int init(struct sr_context *sr_ctx, int dmm)
-{
-       sr_dbg("Selected '%s' subdriver.", dmms[dmm].di->name);
-
-       return std_init(sr_ctx, dmms[dmm].di, LOG_PREFIX);
-}
-
-static GSList *sdmm_scan(const char *conn, const char *serialcomm, int dmm)
-{
-       struct sr_dev_inst *sdi;
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       struct sr_channel *ch;
-       struct sr_serial_dev_inst *serial;
-       GSList *devices;
-       int dropped, ret;
-       size_t len;
-       uint8_t buf[128];
-
-       if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
-               return NULL;
-
-       if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
-               return NULL;
-
-       sr_info("Probing serial port %s.", conn);
-
-       drvc = dmms[dmm].di->priv;
-       devices = NULL;
-       serial_flush(serial);
-
-       /* Request a packet if the DMM requires this. */
-       if (dmms[dmm].packet_request) {
-               if ((ret = dmms[dmm].packet_request(serial)) < 0) {
-                       sr_err("Failed to request packet: %d.", ret);
-                       return FALSE;
-               }
-       }
-
-       /*
-        * There's no way to get an ID from the multimeter. It just sends data
-        * periodically (or upon request), so the best we can do is check if
-        * the packets match the expected format.
-        */
-
-       /* Let's get a bit of data and see if we can find a packet. */
-       len = sizeof(buf);
-       ret = serial_stream_detect(serial, buf, &len, dmms[dmm].packet_size,
-                                  dmms[dmm].packet_valid, 3000,
-                                  dmms[dmm].baudrate);
-       if (ret != SR_OK)
-               goto scan_cleanup;
-
-       /*
-        * If we dropped more than two packets worth of data, something is
-        * wrong. We shouldn't quit however, since the dropped bytes might be
-        * just zeroes at the beginning of the stream. Those can occur as a
-        * combination of the nonstandard cable that ships with some devices
-        * and the serial port or USB to serial adapter.
-        */
-       dropped = len - dmms[dmm].packet_size;
-       if (dropped > 2 * dmms[dmm].packet_size)
-               sr_warn("Had to drop too much data.");
-
-       sr_info("Found device on port %s.", conn);
-
-       if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, dmms[dmm].vendor,
-                                   dmms[dmm].device, NULL)))
-               goto scan_cleanup;
-
-       if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
-               sr_err("Device context malloc failed.");
-               goto scan_cleanup;
-       }
-
-       sdi->inst_type = SR_INST_SERIAL;
-       sdi->conn = serial;
-
-       sdi->priv = devc;
-       sdi->driver = dmms[dmm].di;
-       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1")))
-               goto scan_cleanup;
-       sdi->channels = g_slist_append(sdi->channels, ch);
-       drvc->instances = g_slist_append(drvc->instances, sdi);
-       devices = g_slist_append(devices, sdi);
-
-scan_cleanup:
-       serial_close(serial);
-
-       return devices;
-}
-
-static GSList *scan(GSList *options, int dmm)
-{
-       struct sr_config *src;
-       GSList *l, *devices;
-       const char *conn, *serialcomm;
-
-       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 = sdmm_scan(conn, serialcomm, dmm);
-       } else {
-               /* Try the default. */
-               devices = sdmm_scan(conn, dmms[dmm].conn, dmm);
-       }
-
-       return devices;
-}
-
-static GSList *dev_list(int dmm)
-{
-       return ((struct drv_context *)(dmms[dmm].di->priv))->instances;
-}
-
-static int cleanup(int dmm)
-{
-       return dev_clear(dmm);
-}
-
-static int config_set(int id, 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;
-
-       if (!(devc = sdi->priv)) {
-               sr_err("sdi->priv was NULL.");
-               return SR_ERR_BUG;
-       }
-
-       switch (id) {
-       case SR_CONF_LIMIT_SAMPLES:
-               devc->limit_samples = g_variant_get_uint64(data);
-               sr_dbg("Setting sample limit to %" PRIu64 ".",
-                      devc->limit_samples);
-               break;
-       case SR_CONF_LIMIT_MSEC:
-               devc->limit_msec = g_variant_get_uint64(data);
-               sr_dbg("Setting time limit to %" PRIu64 "ms.",
-                      devc->limit_msec);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_list(int 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_INT32,
-                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
-               break;
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi,
-                                   void *cb_data, int dmm)
-{
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       if (!(devc = sdi->priv)) {
-               sr_err("sdi->priv was NULL.");
-               return SR_ERR_BUG;
-       }
-
-       devc->cb_data = cb_data;
-
-       /*
-        * Reset the number of samples to take. If we've already collected our
-        * quota, but we start a new session, and don't reset this, we'll just
-        * quit without acquiring any new samples.
-        */
-       devc->num_samples = 0;
-       devc->starttime = g_get_monotonic_time();
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(cb_data, LOG_PREFIX);
-
-       /* Poll every 50ms, or whenever some data comes in. */
-       serial = sdi->conn;
-       serial_source_add(sdi->session, serial, G_IO_IN, 50,
-                     dmms[dmm].receive_data, (void *)sdi);
-
-       return SR_OK;
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       return std_serial_dev_acquisition_stop(sdi, cb_data, std_serial_dev_close,
-                       sdi->conn, LOG_PREFIX);
-}
-
-/* Driver-specific API function wrappers */
-#define HW_INIT(X) \
-static int init_##X(struct sr_context *sr_ctx) { return init(sr_ctx, X); }
-#define HW_CLEANUP(X) \
-static int cleanup_##X(void) { return cleanup(X); }
-#define HW_SCAN(X) \
-static GSList *scan_##X(GSList *options) { return scan(options, X); }
-#define HW_DEV_LIST(X) \
-static GSList *dev_list_##X(void) { return dev_list(X); }
-#define HW_DEV_CLEAR(X) \
-static int dev_clear_##X(void) { return dev_clear(X); }
-#define HW_DEV_ACQUISITION_START(X) \
-static int dev_acquisition_start_##X(const struct sr_dev_inst *sdi, \
-void *cb_data) { return dev_acquisition_start(sdi, cb_data, X); }
-
-/* Driver structs and API function wrappers */
-#define DRV(ID, ID_UPPER, NAME, LONGNAME) \
-HW_INIT(ID_UPPER) \
-HW_CLEANUP(ID_UPPER) \
-HW_SCAN(ID_UPPER) \
-HW_DEV_LIST(ID_UPPER) \
-HW_DEV_CLEAR(ID_UPPER) \
-HW_DEV_ACQUISITION_START(ID_UPPER) \
-SR_PRIV struct sr_dev_driver ID##_driver_info = { \
-       .name = NAME, \
-       .longname = LONGNAME, \
-       .api_version = 1, \
-       .init = init_##ID_UPPER, \
-       .cleanup = cleanup_##ID_UPPER, \
-       .scan = scan_##ID_UPPER, \
-       .dev_list = dev_list_##ID_UPPER, \
-       .dev_clear = dev_clear_##ID_UPPER, \
-       .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_##ID_UPPER, \
-       .dev_acquisition_stop = dev_acquisition_stop, \
-       .priv = NULL, \
-};
-
-DRV(bbcgm_m2110, BBCGM_M2110, "bbcgm-m2110", "BBC Goertz Metrawatt M2110")
-DRV(digitek_dt4000zc, DIGITEK_DT4000ZC, "digitek-dt4000zc", "Digitek DT4000ZC")
-DRV(tekpower_tp4000zc, TEKPOWER_TP4000ZC, "tekpower-tp4000zc", "TekPower TP4000ZC")
-DRV(metex_me31, METEX_ME31, "metex-me31", "Metex ME-31")
-DRV(peaktech_3410, PEAKTECH_3410, "peaktech-3410", "PeakTech 3410")
-DRV(mastech_mas345, MASTECH_MAS345, "mastech-mas345", "MASTECH MAS345")
-DRV(va_va18b, VA_VA18B, "va-va18b", "V&A VA18B")
-DRV(va_va40b, VA_VA40B, "va-va40b", "V&A VA40B")
-DRV(metex_m3640d, METEX_M3640D, "metex-m3640d", "Metex M-3640D")
-DRV(metex_m4650cr, METEX_M4650CR, "metex-m4650cr", "Metex M-4650CR")
-DRV(peaktech_4370, PEAKTECH_4370, "peaktech-4370", "PeakTech 4370")
-DRV(pce_pce_dm32, PCE_PCE_DM32, "pce-pce-dm32", "PCE PCE-DM32")
-DRV(radioshack_22_168, RADIOSHACK_22_168, "radioshack-22-168", "RadioShack 22-168")
-DRV(radioshack_22_805, RADIOSHACK_22_805, "radioshack-22-805", "RadioShack 22-805")
-DRV(radioshack_22_812, RADIOSHACK_22_812, "radioshack-22-812", "RadioShack 22-812")
-DRV(tecpel_dmm_8061_ser, TECPEL_DMM_8061_SER, "tecpel-dmm-8061-ser", "Tecpel DMM-8061 (UT-D02 cable)")
-DRV(voltcraft_m3650cr, VOLTCRAFT_M3650CR, "voltcraft-m3650cr", "Voltcraft M-3650CR")
-DRV(voltcraft_m3650d, VOLTCRAFT_M3650D, "voltcraft-m3650d", "Voltcraft M-3650D")
-DRV(voltcraft_m4650cr, VOLTCRAFT_M4650CR, "voltcraft-m4650cr", "Voltcraft M-4650CR")
-DRV(voltcraft_me42, VOLTCRAFT_ME42, "voltcraft-me42", "Voltcraft ME-42")
-DRV(voltcraft_vc820_ser, VOLTCRAFT_VC820_SER, "voltcraft-vc820-ser", "Voltcraft VC-820 (UT-D02 cable)")
-DRV(voltcraft_vc830_ser, VOLTCRAFT_VC830_SER, "voltcraft-vc830-ser", "Voltcraft VC-830 (UT-D02 cable)")
-DRV(voltcraft_vc840_ser, VOLTCRAFT_VC840_SER, "voltcraft-vc840-ser", "Voltcraft VC-840 (UT-D02 cable)")
-DRV(uni_t_ut60a_ser, UNI_T_UT60A_SER, "uni-t-ut60a-ser", "UNI-T UT60A (UT-D02 cable)")
-DRV(uni_t_ut60e_ser, UNI_T_UT60E_SER, "uni-t-ut60e-ser", "UNI-T UT60E (UT-D02 cable)")
-DRV(uni_t_ut60g_ser, UNI_T_UT60G_SER, "uni-t-ut60g-ser", "UNI-T UT60G (UT-D02 cable)")
-DRV(uni_t_ut61b_ser, UNI_T_UT61B_SER, "uni-t-ut61b-ser", "UNI-T UT61B (UT-D02 cable)")
-DRV(uni_t_ut61c_ser, UNI_T_UT61C_SER, "uni-t-ut61c-ser", "UNI-T UT61C (UT-D02 cable)")
-DRV(uni_t_ut61d_ser, UNI_T_UT61D_SER, "uni-t-ut61d-ser", "UNI-T UT61D (UT-D02 cable)")
-DRV(uni_t_ut61e_ser, UNI_T_UT61E_SER, "uni-t-ut61e-ser", "UNI-T UT61E (UT-D02 cable)")
-DRV(iso_tech_idm103n, ISO_TECH_IDM103N, "iso-tech-idm103n", "ISO-TECH IDM103N")
-DRV(tenma_72_7745_ser, TENMA_72_7745_SER, "tenma-72-7745-ser", "Tenma 72-7745 (UT-D02 cable)")
-DRV(tenma_72_7750_ser, TENMA_72_7750_SER, "tenma-72-7750-ser", "Tenma 72-7750 (UT-D02 cable)")
diff --git a/hardware/serial-dmm/protocol.c b/hardware/serial-dmm/protocol.c
deleted file mode 100644 (file)
index 0b2472f..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@gmail.com>
- * Copyright (C) 2012 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 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 <stdlib.h>
-#include <math.h>
-#include <string.h>
-#include <errno.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-#include "protocol.h"
-
-static void log_dmm_packet(const uint8_t *buf)
-{
-       sr_dbg("DMM packet: %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]);
-}
-
-static void handle_packet(const uint8_t *buf, struct sr_dev_inst *sdi,
-                         int dmm, void *info)
-{
-       float floatval;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_analog analog;
-       struct dev_context *devc;
-
-       log_dmm_packet(buf);
-       devc = sdi->priv;
-
-       memset(&analog, 0, sizeof(struct sr_datafeed_analog));
-
-       analog.channels = sdi->channels;
-       analog.num_samples = 1;
-       analog.mq = -1;
-
-       dmms[dmm].packet_parse(buf, &floatval, &analog, info);
-       analog.data = &floatval;
-
-       /* If this DMM needs additional handling, call the resp. function. */
-       if (dmms[dmm].dmm_details)
-               dmms[dmm].dmm_details(&analog, info);
-
-       if (analog.mq != -1) {
-               /* Got a measurement. */
-               packet.type = SR_DF_ANALOG;
-               packet.payload = &analog;
-               sr_session_send(devc->cb_data, &packet);
-               devc->num_samples++;
-       }
-}
-
-/** Request packet, if required. */
-SR_PRIV int req_packet(struct sr_dev_inst *sdi, int dmm)
-{
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-       int ret;
-
-       if (!dmms[dmm].packet_request)
-               return SR_OK;
-
-       devc = sdi->priv;
-       serial = sdi->conn;
-
-       if (devc->req_next_at && (devc->req_next_at > g_get_monotonic_time())) {
-               sr_spew("Not requesting new packet yet, %" PRIi64 " ms left.",
-                       ((devc->req_next_at - g_get_monotonic_time()) / 1000));
-               return SR_OK;
-       }
-
-       ret = dmms[dmm].packet_request(serial);
-       if (ret < 0) {
-               sr_err("Failed to request packet: %d.", ret);
-               return ret;
-       }
-
-       if (dmms[dmm].req_timeout_ms)
-               devc->req_next_at = g_get_monotonic_time() + (dmms[dmm].req_timeout_ms * 1000);
-
-       return SR_OK;
-}
-
-static void handle_new_data(struct sr_dev_inst *sdi, int dmm, void *info)
-{
-       struct dev_context *devc;
-       int len, i, 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(serial, devc->buf + devc->buflen, len);
-       if (len == 0)
-               return; /* No new bytes, nothing to do. */
-       if (len < 0) {
-               sr_err("Serial port read error: %d.", len);
-               return;
-       }
-       devc->buflen += len;
-
-       /* Now look for packets in that data. */
-       while ((devc->buflen - offset) >= dmms[dmm].packet_size) {
-               if (dmms[dmm].packet_valid(devc->buf + offset)) {
-                       handle_packet(devc->buf + offset, sdi, dmm, info);
-                       offset += dmms[dmm].packet_size;
-
-                       /* Request next packet, if required. */
-                       if (!dmms[dmm].packet_request)
-                               break;
-                       if (dmms[dmm].req_timeout_ms || dmms[dmm].req_delay_ms)
-                               devc->req_next_at = g_get_monotonic_time() +
-                                       dmms[dmm].req_delay_ms * 1000;
-                       req_packet(sdi, dmm);
-               } else {
-                       offset++;
-               }
-       }
-
-       /* If we have any data left, move it to the beginning of our buffer. */
-       for (i = 0; i < devc->buflen - offset; i++)
-               devc->buf[i] = devc->buf[offset + i];
-       devc->buflen -= offset;
-}
-
-static int receive_data(int fd, int revents, int dmm, void *info, void *cb_data)
-{
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-       int64_t time;
-
-       (void)fd;
-
-       if (!(sdi = cb_data))
-               return TRUE;
-
-       if (!(devc = sdi->priv))
-               return TRUE;
-
-       if (revents == G_IO_IN) {
-               /* Serial data arrived. */
-               handle_new_data(sdi, dmm, info);
-       } else {
-               /* Timeout; send another packet request if DMM needs it. */
-               if (dmms[dmm].packet_request && (req_packet(sdi, dmm) < 0))
-                       return FALSE;
-       }
-
-       if (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
-               sr_info("Requested number of samples reached.");
-               sdi->driver->dev_acquisition_stop(sdi, cb_data);
-               return TRUE;
-       }
-
-       if (devc->limit_msec) {
-               time = (g_get_monotonic_time() - devc->starttime) / 1000;
-               if (time > (int64_t)devc->limit_msec) {
-                       sr_info("Requested time limit reached.");
-                       sdi->driver->dev_acquisition_stop(sdi, cb_data);
-                       return TRUE;
-               }
-       }
-
-       return TRUE;
-}
-
-#define RECEIVE_DATA(ID_UPPER, DMM_DRIVER) \
-SR_PRIV int receive_data_##ID_UPPER(int fd, int revents, void *cb_data) { \
-       struct DMM_DRIVER##_info info; \
-       return receive_data(fd, revents, ID_UPPER, &info, cb_data); }
-
-/* Driver-specific receive_data() wrappers */
-RECEIVE_DATA(BBCGM_M2110, metex14) /* metex14_info used as a dummy. */
-RECEIVE_DATA(DIGITEK_DT4000ZC, fs9721)
-RECEIVE_DATA(TEKPOWER_TP4000ZC, fs9721)
-RECEIVE_DATA(METEX_ME31, metex14)
-RECEIVE_DATA(PEAKTECH_3410, metex14)
-RECEIVE_DATA(MASTECH_MAS345, metex14)
-RECEIVE_DATA(VA_VA18B, fs9721)
-RECEIVE_DATA(VA_VA40B, fs9721)
-RECEIVE_DATA(METEX_M3640D, metex14)
-RECEIVE_DATA(METEX_M4650CR, metex14)
-RECEIVE_DATA(PEAKTECH_4370, metex14)
-RECEIVE_DATA(PCE_PCE_DM32, fs9721)
-RECEIVE_DATA(RADIOSHACK_22_168, metex14)
-RECEIVE_DATA(RADIOSHACK_22_805, metex14)
-RECEIVE_DATA(RADIOSHACK_22_812, rs9lcd)
-RECEIVE_DATA(TECPEL_DMM_8061_SER, fs9721)
-RECEIVE_DATA(VOLTCRAFT_M3650CR, metex14)
-RECEIVE_DATA(VOLTCRAFT_M3650D, metex14)
-RECEIVE_DATA(VOLTCRAFT_M4650CR, metex14)
-RECEIVE_DATA(VOLTCRAFT_ME42, metex14)
-RECEIVE_DATA(VOLTCRAFT_VC820_SER, fs9721)
-RECEIVE_DATA(VOLTCRAFT_VC830_SER, fs9922)
-RECEIVE_DATA(VOLTCRAFT_VC840_SER, fs9721)
-RECEIVE_DATA(UNI_T_UT60A_SER, fs9721)
-RECEIVE_DATA(UNI_T_UT60E_SER, fs9721)
-RECEIVE_DATA(UNI_T_UT60G_SER, es519xx)
-RECEIVE_DATA(UNI_T_UT61B_SER, fs9922)
-RECEIVE_DATA(UNI_T_UT61C_SER, fs9922)
-RECEIVE_DATA(UNI_T_UT61D_SER, fs9922)
-RECEIVE_DATA(UNI_T_UT61E_SER, es519xx)
-RECEIVE_DATA(ISO_TECH_IDM103N, es519xx)
-RECEIVE_DATA(TENMA_72_7745_SER, fs9721)
-RECEIVE_DATA(TENMA_72_7750_SER, es519xx)
diff --git a/hardware/serial-dmm/protocol.h b/hardware/serial-dmm/protocol.h
deleted file mode 100644 (file)
index fb5a2a3..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * 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_SERIAL_DMM_PROTOCOL_H
-#define LIBSIGROK_HARDWARE_SERIAL_DMM_PROTOCOL_H
-
-#define LOG_PREFIX "serial-dmm"
-
-enum {
-       BBCGM_M2110,
-       DIGITEK_DT4000ZC,
-       TEKPOWER_TP4000ZC,
-       METEX_ME31,
-       PEAKTECH_3410,
-       MASTECH_MAS345,
-       VA_VA18B,
-       VA_VA40B,
-       METEX_M3640D,
-       METEX_M4650CR,
-       PEAKTECH_4370,
-       PCE_PCE_DM32,
-       RADIOSHACK_22_168,
-       RADIOSHACK_22_805,
-       RADIOSHACK_22_812,
-       TECPEL_DMM_8061_SER,
-       VOLTCRAFT_M3650CR,
-       VOLTCRAFT_M3650D,
-       VOLTCRAFT_M4650CR,
-       VOLTCRAFT_ME42,
-       VOLTCRAFT_VC820_SER,
-       VOLTCRAFT_VC830_SER,
-       VOLTCRAFT_VC840_SER,
-       UNI_T_UT60A_SER,
-       UNI_T_UT60E_SER,
-       UNI_T_UT60G_SER,
-       UNI_T_UT61B_SER,
-       UNI_T_UT61C_SER,
-       UNI_T_UT61D_SER,
-       UNI_T_UT61E_SER,
-       ISO_TECH_IDM103N,
-       TENMA_72_7745_SER,
-       TENMA_72_7750_SER,
-};
-
-struct dmm_info {
-       /** Manufacturer/brand. */
-       char *vendor;
-       /** Model. */
-       char *device;
-       /** serialconn string. */
-       char *conn;
-       /** Baud rate. */
-       uint32_t baudrate;
-       /** Packet size in bytes. */
-       int packet_size;
-       /** Request timeout [ms] before request is considered lost and a new
-        *  one is sent. Used only if device needs polling. */
-       int64_t req_timeout_ms;
-       /** Delay between reception of packet and next request. Some DMMs
-        *  need this. Used only if device needs polling. */
-       int64_t req_delay_ms;
-       /** Packet request function. */
-       int (*packet_request)(struct sr_serial_dev_inst *);
-       /** Packet validation function. */
-       gboolean (*packet_valid)(const uint8_t *);
-       /** Packet parsing function. */
-       int (*packet_parse)(const uint8_t *, float *,
-                           struct sr_datafeed_analog *, void *);
-       /** */
-       void (*dmm_details)(struct sr_datafeed_analog *, void *);
-       /** libsigrok driver info struct. */
-       struct sr_dev_driver *di;
-       /** Data reception function. */
-       int (*receive_data)(int, int, void *);
-};
-
-extern SR_PRIV struct dmm_info dmms[];
-
-#define DMM_BUFSIZE 256
-
-/** Private, per-device-instance driver context. */
-struct dev_context {
-       /** The current sampling limit (in number of samples). */
-       uint64_t limit_samples;
-
-       /** The time limit (in milliseconds). */
-       uint64_t limit_msec;
-
-       /** Opaque pointer passed in by the frontend. */
-       void *cb_data;
-
-       /** The current number of already received samples. */
-       uint64_t num_samples;
-
-       /** The starting time of current sampling run. */
-       int64_t starttime;
-
-       uint8_t buf[DMM_BUFSIZE];
-       int bufoffset;
-       int buflen;
-
-       /** The timestamp [µs] to send the next request.
-        *  Used only if device needs polling. */
-       int64_t req_next_at;
-};
-
-SR_PRIV int req_packet(struct sr_dev_inst *sdi, int dmm);
-
-SR_PRIV int receive_data_BBCGM_M2110(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_DIGITEK_DT4000ZC(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_TEKPOWER_TP4000ZC(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_METEX_ME31(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_PEAKTECH_3410(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_MASTECH_MAS345(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_VA_VA18B(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_VA_VA40B(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_METEX_M3640D(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_METEX_M4650CR(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_PEAKTECH_4370(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_PCE_PCE_DM32(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_RADIOSHACK_22_168(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_RADIOSHACK_22_805(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_RADIOSHACK_22_812(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_TECPEL_DMM_8061_SER(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_VOLTCRAFT_M3650CR(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_VOLTCRAFT_M3650D(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_VOLTCRAFT_M4650CR(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_VOLTCRAFT_ME42(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_VOLTCRAFT_VC820_SER(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_VOLTCRAFT_VC830_SER(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_VOLTCRAFT_VC840_SER(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_UNI_T_UT60A_SER(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_UNI_T_UT60E_SER(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_UNI_T_UT60G_SER(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_UNI_T_UT61B_SER(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_UNI_T_UT61C_SER(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_UNI_T_UT61D_SER(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_UNI_T_UT61E_SER(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_ISO_TECH_IDM103N(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_TENMA_72_7745_SER(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_TENMA_72_7750_SER(int fd, int revents, void *cb_data);
-
-#endif
diff --git a/hardware/sysclk-lwla/api.c b/hardware/sysclk-lwla/api.c
deleted file mode 100644 (file)
index a4346a0..0000000
+++ /dev/null
@@ -1,584 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2014 Daniel Elstner <daniel.kitta@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 "protocol.h"
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-#include <glib.h>
-#include <libusb.h>
-#include <stdlib.h>
-#include <string.h>
-
-static const int32_t hwopts[] = {
-       SR_CONF_CONN,
-};
-
-static const int32_t hwcaps[] = {
-       SR_CONF_LOGIC_ANALYZER,
-       SR_CONF_SAMPLERATE,
-       SR_CONF_EXTERNAL_CLOCK,
-       SR_CONF_CLOCK_EDGE,
-       SR_CONF_TRIGGER_MATCH,
-       SR_CONF_TRIGGER_SOURCE,
-       SR_CONF_TRIGGER_SLOPE,
-       SR_CONF_LIMIT_MSEC,
-       SR_CONF_LIMIT_SAMPLES,
-};
-
-static const int32_t trigger_matches[] = {
-       SR_TRIGGER_ZERO,
-       SR_TRIGGER_ONE,
-       SR_TRIGGER_RISING,
-       SR_TRIGGER_FALLING,
-};
-
-/* The hardware supports more samplerates than these, but these are the
- * options hardcoded into the vendor's Windows GUI.
- */
-static const uint64_t samplerates[] = {
-       SR_MHZ(125), SR_MHZ(100),
-       SR_MHZ(50),  SR_MHZ(20),  SR_MHZ(10),
-       SR_MHZ(5),   SR_MHZ(2),   SR_MHZ(1),
-       SR_KHZ(500), SR_KHZ(200), SR_KHZ(100),
-       SR_KHZ(50),  SR_KHZ(20),  SR_KHZ(10),
-       SR_KHZ(5),   SR_KHZ(2),   SR_KHZ(1),
-       SR_HZ(500),  SR_HZ(200),  SR_HZ(100),
-};
-
-/* Names assigned to available trigger sources.  Indices must match
- * trigger_source enum values.
- */
-static const char *const trigger_source_names[] = { "CH", "TRG" };
-
-/* Names assigned to available trigger slope choices.  Indices must
- * match the signal_edge enum values.
- */
-static const char *const signal_edge_names[] = { "r", "f" };
-
-SR_PRIV struct sr_dev_driver sysclk_lwla_driver_info;
-static struct sr_dev_driver *const di = &sysclk_lwla_driver_info;
-
-static int init(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, di, LOG_PREFIX);
-}
-
-static GSList *gen_channel_list(int num_channels)
-{
-       GSList *list;
-       struct sr_channel *ch;
-       int i;
-       char name[8];
-
-       list = NULL;
-
-       for (i = num_channels; i > 0; --i) {
-               /* The LWLA series simply number channels from CH1 to CHxx. */
-               g_snprintf(name, sizeof(name), "CH%d", i);
-
-               ch = sr_channel_new(i - 1, SR_CHANNEL_LOGIC, TRUE, name);
-               list = g_slist_prepend(list, ch);
-       }
-
-       return list;
-}
-
-static struct sr_dev_inst *dev_inst_new(int device_index)
-{
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-
-       /* Allocate memory for our private driver context. */
-       devc = g_try_new0(struct dev_context, 1);
-       if (!devc) {
-               sr_err("Device context malloc failed.");
-               return NULL;
-       }
-
-       /* Register the device with libsigrok. */
-       sdi = sr_dev_inst_new(device_index, SR_ST_INACTIVE,
-                             VENDOR_NAME, MODEL_NAME, NULL);
-       if (!sdi) {
-               sr_err("Failed to instantiate device.");
-               g_free(devc);
-               return NULL;
-       }
-
-       /* Enable all channels to match the default channel configuration. */
-       devc->channel_mask = ALL_CHANNELS_MASK;
-       devc->samplerate = DEFAULT_SAMPLERATE;
-
-       sdi->priv = devc;
-       sdi->channels = gen_channel_list(NUM_CHANNELS);
-
-       return sdi;
-}
-
-static GSList *scan(GSList *options)
-{
-       GSList *usb_devices, *devices, *node;
-       struct drv_context *drvc;
-       struct sr_dev_inst *sdi;
-       struct sr_usb_dev_inst *usb;
-       struct sr_config *src;
-       const char *conn;
-       int device_index;
-
-       drvc = di->priv;
-       conn = USB_VID_PID;
-
-       for (node = options; node != NULL; node = node->next) {
-               src = node->data;
-               if (src->key == SR_CONF_CONN) {
-                       conn = g_variant_get_string(src->data, NULL);
-                       break;
-               }
-       }
-       usb_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn);
-       devices = NULL;
-       device_index = g_slist_length(drvc->instances);
-
-       for (node = usb_devices; node != NULL; node = node->next) {
-               usb = node->data;
-
-               /* Create sigrok device instance. */
-               sdi = dev_inst_new(device_index);
-               if (!sdi) {
-                       sr_usb_dev_inst_free(usb);
-                       continue;
-               }
-               sdi->driver = di;
-               sdi->inst_type = SR_INST_USB;
-               sdi->conn = usb;
-
-               /* Register device instance with driver. */
-               drvc->instances = g_slist_append(drvc->instances, sdi);
-               devices = g_slist_append(devices, sdi);
-       }
-
-       g_slist_free(usb_devices);
-
-       return devices;
-}
-
-static GSList *dev_list(void)
-{
-       struct drv_context *drvc;
-
-       drvc = di->priv;
-
-       return drvc->instances;
-}
-
-static void clear_dev_context(void *priv)
-{
-       struct dev_context *devc;
-
-       devc = priv;
-
-       sr_dbg("Device context cleared.");
-
-       lwla_free_acquisition_state(devc->acquisition);
-       g_free(devc);
-}
-
-static int dev_clear(void)
-{
-       return std_dev_clear(di, &clear_dev_context);
-}
-
-static int dev_open(struct sr_dev_inst *sdi)
-{
-       struct drv_context *drvc;
-       struct sr_usb_dev_inst *usb;
-       int ret;
-
-       drvc = di->priv;
-
-       if (!drvc) {
-               sr_err("Driver was not initialized.");
-               return SR_ERR;
-       }
-
-       usb = sdi->conn;
-
-       ret = sr_usb_open(drvc->sr_ctx->libusb_ctx, usb);
-       if (ret != SR_OK)
-               return ret;
-
-       ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE);
-       if (ret < 0) {
-               sr_err("Failed to claim interface: %s.",
-                       libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-       sdi->status = SR_ST_INITIALIZING;
-
-       ret = lwla_init_device(sdi);
-
-       if (ret == SR_OK)
-               sdi->status = SR_ST_ACTIVE;
-
-       return ret;
-}
-
-static int dev_close(struct sr_dev_inst *sdi)
-{
-       struct sr_usb_dev_inst *usb;
-
-       if (!di->priv) {
-               sr_err("Driver was not initialized.");
-               return SR_ERR;
-       }
-
-       usb = sdi->conn;
-       if (!usb->devhdl)
-               return SR_OK;
-
-       sdi->status = SR_ST_INACTIVE;
-
-       /* Trigger download of the shutdown bitstream. */
-       if (lwla_set_clock_config(sdi) != SR_OK)
-               sr_err("Unable to shut down device.");
-
-       libusb_release_interface(usb->devhdl, USB_INTERFACE);
-       libusb_close(usb->devhdl);
-
-       usb->devhdl = NULL;
-
-       return SR_OK;
-}
-
-static int cleanup(void)
-{
-       return dev_clear();
-}
-
-static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
-                     const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       size_t idx;
-
-       (void)cg;
-
-       if (!sdi)
-               return SR_ERR_ARG;
-
-       devc = sdi->priv;
-
-       switch (key) {
-       case SR_CONF_SAMPLERATE:
-               *data = g_variant_new_uint64(devc->samplerate);
-               break;
-       case SR_CONF_LIMIT_MSEC:
-               *data = g_variant_new_uint64(devc->limit_msec);
-               break;
-       case SR_CONF_LIMIT_SAMPLES:
-               *data = g_variant_new_uint64(devc->limit_samples);
-               break;
-       case SR_CONF_EXTERNAL_CLOCK:
-               *data = g_variant_new_boolean(devc->cfg_clock_source
-                                               == CLOCK_EXT_CLK);
-               break;
-       case SR_CONF_CLOCK_EDGE:
-               idx = devc->cfg_clock_edge;
-               if (idx >= G_N_ELEMENTS(signal_edge_names))
-                       return SR_ERR_BUG;
-               *data = g_variant_new_string(signal_edge_names[idx]);
-               break;
-       case SR_CONF_TRIGGER_SOURCE:
-               idx = devc->cfg_trigger_source;
-               if (idx >= G_N_ELEMENTS(trigger_source_names))
-                       return SR_ERR_BUG;
-               *data = g_variant_new_string(trigger_source_names[idx]);
-               break;
-       case SR_CONF_TRIGGER_SLOPE:
-               idx = devc->cfg_trigger_slope;
-               if (idx >= G_N_ELEMENTS(signal_edge_names))
-                       return SR_ERR_BUG;
-               *data = g_variant_new_string(signal_edge_names[idx]);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-/* Helper for mapping a string-typed configuration value to an index
- * within a table of possible values.
- */
-static int lookup_index(GVariant *value, const char *const *table, int len)
-{
-       const char *entry;
-       int i;
-
-       entry = g_variant_get_string(value, NULL);
-       if (!entry)
-               return -1;
-
-       /* Linear search is fine for very small tables. */
-       for (i = 0; i < len; ++i) {
-               if (strcmp(entry, table[i]) == 0)
-                       return i;
-       }
-       return -1;
-}
-
-static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
-                     const struct sr_channel_group *cg)
-{
-       uint64_t value;
-       struct dev_context *devc;
-       int idx;
-
-       (void)cg;
-
-       devc = sdi->priv;
-       if (!devc)
-               return SR_ERR_DEV_CLOSED;
-
-       switch (key) {
-       case SR_CONF_SAMPLERATE:
-               value = g_variant_get_uint64(data);
-               if (value < samplerates[G_N_ELEMENTS(samplerates) - 1]
-                               || value > samplerates[0])
-                       return SR_ERR_SAMPLERATE;
-               devc->samplerate = value;
-               break;
-       case SR_CONF_LIMIT_MSEC:
-               value = g_variant_get_uint64(data);
-               if (value > MAX_LIMIT_MSEC)
-                       return SR_ERR_ARG;
-               devc->limit_msec = value;
-               break;
-       case SR_CONF_LIMIT_SAMPLES:
-               value = g_variant_get_uint64(data);
-               if (value > MAX_LIMIT_SAMPLES)
-                       return SR_ERR_ARG;
-               devc->limit_samples = value;
-               break;
-       case SR_CONF_EXTERNAL_CLOCK:
-               devc->cfg_clock_source = (g_variant_get_boolean(data))
-                       ? CLOCK_EXT_CLK : CLOCK_INTERNAL;
-               break;
-       case SR_CONF_CLOCK_EDGE:
-               idx = lookup_index(data, signal_edge_names,
-                                  G_N_ELEMENTS(signal_edge_names));
-               if (idx < 0)
-                       return SR_ERR_ARG;
-               devc->cfg_clock_edge = idx;
-               break;
-       case SR_CONF_TRIGGER_SOURCE:
-               idx = lookup_index(data, trigger_source_names,
-                                  G_N_ELEMENTS(trigger_source_names));
-               if (idx < 0)
-                       return SR_ERR_ARG;
-               devc->cfg_trigger_source = idx;
-               break;
-       case SR_CONF_TRIGGER_SLOPE:
-               idx = lookup_index(data, signal_edge_names,
-                                  G_N_ELEMENTS(signal_edge_names));
-               if (idx < 0)
-                       return SR_ERR_ARG;
-               devc->cfg_trigger_slope = idx;
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_channel_set(const struct sr_dev_inst *sdi,
-               struct sr_channel *ch, unsigned int changes)
-{
-       uint64_t channel_bit;
-       struct dev_context *devc;
-
-       devc = sdi->priv;
-       if (!devc)
-               return SR_ERR_DEV_CLOSED;
-
-       if (ch->index < 0 || ch->index >= NUM_CHANNELS) {
-               sr_err("Channel index %d out of range.", ch->index);
-               return SR_ERR_BUG;
-       }
-       channel_bit = (uint64_t)1 << ch->index;
-
-       if ((changes & SR_CHANNEL_SET_ENABLED) != 0) {
-               /* Enable or disable input channel for this channel. */
-               if (ch->enabled)
-                       devc->channel_mask |= channel_bit;
-               else
-                       devc->channel_mask &= ~channel_bit;
-       }
-
-       return SR_OK;
-}
-
-static int config_commit(const struct sr_dev_inst *sdi)
-{
-       if (sdi->status != SR_ST_ACTIVE) {
-               sr_err("Device not ready (status %d).", (int)sdi->status);
-               return SR_ERR;
-       }
-
-       return lwla_set_clock_config(sdi);
-}
-
-static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
-                      const struct sr_channel_group *cg)
-{
-       GVariant *gvar;
-       GVariantBuilder gvb;
-
-       (void)sdi;
-       (void)cg;
-
-       switch (key) {
-       case SR_CONF_SCAN_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               hwopts, G_N_ELEMENTS(hwopts), sizeof(int32_t));
-               break;
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               hwcaps, G_N_ELEMENTS(hwcaps), sizeof(int32_t));
-               break;
-       case SR_CONF_SAMPLERATE:
-               g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
-               gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"),
-                               samplerates, G_N_ELEMENTS(samplerates),
-                               sizeof(uint64_t));
-               g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar);
-               *data = g_variant_builder_end(&gvb);
-               break;
-       case SR_CONF_TRIGGER_MATCH:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               trigger_matches, ARRAY_SIZE(trigger_matches),
-                               sizeof(int32_t));
-               break;
-       case SR_CONF_TRIGGER_SOURCE:
-               *data = g_variant_new_strv(trigger_source_names,
-                                          G_N_ELEMENTS(trigger_source_names));
-               break;
-       case SR_CONF_TRIGGER_SLOPE:
-       case SR_CONF_CLOCK_EDGE:
-               *data = g_variant_new_strv(signal_edge_names,
-                                          G_N_ELEMENTS(signal_edge_names));
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       struct acquisition_state *acq;
-       int ret;
-
-       (void)cb_data;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       devc = sdi->priv;
-       drvc = di->priv;
-
-       if (devc->acquisition) {
-               sr_err("Acquisition still in progress?");
-               return SR_ERR;
-       }
-       acq = lwla_alloc_acquisition_state();
-       if (!acq)
-               return SR_ERR_MALLOC;
-
-       devc->stopping_in_progress = FALSE;
-       devc->transfer_error = FALSE;
-
-       sr_info("Starting acquisition.");
-
-       devc->acquisition = acq;
-       lwla_convert_trigger(sdi);
-       ret = lwla_setup_acquisition(sdi);
-       if (ret != SR_OK) {
-               sr_err("Failed to set up acquisition.");
-               devc->acquisition = NULL;
-               lwla_free_acquisition_state(acq);
-               return ret;
-       }
-
-       ret = lwla_start_acquisition(sdi);
-       if (ret != SR_OK) {
-               sr_err("Failed to start acquisition.");
-               devc->acquisition = NULL;
-               lwla_free_acquisition_state(acq);
-               return ret;
-       }
-       usb_source_add(sdi->session, drvc->sr_ctx, 100, &lwla_receive_data,
-                      (struct sr_dev_inst *)sdi);
-
-       sr_info("Waiting for data.");
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(sdi, LOG_PREFIX);
-
-       return SR_OK;
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       (void)cb_data;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       sr_dbg("Stopping acquisition.");
-
-       sdi->status = SR_ST_STOPPING;
-
-       return SR_OK;
-}
-
-SR_PRIV struct sr_dev_driver sysclk_lwla_driver_info = {
-       .name = "sysclk-lwla",
-       .longname = "SysClk LWLA series",
-       .api_version = 1,
-       .init = init,
-       .cleanup = cleanup,
-       .scan = scan,
-       .dev_list = dev_list,
-       .dev_clear = dev_clear,
-       .config_get = config_get,
-       .config_set = config_set,
-       .config_channel_set = config_channel_set,
-       .config_commit = config_commit,
-       .config_list = config_list,
-       .dev_open = dev_open,
-       .dev_close = dev_close,
-       .dev_acquisition_start = dev_acquisition_start,
-       .dev_acquisition_stop = dev_acquisition_stop,
-       .priv = NULL,
-};
diff --git a/hardware/sysclk-lwla/lwla.c b/hardware/sysclk-lwla/lwla.c
deleted file mode 100644 (file)
index dcb7af7..0000000
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2014 Daniel Elstner <daniel.kitta@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 "lwla.h"
-#include "protocol.h"
-#include "libsigrok-internal.h"
-#include <errno.h>
-#include <glib/gstdio.h>
-
-#define BITSTREAM_MAX_SIZE     262144  /* bitstream size limit for safety */
-#define BITSTREAM_HEADER_SIZE  4       /* transfer header size in bytes */
-
-/* Load a bitstream file into memory.  Returns a newly allocated array
- * consisting of a 32-bit length field followed by the bitstream data.
- */
-static unsigned char *load_bitstream_file(const char *filename, int *length_p)
-{
-       GStatBuf statbuf;
-       FILE *file;
-       unsigned char *stream;
-       size_t length, count;
-
-       /* Retrieve and validate the file size. */
-       if (g_stat(filename, &statbuf) < 0) {
-               sr_err("Failed to access bitstream file: %s.",
-                      g_strerror(errno));
-               return NULL;
-       }
-       if (!S_ISREG(statbuf.st_mode)) {
-               sr_err("Bitstream is not a regular file.");
-               return NULL;
-       }
-       if (statbuf.st_size <= 0 || statbuf.st_size > BITSTREAM_MAX_SIZE) {
-               sr_err("Refusing to load bitstream of unreasonable size "
-                      "(%" PRIu64 " bytes).", (uint64_t)statbuf.st_size);
-               return NULL;
-       }
-
-       /* The message length includes the 4-byte header. */
-       length = BITSTREAM_HEADER_SIZE + statbuf.st_size;
-       stream = g_try_malloc(length);
-       if (!stream) {
-               sr_err("Failed to allocate bitstream buffer.");
-               return NULL;
-       }
-
-       file = g_fopen(filename, "rb");
-       if (!file) {
-               sr_err("Failed to open bitstream file: %s.", g_strerror(errno));
-               g_free(stream);
-               return NULL;
-       }
-
-       /* Write the message length header. */
-       *(uint32_t *)stream = GUINT32_TO_BE(length);
-
-       count = fread(stream + BITSTREAM_HEADER_SIZE,
-                     length - BITSTREAM_HEADER_SIZE, 1, file);
-       if (count != 1) {
-               sr_err("Failed to read bitstream file: %s.", g_strerror(errno));
-               fclose(file);
-               g_free(stream);
-               return NULL;
-       }
-       fclose(file);
-
-       *length_p = length;
-       return stream;
-}
-
-/* Load a Raw Binary File (.rbf) from the firmware directory and transfer
- * it to the device.
- */
-SR_PRIV int lwla_send_bitstream(const struct sr_usb_dev_inst *usb,
-                               const char *basename)
-{
-       char *filename;
-       unsigned char *stream;
-       int ret;
-       int length;
-       int xfer_len;
-
-       if (!usb || !basename)
-               return SR_ERR_BUG;
-
-       filename = g_build_filename(FIRMWARE_DIR, basename, NULL);
-       sr_info("Downloading FPGA bitstream at '%s'.", filename);
-
-       stream = load_bitstream_file(filename, &length);
-       g_free(filename);
-
-       if (!stream)
-               return SR_ERR;
-
-       /* Transfer the entire bitstream in one URB. */
-       ret = libusb_bulk_transfer(usb->devhdl, EP_BITSTREAM,
-                                  stream, length, &xfer_len, USB_TIMEOUT);
-       g_free(stream);
-
-       if (ret != 0) {
-               sr_err("Failed to transfer bitstream: %s.",
-                      libusb_error_name(ret));
-               return SR_ERR;
-       }
-       if (xfer_len != length) {
-               sr_err("Failed to transfer bitstream: incorrect length "
-                      "%d != %d.", xfer_len, length);
-               return SR_ERR;
-       }
-       sr_info("FPGA bitstream download of %d bytes done.", xfer_len);
-
-       /* This delay appears to be necessary for reliable operation. */
-       g_usleep(30000);
-
-       return SR_OK;
-}
-
-SR_PRIV int lwla_send_command(const struct sr_usb_dev_inst *usb,
-                             const uint16_t *command, int cmd_len)
-{
-       int ret;
-       int xfer_len;
-
-       if (!usb || !command || cmd_len <= 0)
-               return SR_ERR_BUG;
-
-       xfer_len = 0;
-       ret = libusb_bulk_transfer(usb->devhdl, EP_COMMAND,
-                                  (unsigned char *)command, cmd_len * 2,
-                                  &xfer_len, USB_TIMEOUT);
-       if (ret != 0) {
-               sr_dbg("Failed to send command %d: %s.",
-                      LWLA_TO_UINT16(command[0]), libusb_error_name(ret));
-               return SR_ERR;
-       }
-       if (xfer_len != cmd_len * 2) {
-               sr_dbg("Failed to send command %d: incorrect length %d != %d.",
-                      LWLA_TO_UINT16(command[0]), xfer_len, cmd_len * 2);
-               return SR_ERR;
-       }
-       return SR_OK;
-}
-
-SR_PRIV int lwla_receive_reply(const struct sr_usb_dev_inst *usb,
-                              uint32_t *reply, int reply_len, int expect_len)
-{
-       int ret;
-       int xfer_len;
-
-       if (!usb || !reply || reply_len <= 0)
-               return SR_ERR_BUG;
-
-       xfer_len = 0;
-       ret = libusb_bulk_transfer(usb->devhdl, EP_REPLY,
-                                  (unsigned char *)reply, reply_len * 4,
-                                  &xfer_len, USB_TIMEOUT);
-       if (ret != 0) {
-               sr_dbg("Failed to receive reply: %s.", libusb_error_name(ret));
-               return SR_ERR;
-       }
-       if (xfer_len != expect_len * 4) {
-               sr_dbg("Failed to receive reply: incorrect length %d != %d.",
-                      xfer_len, expect_len * 4);
-               return SR_ERR;
-       }
-       return SR_OK;
-}
-
-SR_PRIV int lwla_read_reg(const struct sr_usb_dev_inst *usb,
-                         uint16_t reg, uint32_t *value)
-{
-       int ret;
-       uint16_t command[2];
-       uint32_t reply[128]; /* full EP buffer to avoid overflows */
-
-       command[0] = LWLA_WORD(CMD_READ_REG);
-       command[1] = LWLA_WORD(reg);
-
-       ret = lwla_send_command(usb, command, G_N_ELEMENTS(command));
-
-       if (ret != SR_OK)
-               return ret;
-
-       ret = lwla_receive_reply(usb, reply, G_N_ELEMENTS(reply), 1);
-
-       if (ret == SR_OK)
-               *value = LWLA_TO_UINT32(reply[0]);
-
-       return ret;
-}
-
-SR_PRIV int lwla_write_reg(const struct sr_usb_dev_inst *usb,
-                          uint16_t reg, uint32_t value)
-{
-       uint16_t command[4];
-
-       command[0] = LWLA_WORD(CMD_WRITE_REG);
-       command[1] = LWLA_WORD(reg);
-       command[2] = LWLA_WORD_0(value);
-       command[3] = LWLA_WORD_1(value);
-
-       return lwla_send_command(usb, command, G_N_ELEMENTS(command));
-}
-
-SR_PRIV int lwla_write_regs(const struct sr_usb_dev_inst *usb,
-                           const struct regval_pair *regvals, int count)
-{
-       int i;
-       int ret;
-
-       ret = SR_OK;
-
-       for (i = 0; i < count; ++i) {
-               ret = lwla_write_reg(usb, regvals[i].reg, regvals[i].val);
-
-               if (ret != SR_OK)
-                       break;
-       }
-
-       return ret;
-}
diff --git a/hardware/sysclk-lwla/lwla.h b/hardware/sysclk-lwla/lwla.h
deleted file mode 100644 (file)
index 94db07e..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2014 Daniel Elstner <daniel.kitta@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_SYSCLK_LWLA_LWLA_H
-#define LIBSIGROK_HARDWARE_SYSCLK_LWLA_LWLA_H
-
-#include "libsigrok.h"
-#include <stdint.h>
-#include <libusb.h>
-#include <glib.h>
-
-struct sr_usb_dev_inst;
-
-/* Rotate argument n bits to the left.
- * This construct is an idiom recognized by GCC as bit rotation.
- */
-#define LROTATE(a, n) (((a) << (n)) | ((a) >> (CHAR_BIT * sizeof(a) - (n))))
-
-/* Convert 16-bit little endian LWLA protocol word to machine word order. */
-#define LWLA_TO_UINT16(val) GUINT16_FROM_LE(val)
-
-/* Convert 32-bit mixed endian LWLA protocol word to machine word order. */
-#define LWLA_TO_UINT32(val) LROTATE(GUINT32_FROM_LE(val), 16)
-
-/* Convert 16-bit argument to LWLA protocol word. */
-#define LWLA_WORD(val) GUINT16_TO_LE(val)
-
-/* Extract 16-bit units in mixed endian order from 32/64-bit value. */
-#define LWLA_WORD_0(val) GUINT16_TO_LE(((val) >> 16) & 0xFFFF)
-#define LWLA_WORD_1(val) GUINT16_TO_LE((val) & 0xFFFF)
-#define LWLA_WORD_2(val) GUINT16_TO_LE(((val) >> 48) & 0xFFFF)
-#define LWLA_WORD_3(val) GUINT16_TO_LE(((val) >> 32) & 0xFFFF)
-
-/** USB device end points.
- */
-enum {
-       EP_COMMAND   = 2,
-       EP_BITSTREAM = 4,
-       EP_REPLY     = 6 | LIBUSB_ENDPOINT_IN
-};
-
-/** LWLA protocol command ID codes.
- */
-enum {
-       CMD_READ_REG    = 1,
-       CMD_WRITE_REG   = 2,
-       CMD_READ_MEM    = 6,
-       CMD_CAP_SETUP   = 7,
-       CMD_CAP_STATUS  = 8,
-};
-
-/** LWLA capture state flags.
- */
-enum {
-       STATUS_CAPTURING = 1 << 1,
-       STATUS_TRIGGERED = 1 << 4,
-       STATUS_MEM_AVAIL = 1 << 5,
-       STATUS_FLAG_MASK = 0x3F
-};
-
-/** LWLA register addresses.
- */
-enum {
-       REG_MEM_CTRL2   = 0x1074, /* capture buffer control ??? */
-       REG_MEM_FILL    = 0x1078, /* capture buffer fill level */
-       REG_MEM_CTRL4   = 0x107C, /* capture buffer control ??? */
-
-       REG_DIV_BYPASS  = 0x1094, /* bypass clock divider flag */
-
-       REG_CMD_CTRL1   = 0x10B0, /* command control ??? */
-       REG_CMD_CTRL2   = 0x10B4, /* command control ??? */
-       REG_CMD_CTRL3   = 0x10B8, /* command control ??? */
-       REG_CMD_CTRL4   = 0x10BC, /* command control ??? */
-
-       REG_FREQ_CH1    = 0x10C0, /* channel 1 live frequency */
-       REG_FREQ_CH2    = 0x10C4, /* channel 2 live frequency */
-       REG_FREQ_CH3    = 0x10C8, /* channel 3 live frequency */
-       REG_FREQ_CH4    = 0x10CC, /* channel 4 live frequency */
-};
-
-/** Register/value pair.
- */
-struct regval_pair {
-       unsigned int reg;
-       unsigned int val;
-};
-
-SR_PRIV int lwla_send_bitstream(const struct sr_usb_dev_inst *usb,
-                               const char *basename);
-
-SR_PRIV int lwla_send_command(const struct sr_usb_dev_inst *usb,
-                             const uint16_t *command, int cmd_len);
-
-SR_PRIV int lwla_receive_reply(const struct sr_usb_dev_inst *usb,
-                              uint32_t *reply, int reply_len, int expect_len);
-
-SR_PRIV int lwla_read_reg(const struct sr_usb_dev_inst *usb,
-                         uint16_t reg, uint32_t *value);
-
-SR_PRIV int lwla_write_reg(const struct sr_usb_dev_inst *usb,
-                          uint16_t reg, uint32_t value);
-
-SR_PRIV int lwla_write_regs(const struct sr_usb_dev_inst *usb,
-                           const struct regval_pair *regvals, int count);
-
-#endif /* !LIBSIGROK_HARDWARE_SYSCLK_LWLA_LWLA_H */
diff --git a/hardware/sysclk-lwla/protocol.c b/hardware/sysclk-lwla/protocol.c
deleted file mode 100644 (file)
index f1ae8b3..0000000
+++ /dev/null
@@ -1,1034 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2014 Daniel Elstner <daniel.kitta@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 "protocol.h"
-#include <string.h>
-
-/* Bit mask for the RLE repeat-count-follows flag. */
-#define RLE_FLAG_LEN_FOLLOWS ((uint64_t)1 << 35)
-
-/* Start address of capture status memory area to read. */
-#define CAP_STAT_ADDR 5
-
-/* Number of 64-bit words read from the capture status memory. */
-#define CAP_STAT_LEN 5
-
-/* The bitstream filenames are indexed by the clock_config enumeration.
- */
-static const char bitstream_map[][32] = {
-       "sysclk-lwla1034-off.rbf",
-       "sysclk-lwla1034-int.rbf",
-       "sysclk-lwla1034-extpos.rbf",
-       "sysclk-lwla1034-extneg.rbf",
-};
-
-/* Submit an already filled-in USB transfer.
- */
-static int submit_transfer(struct dev_context *devc,
-                          struct libusb_transfer *xfer)
-{
-       int ret;
-
-       ret = libusb_submit_transfer(xfer);
-
-       if (ret != 0) {
-               sr_err("Submit transfer failed: %s.", libusb_error_name(ret));
-               devc->transfer_error = TRUE;
-               return SR_ERR;
-       }
-
-       return SR_OK;
-}
-
-/* Set up the LWLA in preparation for an acquisition session.
- */
-static int capture_setup(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct acquisition_state *acq;
-       uint64_t divider_count;
-       uint64_t trigger_mask;
-       uint64_t memory_limit;
-       uint16_t command[3 + 10*4];
-
-       devc = sdi->priv;
-       acq  = devc->acquisition;
-
-       command[0] = LWLA_WORD(CMD_CAP_SETUP);
-       command[1] = LWLA_WORD(0); /* address */
-       command[2] = LWLA_WORD(10); /* length */
-
-       command[3] = LWLA_WORD_0(devc->channel_mask);
-       command[4] = LWLA_WORD_1(devc->channel_mask);
-       command[5] = LWLA_WORD_2(devc->channel_mask);
-       command[6] = LWLA_WORD_3(devc->channel_mask);
-
-       /* Set the clock divide counter maximum for samplerates of up to
-        * 100 MHz. At the highest samplerate of 125 MHz the clock divider
-        * is bypassed.
-        */
-       if (!acq->bypass_clockdiv && devc->samplerate > 0)
-               divider_count = SR_MHZ(100) / devc->samplerate - 1;
-       else
-               divider_count = 0;
-
-       command[7]  = LWLA_WORD_0(divider_count);
-       command[8]  = LWLA_WORD_1(divider_count);
-       command[9]  = LWLA_WORD_2(divider_count);
-       command[10] = LWLA_WORD_3(divider_count);
-
-       command[11] = LWLA_WORD_0(devc->trigger_values);
-       command[12] = LWLA_WORD_1(devc->trigger_values);
-       command[13] = LWLA_WORD_2(devc->trigger_values);
-       command[14] = LWLA_WORD_3(devc->trigger_values);
-
-       command[15] = LWLA_WORD_0(devc->trigger_edge_mask);
-       command[16] = LWLA_WORD_1(devc->trigger_edge_mask);
-       command[17] = LWLA_WORD_2(devc->trigger_edge_mask);
-       command[18] = LWLA_WORD_3(devc->trigger_edge_mask);
-
-       trigger_mask = devc->trigger_mask;
-       /* Set bits to select external TRG input edge. */
-       if (devc->cfg_trigger_source == TRIGGER_EXT_TRG)
-               switch (devc->cfg_trigger_slope) {
-               case EDGE_POSITIVE: trigger_mask |= (uint64_t)1 << 35; break; 
-               case EDGE_NEGATIVE: trigger_mask |= (uint64_t)1 << 34; break; 
-               }
-
-       command[19] = LWLA_WORD_0(trigger_mask);
-       command[20] = LWLA_WORD_1(trigger_mask);
-       command[21] = LWLA_WORD_2(trigger_mask);
-       command[22] = LWLA_WORD_3(trigger_mask);
-
-       /* Set the capture memory full threshold. This is slightly less
-        * than the actual maximum, most likely in order to compensate for
-        * pipeline latency.
-        */
-       memory_limit = MEMORY_DEPTH - 16;
-
-       command[23] = LWLA_WORD_0(memory_limit);
-       command[24] = LWLA_WORD_1(memory_limit);
-       command[25] = LWLA_WORD_2(memory_limit);
-       command[26] = LWLA_WORD_3(memory_limit);
-
-       /* Fill remaining 64-bit words with zeroes. */
-       memset(&command[27], 0, 16 * sizeof(uint16_t));
-
-       return lwla_send_command(sdi->conn, command, G_N_ELEMENTS(command));
-}
-
-/* Issue a register write command as an asynchronous USB transfer.
- */
-static int issue_write_reg(const struct sr_dev_inst *sdi,
-                          unsigned int reg, unsigned int value)
-{
-       struct dev_context *devc;
-       struct acquisition_state *acq;
-
-       devc = sdi->priv;
-       acq  = devc->acquisition;
-
-       acq->xfer_buf_out[0] = LWLA_WORD(CMD_WRITE_REG);
-       acq->xfer_buf_out[1] = LWLA_WORD(reg);
-       acq->xfer_buf_out[2] = LWLA_WORD_0(value);
-       acq->xfer_buf_out[3] = LWLA_WORD_1(value);
-
-       acq->xfer_out->length = 4 * sizeof(uint16_t);
-
-       return submit_transfer(devc, acq->xfer_out);
-}
-
-/* Issue a register write command as an asynchronous USB transfer for the
- * next register/value pair of the currently active register write sequence.
- */
-static int issue_next_write_reg(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct regval_pair *regval;
-       int ret;
-
-       devc = sdi->priv;
-
-       if (devc->reg_write_pos >= devc->reg_write_len) {
-               sr_err("Already written all registers in sequence.");
-               return SR_ERR_BUG;
-       }
-       regval = &devc->reg_write_seq[devc->reg_write_pos];
-
-       ret = issue_write_reg(sdi, regval->reg, regval->val);
-       if (ret != SR_OK)
-               return ret;
-
-       ++devc->reg_write_pos;
-       return SR_OK;
-}
-
-/* Issue a capture status request as an asynchronous USB transfer.
- */
-static void request_capture_status(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct acquisition_state *acq;
-
-       devc = sdi->priv;
-       acq  = devc->acquisition;
-
-       acq->xfer_buf_out[0] = LWLA_WORD(CMD_CAP_STATUS);
-       acq->xfer_buf_out[1] = LWLA_WORD(CAP_STAT_ADDR);
-       acq->xfer_buf_out[2] = LWLA_WORD(CAP_STAT_LEN);
-
-       acq->xfer_out->length = 3 * sizeof(uint16_t);
-
-       if (submit_transfer(devc, acq->xfer_out) == SR_OK)
-               devc->state = STATE_STATUS_REQUEST;
-}
-
-/* Issue a request for the capture buffer fill level as
- * an asynchronous USB transfer.
- */
-static void request_capture_length(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct acquisition_state *acq;
-
-       devc = sdi->priv;
-       acq  = devc->acquisition;
-
-       acq->xfer_buf_out[0] = LWLA_WORD(CMD_READ_REG);
-       acq->xfer_buf_out[1] = LWLA_WORD(REG_MEM_FILL);
-
-       acq->xfer_out->length = 2 * sizeof(uint16_t);
-
-       if (submit_transfer(devc, acq->xfer_out) == SR_OK)
-               devc->state = STATE_LENGTH_REQUEST;
-}
-
-/* Initiate the capture memory read operation:  Reset the acquisition state
- * and start a sequence of register writes in order to set up the device for
- * reading from the capture buffer.
- */
-static void issue_read_start(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct acquisition_state *acq;
-       struct regval_pair *regvals;
-
-       devc = sdi->priv;
-       acq  = devc->acquisition;
-
-       /* Reset RLE state. */
-       acq->rle = RLE_STATE_DATA;
-       acq->sample  = 0;
-       acq->run_len = 0;
-
-       acq->samples_done = 0;
-
-       /* For some reason, the start address is 4 rather than 0. */
-       acq->mem_addr_done = 4;
-       acq->mem_addr_next = 4;
-       acq->mem_addr_stop = acq->mem_addr_fill;
-
-       /* Sample position in the packet output buffer. */
-       acq->out_index = 0;
-
-       regvals = devc->reg_write_seq;
-
-       regvals[0].reg = REG_DIV_BYPASS;
-       regvals[0].val = 1;
-
-       regvals[1].reg = REG_MEM_CTRL2;
-       regvals[1].val = 2;
-
-       regvals[2].reg = REG_MEM_CTRL4;
-       regvals[2].val = 4;
-
-       devc->reg_write_pos = 0;
-       devc->reg_write_len = 3;
-
-       if (issue_next_write_reg(sdi) == SR_OK)
-               devc->state = STATE_READ_PREPARE;
-}
-
-/* Issue a command as an asynchronous USB transfer which returns the device
- * to normal state after a read operation.  Sets a new device context state
- * on success.
- */
-static void issue_read_end(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-
-       devc = sdi->priv;
-
-       if (issue_write_reg(sdi, REG_DIV_BYPASS, 0) == SR_OK)
-               devc->state = STATE_READ_END;
-}
-
-/* Decode an incoming reponse to a buffer fill level request and act on it
- * as appropriate.  Note that this function changes the device context state.
- */
-static void process_capture_length(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct acquisition_state *acq;
-
-       devc = sdi->priv;
-       acq  = devc->acquisition;
-
-       if (acq->xfer_in->actual_length != 4) {
-               sr_err("Received size %d doesn't match expected size 4.",
-                      acq->xfer_in->actual_length);
-               devc->transfer_error = TRUE;
-               return;
-       }
-       acq->mem_addr_fill = LWLA_TO_UINT32(acq->xfer_buf_in[0]);
-
-       sr_dbg("%zu words in capture buffer.", acq->mem_addr_fill);
-
-       if (acq->mem_addr_fill > 0 && sdi->status == SR_ST_ACTIVE)
-               issue_read_start(sdi);
-       else
-               issue_read_end(sdi);
-}
-
-/* Initiate a sequence of register write commands with the effect of
- * cancelling a running capture operation.  This sets a new device state
- * if issuing the first command succeeds.
- */
-static void issue_stop_capture(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct regval_pair *regvals;
-
-       devc = sdi->priv;
-
-       if (devc->stopping_in_progress)
-               return;
-
-       regvals = devc->reg_write_seq;
-
-       regvals[0].reg = REG_CMD_CTRL2;
-       regvals[0].val = 10;
-
-       regvals[1].reg = REG_CMD_CTRL3;
-       regvals[1].val = 0;
-
-       regvals[2].reg = REG_CMD_CTRL4;
-       regvals[2].val = 0;
-
-       regvals[3].reg = REG_CMD_CTRL1;
-       regvals[3].val = 0;
-
-       regvals[4].reg = REG_DIV_BYPASS;
-       regvals[4].val = 0;
-
-       devc->reg_write_pos = 0;
-       devc->reg_write_len = 5;
-
-       if (issue_next_write_reg(sdi) == SR_OK) {
-               devc->stopping_in_progress = TRUE;
-               devc->state = STATE_STOP_CAPTURE;
-       }
-}
-
-/* Decode an incoming capture status reponse and act on it as appropriate.
- * Note that this function changes the device state.
- */
-static void process_capture_status(const struct sr_dev_inst *sdi)
-{
-       uint64_t duration;
-       struct dev_context *devc;
-       struct acquisition_state *acq;
-       unsigned int mem_fill;
-       unsigned int flags;
-
-       devc = sdi->priv;
-       acq  = devc->acquisition;
-
-       if (acq->xfer_in->actual_length != CAP_STAT_LEN * 8) {
-               sr_err("Received size %d doesn't match expected size %d.",
-                      acq->xfer_in->actual_length, CAP_STAT_LEN * 8);
-               devc->transfer_error = TRUE;
-               return;
-       }
-
-       /* TODO: Find out the actual bit width of these fields as stored
-        * in the FPGA.  These fields are definitely less than 64 bit wide
-        * internally, and the unused bits occasionally even contain garbage.
-        */
-       mem_fill = LWLA_TO_UINT32(acq->xfer_buf_in[0]);
-       duration = LWLA_TO_UINT32(acq->xfer_buf_in[4]);
-       flags    = LWLA_TO_UINT32(acq->xfer_buf_in[8]) & STATUS_FLAG_MASK;
-
-       /* The LWLA1034 runs at 125 MHz if the clock divider is bypassed.
-        * However, the time base used for the duration is apparently not
-        * adjusted for this "boost" mode.  Whereas normally the duration
-        * unit is 1 ms, it is 0.8 ms when the clock divider is bypassed.
-        * As 0.8 = 100 MHz / 125 MHz, it seems that the internal cycle
-        * counter period is the same as at the 100 MHz setting.
-        */
-       if (acq->bypass_clockdiv)
-               acq->duration_now = duration * 4 / 5;
-       else
-               acq->duration_now = duration;
-
-       sr_spew("Captured %u words, %" PRIu64 " ms, flags 0x%02X.",
-               mem_fill, acq->duration_now, flags);
-
-       if ((flags & STATUS_TRIGGERED) > (acq->capture_flags & STATUS_TRIGGERED))
-               sr_info("Capture triggered.");
-
-       acq->capture_flags = flags;
-
-       if (acq->duration_now >= acq->duration_max) {
-               sr_dbg("Time limit reached, stopping capture.");
-               issue_stop_capture(sdi);
-               return;
-       }
-       devc->state = STATE_STATUS_WAIT;
-
-       if ((acq->capture_flags & STATUS_TRIGGERED) == 0) {
-               sr_spew("Waiting for trigger.");
-       } else if ((acq->capture_flags & STATUS_MEM_AVAIL) == 0) {
-               sr_dbg("Capture memory filled.");
-               request_capture_length(sdi);
-       } else if ((acq->capture_flags & STATUS_CAPTURING) != 0) {
-               sr_spew("Sampling in progress.");
-       }
-}
-
-/* Issue a capture buffer read request as an asynchronous USB transfer.
- * The address and size of the memory area to read are derived from the
- * current acquisition state.
- */
-static void request_read_mem(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct acquisition_state *acq;
-       size_t count;
-
-       devc = sdi->priv;
-       acq  = devc->acquisition;
-
-       if (acq->mem_addr_next >= acq->mem_addr_stop)
-               return;
-
-       /* Always read a multiple of 8 device words. */
-       count = (acq->mem_addr_stop - acq->mem_addr_next + 7) / 8 * 8;
-       count = MIN(count, READ_CHUNK_LEN);
-
-       acq->xfer_buf_out[0] = LWLA_WORD(CMD_READ_MEM);
-       acq->xfer_buf_out[1] = LWLA_WORD_0(acq->mem_addr_next);
-       acq->xfer_buf_out[2] = LWLA_WORD_1(acq->mem_addr_next);
-       acq->xfer_buf_out[3] = LWLA_WORD_0(count);
-       acq->xfer_buf_out[4] = LWLA_WORD_1(count);
-
-       acq->xfer_out->length = 5 * sizeof(uint16_t);
-
-       if (submit_transfer(devc, acq->xfer_out) == SR_OK) {
-               acq->mem_addr_next += count;
-               devc->state = STATE_READ_REQUEST;
-       }
-}
-
-/* Demangle and decompress incoming sample data from the capture buffer.
- * The data chunk is taken from the acquisition state, and is expected to
- * contain a multiple of 8 device words.
- * All data currently in the acquisition buffer will be processed.  Packets
- * of decoded samples are sent off to the session bus whenever the output
- * buffer becomes full while decoding.
- */
-static int process_sample_data(const struct sr_dev_inst *sdi)
-{
-       uint64_t sample;
-       uint64_t high_nibbles;
-       uint64_t word;
-       struct dev_context *devc;
-       struct acquisition_state *acq;
-       uint8_t *out_p;
-       uint32_t *slice;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_logic logic;
-       size_t expect_len;
-       size_t actual_len;
-       size_t out_max_samples;
-       size_t out_run_samples;
-       size_t ri;
-       size_t in_words_left;
-       size_t si;
-
-       devc = sdi->priv;
-       acq  = devc->acquisition;
-
-       if (acq->mem_addr_done >= acq->mem_addr_stop
-                       || acq->samples_done >= acq->samples_max)
-               return SR_OK;
-
-       in_words_left = MIN(acq->mem_addr_stop - acq->mem_addr_done,
-                           READ_CHUNK_LEN);
-       expect_len = LWLA1034_MEMBUF_LEN(in_words_left) * sizeof(uint32_t);
-       actual_len = acq->xfer_in->actual_length;
-
-       if (actual_len != expect_len) {
-               sr_err("Received size %zu does not match expected size %zu.",
-                      actual_len, expect_len);
-               devc->transfer_error = TRUE;
-               return SR_ERR;
-       }
-       acq->mem_addr_done += in_words_left;
-
-       /* Prepare session packet. */
-       packet.type    = SR_DF_LOGIC;
-       packet.payload = &logic;
-       logic.unitsize = UNIT_SIZE;
-       logic.data     = acq->out_packet;
-
-       slice = acq->xfer_buf_in;
-       si = 0; /* word index within slice */
-
-       for (;;) {
-               /* Calculate number of samples to write into packet. */
-               out_max_samples = MIN(acq->samples_max - acq->samples_done,
-                                     PACKET_LENGTH - acq->out_index);
-               out_run_samples = MIN(acq->run_len, out_max_samples);
-
-               /* Expand run-length samples into session packet. */
-               sample = acq->sample;
-               out_p = &acq->out_packet[acq->out_index * UNIT_SIZE];
-
-               for (ri = 0; ri < out_run_samples; ++ri) {
-                       out_p[0] =  sample        & 0xFF;
-                       out_p[1] = (sample >>  8) & 0xFF;
-                       out_p[2] = (sample >> 16) & 0xFF;
-                       out_p[3] = (sample >> 24) & 0xFF;
-                       out_p[4] = (sample >> 32) & 0xFF;
-                       out_p += UNIT_SIZE;
-               }
-               acq->run_len -= out_run_samples;
-               acq->out_index += out_run_samples;
-               acq->samples_done += out_run_samples;
-
-               /* Packet full or sample count limit reached? */
-               if (out_run_samples == out_max_samples) {
-                       logic.length = acq->out_index * UNIT_SIZE;
-                       sr_session_send(sdi, &packet);
-                       acq->out_index = 0;
-
-                       if (acq->samples_done >= acq->samples_max)
-                               return SR_OK; /* sample limit reached */
-                       if (acq->run_len > 0)
-                               continue; /* need another packet */
-               }
-
-               if (in_words_left == 0)
-                       break; /* done with current chunk */
-
-               /* Now work on the current slice. */
-               high_nibbles = LWLA_TO_UINT32(slice[8]);
-               word = LWLA_TO_UINT32(slice[si]);
-               word |= (high_nibbles << (4 * si + 4)) & ((uint64_t)0xF << 32);
-
-               if (acq->rle == RLE_STATE_DATA) {
-                       acq->sample = word & ALL_CHANNELS_MASK;
-                       acq->run_len = ((word >> NUM_CHANNELS) & 1) + 1;
-                       if (word & RLE_FLAG_LEN_FOLLOWS)
-                               acq->rle = RLE_STATE_LEN;
-               } else {
-                       acq->run_len += word << 1;
-                       acq->rle = RLE_STATE_DATA;
-               }
-
-               /* Move to next word. */
-               si = (si + 1) % 8;
-               if (si == 0)
-                       slice += 9;
-               --in_words_left;
-       }
-
-       /* Send out partially filled packet if this was the last chunk. */
-       if (acq->mem_addr_done >= acq->mem_addr_stop && acq->out_index > 0) {
-               logic.length = acq->out_index * UNIT_SIZE;
-               sr_session_send(sdi, &packet);
-               acq->out_index = 0;
-       }
-       return SR_OK;
-}
-
-/* Finish an acquisition session.  This sends the end packet to the session
- * bus and removes the listener for asynchronous USB transfers.
- */
-static void end_acquisition(struct sr_dev_inst *sdi)
-{
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       struct sr_datafeed_packet packet;
-
-       drvc = sdi->driver->priv;
-       devc = sdi->priv;
-
-       if (devc->state == STATE_IDLE)
-               return;
-
-       devc->state = STATE_IDLE;
-
-       /* Remove USB file descriptors from polling. */
-       usb_source_remove(sdi->session, drvc->sr_ctx);
-
-       packet.type = SR_DF_END;
-       sr_session_send(sdi, &packet);
-
-       lwla_free_acquisition_state(devc->acquisition);
-       devc->acquisition = NULL;
-
-       sdi->status = SR_ST_ACTIVE;
-}
-
-/* USB output transfer completion callback.
- */
-static void receive_transfer_out(struct libusb_transfer *transfer)
-{
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-
-       sdi  = transfer->user_data;
-       devc = sdi->priv;
-
-       if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
-               sr_err("Transfer to device failed: %d.", transfer->status);
-               devc->transfer_error = TRUE;
-               return;
-       }
-
-       if (devc->reg_write_pos < devc->reg_write_len) {
-               issue_next_write_reg(sdi);
-       } else {
-               switch (devc->state) {
-               case STATE_START_CAPTURE:
-                       devc->state = STATE_STATUS_WAIT;
-                       break;
-               case STATE_STATUS_REQUEST:
-                       devc->state = STATE_STATUS_RESPONSE;
-                       submit_transfer(devc, devc->acquisition->xfer_in);
-                       break;
-               case STATE_STOP_CAPTURE:
-                       if (sdi->status == SR_ST_ACTIVE)
-                               request_capture_length(sdi);
-                       else
-                               end_acquisition(sdi);
-                       break;
-               case STATE_LENGTH_REQUEST:
-                       devc->state = STATE_LENGTH_RESPONSE;
-                       submit_transfer(devc, devc->acquisition->xfer_in);
-                       break;
-               case STATE_READ_PREPARE:
-                       request_read_mem(sdi);
-                       break;
-               case STATE_READ_REQUEST:
-                       devc->state = STATE_READ_RESPONSE;
-                       submit_transfer(devc, devc->acquisition->xfer_in);
-                       break;
-               case STATE_READ_END:
-                       end_acquisition(sdi);
-                       break;
-               default:
-                       sr_err("Unexpected device state %d.", devc->state);
-                       break;
-               }
-       }
-}
-
-/* USB input transfer completion callback.
- */
-static void receive_transfer_in(struct libusb_transfer *transfer)
-{
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-       struct acquisition_state *acq;
-
-       sdi  = transfer->user_data;
-       devc = sdi->priv;
-       acq  = devc->acquisition;
-
-       if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
-               sr_err("Transfer from device failed: %d.", transfer->status);
-               devc->transfer_error = TRUE;
-               return;
-       }
-
-       switch (devc->state) {
-       case STATE_STATUS_RESPONSE:
-               process_capture_status(sdi);
-               break;
-       case STATE_LENGTH_RESPONSE:
-               process_capture_length(sdi);
-               break;
-       case STATE_READ_RESPONSE:
-               if (process_sample_data(sdi) == SR_OK
-                               && acq->mem_addr_next < acq->mem_addr_stop
-                               && acq->samples_done < acq->samples_max)
-                       request_read_mem(sdi);
-               else
-                       issue_read_end(sdi);
-               break;
-       default:
-               sr_err("Unexpected device state %d.", devc->state);
-               break;
-       }
-}
-
-/* Initialize the LWLA.  This downloads a bitstream into the FPGA
- * and executes a simple device test sequence.
- */
-SR_PRIV int lwla_init_device(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       int ret;
-       uint32_t value;
-
-       devc = sdi->priv;
-
-       /* Force reload of bitstream */
-       devc->cur_clock_config = CONF_CLOCK_NONE;
-
-       ret = lwla_set_clock_config(sdi);
-
-       if (ret != SR_OK)
-               return ret;
-
-       ret = lwla_write_reg(sdi->conn, REG_CMD_CTRL2, 100);
-       if (ret != SR_OK)
-               return ret;
-
-       ret = lwla_read_reg(sdi->conn, REG_CMD_CTRL1, &value);
-       if (ret != SR_OK)
-               return ret;
-       sr_dbg("Received test word 0x%08X back.", value);
-       if (value != 0x12345678)
-               return SR_ERR;
-
-       ret = lwla_read_reg(sdi->conn, REG_CMD_CTRL4, &value);
-       if (ret != SR_OK)
-               return ret;
-       sr_dbg("Received test word 0x%08X back.", value);
-       if (value != 0x12345678)
-               return SR_ERR;
-
-       ret = lwla_read_reg(sdi->conn, REG_CMD_CTRL3, &value);
-       if (ret != SR_OK)
-               return ret;
-       sr_dbg("Received test word 0x%08X back.", value);
-       if (value != 0x87654321)
-               return SR_ERR;
-
-       return ret;
-}
-
-SR_PRIV int lwla_convert_trigger(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_trigger *trigger;
-       struct sr_trigger_stage *stage;
-       struct sr_trigger_match *match;
-       const GSList *l, *m;
-       uint64_t channel_index;
-
-       devc = sdi->priv;
-
-       devc->trigger_mask = 0;
-       devc->trigger_values = 0;
-       devc->trigger_edge_mask = 0;
-
-       if (!(trigger = sr_session_trigger_get(sdi->session)))
-               return SR_OK;
-
-       if (g_slist_length(trigger->stages) > 1) {
-               sr_err("This device only supports 1 trigger stage.");
-               return SR_ERR;
-       }
-
-       for (l = trigger->stages; l; l = l->next) {
-               stage = l->data;
-               for (m = stage->matches; m; m = m->next) {
-                       match = m->data;
-                       if (!match->channel->enabled)
-                               /* Ignore disabled channels with a trigger. */
-                               continue;
-                       channel_index = 1 << match->channel->index;
-                       devc->trigger_mask |= channel_index;
-                       switch (match->match) {
-                       case SR_TRIGGER_ONE:
-                               devc->trigger_values |= channel_index;
-                               break;
-                       case SR_TRIGGER_RISING:
-                               devc->trigger_values |= channel_index;
-                               /* Fall through for edge mask. */
-                       case SR_TRIGGER_FALLING:
-                               devc->trigger_edge_mask |= channel_index;
-                               break;
-                       }
-               }
-       }
-
-       return SR_OK;
-}
-
-/* Select the LWLA clock configuration.  If the clock source changed from
- * the previous setting, this will download a new bitstream to the FPGA.
- */
-SR_PRIV int lwla_set_clock_config(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       int ret;
-       enum clock_config choice;
-
-       devc = sdi->priv;
-
-       if (sdi->status == SR_ST_INACTIVE)
-               choice = CONF_CLOCK_NONE;
-       else if (devc->cfg_clock_source == CLOCK_INTERNAL)
-               choice = CONF_CLOCK_INT;
-       else if (devc->cfg_clock_edge == EDGE_POSITIVE)
-               choice = CONF_CLOCK_EXT_RISE;
-       else
-               choice = CONF_CLOCK_EXT_FALL;
-
-       if (choice != devc->cur_clock_config) {
-               devc->cur_clock_config = CONF_CLOCK_NONE;
-               ret = lwla_send_bitstream(sdi->conn, bitstream_map[choice]);
-               if (ret == SR_OK)
-                       devc->cur_clock_config = choice;
-               return ret;
-       }
-       return SR_OK;
-}
-
-/* Configure the LWLA in preparation for an acquisition session.
- */
-SR_PRIV int lwla_setup_acquisition(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_usb_dev_inst *usb;
-       struct acquisition_state *acq;
-       struct regval_pair regvals[7];
-       int ret;
-
-       devc = sdi->priv;
-       usb  = sdi->conn;
-       acq  = devc->acquisition;
-
-       if (devc->limit_msec > 0) {
-               acq->duration_max = devc->limit_msec;
-               sr_info("Acquisition time limit %" PRIu64 " ms.",
-                       devc->limit_msec);
-       } else
-               acq->duration_max = MAX_LIMIT_MSEC;
-
-       if (devc->limit_samples > 0) {
-               acq->samples_max = devc->limit_samples;
-               sr_info("Acquisition sample count limit %" PRIu64 ".",
-                       devc->limit_samples);
-       } else
-               acq->samples_max = MAX_LIMIT_SAMPLES;
-
-       if (devc->cfg_clock_source == CLOCK_INTERNAL) {
-               sr_info("Internal clock, samplerate %" PRIu64 ".",
-                       devc->samplerate);
-               if (devc->samplerate == 0)
-                       return SR_ERR_BUG;
-               /* At 125 MHz, the clock divider is bypassed. */
-               acq->bypass_clockdiv = (devc->samplerate > SR_MHZ(100));
-
-               /* If only one of the limits is set, derive the other one. */
-               if (devc->limit_msec == 0 && devc->limit_samples > 0)
-                       acq->duration_max = devc->limit_samples
-                                       * 1000 / devc->samplerate + 1;
-               else if (devc->limit_samples == 0 && devc->limit_msec > 0)
-                       acq->samples_max = devc->limit_msec
-                                       * devc->samplerate / 1000;
-       } else {
-               acq->bypass_clockdiv = TRUE;
-
-               if (devc->cfg_clock_edge == EDGE_NEGATIVE)
-                       sr_info("External clock, falling edge.");
-               else
-                       sr_info("External clock, rising edge.");
-       }
-
-       regvals[0].reg = REG_MEM_CTRL2;
-       regvals[0].val = 2;
-
-       regvals[1].reg = REG_MEM_CTRL2;
-       regvals[1].val = 1;
-
-       regvals[2].reg = REG_CMD_CTRL2;
-       regvals[2].val = 10;
-
-       regvals[3].reg = REG_CMD_CTRL3;
-       regvals[3].val = 0x74;
-
-       regvals[4].reg = REG_CMD_CTRL4;
-       regvals[4].val = 0;
-
-       regvals[5].reg = REG_CMD_CTRL1;
-       regvals[5].val = 0;
-
-       regvals[6].reg = REG_DIV_BYPASS;
-       regvals[6].val = acq->bypass_clockdiv;
-
-       ret = lwla_write_regs(usb, regvals, G_N_ELEMENTS(regvals));
-       if (ret != SR_OK)
-               return ret;
-
-       return capture_setup(sdi);
-}
-
-/* Start the capture operation on the LWLA device.  Beginning with this
- * function, all USB transfers will be asynchronous until the end of the
- * acquisition session.
- */
-SR_PRIV int lwla_start_acquisition(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_usb_dev_inst *usb;
-       struct acquisition_state *acq;
-       struct regval_pair *regvals;
-
-       devc = sdi->priv;
-       usb  = sdi->conn;
-       acq  = devc->acquisition;
-
-       acq->duration_now  = 0;
-       acq->mem_addr_fill = 0;
-       acq->capture_flags = 0;
-
-       libusb_fill_bulk_transfer(acq->xfer_out, usb->devhdl, EP_COMMAND,
-                                 (unsigned char *)acq->xfer_buf_out, 0,
-                                 &receive_transfer_out,
-                                 (struct sr_dev_inst *)sdi, USB_TIMEOUT);
-
-       libusb_fill_bulk_transfer(acq->xfer_in, usb->devhdl, EP_REPLY,
-                                 (unsigned char *)acq->xfer_buf_in,
-                                 sizeof acq->xfer_buf_in,
-                                 &receive_transfer_in,
-                                 (struct sr_dev_inst *)sdi, USB_TIMEOUT);
-
-       regvals = devc->reg_write_seq;
-
-       regvals[0].reg = REG_CMD_CTRL2;
-       regvals[0].val = 10;
-
-       regvals[1].reg = REG_CMD_CTRL3;
-       regvals[1].val = 1;
-
-       regvals[2].reg = REG_CMD_CTRL4;
-       regvals[2].val = 0;
-
-       regvals[3].reg = REG_CMD_CTRL1;
-       regvals[3].val = 0;
-
-       devc->reg_write_pos = 0;
-       devc->reg_write_len = 4;
-
-       devc->state = STATE_START_CAPTURE;
-
-       return issue_next_write_reg(sdi);
-}
-
-/* Allocate an acquisition state object.
- */
-SR_PRIV struct acquisition_state *lwla_alloc_acquisition_state(void)
-{
-       struct acquisition_state *acq;
-
-       acq = g_try_new0(struct acquisition_state, 1);
-       if (!acq) {
-               sr_err("Acquisition state malloc failed.");
-               return NULL;
-       }
-
-       acq->xfer_in = libusb_alloc_transfer(0);
-       if (!acq->xfer_in) {
-               sr_err("Transfer malloc failed.");
-               g_free(acq);
-               return NULL;
-       }
-
-       acq->xfer_out = libusb_alloc_transfer(0);
-       if (!acq->xfer_out) {
-               sr_err("Transfer malloc failed.");
-               libusb_free_transfer(acq->xfer_in);
-               g_free(acq);
-               return NULL;
-       }
-
-       return acq;
-}
-
-/* Deallocate an acquisition state object.
- */
-SR_PRIV void lwla_free_acquisition_state(struct acquisition_state *acq)
-{
-       if (acq) {
-               libusb_free_transfer(acq->xfer_out);
-               libusb_free_transfer(acq->xfer_in);
-               g_free(acq);
-       }
-}
-
-/* USB I/O source callback.
- */
-SR_PRIV int lwla_receive_data(int fd, int revents, void *cb_data)
-{
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-       struct drv_context *drvc;
-       struct timeval tv;
-       int ret;
-
-       (void)fd;
-
-       sdi  = cb_data;
-       devc = sdi->priv;
-       drvc = sdi->driver->priv;
-
-       if (!devc || !drvc)
-               return FALSE;
-
-       /* No timeout: return immediately. */
-       tv.tv_sec  = 0;
-       tv.tv_usec = 0;
-
-       ret = libusb_handle_events_timeout_completed(drvc->sr_ctx->libusb_ctx,
-                                                    &tv, NULL);
-       if (ret != 0)
-               sr_err("Event handling failed: %s.", libusb_error_name(ret));
-
-       /* If no event flags are set the timeout must have expired. */
-       if (revents == 0 && devc->state == STATE_STATUS_WAIT) {
-               if (sdi->status == SR_ST_STOPPING)
-                       issue_stop_capture(sdi);
-               else
-                       request_capture_status(sdi);
-       }
-
-       /* Check if an error occurred on a transfer. */
-       if (devc->transfer_error)
-               end_acquisition(sdi);
-
-       return TRUE;
-}
diff --git a/hardware/sysclk-lwla/protocol.h b/hardware/sysclk-lwla/protocol.h
deleted file mode 100644 (file)
index 1e353ad..0000000
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2014 Daniel Elstner <daniel.kitta@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_SYSCLK_LWLA_PROTOCOL_H
-#define LIBSIGROK_HARDWARE_SYSCLK_LWLA_PROTOCOL_H
-
-#define LOG_PREFIX "sysclk-lwla"
-
-#include "lwla.h"
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-#include <stdint.h>
-#include <glib.h>
-
-/* For now, only the LWLA1034 is supported.
- */
-#define VENDOR_NAME    "SysClk"
-#define MODEL_NAME     "LWLA1034"
-
-#define USB_VID_PID    "2961.6689"
-#define USB_INTERFACE  0
-#define USB_TIMEOUT    3000 /* ms */
-
-#define NUM_CHANNELS   34
-
-/* Bit mask covering all 34 channels.
- */
-#define ALL_CHANNELS_MASK (((uint64_t)1 << NUM_CHANNELS) - 1)
-
-/** Unit and packet size for the sigrok logic datafeed.
- */
-#define UNIT_SIZE      ((NUM_CHANNELS + 7) / 8)
-#define PACKET_LENGTH  10000   /* units */
-
-/** Size of the acquisition buffer in device memory units.
- */
-#define MEMORY_DEPTH   (256 * 1024)    /* 256k x 36 bit */
-
-/** Number of device memory units (36 bit) to read at a time.  Slices of 8
- * consecutive 36-bit words are mapped to 9 32-bit words each, so the chunk
- * length should be a multiple of 8 to ensure alignment to slice boundaries.
- *
- * Experimentation has shown that reading chunks larger than about 1024 bytes
- * is unreliable.  The threshold seems to relate to the buffer size on the FX2
- * USB chip:  The configured endpoint buffer size is 512, and with double or
- * triple buffering enabled a multiple of 512 bytes can be kept in fly.
- *
- * The vendor software limits reads to 120 words (15 slices, 540 bytes) at
- * a time.  So far, it appears safe to increase this to 224 words (28 slices,
- * 1008 bytes), thus making the most of two 512 byte buffers.
- */
-#define READ_CHUNK_LEN (28 * 8)
-
-/** Calculate the required buffer size in 32-bit units for reading a given
- * number of device memory words.  Rounded to a multiple of 8 device words.
- */
-#define LWLA1034_MEMBUF_LEN(count) (((count) + 7) / 8 * 9)
-
-/** Maximum number of 16-bit words sent at a time during acquisition.
- * Used for allocating the libusb transfer buffer.
- */
-#define MAX_ACQ_SEND_WORDS     8 /* 5 for memory read request plus stuffing */
-
-/** Maximum number of 32-bit words received at a time during acquisition.
- * Round to the next multiple of the endpoint buffer size to avoid nasty
- * transfer overflow conditions on hiccups.
- */
-#define MAX_ACQ_RECV_LEN       ((READ_CHUNK_LEN / 8 * 9 + 127) / 128 * 128)
-
-/** Maximum length of a register write sequence.
- */
-#define MAX_REG_WRITE_SEQ_LEN   5
-
-/** Default configured samplerate.
- */
-#define DEFAULT_SAMPLERATE     SR_MHZ(125)
-
-/** Maximum configurable sample count limit.
- */
-#define MAX_LIMIT_SAMPLES      (UINT64_C(1) << 48)
-
-/** Maximum configurable capture duration in milliseconds.
- */
-#define MAX_LIMIT_MSEC         (UINT64_C(1) << 32)
-
-/** LWLA1034 FPGA clock configurations.
- */
-enum clock_config {
-       CONF_CLOCK_NONE,
-       CONF_CLOCK_INT,
-       CONF_CLOCK_EXT_RISE,
-       CONF_CLOCK_EXT_FALL,
-};
-
-/** Available clock sources.
- */
-enum clock_source {
-       CLOCK_INTERNAL,
-       CLOCK_EXT_CLK,
-};
-
-/** Available trigger sources.
- */
-enum trigger_source {
-       TRIGGER_CHANNELS = 0,
-       TRIGGER_EXT_TRG,
-};
-
-/** Available edge choices for the external clock and trigger inputs.
- */
-enum signal_edge {
-       EDGE_POSITIVE = 0,
-       EDGE_NEGATIVE,
-};
-
-/** LWLA device states.
- */
-enum device_state {
-       STATE_IDLE = 0,
-
-       STATE_START_CAPTURE,
-
-       STATE_STATUS_WAIT,
-       STATE_STATUS_REQUEST,
-       STATE_STATUS_RESPONSE,
-
-       STATE_STOP_CAPTURE,
-
-       STATE_LENGTH_REQUEST,
-       STATE_LENGTH_RESPONSE,
-
-       STATE_READ_PREPARE,
-       STATE_READ_REQUEST,
-       STATE_READ_RESPONSE,
-       STATE_READ_END,
-};
-
-/** LWLA run-length encoding states.
- */
-enum rle_state {
-       RLE_STATE_DATA,
-       RLE_STATE_LEN
-};
-
-/** LWLA sample acquisition and decompression state.
- */
-struct acquisition_state {
-       uint64_t sample;
-       uint64_t run_len;
-
-       /** Maximum number of samples to process. */
-       uint64_t samples_max;
-       /** Number of samples sent to the session bus. */
-       uint64_t samples_done;
-
-       /** Maximum duration of capture, in milliseconds. */
-       uint64_t duration_max;
-       /** Running capture duration since trigger event. */
-       uint64_t duration_now;
-
-       /** Capture memory fill level. */
-       size_t mem_addr_fill;
-
-       size_t mem_addr_done;
-       size_t mem_addr_next;
-       size_t mem_addr_stop;
-
-       size_t out_index;
-
-       struct libusb_transfer *xfer_in;
-       struct libusb_transfer *xfer_out;
-
-       unsigned int capture_flags;
-
-       enum rle_state rle;
-
-       /** Whether to bypass the clock divider. */
-       gboolean bypass_clockdiv;
-
-       /* Payload data buffers for incoming and outgoing transfers. */
-       uint32_t xfer_buf_in[MAX_ACQ_RECV_LEN];
-       uint16_t xfer_buf_out[MAX_ACQ_SEND_WORDS];
-
-       /* Payload buffer for sigrok logic packets. */
-       uint8_t out_packet[PACKET_LENGTH * UNIT_SIZE];
-};
-
-/** Private, per-device-instance driver context.
- */
-struct dev_context {
-       /** The samplerate selected by the user. */
-       uint64_t samplerate;
-
-       /** The maximimum sampling duration, in milliseconds. */
-       uint64_t limit_msec;
-
-       /** The maximimum number of samples to acquire. */
-       uint64_t limit_samples;
-
-       /** Channels to use. */
-       uint64_t channel_mask;
-
-       uint64_t trigger_mask;
-       uint64_t trigger_edge_mask;
-       uint64_t trigger_values;
-
-       struct acquisition_state *acquisition;
-
-       struct regval_pair reg_write_seq[MAX_REG_WRITE_SEQ_LEN];
-       int reg_write_pos;
-       int reg_write_len;
-
-       enum device_state state;
-
-       /** The currently active clock configuration of the device. */
-       enum clock_config cur_clock_config;
-
-       /** Clock source configuration setting. */
-       enum clock_source cfg_clock_source;
-       /** Clock edge configuration setting. */
-       enum signal_edge cfg_clock_edge;
-
-       /** Trigger source configuration setting. */
-       enum trigger_source cfg_trigger_source;
-       /** Trigger slope configuration setting. */
-       enum signal_edge cfg_trigger_slope;
-
-       /* Indicates that stopping the acquisition is currently in progress. */
-       gboolean stopping_in_progress;
-
-       /* Indicates whether a transfer failed. */
-       gboolean transfer_error;
-};
-
-SR_PRIV struct acquisition_state *lwla_alloc_acquisition_state(void);
-SR_PRIV void lwla_free_acquisition_state(struct acquisition_state *acq);
-
-SR_PRIV int lwla_init_device(const struct sr_dev_inst *sdi);
-SR_PRIV int lwla_convert_trigger(const struct sr_dev_inst *sdi);
-SR_PRIV int lwla_set_clock_config(const struct sr_dev_inst *sdi);
-SR_PRIV int lwla_setup_acquisition(const struct sr_dev_inst *sdi);
-SR_PRIV int lwla_start_acquisition(const struct sr_dev_inst *sdi);
-SR_PRIV int lwla_abort_acquisition(const struct sr_dev_inst *sdi);
-
-SR_PRIV int lwla_receive_data(int fd, int revents, void *cb_data);
-
-#endif /* !LIBSIGROK_HARDWARE_SYSCLK_LWLA_PROTOCOL_H */
diff --git a/hardware/teleinfo/api.c b/hardware/teleinfo/api.c
deleted file mode 100644 (file)
index c4fd846..0000000
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 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 <stdlib.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-#include "protocol.h"
-
-static const int32_t hwopts[] = {
-       SR_CONF_CONN,
-       SR_CONF_SERIALCOMM,
-};
-
-static const int32_t hwcaps[] = {
-       SR_CONF_ENERGYMETER,
-       SR_CONF_LIMIT_SAMPLES,
-       SR_CONF_LIMIT_MSEC,
-       SR_CONF_CONTINUOUS,
-};
-
-SR_PRIV struct sr_dev_driver teleinfo_driver_info;
-static struct sr_dev_driver *di = &teleinfo_driver_info;
-
-static int init(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, di, LOG_PREFIX);
-}
-
-static GSList *scan(GSList *options)
-{
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-       struct sr_dev_inst *sdi;
-       struct sr_channel *ch;
-       GSList *devices = NULL, *l;
-       const char *conn = NULL, *serialcomm = NULL;
-       uint8_t buf[292];
-       size_t len;
-       struct sr_config *src;
-
-       len = sizeof(buf);
-
-       for (l = options; l; l = l->next) {
-               src = l->data;
-               switch (src->key) {
-               case SR_CONF_CONN:
-                       conn = g_variant_get_string(src->data, NULL);
-                       break;
-               case SR_CONF_SERIALCOMM:
-                       serialcomm = g_variant_get_string(src->data, NULL);
-                       break;
-               }
-       }
-       if (!conn)
-               return NULL;
-       if (!serialcomm)
-               serialcomm = "1200/7e1";
-
-       if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
-               return NULL;
-       if (serial_open(serial, SERIAL_RDONLY | SERIAL_NONBLOCK) != SR_OK)
-               return NULL;
-
-       sr_info("Probing serial port %s.", conn);
-
-       drvc = di->priv;
-       drvc->instances = NULL;
-       serial_flush(serial);
-
-       /* Let's get a bit of data and see if we can find a packet. */
-       if (serial_stream_detect(serial, buf, &len, len,
-                                teleinfo_packet_valid, 3000, 1200) != SR_OK)
-               goto scan_cleanup;
-
-       sr_info("Found device on port %s.", conn);
-
-       if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "EDF", "Teleinfo", NULL)))
-               goto scan_cleanup;
-
-       if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
-               sr_err("Device context malloc failed.");
-               goto scan_cleanup;
-       }
-
-       devc->optarif = teleinfo_get_optarif(buf);
-
-       sdi->inst_type = SR_INST_SERIAL;
-       sdi->conn = serial;
-       sdi->priv = devc;
-       sdi->driver = di;
-
-       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P")))
-               goto scan_cleanup;
-       sdi->channels = g_slist_append(sdi->channels, ch);
-
-       if (devc->optarif == OPTARIF_BASE) {
-               if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "BASE")))
-                       goto scan_cleanup;
-               sdi->channels = g_slist_append(sdi->channels, ch);
-       } else if (devc->optarif == OPTARIF_HC) {
-               if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "HP")))
-                       goto scan_cleanup;
-               sdi->channels = g_slist_append(sdi->channels, ch);
-               if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "HC")))
-                       goto scan_cleanup;
-               sdi->channels = g_slist_append(sdi->channels, ch);
-       } else if (devc->optarif == OPTARIF_EJP) {
-               if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "HN")))
-                       goto scan_cleanup;
-               sdi->channels = g_slist_append(sdi->channels, ch);
-               if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "HPM")))
-                       goto scan_cleanup;
-               sdi->channels = g_slist_append(sdi->channels, ch);
-       } else if (devc->optarif == OPTARIF_BBR) {
-               if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "HPJB")))
-                       goto scan_cleanup;
-               sdi->channels = g_slist_append(sdi->channels, ch);
-               if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "HPJW")))
-                       goto scan_cleanup;
-               sdi->channels = g_slist_append(sdi->channels, ch);
-               if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "HPJR")))
-                       goto scan_cleanup;
-               sdi->channels = g_slist_append(sdi->channels, ch);
-               if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "HCJB")))
-                       goto scan_cleanup;
-               sdi->channels = g_slist_append(sdi->channels, ch);
-               if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "HCJW")))
-                       goto scan_cleanup;
-               sdi->channels = g_slist_append(sdi->channels, ch);
-               if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "HCJR")))
-                       goto scan_cleanup;
-               sdi->channels = g_slist_append(sdi->channels, ch);
-       }
-
-       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "IINST")))
-               goto scan_cleanup;
-       sdi->channels = g_slist_append(sdi->channels, ch);
-
-       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "PAPP")))
-               goto scan_cleanup;
-       sdi->channels = g_slist_append(sdi->channels, ch);
-
-       drvc->instances = g_slist_append(drvc->instances, sdi);
-       devices = g_slist_append(devices, sdi);
-
-scan_cleanup:
-       serial_close(serial);
-
-       return devices;
-}
-
-static GSList *dev_list(void)
-{
-       return ((struct drv_context *)(di->priv))->instances;
-}
-
-static int cleanup(void)
-{
-       return std_dev_clear(di, NULL);
-}
-
-static int config_set(int 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;
-
-       if (!(devc = sdi->priv)) {
-               sr_err("sdi->priv was NULL.");
-               return SR_ERR_BUG;
-       }
-
-       switch (key) {
-       case SR_CONF_LIMIT_SAMPLES:
-               devc->limit_samples = g_variant_get_uint64(data);
-               sr_dbg("Setting sample limit to %" PRIu64 ".", devc->limit_samples);
-               break;
-       case SR_CONF_LIMIT_MSEC:
-               devc->limit_msec = g_variant_get_uint64(data);
-               sr_dbg("Setting time limit to %" PRIu64 "ms.", devc->limit_msec);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_list(int 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_INT32,
-                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
-               break;
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct sr_serial_dev_inst *serial = sdi->conn;
-       struct dev_context *devc;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       if (!(devc = sdi->priv)) {
-               sr_err("sdi->priv was NULL.");
-               return SR_ERR_BUG;
-       }
-
-       devc->session_cb_data = cb_data;
-
-       /*
-        * Reset the number of samples to take. If we've already collected our
-        * quota, but we start a new session, and don't reset this, we'll just
-        * quit without acquiring any new samples.
-        */
-       devc->num_samples = 0;
-       devc->start_time = g_get_monotonic_time();
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(cb_data, LOG_PREFIX);
-
-       /* Poll every 50ms, or whenever some data comes in. */
-       serial_source_add(sdi->session, serial, G_IO_IN, 50,
-                       teleinfo_receive_data, (void *)sdi);
-
-       return SR_OK;
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       return std_serial_dev_acquisition_stop(sdi, cb_data,
-                       std_serial_dev_close, sdi->conn, LOG_PREFIX);
-}
-
-SR_PRIV struct sr_dev_driver teleinfo_driver_info = {
-       .name = "teleinfo",
-       .longname = "Teleinfo",
-       .api_version = 1,
-       .init = init,
-       .cleanup = cleanup,
-       .scan = scan,
-       .dev_list = 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 = dev_acquisition_stop,
-       .priv = NULL,
-};
diff --git a/hardware/teleinfo/protocol.c b/hardware/teleinfo/protocol.c
deleted file mode 100644 (file)
index a610173..0000000
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 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 <stdlib.h>
-#include <string.h>
-#include <glib.h>
-#include "protocol.h"
-
-#define STX  0x02
-#define ETX  0x03
-#define EOT  0x04
-#define LF   0x0A
-#define CR   0x0D
-
-static gboolean teleinfo_control_check(char *label, char *data, char control)
-{
-       int sum = 0;
-       while (*label)
-               sum += *label++;
-       sum += ' ';
-       while (*data)
-               sum += *data++;
-       return ((sum & 0x3F) + ' ') == control;
-}
-
-static gint teleinfo_channel_compare(gconstpointer a, gconstpointer b)
-{
-       const struct sr_channel *ch = a;
-       const char *name = b;
-       return strcmp(ch->name, name);
-}
-
-static struct sr_channel *teleinfo_find_channel(struct sr_dev_inst *sdi,
-                                            const char *name)
-{
-       GSList *elem = g_slist_find_custom(sdi->channels, name,
-                                          teleinfo_channel_compare);
-       return elem ? elem->data : NULL;
-}
-
-static void teleinfo_send_value(struct sr_dev_inst *sdi, const char *channel_name,
-                                float value, int mq, int unit)
-{
-       struct dev_context *devc;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_analog analog;
-       struct sr_channel *ch;
-
-       devc = sdi->priv;
-       ch = teleinfo_find_channel(sdi, channel_name);
-
-       if (!ch || !ch->enabled)
-               return;
-
-       memset(&analog, 0, sizeof(struct sr_datafeed_analog));
-       analog.channels = g_slist_append(analog.channels, ch);
-       analog.num_samples = 1;
-       analog.mq = mq;
-       analog.unit = unit;
-       analog.data = &value;
-
-       packet.type = SR_DF_ANALOG;
-       packet.payload = &analog;
-       sr_session_send(devc->session_cb_data, &packet);
-       g_slist_free(analog.channels);
-}
-
-static void teleinfo_handle_mesurement(struct sr_dev_inst *sdi,
-                                       const char *label, const char *data,
-                                       char *optarif)
-{
-       struct dev_context *devc;
-       int v = atoi(data);
-
-       if (!sdi || !(devc = sdi->priv)) {
-               if (optarif && !strcmp(label, "OPTARIF"))
-                       strcpy(optarif, data);
-               return;
-       }
-
-       if (!strcmp(label, "ADCO")) {
-               devc->num_samples++;
-       } else if (!strcmp(label, "BASE")) {
-               teleinfo_send_value(sdi, "BASE", v, SR_MQ_POWER, SR_UNIT_WATT_HOUR);
-       } else if (!strcmp(label, "HCHP")) {
-               teleinfo_send_value(sdi, "HP"  , v, SR_MQ_POWER, SR_UNIT_WATT_HOUR);
-       } else if (!strcmp(label, "HCHC")) {
-               teleinfo_send_value(sdi, "HC"  , v, SR_MQ_POWER, SR_UNIT_WATT_HOUR);
-       } else if (!strcmp(label, "EJPHN")) {
-               teleinfo_send_value(sdi, "HN"  , v, SR_MQ_POWER, SR_UNIT_WATT_HOUR);
-       } else if (!strcmp(label, "EJPHPM")) {
-               teleinfo_send_value(sdi, "HPM" , v, SR_MQ_POWER, SR_UNIT_WATT_HOUR);
-       } else if (!strcmp(label, "BBRHPJB")) {
-               teleinfo_send_value(sdi, "HPJB", v, SR_MQ_POWER, SR_UNIT_WATT_HOUR);
-       } else if (!strcmp(label, "BBRHPJW")) {
-               teleinfo_send_value(sdi, "HPJW", v, SR_MQ_POWER, SR_UNIT_WATT_HOUR);
-       } else if (!strcmp(label, "BBRHPJR")) {
-               teleinfo_send_value(sdi, "HPJR", v, SR_MQ_POWER, SR_UNIT_WATT_HOUR);
-       } else if (!strcmp(label, "BBRHCJB")) {
-               teleinfo_send_value(sdi, "HCJB", v, SR_MQ_POWER, SR_UNIT_WATT_HOUR);
-       } else if (!strcmp(label, "BBRHCJW")) {
-               teleinfo_send_value(sdi, "HCJW", v, SR_MQ_POWER, SR_UNIT_WATT_HOUR);
-       } else if (!strcmp(label, "BBRHCJR")) {
-               teleinfo_send_value(sdi, "HCJR", v, SR_MQ_POWER, SR_UNIT_WATT_HOUR);
-       } else if (!strcmp(label, "IINST")) {
-               teleinfo_send_value(sdi, "IINST", v, SR_MQ_CURRENT, SR_UNIT_AMPERE);
-       } else if (!strcmp(label, "PAPP")) {
-               teleinfo_send_value(sdi, "PAPP", v, SR_MQ_POWER, SR_UNIT_VOLT_AMPERE);
-       }
-}
-
-static gboolean teleinfo_parse_group(struct sr_dev_inst *sdi,
-                                     const uint8_t *group, char *optarif)
-{
-       char label[9], data[13], control, cr;
-       const char *str = (const char *)group;
-       if (sscanf(str, "\x0A%8s %13s %c%c", label, data, &control, &cr) != 4
-           || cr != CR)
-               return FALSE;
-       if (!teleinfo_control_check(label, data, control))
-               return FALSE;
-       teleinfo_handle_mesurement(sdi, label, data, optarif);
-       return TRUE;
-}
-
-static const uint8_t *teleinfo_parse_data(struct sr_dev_inst *sdi,
-                                          const uint8_t *buf, int len,
-                                          char *optarif)
-{
-       const uint8_t *group_start, *group_end;
-
-       group_start = memchr(buf, LF, len);
-       if (!group_start)
-               return NULL;
-
-       group_end = memchr(group_start, CR, len - (group_start - buf));
-       if (!group_end)
-               return NULL;
-
-       teleinfo_parse_group(sdi, group_start, optarif);
-       return group_end + 1;
-}
-
-SR_PRIV int teleinfo_get_optarif(const uint8_t *buf)
-{
-       const uint8_t *ptr = buf;
-       char optarif[5] = { 0 };
-
-       while ((ptr = teleinfo_parse_data(NULL, ptr, 292-(ptr-buf), optarif)));
-       if (!strcmp(optarif, "BASE"))
-               return OPTARIF_BASE;
-       else if (!strcmp(optarif, "HC.."))
-               return OPTARIF_HC;
-       else if (!strcmp(optarif, "EJP."))
-               return OPTARIF_EJP;
-       else if (!strncmp(optarif, "BBR", 3))
-               return OPTARIF_BBR;
-       return OPTARIF_NONE;
-}
-
-SR_PRIV gboolean teleinfo_packet_valid(const uint8_t *buf)
-{
-       return !!teleinfo_get_optarif(buf);
-}
-
-SR_PRIV int teleinfo_receive_data(int fd, int revents, void *cb_data)
-{
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-       const uint8_t *ptr, *next_ptr, *end_ptr;
-       int len;
-       int64_t time;
-
-       (void)fd;
-
-       if (!(sdi = cb_data) || !(devc = sdi->priv) || revents != G_IO_IN)
-               return TRUE;
-       serial = sdi->conn;
-
-       /* Try to get as much data as the buffer can hold. */
-       len = TELEINFO_BUF_SIZE - devc->buf_len;
-       len = serial_read(serial, devc->buf + devc->buf_len, len);
-       if (len < 1) {
-               sr_err("Serial port read error: %d.", len);
-               return FALSE;
-       }
-       devc->buf_len += len;
-
-       /* Now look for packets in that data. */
-       ptr = devc->buf;
-       end_ptr = ptr + devc->buf_len;
-       while ((next_ptr = teleinfo_parse_data(sdi, ptr, end_ptr - ptr, NULL)))
-               ptr = next_ptr;
-
-       /* If we have any data left, move it to the beginning of our buffer. */
-       memmove(devc->buf, ptr, end_ptr - ptr);
-       devc->buf_len -= ptr - devc->buf;
-
-       /* If buffer is full and no valid packet was found, wipe buffer. */
-       if (devc->buf_len >= TELEINFO_BUF_SIZE) {
-               devc->buf_len = 0;
-               return FALSE;
-       }
-
-       if (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
-               sr_info("Requested number of samples reached.");
-               sdi->driver->dev_acquisition_stop(sdi, devc->session_cb_data);
-               return TRUE;
-       }
-
-       if (devc->limit_msec) {
-               time = (g_get_monotonic_time() - devc->start_time) / 1000;
-               if (time > (int64_t)devc->limit_msec) {
-                       sr_info("Requested time limit reached.");
-                       sdi->driver->dev_acquisition_stop(sdi, devc->session_cb_data);
-                       return TRUE;
-               }
-       }
-       return TRUE;
-}
diff --git a/hardware/teleinfo/protocol.h b/hardware/teleinfo/protocol.h
deleted file mode 100644 (file)
index f95c50e..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Aurelien Jacobs <aurel@gnuage.org>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef LIBSIGROK_HARDWARE_TELEINFO_PROTOCOL_H
-#define LIBSIGROK_HARDWARE_TELEINFO_PROTOCOL_H
-
-#include <stdint.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "teleinfo"
-
-enum optarif {
-       OPTARIF_NONE,
-       OPTARIF_BASE,
-       OPTARIF_HC,
-       OPTARIF_EJP,
-       OPTARIF_BBR,
-};
-
-#define TELEINFO_BUF_SIZE 256
-
-/** Private, per-device-instance driver context. */
-struct dev_context {
-       /* Acquisition settings */
-       uint64_t limit_samples;   /**< The sampling limit (in number of samples). */
-       uint64_t limit_msec;      /**< The time limit (in milliseconds). */
-       void *session_cb_data;    /**< Opaque pointer passed in by the frontend. */
-
-       /* Operational state */
-       enum optarif optarif;     /**< The device mode (which mesures are reported) */
-       uint64_t num_samples;     /**< The number of already received samples. */
-       int64_t start_time;       /**< The time at which sampling started. */
-
-       /* Temporary state across callbacks */
-       uint8_t buf[TELEINFO_BUF_SIZE];
-       int buf_len;
-};
-
-SR_PRIV gboolean teleinfo_packet_valid(const uint8_t *buf);
-SR_PRIV int teleinfo_receive_data(int fd, int revents, void *cb_data);
-SR_PRIV int teleinfo_get_optarif(const uint8_t *buf);
-
-#endif
diff --git a/hardware/testo/api.c b/hardware/testo/api.c
deleted file mode 100644 (file)
index 2b4c963..0000000
+++ /dev/null
@@ -1,535 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2014 Bert Vermeulen <bert@biot.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 <string.h>
-#include "protocol.h"
-
-#define SERIALCOMM "115200/8n1"
-
-SR_PRIV struct sr_dev_driver testo_driver_info;
-static struct sr_dev_driver *di = &testo_driver_info;
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data);
-
-static const int32_t scanopts[] = {
-       SR_CONF_CONN,
-};
-
-static const int32_t devopts[] = {
-       SR_CONF_MULTIMETER,
-       SR_CONF_LIMIT_MSEC,
-       SR_CONF_LIMIT_SAMPLES,
-       SR_CONF_CONTINUOUS,
-};
-
-unsigned char TESTO_x35_REQUEST[] = { 0x12, 0, 0, 0, 1, 1, 0x55, 0xd1, 0xb7 };
-struct testo_model models[] = {
-       { "435", 9, TESTO_x35_REQUEST },
-};
-
-static int init(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, di, LOG_PREFIX);
-}
-
-static GSList *scan(GSList *options)
-{
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       struct sr_config *src;
-       struct sr_dev_inst *sdi;
-       struct sr_usb_dev_inst *usb;
-       struct libusb_device_descriptor des;
-       libusb_device **devlist;
-       struct libusb_device_handle *hdl;
-       GSList *conn_devices, *devices, *l;
-       int devcnt, ret, i;
-       const char *str;
-       char manufacturer[64], product[64];
-
-       devices = NULL;
-       drvc = di->priv;
-       drvc->instances = NULL;
-
-       conn_devices = NULL;
-       for (l = options; l; l = l->next) {
-               src = l->data;
-               if (src->key != SR_CONF_CONN)
-                       continue;
-               str = g_variant_get_string(src->data, NULL);
-               conn_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, str);
-       }
-
-       libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
-       for (i = 0; devlist[i]; i++) {
-               if (conn_devices) {
-                       usb = NULL;
-                       for (l = conn_devices; l; l = l->next) {
-                               usb = l->data;
-                               if (usb->bus == libusb_get_bus_number(devlist[i])
-                                       && usb->address == libusb_get_device_address(devlist[i]))
-                                       break;
-                       }
-                       if (!l)
-                               /* This device matched none of the ones that
-                                * matched the conn specification. */
-                               continue;
-               }
-
-               if ((ret = libusb_get_device_descriptor( devlist[i], &des)) != 0) {
-                       sr_warn("Failed to get device descriptor: %s.",
-                               libusb_error_name(ret));
-                       continue;
-               }
-
-               if ((ret = libusb_open(devlist[i], &hdl)) < 0)
-                       continue;
-
-               manufacturer[0] = product[0] = '\0';
-               if (des.iManufacturer && (ret = libusb_get_string_descriptor_ascii(
-                               hdl, des.iManufacturer, (unsigned char *) manufacturer,
-                               sizeof(manufacturer))) < 0) {
-                       sr_warn("Failed to get manufacturer string descriptor: %s.",
-                               libusb_error_name(ret));
-               }
-               if (des.iProduct && (ret = libusb_get_string_descriptor_ascii(
-                               hdl, des.iProduct, (unsigned char *) product,
-                               sizeof(product))) < 0) {
-                       sr_warn("Failed to get product string descriptor: %s.",
-                               libusb_error_name(ret));
-               }
-               libusb_close(hdl);
-
-               if (strncmp(manufacturer, "testo", 5))
-                       continue;
-
-               /* Hardcode the 435 for now.*/
-               if (strcmp(product, "testo 435/635/735"))
-                       continue;
-
-               devcnt = g_slist_length(drvc->instances);
-               sdi = sr_dev_inst_new(devcnt, SR_ST_INACTIVE, "Testo",
-                               "435/635/735", NULL);
-               sdi->driver = di;
-               sdi->inst_type = SR_INST_USB;
-               sdi->conn = sr_usb_dev_inst_new(libusb_get_bus_number(devlist[i]),
-                               libusb_get_device_address(devlist[i]), NULL);
-               devc = g_malloc(sizeof(struct dev_context));
-               devc->model = &models[0];
-               devc->limit_msec = 0;
-               devc->limit_samples = 0;
-               sdi->priv = devc;
-               if (testo_probe_channels(sdi) != SR_OK)
-                       continue;
-               drvc->instances = g_slist_append(drvc->instances, sdi);
-               devices = g_slist_append(devices, sdi);
-       }
-       libusb_free_device_list(devlist, 1);
-       g_slist_free_full(conn_devices, (GDestroyNotify)sr_usb_dev_inst_free);
-
-       return devices;
-}
-
-static GSList *dev_list(void)
-{
-       return ((struct drv_context *)(di->priv))->instances;
-}
-
-static int dev_clear(void)
-{
-       return std_dev_clear(di, NULL);
-}
-
-static int dev_open(struct sr_dev_inst *sdi)
-{
-       struct drv_context *drvc = di->priv;
-       struct sr_usb_dev_inst *usb;
-       libusb_device **devlist;
-       int ret, i;
-
-       if (!di->priv) {
-               sr_err("Driver was not initialized.");
-               return SR_ERR;
-       }
-
-       usb = sdi->conn;
-       libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
-       for (i = 0; devlist[i]; i++) {
-               if (libusb_get_bus_number(devlist[i]) != usb->bus
-                               || libusb_get_device_address(devlist[i]) != usb->address)
-                       continue;
-               if ((ret = libusb_open(devlist[i], &usb->devhdl))) {
-                       sr_err("Failed to open device: %s.", libusb_error_name(ret));
-                       return SR_ERR;
-               }
-               break;
-       }
-       libusb_free_device_list(devlist, 1);
-       if (!devlist[i]) {
-               sr_err("Device not found.");
-               return SR_ERR;
-       }
-
-       if (libusb_has_capability(LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER)) {
-               if (libusb_kernel_driver_active(usb->devhdl, 0) == 1) {
-                       if ((ret = libusb_detach_kernel_driver(usb->devhdl, 0)) < 0) {
-                               sr_err("Failed to detach kernel driver: %s.",
-                                          libusb_error_name(ret));
-                               return SR_ERR;
-                       }
-               }
-       }
-
-       if ((ret = libusb_claim_interface(usb->devhdl, 0))) {
-               sr_err("Failed to claim interface: %s.", libusb_error_name(ret));
-               return SR_ERR;
-       }
-       sdi->status = SR_ST_ACTIVE;
-
-       return SR_OK;
-}
-
-static int dev_close(struct sr_dev_inst *sdi)
-{
-       struct sr_usb_dev_inst *usb;
-
-       if (!di->priv) {
-               sr_err("Driver was not initialized.");
-               return SR_ERR;
-       }
-
-       usb = sdi->conn;
-       if (!usb->devhdl)
-               /*  Nothing to do. */
-               return SR_OK;
-
-       libusb_release_interface(usb->devhdl, 0);
-       libusb_close(usb->devhdl);
-       usb->devhdl = NULL;
-       sdi->status = SR_ST_INACTIVE;
-
-       return SR_OK;
-}
-
-static int cleanup(void)
-{
-       int ret;
-       struct drv_context *drvc;
-
-       if (!(drvc = di->priv))
-               return SR_OK;
-
-       ret = dev_clear();
-       g_free(drvc);
-       di->priv = NULL;
-
-       return ret;
-}
-
-static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct sr_usb_dev_inst *usb;
-       char str[128];
-
-       (void)cg;
-
-       switch (key) {
-       case SR_CONF_CONN:
-               if (!sdi || !sdi->conn)
-                       return SR_ERR_ARG;
-               usb = sdi->conn;
-               snprintf(str, 128, "%d.%d", usb->bus, usb->address);
-               *data = g_variant_new_string(str);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       gint64 now;
-       int ret;
-
-       (void)cg;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       if (!di->priv) {
-               sr_err("Driver was not initialized.");
-               return SR_ERR;
-       }
-
-       devc = sdi->priv;
-       ret = SR_OK;
-       switch (key) {
-       case SR_CONF_LIMIT_MSEC:
-               devc->limit_msec = g_variant_get_uint64(data);
-               now = g_get_monotonic_time() / 1000;
-               devc->end_time = now + devc->limit_msec;
-               sr_dbg("Setting time limit to %" PRIu64 "ms.",
-                      devc->limit_msec);
-               break;
-       case SR_CONF_LIMIT_SAMPLES:
-               devc->limit_samples = g_variant_get_uint64(data);
-               sr_dbg("Setting sample limit to %" PRIu64 ".",
-                      devc->limit_samples);
-               break;
-       default:
-               ret = SR_ERR_NA;
-       }
-
-       return ret;
-}
-
-static int config_list(int 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_INT32,
-                               scanopts, ARRAY_SIZE(scanopts), sizeof(int32_t));
-               break;
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               devopts, ARRAY_SIZE(devopts), sizeof(int32_t));
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static void receive_data(struct sr_dev_inst *sdi, unsigned char *data, int len)
-{
-       struct dev_context *devc;
-       int packet_size;
-       uint16_t crc;
-
-       devc = sdi->priv;
-
-       if (devc->reply_size + len > MAX_REPLY_SIZE) {
-               /* Something went very wrong. */
-               sr_dbg("Receive buffer overrun.");
-               devc->reply_size = 0;
-               return;
-       }
-
-       memcpy(devc->reply + devc->reply_size, data, len);
-       devc->reply_size += len;
-       /* Sixth byte contains the length of the packet. */
-       if (devc->reply_size < 7)
-               return;
-
-       packet_size = 7 + devc->reply[6] * 7 + 2;
-       if (devc->reply_size < packet_size)
-               return;
-
-       if (!testo_check_packet_prefix(devc->reply, devc->reply_size))
-               return;
-
-       crc = crc16_mcrf4xx(0xffff, devc->reply, devc->reply_size - 2);
-       if (crc == RL16(&devc->reply[devc->reply_size - 2])) {
-               testo_receive_packet(sdi);
-               devc->num_samples++;
-       } else {
-               sr_dbg("Packet has invalid CRC.");
-       }
-
-       devc->reply_size = 0;
-       if (devc->limit_samples && devc->num_samples >= devc->limit_samples)
-               dev_acquisition_stop(sdi, devc->cb_data);
-       else
-               testo_request_packet(sdi);
-
-}
-
-SR_PRIV void receive_transfer(struct libusb_transfer *transfer)
-{
-       struct dev_context *devc;
-       struct sr_dev_inst *sdi;
-       int ret;
-
-       sdi = transfer->user_data;
-       devc = sdi->priv;
-       if (transfer == devc->out_transfer)
-               /* Just the command acknowledgement. */
-               return;
-
-       if (transfer->status == LIBUSB_TRANSFER_NO_DEVICE) {
-               /* USB device was unplugged. */
-               dev_acquisition_stop(sdi, devc->cb_data);
-       } else if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
-               /* First two bytes in any transfer are FTDI status bytes. */
-               if (transfer->actual_length > 2)
-                       receive_data(sdi, transfer->buffer + 2, transfer->actual_length - 2);
-       }
-       /* Anything else is either an error or a timeout, which is fine:
-        * we were just going to send another transfer request anyway. */
-
-       if (sdi->status == SR_ST_ACTIVE) {
-               if ((ret = libusb_submit_transfer(transfer) != 0)) {
-                       sr_err("Unable to resubmit transfer: %s.",
-                              libusb_error_name(ret));
-                       g_free(transfer->buffer);
-                       libusb_free_transfer(transfer);
-                       dev_acquisition_stop(sdi, devc->cb_data);
-               }
-       } else {
-               /* This was the last transfer we're going to receive, so
-                * clean up now. */
-               g_free(transfer->buffer);
-               libusb_free_transfer(transfer);
-       }
-}
-
-static int handle_events(int fd, int revents, void *cb_data)
-{
-       struct dev_context *devc;
-       struct drv_context *drvc = di->priv;
-       struct sr_datafeed_packet packet;
-       struct sr_dev_inst *sdi;
-       struct timeval tv;
-       gint64 now;
-
-       (void)fd;
-       (void)revents;
-
-       sdi = cb_data;
-       devc = sdi->priv;
-
-       if (devc->limit_msec) {
-               now = g_get_monotonic_time() / 1000;
-               if (now > devc->end_time)
-                       dev_acquisition_stop(sdi, devc->cb_data);
-       }
-
-       if (sdi->status == SR_ST_STOPPING) {
-               usb_source_remove(sdi->session, drvc->sr_ctx);
-
-               dev_close(sdi);
-
-               packet.type = SR_DF_END;
-               sr_session_send(sdi, &packet);
-       }
-
-       memset(&tv, 0, sizeof(struct timeval));
-       libusb_handle_events_timeout_completed(drvc->sr_ctx->libusb_ctx, &tv,
-                       NULL);
-
-       return TRUE;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       struct sr_usb_dev_inst *usb;
-       struct libusb_transfer *transfer;
-       int ret;
-       unsigned char *buf;
-
-       drvc = di->priv;
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       if (!di->priv) {
-               sr_err("Driver was not initialized.");
-               return SR_ERR;
-       }
-
-       devc = sdi->priv;
-       usb = sdi->conn;
-       devc->cb_data = cb_data;
-       devc->end_time = 0;
-       devc->num_samples = 0;
-       devc->reply_size = 0;
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(cb_data, LOG_PREFIX);
-
-       usb_source_add(sdi->session, drvc->sr_ctx, 100,
-                       handle_events, (void *)sdi);
-
-       if (testo_set_serial_params(usb) != SR_OK)
-               return SR_ERR;
-
-       devc->out_transfer = libusb_alloc_transfer(0);
-       if (testo_request_packet(sdi) != SR_OK)
-               return SR_ERR;
-
-       buf = g_try_malloc(MAX_REPLY_SIZE);
-       transfer = libusb_alloc_transfer(0);
-       libusb_fill_bulk_transfer(transfer, usb->devhdl, EP_IN, buf,
-                       MAX_REPLY_SIZE, receive_transfer, (void *)sdi, 100);
-       if ((ret = libusb_submit_transfer(transfer) != 0)) {
-               sr_err("Unable to submit transfer: %s.", libusb_error_name(ret));
-               libusb_free_transfer(transfer);
-               g_free(buf);
-               return SR_ERR;
-       }
-       devc->reply_size = 0;
-
-       return SR_OK;
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       (void)cb_data;
-
-       if (!di->priv) {
-               sr_err("Driver was not initialized.");
-               return SR_ERR;
-       }
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       sdi->status = SR_ST_STOPPING;
-
-       return SR_OK;
-}
-
-SR_PRIV struct sr_dev_driver testo_driver_info = {
-       .name = "testo",
-       .longname = "Testo",
-       .api_version = 1,
-       .init = init,
-       .cleanup = cleanup,
-       .scan = scan,
-       .dev_list = dev_list,
-       .dev_clear = dev_clear,
-       .config_get = config_get,
-       .config_set = config_set,
-       .config_list = config_list,
-       .dev_open = dev_open,
-       .dev_close = dev_close,
-       .dev_acquisition_start = dev_acquisition_start,
-       .dev_acquisition_stop = dev_acquisition_stop,
-       .priv = NULL,
-};
diff --git a/hardware/testo/protocol.c b/hardware/testo/protocol.c
deleted file mode 100644 (file)
index bdfaf1f..0000000
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2014 Bert Vermeulen <bert@biot.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 <string.h>
-#include "protocol.h"
-
-SR_PRIV int testo_set_serial_params(struct sr_usb_dev_inst *usb)
-{
-       int ret;
-
-    if ((ret = libusb_control_transfer(usb->devhdl, 0x40, FTDI_SET_BAUDRATE,
-                       FTDI_BAUDRATE_115200, FTDI_INDEX, NULL, 0, 10)) < 0) {
-                       sr_err("Failed to set baudrate: %s", libusb_error_name(ret));
-                       return SR_ERR;
-       }
-
-    if ((ret = libusb_control_transfer(usb->devhdl, 0x40, FTDI_SET_PARAMS,
-                       FTDI_PARAMS_8N1, FTDI_INDEX, NULL, 0, 10)) < 0) {
-                       sr_err("Failed to set comm parameters: %s", libusb_error_name(ret));
-                       return SR_ERR;
-       }
-
-    if ((ret = libusb_control_transfer(usb->devhdl, 0x40, FTDI_SET_FLOWCTRL,
-                       FTDI_FLOW_NONE, FTDI_INDEX, NULL, 0, 10)) < 0) {
-                       sr_err("Failed to set flow control: %s", libusb_error_name(ret));
-                       return SR_ERR;
-       }
-
-    if ((ret = libusb_control_transfer(usb->devhdl, 0x40, FTDI_SET_MODEMCTRL,
-                       FTDI_MODEM_ALLHIGH, FTDI_INDEX, NULL, 0, 10)) < 0) {
-                       sr_err("Failed to set modem control: %s", libusb_error_name(ret));
-                       return SR_ERR;
-       }
-
-       return SR_OK;
-}
-
-
-/* Due to the modular nature of the Testo hardware, you can't assume
- * which measurements the device will supply. Fetch a single result
- * set synchronously to see which measurements it has. */
-SR_PRIV int testo_probe_channels(struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_usb_dev_inst *usb;
-       struct sr_channel *ch;
-       int unit, packet_len, len, i;
-       unsigned char packet[MAX_REPLY_SIZE], buf[MAX_REPLY_SIZE];
-       char *probe_name;
-
-       devc = sdi->priv;
-       usb = sdi->conn;
-
-       sr_dbg("Probing for channels.");
-       if (sdi->driver->dev_open(sdi) != SR_OK)
-               return SR_ERR;
-       if (testo_set_serial_params(usb) != SR_OK)
-               return SR_ERR;
-
-       /* Flush anything buffered from a previous run. */
-       do {
-               libusb_bulk_transfer(usb->devhdl, EP_IN, buf, MAX_REPLY_SIZE, &len, 10);
-       } while (len > 2);
-
-       if (libusb_bulk_transfer(usb->devhdl, EP_OUT, devc->model->request,
-                       devc->model->request_size, &devc->reply_size, 10) < 0)
-               return SR_ERR;
-
-       packet_len = 0;
-       while(TRUE) {
-               if (libusb_bulk_transfer(usb->devhdl, EP_IN, buf, MAX_REPLY_SIZE,
-                               &len, 250) < 0)
-                       return SR_ERR;
-               if (len == 2)
-                       /* FTDI cruft */
-                       continue;
-               if (packet_len + len - 2 > MAX_REPLY_SIZE)
-                       return SR_ERR;
-
-               memcpy(packet + packet_len, buf + 2, len - 2);
-               packet_len += len - 2;
-               if (packet_len < 5)
-                       /* Not even enough to check prefix yet. */
-                       continue;
-
-               if (!testo_check_packet_prefix(packet, packet_len)) {
-                       /* Tail end of some previous data, drop it. */
-                       packet_len = 0;
-                       continue;
-               }
-
-               if (packet_len >= 7 + packet[6] * 7 + 2)
-                       /* Got a complete packet. */
-                       break;
-       }
-       sdi->driver->dev_close(sdi);
-
-       if (packet[6] > MAX_CHANNELS) {
-               sr_err("Device says it has %d channels!", packet[6]);
-               return SR_ERR;
-       }
-
-       for (i = 0; i < packet[6]; i++) {
-               unit = packet[7 + i * 7 + 4];
-               devc->channel_units[i] = unit;
-               switch (unit) {
-               case 1:
-                       probe_name = "Temperature";
-                       break;
-               case 3:
-                       probe_name = "Humidity";
-                       break;
-               case 5:
-                       probe_name = "Windspeed";
-                       break;
-               case 24:
-                       probe_name = "Pressure";
-                       break;
-               default:
-                       sr_dbg("Unsupported measurement unit %d", unit);
-                       return SR_ERR;
-               }
-               ch = sr_channel_new(i, SR_CHANNEL_ANALOG, TRUE, probe_name);
-               sdi->channels = g_slist_append(sdi->channels, ch);
-       }
-       devc->num_channels = packet[6];
-       sr_dbg("Found %d channel%s.", devc->num_channels,
-                       devc->num_channels > 1 ? "s" : "");
-
-       return SR_OK;
-}
-
-SR_PRIV int testo_request_packet(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_usb_dev_inst *usb;
-       int ret;
-
-       devc = sdi->priv;
-       usb = sdi->conn;
-
-       libusb_fill_bulk_transfer(devc->out_transfer, usb->devhdl, EP_OUT,
-                       devc->model->request, devc->model->request_size,
-                       receive_transfer, (void *)sdi, 100);
-       if ((ret = libusb_submit_transfer(devc->out_transfer) != 0)) {
-               sr_err("Failed to request packet: %s.", libusb_error_name(ret));
-               sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi,
-                               devc->cb_data);
-               return SR_ERR;
-       }
-       sr_dbg("Requested new packet.");
-
-       return SR_OK;
-}
-
-/* Check if the packet is well-formed. This matches packets for the
- * Testo 175/177/400/650/950/435/635/735/445/645/945/946/545. */
-SR_PRIV gboolean testo_check_packet_prefix(unsigned char *buf, int len)
-{
-       int i;
-       unsigned char check[] = { 0x21, 0, 0, 0, 1 };
-
-       if (len < 5)
-               return FALSE;
-
-       for (i = 0; i < 5; i++) {
-               if (buf[i] != check[i]) {
-                       sr_dbg("Packet has invalid prefix.");
-                       return FALSE;
-               }
-       }
-
-       return TRUE;
-}
-
-SR_PRIV uint16_t crc16_mcrf4xx(uint16_t crc, uint8_t *data, size_t len)
-{
-       int i;
-
-       if (!data || !len)
-               return crc;
-
-       while (len--) {
-               crc ^= *data++;
-               for (i = 0; i < 8; i++) {
-                       if (crc & 1)
-                               crc = (crc >> 1) ^ 0x8408;
-                       else
-                               crc = (crc >> 1);
-               }
-       }
-
-       return crc;
-}
-
-static float binary32_le_to_float(unsigned char *buf)
-{
-       GFloatIEEE754 f;
-
-       f.v_float = 0;
-       f.mpn.sign = (buf[3] & 0x80) ? 1 : 0;
-       f.mpn.biased_exponent = (buf[3] << 1) | (buf[2] >> 7);
-       f.mpn.mantissa = buf[0] | (buf[1] << 8) | ((buf[2] & 0x7f) << 16);
-
-       return f.v_float;
-}
-
-SR_PRIV void testo_receive_packet(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_analog analog;
-       struct sr_channel *ch;
-       GString *dbg;
-       float value;
-       int i;
-       unsigned char *buf;
-
-       devc = sdi->priv;
-       sr_dbg("Got %d-byte packet.", devc->reply_size);
-
-       if (sr_log_loglevel_get() >= SR_LOG_SPEW) {
-               dbg = g_string_sized_new(128);
-               g_string_printf(dbg, "Packet:");
-               for (i = 0; i < devc->reply_size; i++)
-                       g_string_append_printf(dbg, " %.2x", devc->reply[i]);
-               sr_spew("%s", dbg->str);
-               g_string_free(dbg, TRUE);
-       }
-
-       packet.type = SR_DF_ANALOG;
-       packet.payload = &analog;
-       analog.num_samples = 1;
-       analog.mqflags = 0;
-       analog.data = &value;
-       /* Decode 7-byte values */
-       for (i = 0; i < devc->reply[6]; i++) {
-               buf = devc->reply + 7 + i * 7;
-               value = binary32_le_to_float(buf);
-               switch (buf[4]) {
-               case 1:
-                       analog.mq = SR_MQ_TEMPERATURE;
-                       analog.unit = SR_UNIT_CELSIUS;
-                       break;
-               case 3:
-                       analog.mq = SR_MQ_RELATIVE_HUMIDITY;
-                       analog.unit = SR_UNIT_HUMIDITY_293K;
-                       break;
-               case 5:
-                       analog.mq = SR_MQ_WIND_SPEED;
-                       analog.unit = SR_UNIT_METER_SECOND;
-                       break;
-               case 24:
-                       analog.mq = SR_MQ_PRESSURE;
-                       analog.unit = SR_UNIT_HECTOPASCAL;
-                       break;
-               default:
-                       sr_dbg("Unsupported measurement unit %d.", buf[4]);
-                       return;
-               }
-
-               /* Match this measurement with its channel. */
-               for (i = 0; i < devc->num_channels; i++) {
-                       if (devc->channel_units[i] == buf[4])
-                               break;
-               }
-               if (i == devc->num_channels) {
-                       /* Shouldn't happen. */
-                       sr_err("Some channel hotswapped in!");
-                       return;
-               }
-               ch = g_slist_nth_data(sdi->channels, i);
-               analog.channels = g_slist_append(NULL, ch);
-               sr_session_send(sdi, &packet);
-               g_slist_free(analog.channels);
-       }
-}
-
diff --git a/hardware/testo/protocol.h b/hardware/testo/protocol.h
deleted file mode 100644 (file)
index f61fe2d..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2014 Bert Vermeulen <bert@biot.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_TESTO_PROTOCOL_H
-#define LIBSIGROK_HARDWARE_TESTO_PROTOCOL_H
-
-#include <stdint.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "testo"
-
-#define MAX_REPLY_SIZE       128
-#define MAX_CHANNELS         16
-
-/* FTDI commands */
-#define FTDI_SET_MODEMCTRL   0x01
-#define FTDI_SET_FLOWCTRL    0x02
-#define FTDI_SET_BAUDRATE    0x03
-#define FTDI_SET_PARAMS      0x04
-/* FTDI command values */
-#define FTDI_BAUDRATE_115200 0x001a
-#define FTDI_PARAMS_8N1      0x0008
-#define FTDI_FLOW_NONE       0x0008
-#define FTDI_MODEM_ALLHIGH   0x0303
-#define FTDI_INDEX           0x0000
-/* FTDI USB stuff */
-#define EP_IN                1 | LIBUSB_ENDPOINT_IN
-#define EP_OUT               2 | LIBUSB_ENDPOINT_OUT
-
-struct testo_model {
-       char *name;
-       int request_size;
-       unsigned char *request;
-};
-
-/** Private, per-device-instance driver context. */
-struct dev_context {
-       /* Model-specific information */
-       struct testo_model *model;
-
-       /* Acquisition settings */
-       uint64_t limit_msec;
-       uint64_t limit_samples;
-       void *cb_data;
-
-       /* Operational state */
-       gint64 end_time;
-       uint64_t num_samples;
-       uint8_t channel_units[MAX_CHANNELS];
-       int num_channels;
-
-       /* Temporary state across callbacks */
-       struct libusb_transfer *out_transfer;
-       unsigned char reply[MAX_REPLY_SIZE];
-       int reply_size;
-};
-
-SR_PRIV int testo_set_serial_params(struct sr_usb_dev_inst *usb);
-SR_PRIV int testo_probe_channels(struct sr_dev_inst *sdi);
-SR_PRIV void receive_transfer(struct libusb_transfer *transfer);
-SR_PRIV int testo_request_packet(const struct sr_dev_inst *sdi);
-SR_PRIV gboolean testo_check_packet_prefix(unsigned char *buf, int len);
-SR_PRIV uint16_t crc16_mcrf4xx(uint16_t crc, uint8_t *data, size_t len);
-SR_PRIV void testo_receive_packet(const struct sr_dev_inst *sdi);
-#endif
diff --git a/hardware/tondaj-sl-814/api.c b/hardware/tondaj-sl-814/api.c
deleted file mode 100644 (file)
index 7917c8d..0000000
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include <fcntl.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-#include "protocol.h"
-
-#define SERIALCOMM "9600/8e1"
-
-static const int32_t hwopts[] = {
-       SR_CONF_CONN,
-       SR_CONF_SERIALCOMM,
-};
-
-static const int32_t hwcaps[] = {
-       SR_CONF_SOUNDLEVELMETER,
-       SR_CONF_LIMIT_SAMPLES,
-       SR_CONF_CONTINUOUS,
-};
-
-SR_PRIV struct sr_dev_driver tondaj_sl_814_driver_info;
-static struct sr_dev_driver *di = &tondaj_sl_814_driver_info;
-
-static int init(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, di, LOG_PREFIX);
-}
-
-static GSList *scan(GSList *options)
-{
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       struct sr_dev_inst *sdi;
-       struct sr_config *src;
-       struct sr_channel *ch;
-       GSList *devices, *l;
-       const char *conn, *serialcomm;
-       struct sr_serial_dev_inst *serial;
-
-       drvc = di->priv;
-       drvc->instances = NULL;
-
-       devices = NULL;
-
-       conn = serialcomm = NULL;
-       for (l = options; l; l = l->next) {
-               if (!(src = l->data)) {
-                       sr_err("Invalid option data, skipping.");
-                       continue;
-               }
-               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;
-               default:
-                       sr_err("Unknown option %d, skipping.", src->key);
-                       break;
-               }
-       }
-       if (!conn)
-               return NULL;
-       if (!serialcomm)
-               serialcomm = SERIALCOMM;
-
-       if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "Tondaj",
-                                   "SL-814", NULL))) {
-               sr_err("Failed to create device instance.");
-               return NULL;
-       }
-
-       if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
-               sr_err("Device context malloc failed.");
-               return NULL;
-       }
-
-       if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
-               return NULL;
-
-       if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
-               return NULL;
-
-       sdi->inst_type = SR_INST_SERIAL;
-       sdi->conn = serial;
-
-       sdi->priv = devc;
-       sdi->driver = di;
-       ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1");
-       if (!ch) {
-               sr_err("Failed to create channel.");
-               return NULL;
-       }
-       sdi->channels = g_slist_append(sdi->channels, ch);
-       drvc->instances = g_slist_append(drvc->instances, sdi);
-       devices = g_slist_append(devices, sdi);
-
-       return devices;
-}
-
-static GSList *dev_list(void)
-{
-       return ((struct drv_context *)(di->priv))->instances;
-}
-
-static int cleanup(void)
-{
-       return std_dev_clear(di, NULL);
-}
-
-static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-
-       (void)cg;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       devc = sdi->priv;
-
-       switch (id) {
-       case SR_CONF_LIMIT_SAMPLES:
-               devc->limit_samples = g_variant_get_uint64(data);
-               sr_dbg("Setting sample limit to %" PRIu64 ".",
-                      devc->limit_samples);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_list(int 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_INT32,
-                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
-               break;
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi,
-                                   void *cb_data)
-{
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       devc = sdi->priv;
-       devc->cb_data = cb_data;
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(cb_data, LOG_PREFIX);
-
-       /* Poll every 500ms, or whenever some data comes in. */
-       serial = sdi->conn;
-       serial_source_add(sdi->session, serial, G_IO_IN, 500,
-                     tondaj_sl_814_receive_data, (void *)sdi);
-
-       return SR_OK;
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       return std_serial_dev_acquisition_stop(sdi, cb_data, std_serial_dev_close,
-                       sdi->conn, LOG_PREFIX);
-}
-
-SR_PRIV struct sr_dev_driver tondaj_sl_814_driver_info = {
-       .name = "tondaj-sl-814",
-       .longname = "Tondaj SL-814",
-       .api_version = 1,
-       .init = init,
-       .cleanup = cleanup,
-       .scan = scan,
-       .dev_list = 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 = dev_acquisition_stop,
-       .priv = NULL,
-};
diff --git a/hardware/tondaj-sl-814/protocol.c b/hardware/tondaj-sl-814/protocol.c
deleted file mode 100644 (file)
index feeec69..0000000
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include <string.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-#include "protocol.h"
-
-/* States */
-enum {
-       SEND_INIT,
-       GET_INIT_REPLY,
-       SEND_PACKET_REQUEST,
-       GET_PACKET,
-};
-
-static void parse_packet(const uint8_t *buf, float *floatval,
-                        struct sr_datafeed_analog *analog)
-{
-       gboolean is_a, is_fast;
-       uint16_t intval;
-       uint8_t level = 0, level_bits;
-
-       /* Byte 0 [7:7]: 0 = A, 1 = C */
-       is_a = ((buf[0] & (1 << 7)) == 0);
-
-       /* Byte 0 [6:6]: Unknown/unused? */
-
-       /* Byte 0 [5:4]: Level (00 = 40, 01 = 60, 10 = 80, 11 = 100) */
-       level_bits = (buf[0] >> 4) & 0x03;
-       if (level_bits == 0)
-               level = 40;
-       else if (level_bits == 1)
-               level = 60;
-       else if (level_bits == 2)
-               level = 80;
-       else if (level_bits == 3)
-               level = 100;
-
-       /* Byte 0 [3:3]: 0 = fast, 1 = slow */
-       is_fast = ((buf[0] & (1 << 3)) == 0);
-
-       /* Byte 0 [2:0]: value[10..8] */
-       /* Byte 1 [7:0]: value[7..0] */
-       intval = (buf[0] & 0x7) << 8;
-       intval |= buf[1];
-
-       *floatval = (float)intval;
-
-       /* The value on the display always has one digit after the comma. */
-       *floatval /= 10;
-
-       analog->mq = SR_MQ_SOUND_PRESSURE_LEVEL;
-       analog->unit = SR_UNIT_DECIBEL_SPL;
-
-       if (is_a)
-               analog->mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_A;
-       else
-               analog->mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_C;
-
-       if (is_fast)
-               analog->mqflags |= SR_MQFLAG_SPL_TIME_WEIGHT_F;
-       else
-               analog->mqflags |= SR_MQFLAG_SPL_TIME_WEIGHT_S;
-
-       /* TODO: How to handle level? */
-       (void)level;
-}
-
-static void decode_packet(struct sr_dev_inst *sdi)
-{
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_analog analog;
-       struct dev_context *devc;
-       float floatval;
-
-       devc = sdi->priv;
-       memset(&analog, 0, sizeof(struct sr_datafeed_analog));
-
-       parse_packet(devc->buf, &floatval, &analog);
-
-       /* Send a sample packet with one analog value. */
-       analog.channels = sdi->channels;
-       analog.num_samples = 1;
-       analog.data = &floatval;
-       packet.type = SR_DF_ANALOG;
-       packet.payload = &analog;
-       sr_session_send(devc->cb_data, &packet);
-
-       devc->num_samples++;
-}
-
-int tondaj_sl_814_receive_data(int fd, int revents, void *cb_data)
-{
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-       struct sr_serial_dev_inst *serial;
-       uint8_t buf[3];
-       int ret;
-
-       (void)fd;
-       (void)revents;
-
-       sdi = cb_data;
-       serial = sdi->conn;
-       devc = sdi->priv;
-
-       /* TODO: Parts of this code need to be improved later. */
-
-       /* State machine. */
-       if (devc->state == SEND_INIT) {
-               /* On the first run, send the "init" command. */
-               buf[0] = 0x10;
-               buf[1] = 0x04;
-               buf[2] = 0x0d;
-               sr_spew("Sending init command: %02x %02x %02x.",
-                       buf[0], buf[1], buf[2]);
-               if ((ret = serial_write(serial, buf, 3)) < 0) {
-                       sr_err("Error sending init command: %d.", ret);
-                       return FALSE;
-               }
-               devc->state = GET_INIT_REPLY;
-       } else if (devc->state == GET_INIT_REPLY) {
-               /* If we just sent the "init" command, get its reply. */
-               if ((ret = serial_read(serial, buf, 2)) < 0) {
-                       sr_err("Error reading init reply: %d.", ret);
-                       return FALSE;
-               }
-               sr_spew("Received init reply: %02x %02x.", buf[0], buf[1]);
-               /* Expected reply: 0x05 0x0d */
-               if (buf[0] != 0x05 || buf[1] != 0x0d) {
-                       sr_err("Received incorrect init reply, retrying.");
-                       devc->state = SEND_INIT;
-                       return TRUE;
-               }
-               devc->state = SEND_PACKET_REQUEST;
-       } else if (devc->state == SEND_PACKET_REQUEST) {
-               /* Request a packet (send 0x30 ZZ 0x0d). */
-               buf[0] = 0x30;
-               buf[1] = 0x00; /* ZZ */
-               buf[2] = 0x0d;
-               sr_spew("Sending data request command: %02x %02x %02x.",
-                       buf[0], buf[1], buf[2]);
-               if ((ret = serial_write(serial, buf, 3)) < 0) {
-                       sr_err("Error sending request command: %d.", ret);
-                       return FALSE;
-               }
-               devc->buflen = 0;
-               devc->state = GET_PACKET;
-       } else if (devc->state == GET_PACKET) {
-               /* Read a packet from the device. */
-               ret = serial_read(serial, devc->buf + devc->buflen,
-                                 4 - devc->buflen);
-               if (ret < 0) {
-                       sr_err("Error reading packet: %d.", ret);
-                       return TRUE;
-               }
-
-               devc->buflen += ret;
-
-               /* Didn't receive all 4 bytes, yet. */
-               if (devc->buflen != 4)
-                       return TRUE;
-
-               sr_spew("Received packet: %02x %02x %02x %02x.", devc->buf[0],
-                       devc->buf[1], devc->buf[2], devc->buf[3]);
-
-               /* Expected reply: AA BB ZZ+1 0x0d */
-               if (devc->buf[2] != 0x01 || devc->buf[3] != 0x0d) {
-                       sr_err("Received incorrect request reply, retrying.");
-                       devc->state = SEND_PACKET_REQUEST;
-                       return TRUE;
-               }
-
-               decode_packet(sdi);
-
-               devc->state = SEND_PACKET_REQUEST;
-       } else {
-               sr_err("Invalid state: %d.", devc->state);
-               return FALSE;
-       }
-
-       /* Stop acquisition if we acquired enough samples. */
-       if (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
-               sr_info("Requested number of samples reached.");
-               sdi->driver->dev_acquisition_stop(sdi, cb_data);
-       }
-
-       return TRUE;
-}
diff --git a/hardware/tondaj-sl-814/protocol.h b/hardware/tondaj-sl-814/protocol.h
deleted file mode 100644 (file)
index 027b66d..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#ifndef LIBSIGROK_HARDWARE_TONDAJ_SL_814_PROTOCOL_H
-#define LIBSIGROK_HARDWARE_TONDAJ_SL_814_PROTOCOL_H
-
-#include <stdint.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "tondaj-sl-814"
-
-/** Private, per-device-instance driver context. */
-struct dev_context {
-       /** The current sampling limit (in number of samples). */
-       uint64_t limit_samples;
-
-       /** The current sampling limit (in ms). */
-       uint64_t limit_msec;
-
-       /** Opaque pointer passed in by the frontend. */
-       void *cb_data;
-
-       /** The current number of already received samples. */
-       uint64_t num_samples;
-
-       int state;
-
-       uint8_t buf[4];
-       uint8_t buflen;
-};
-
-SR_PRIV int tondaj_sl_814_receive_data(int fd, int revents, void *cb_data);
-
-#endif
diff --git a/hardware/uni-t-dmm/api.c b/hardware/uni-t-dmm/api.c
deleted file mode 100644 (file)
index f98c4f5..0000000
+++ /dev/null
@@ -1,424 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012-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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-#include "protocol.h"
-
-#define UNI_T_UT_D04_NEW "1a86.e008"
-
-static const int32_t hwopts[] = {
-       SR_CONF_CONN,
-};
-
-static const int32_t hwcaps[] = {
-       SR_CONF_MULTIMETER,
-       SR_CONF_LIMIT_SAMPLES,
-       SR_CONF_LIMIT_MSEC,
-       SR_CONF_CONTINUOUS,
-};
-
-SR_PRIV struct sr_dev_driver tecpel_dmm_8061_driver_info;
-SR_PRIV struct sr_dev_driver uni_t_ut60a_driver_info;
-SR_PRIV struct sr_dev_driver uni_t_ut60e_driver_info;
-SR_PRIV struct sr_dev_driver uni_t_ut60g_driver_info;
-SR_PRIV struct sr_dev_driver uni_t_ut61b_driver_info;
-SR_PRIV struct sr_dev_driver uni_t_ut61c_driver_info;
-SR_PRIV struct sr_dev_driver uni_t_ut61d_driver_info;
-SR_PRIV struct sr_dev_driver uni_t_ut61e_driver_info;
-SR_PRIV struct sr_dev_driver voltcraft_vc820_driver_info;
-SR_PRIV struct sr_dev_driver voltcraft_vc830_driver_info;
-SR_PRIV struct sr_dev_driver voltcraft_vc840_driver_info;
-SR_PRIV struct sr_dev_driver tenma_72_7745_driver_info;
-SR_PRIV struct sr_dev_driver tenma_72_7750_driver_info;
-
-SR_PRIV struct dmm_info udmms[] = {
-       {
-               "Tecpel", "DMM-8061", 2400,
-               FS9721_PACKET_SIZE,
-               sr_fs9721_packet_valid, sr_fs9721_parse,
-               sr_fs9721_00_temp_c,
-               &tecpel_dmm_8061_driver_info, receive_data_TECPEL_DMM_8061,
-       },
-       {
-               "UNI-T", "UT60A", 2400,
-               FS9721_PACKET_SIZE,
-               sr_fs9721_packet_valid, sr_fs9721_parse,
-               NULL,
-               &uni_t_ut60a_driver_info, receive_data_UNI_T_UT60A,
-       },
-       {
-               "UNI-T", "UT60E", 2400,
-               FS9721_PACKET_SIZE,
-               sr_fs9721_packet_valid, sr_fs9721_parse,
-               sr_fs9721_00_temp_c,
-               &uni_t_ut60e_driver_info, receive_data_UNI_T_UT60E,
-       },
-       {
-               /* The baudrate is actually 19230, see "Note 1" below. */
-               "UNI-T", "UT60G", 19200,
-               ES519XX_11B_PACKET_SIZE,
-               sr_es519xx_19200_11b_packet_valid, sr_es519xx_19200_11b_parse,
-               NULL,
-               &uni_t_ut60g_driver_info, receive_data_UNI_T_UT60G,
-       },
-       {
-               "UNI-T", "UT61B", 2400,
-               FS9922_PACKET_SIZE,
-               sr_fs9922_packet_valid, sr_fs9922_parse,
-               NULL,
-               &uni_t_ut61b_driver_info, receive_data_UNI_T_UT61B,
-       },
-       {
-               "UNI-T", "UT61C", 2400,
-               FS9922_PACKET_SIZE,
-               sr_fs9922_packet_valid, sr_fs9922_parse,
-               NULL,
-               &uni_t_ut61c_driver_info, receive_data_UNI_T_UT61C,
-       },
-       {
-               "UNI-T", "UT61D", 2400,
-               FS9922_PACKET_SIZE,
-               sr_fs9922_packet_valid, sr_fs9922_parse,
-               NULL,
-               &uni_t_ut61d_driver_info, receive_data_UNI_T_UT61D,
-       },
-       {
-               /* The baudrate is actually 19230, see "Note 1" below. */
-               "UNI-T", "UT61E", 19200,
-               ES519XX_14B_PACKET_SIZE,
-               sr_es519xx_19200_14b_packet_valid, sr_es519xx_19200_14b_parse,
-               NULL,
-               &uni_t_ut61e_driver_info, receive_data_UNI_T_UT61E,
-       },
-       {
-               "Voltcraft", "VC-820", 2400,
-               FS9721_PACKET_SIZE,
-               sr_fs9721_packet_valid, sr_fs9721_parse,
-               NULL,
-               &voltcraft_vc820_driver_info, receive_data_VOLTCRAFT_VC820,
-       },
-       {
-               /*
-                * Note: The VC830 doesn't set the 'volt' and 'diode' bits of
-                * the FS9922 protocol. Instead, it only sets the user-defined
-                * bit "z1" to indicate "diode mode" and "voltage".
-                */
-               "Voltcraft", "VC-830", 2400,
-               FS9922_PACKET_SIZE,
-               sr_fs9922_packet_valid, sr_fs9922_parse,
-               &sr_fs9922_z1_diode,
-               &voltcraft_vc830_driver_info, receive_data_VOLTCRAFT_VC830,
-       },
-       {
-               "Voltcraft", "VC-840", 2400,
-               FS9721_PACKET_SIZE,
-               sr_fs9721_packet_valid, sr_fs9721_parse,
-               sr_fs9721_00_temp_c,
-               &voltcraft_vc840_driver_info, receive_data_VOLTCRAFT_VC840,
-       },
-       {
-               "Tenma", "72-7745", 2400,
-               FS9721_PACKET_SIZE,
-               sr_fs9721_packet_valid, sr_fs9721_parse,
-               sr_fs9721_00_temp_c,
-               &tenma_72_7745_driver_info, receive_data_TENMA_72_7745,
-       },
-       {
-               /* The baudrate is actually 19230, see "Note 1" below. */
-               "Tenma", "72-7750", 19200,
-               ES519XX_11B_PACKET_SIZE,
-               sr_es519xx_19200_11b_packet_valid, sr_es519xx_19200_11b_parse,
-               NULL,
-               &tenma_72_7750_driver_info, receive_data_TENMA_72_7750,
-       },
-};
-
-/*
- * Note 1: The actual baudrate of the Cyrustek ES519xx chip used in this DMM
- * is 19230. However, the WCH CH9325 chip (UART to USB/HID) used in (some
- * versions of) the UNI-T UT-D04 cable doesn't support 19230 baud. It only
- * supports 19200, and setting an unsupported baudrate will result in the
- * default of 2400 being used (which will not work with this DMM, of course).
- */
-
-static int dev_clear(int dmm)
-{
-       return std_dev_clear(udmms[dmm].di, NULL);
-}
-
-static int init(struct sr_context *sr_ctx, int dmm)
-{
-       sr_dbg("Selected '%s' subdriver.", udmms[dmm].di->name);
-
-       return std_init(sr_ctx, udmms[dmm].di, LOG_PREFIX);
-}
-
-static GSList *scan(GSList *options, int dmm)
-{
-       GSList *usb_devices, *devices, *l;
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-       struct drv_context *drvc;
-       struct sr_usb_dev_inst *usb;
-       struct sr_config *src;
-       struct sr_channel *ch;
-       const char *conn;
-
-       drvc = udmms[dmm].di->priv;
-
-       conn = NULL;
-       for (l = options; l; l = l->next) {
-               src = l->data;
-               switch (src->key) {
-               case SR_CONF_CONN:
-                       conn = g_variant_get_string(src->data, NULL);
-                       break;
-               }
-       }
-       if (!conn)
-               return NULL;
-
-       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;
-
-               if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
-                       sr_err("Device context malloc failed.");
-                       return NULL;
-               }
-
-               devc->first_run = TRUE;
-
-               if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE,
-                               udmms[dmm].vendor, udmms[dmm].device, NULL))) {
-                       sr_err("sr_dev_inst_new returned NULL.");
-                       return NULL;
-               }
-               sdi->priv = devc;
-               sdi->driver = udmms[dmm].di;
-               if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1")))
-                       return NULL;
-               sdi->channels = g_slist_append(sdi->channels, ch);
-
-               sdi->inst_type = SR_INST_USB;
-               sdi->conn = usb;
-
-               drvc->instances = g_slist_append(drvc->instances, sdi);
-               devices = g_slist_append(devices, sdi);
-       }
-
-       return devices;
-}
-
-static GSList *dev_list(int dmm)
-{
-       return ((struct drv_context *)(udmms[dmm].di->priv))->instances;
-}
-
-static int dev_open(struct sr_dev_inst *sdi, int dmm)
-{
-       struct drv_context *drvc;
-       struct sr_usb_dev_inst *usb;
-       int ret;
-
-       drvc = udmms[dmm].di->priv;
-       usb = sdi->conn;
-
-       if ((ret = sr_usb_open(drvc->sr_ctx->libusb_ctx, usb)) == SR_OK)
-               sdi->status = SR_ST_ACTIVE;
-
-       return ret;
-}
-
-static int dev_close(struct sr_dev_inst *sdi)
-{
-       /* TODO */
-
-       sdi->status = SR_ST_INACTIVE;
-
-       return SR_OK;
-}
-
-static int cleanup(int dmm)
-{
-       return dev_clear(dmm);
-}
-
-static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-
-       (void)cg;
-
-       devc = sdi->priv;
-
-       switch (id) {
-       case SR_CONF_LIMIT_MSEC:
-               if (g_variant_get_uint64(data) == 0) {
-                       sr_err("Time limit cannot be 0.");
-                       return SR_ERR;
-               }
-               devc->limit_msec = g_variant_get_uint64(data);
-               sr_dbg("Setting time limit to %" PRIu64 "ms.",
-                      devc->limit_msec);
-               break;
-       case SR_CONF_LIMIT_SAMPLES:
-               if (g_variant_get_uint64(data) == 0) {
-                       sr_err("Sample limit cannot be 0.");
-                       return SR_ERR;
-               }
-               devc->limit_samples = g_variant_get_uint64(data);
-               sr_dbg("Setting sample limit to %" PRIu64 ".",
-                      devc->limit_samples);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_list(int 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_INT32,
-                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
-               break;
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi,
-                                   void *cb_data, int dmm)
-{
-       struct dev_context *devc;
-
-       devc = sdi->priv;
-
-       devc->cb_data = cb_data;
-
-       devc->starttime = g_get_monotonic_time();
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(sdi, LOG_PREFIX);
-
-       sr_session_source_add(sdi->session, 0, 0, 10 /* poll_timeout */,
-                     udmms[dmm].receive_data, (void *)sdi);
-
-       return SR_OK;
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct sr_datafeed_packet packet;
-
-       (void)cb_data;
-
-       sr_dbg("Stopping acquisition.");
-
-       /* Send end packet to the session bus. */
-       sr_dbg("Sending SR_DF_END.");
-       packet.type = SR_DF_END;
-       sr_session_send(sdi, &packet);
-
-       sr_session_source_remove(sdi->session, 0);
-
-       return SR_OK;
-}
-
-/* Driver-specific API function wrappers */
-#define HW_INIT(X) \
-static int init_##X(struct sr_context *sr_ctx) { return init(sr_ctx, X); }
-#define HW_CLEANUP(X) \
-static int cleanup_##X(void) { return cleanup(X); }
-#define HW_SCAN(X) \
-static GSList *scan_##X(GSList *options) { return scan(options, X); }
-#define HW_DEV_LIST(X) \
-static GSList *dev_list_##X(void) { return dev_list(X); }
-#define HW_DEV_CLEAR(X) \
-static int dev_clear_##X(void) { return dev_clear(X); }
-#define HW_DEV_ACQUISITION_START(X) \
-static int dev_acquisition_start_##X(const struct sr_dev_inst *sdi, \
-void *cb_data) { return dev_acquisition_start(sdi, cb_data, X); }
-#define HW_DEV_OPEN(X) \
-static int dev_open_##X(struct sr_dev_inst *sdi) { return dev_open(sdi, X); }
-
-/* Driver structs and API function wrappers */
-#define DRV(ID, ID_UPPER, NAME, LONGNAME) \
-HW_INIT(ID_UPPER) \
-HW_CLEANUP(ID_UPPER) \
-HW_SCAN(ID_UPPER) \
-HW_DEV_LIST(ID_UPPER) \
-HW_DEV_CLEAR(ID_UPPER) \
-HW_DEV_ACQUISITION_START(ID_UPPER) \
-HW_DEV_OPEN(ID_UPPER) \
-SR_PRIV struct sr_dev_driver ID##_driver_info = { \
-       .name = NAME, \
-       .longname = LONGNAME, \
-       .api_version = 1, \
-       .init = init_##ID_UPPER, \
-       .cleanup = cleanup_##ID_UPPER, \
-       .scan = scan_##ID_UPPER, \
-       .dev_list = dev_list_##ID_UPPER, \
-       .dev_clear = dev_clear_##ID_UPPER, \
-       .config_get = NULL, \
-       .config_set = config_set, \
-       .config_list = config_list, \
-       .dev_open = dev_open_##ID_UPPER, \
-       .dev_close = dev_close, \
-       .dev_acquisition_start = dev_acquisition_start_##ID_UPPER, \
-       .dev_acquisition_stop = dev_acquisition_stop, \
-       .priv = NULL, \
-};
-
-DRV(tecpel_dmm_8061, TECPEL_DMM_8061, "tecpel-dmm-8061", "Tecpel DMM-8061")
-DRV(uni_t_ut60a, UNI_T_UT60A, "uni-t-ut60a", "UNI-T UT60A")
-DRV(uni_t_ut60e, UNI_T_UT60E, "uni-t-ut60e", "UNI-T UT60E")
-DRV(uni_t_ut60g, UNI_T_UT60G, "uni-t-ut60g", "UNI-T UT60G")
-DRV(uni_t_ut61b, UNI_T_UT61B, "uni-t-ut61b", "UNI-T UT61B")
-DRV(uni_t_ut61c, UNI_T_UT61C, "uni-t-ut61c", "UNI-T UT61C")
-DRV(uni_t_ut61d, UNI_T_UT61D, "uni-t-ut61d", "UNI-T UT61D")
-DRV(uni_t_ut61e, UNI_T_UT61E, "uni-t-ut61e", "UNI-T UT61E")
-DRV(voltcraft_vc820, VOLTCRAFT_VC820, "voltcraft-vc820", "Voltcraft VC-820")
-DRV(voltcraft_vc830, VOLTCRAFT_VC830, "voltcraft-vc830", "Voltcraft VC-830")
-DRV(voltcraft_vc840, VOLTCRAFT_VC840, "voltcraft-vc840", "Voltcraft VC-840")
-DRV(tenma_72_7745, TENMA_72_7745, "tenma-72-7745", "Tenma 72-7745")
-DRV(tenma_72_7750, TENMA_72_7750, "tenma-72-7750", "Tenma 72-7750")
diff --git a/hardware/uni-t-dmm/protocol.c b/hardware/uni-t-dmm/protocol.c
deleted file mode 100644 (file)
index ca2568e..0000000
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012-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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include <string.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-#include "protocol.h"
-
-extern struct dmm_info udmms[];
-
-/*
- * Driver for various UNI-T multimeters (and rebranded ones).
- *
- * Most UNI-T DMMs can be used with two (three) different PC interface cables:
- *  - The UT-D04 USB/HID cable, old version with Hoitek HE2325U chip.
- *  - The UT-D04 USB/HID cable, new version with WCH CH9325 chip.
- *  - The UT-D02 RS232 cable.
- *
- * This driver is meant to support all USB/HID cables, and various DMMs that
- * can be attached to a PC via these cables. Currently only the UT-D04 cable
- * (new version) is supported/tested.
- * The UT-D02 RS232 cable is handled by the 'serial-dmm' driver.
- *
- * The data for one DMM packet (e.g. 14 bytes if the respective DMM uses a
- * Fortune Semiconductor FS9922-DMM4 chip) is spread across multiple
- * 8-byte chunks.
- *
- * An 8-byte chunk looks like this:
- *  - Byte 0: 0xfz, where z is the number of actual data bytes in this chunk.
- *  - Bytes 1-7: z data bytes, the rest of the bytes should be ignored.
- *
- * Example:
- *  f0 00 00 00 00 00 00 00 (no data bytes)
- *  f2 55 77 00 00 00 00 00 (2 data bytes, 0x55 and 0x77)
- *  f1 d1 00 00 00 00 00 00 (1 data byte, 0xd1)
- */
-
-static void decode_packet(struct sr_dev_inst *sdi, int dmm, const uint8_t *buf,
-                         void *info)
-{
-       struct dev_context *devc;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_analog analog;
-       float floatval;
-       int ret;
-
-       devc = sdi->priv;
-       memset(&analog, 0, sizeof(struct sr_datafeed_analog));
-
-       /* Parse the protocol packet. */
-       ret = udmms[dmm].packet_parse(buf, &floatval, &analog, info);
-       if (ret != SR_OK) {
-               sr_dbg("Invalid DMM packet, ignoring.");
-               return;
-       }
-
-       /* If this DMM needs additional handling, call the resp. function. */
-       if (udmms[dmm].dmm_details)
-               udmms[dmm].dmm_details(&analog, info);
-
-       /* Send a sample packet with one analog value. */
-       analog.channels = sdi->channels;
-       analog.num_samples = 1;
-       analog.data = &floatval;
-       packet.type = SR_DF_ANALOG;
-       packet.payload = &analog;
-       sr_session_send(devc->cb_data, &packet);
-
-       /* Increase sample count. */
-       devc->num_samples++;
-}
-
-static int hid_chip_init(struct sr_dev_inst *sdi, uint16_t baudrate)
-{
-       int ret;
-       uint8_t buf[5];
-       struct sr_usb_dev_inst *usb;
-
-       usb = sdi->conn;
-       
-       /* 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;
-               }
-               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.");
-
-       /* Set data for the HID feature report (e.g. baudrate). */
-       buf[0] = baudrate & 0xff;        /* Baudrate, LSB */
-       buf[1] = (baudrate >> 8) & 0xff; /* Baudrate, MSB */
-       buf[2] = 0x00;                   /* Unknown/unused (?) */
-       buf[3] = 0x00;                   /* Unknown/unused (?) */
-       buf[4] = 0x03;                   /* Unknown, always 0x03. */
-
-       /* Send HID feature report to setup the baudrate/chip. */
-       sr_dbg("Sending initial HID feature report.");
-       sr_spew("HID init = 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x (%d baud)",
-               buf[0], buf[1], buf[2], buf[3], buf[4], baudrate);
-       ret = libusb_control_transfer(
-               usb->devhdl, /* libusb device handle */
-               LIBUSB_REQUEST_TYPE_CLASS |
-               LIBUSB_RECIPIENT_INTERFACE |
-               LIBUSB_ENDPOINT_OUT,
-               9, /* bRequest: HID set_report */
-               0x300, /* wValue: HID feature, report number 0 */
-               0, /* wIndex: interface 0 */
-               (unsigned char *)&buf, /* payload buffer */
-               5, /* wLength: 5 bytes payload */
-               1000 /* timeout (ms) */);
-
-       if (ret < 0) {
-               sr_err("HID feature report error: %s.", libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-       if (ret != 5) {
-               /* TODO: Handle better by also sending the remaining bytes. */
-               sr_err("Short packet: sent %d/5 bytes.", ret);
-               return SR_ERR;
-       }
-
-       sr_dbg("Successfully sent initial HID feature report.");
-
-       return SR_OK;
-}
-
-static void log_8byte_chunk(const uint8_t *buf)
-{
-       sr_spew("8-byte chunk: %02x %02x %02x %02x %02x %02x %02x %02x "
-               "(%d data bytes)", buf[0], buf[1], buf[2], buf[3],
-               buf[4], buf[5], buf[6], buf[7], (buf[0] & 0x0f));
-}
-
-static void log_dmm_packet(const uint8_t *buf)
-{
-       sr_dbg("DMM packet:   %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]);
-}
-
-static int get_and_handle_data(struct sr_dev_inst *sdi, int dmm, void *info)
-{
-       struct dev_context *devc;
-       uint8_t buf[CHUNK_SIZE], *pbuf;
-       int i, ret, len, num_databytes_in_chunk;
-       struct sr_usb_dev_inst *usb;
-
-       devc = sdi->priv;
-       usb = sdi->conn;
-       pbuf = devc->protocol_buf;
-
-       /* On the first run, we need to init the HID chip. */
-       if (devc->first_run) {
-               if ((ret = hid_chip_init(sdi, udmms[dmm].baudrate)) != SR_OK) {
-                       sr_err("HID chip init failed: %d.", ret);
-                       return SR_ERR;
-               }
-               memset(pbuf, 0x00, DMM_BUFSIZE);
-               devc->first_run = FALSE;
-       }
-
-       memset(&buf, 0x00, CHUNK_SIZE);
-
-       /* Get data from EP2 using an interrupt transfer. */
-       ret = libusb_interrupt_transfer(
-               usb->devhdl, /* libusb device handle */
-               LIBUSB_ENDPOINT_IN | 2, /* EP2, IN */
-               (unsigned char *)&buf, /* receive buffer */
-               CHUNK_SIZE, /* wLength */
-               &len, /* actually received byte count */
-               1000 /* timeout (ms) */);
-
-       if (ret < 0) {
-               sr_err("USB receive error: %s.", libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-       if (len != CHUNK_SIZE) {
-               sr_err("Short packet: received %d/%d bytes.", len, CHUNK_SIZE);
-               /* TODO: Print the bytes? */
-               return SR_ERR;
-       }
-
-       log_8byte_chunk((const uint8_t *)&buf);
-
-       /* If there are no data bytes just return (without error). */
-       if (buf[0] == 0xf0)
-               return SR_OK;
-
-       devc->bufoffset = 0;
-
-       /*
-        * Append the 1-7 data bytes of this chunk to pbuf.
-        *
-        * Special case:
-        * DMMs with Cyrustek ES51922 chip need serial settings of
-        * 19230/7o1. The WCH CH9325 UART to USB/HID chip used in (some
-        * versions of) the UNI-T UT-D04 cable however, will also send
-        * the parity bit to the host in the 8-byte data chunks. This bit
-        * is encoded in bit 7 of each of the 1-7 data bytes and must thus
-        * be removed in order for the actual ES51922 protocol parser to
-        * work properly.
-        */
-       num_databytes_in_chunk = buf[0] & 0x0f;
-       for (i = 0; i < num_databytes_in_chunk; i++, devc->buflen++) {
-               pbuf[devc->buflen] = buf[1 + i];
-               if (udmms[dmm].packet_parse == sr_es519xx_19200_14b_parse)
-                       pbuf[devc->buflen] &= ~(1 << 7);
-       }
-
-       /* Now look for packets in that data. */
-       while ((devc->buflen - devc->bufoffset) >= udmms[dmm].packet_size) {
-               if (udmms[dmm].packet_valid(pbuf + devc->bufoffset)) {
-                       log_dmm_packet(pbuf + devc->bufoffset);
-                       decode_packet(sdi, dmm, pbuf + devc->bufoffset, info);
-                       devc->bufoffset += udmms[dmm].packet_size;
-               } else {
-                       devc->bufoffset++;
-               }
-       }
-
-       /* Move remaining bytes to beginning of buffer. */
-       for (i = 0; i < devc->buflen - devc->bufoffset; i++)
-               pbuf[i] = pbuf[devc->bufoffset + i];
-       devc->buflen -= devc->bufoffset;
-
-       return SR_OK;
-}
-
-static int receive_data(int fd, int revents, int dmm, void *info, void *cb_data)
-{
-       int ret;
-       struct sr_dev_inst *sdi;
-       struct dev_context *devc;
-       int64_t time_ms;
-
-       (void)fd;
-       (void)revents;
-
-       sdi = cb_data;
-       devc = sdi->priv;
-
-       if ((ret = get_and_handle_data(sdi, dmm, info)) != SR_OK)
-               return FALSE;
-
-       /* Abort acquisition if we acquired enough samples. */
-       if (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
-               sr_info("Requested number of samples reached.");
-               sdi->driver->dev_acquisition_stop(sdi, cb_data);
-       }
-
-       if (devc->limit_msec) {
-               time_ms = (g_get_monotonic_time() - devc->starttime) / 1000;
-               if (time_ms > (int64_t)devc->limit_msec) {
-                       sr_info("Requested time limit reached.");
-                       sdi->driver->dev_acquisition_stop(sdi, cb_data);
-                       return TRUE;
-               }
-       }
-
-       return TRUE;
-}
-
-#define RECEIVE_DATA(ID_UPPER, DMM_DRIVER) \
-SR_PRIV int receive_data_##ID_UPPER(int fd, int revents, void *cb_data) { \
-       struct DMM_DRIVER##_info info; \
-       return receive_data(fd, revents, ID_UPPER, &info, cb_data); }
-
-/* Driver-specific receive_data() wrappers */
-RECEIVE_DATA(TECPEL_DMM_8061, fs9721)
-RECEIVE_DATA(UNI_T_UT60A, fs9721)
-RECEIVE_DATA(UNI_T_UT60E, fs9721)
-RECEIVE_DATA(UNI_T_UT60G, es519xx)
-RECEIVE_DATA(UNI_T_UT61B, fs9922)
-RECEIVE_DATA(UNI_T_UT61C, fs9922)
-RECEIVE_DATA(UNI_T_UT61D, fs9922)
-RECEIVE_DATA(UNI_T_UT61E, es519xx)
-RECEIVE_DATA(VOLTCRAFT_VC820, fs9721)
-RECEIVE_DATA(VOLTCRAFT_VC830, fs9922)
-RECEIVE_DATA(VOLTCRAFT_VC840, fs9721)
-RECEIVE_DATA(TENMA_72_7745, es519xx)
-RECEIVE_DATA(TENMA_72_7750, es519xx)
diff --git a/hardware/uni-t-dmm/protocol.h b/hardware/uni-t-dmm/protocol.h
deleted file mode 100644 (file)
index 08fb537..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012-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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#ifndef LIBSIGROK_HARDWARE_UNI_T_DMM_PROTOCOL_H
-#define LIBSIGROK_HARDWARE_UNI_T_DMM_PROTOCOL_H
-
-#include <stdint.h>
-#include <glib.h>
-#include <libusb.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "uni-t-dmm"
-
-enum {
-       TECPEL_DMM_8061,
-       UNI_T_UT60A,
-       UNI_T_UT60E,
-       UNI_T_UT60G,
-       UNI_T_UT61B,
-       UNI_T_UT61C,
-       UNI_T_UT61D,
-       UNI_T_UT61E,
-       VOLTCRAFT_VC820,
-       VOLTCRAFT_VC830,
-       VOLTCRAFT_VC840,
-       TENMA_72_7745,
-       TENMA_72_7750,
-};
-
-struct dmm_info {
-       char *vendor;
-       char *device;
-       uint32_t baudrate;
-       int packet_size;
-       gboolean (*packet_valid)(const uint8_t *);
-       int (*packet_parse)(const uint8_t *, float *,
-                           struct sr_datafeed_analog *, void *);
-       void (*dmm_details)(struct sr_datafeed_analog *, void *);
-       struct sr_dev_driver *di;
-       int (*receive_data)(int, int, void *);
-};
-
-#define CHUNK_SIZE             8
-
-#define DMM_BUFSIZE            256
-
-/** Private, per-device-instance driver context. */
-struct dev_context {
-       /** The current sampling limit (in number of samples). */
-       uint64_t limit_samples;
-
-       /** The current sampling limit (in ms). */
-       uint64_t limit_msec;
-
-       /** Opaque pointer passed in by the frontend. */
-       void *cb_data;
-
-       /** The current number of already received samples. */
-       uint64_t num_samples;
-
-       int64_t starttime;
-
-       gboolean first_run;
-
-       uint8_t protocol_buf[DMM_BUFSIZE];
-       uint8_t bufoffset;
-       uint8_t buflen;
-};
-
-SR_PRIV int receive_data_TECPEL_DMM_8061(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_UNI_T_UT60A(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_UNI_T_UT60E(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_UNI_T_UT60G(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_UNI_T_UT61B(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_UNI_T_UT61C(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_UNI_T_UT61D(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_UNI_T_UT61E(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_VOLTCRAFT_VC820(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_VOLTCRAFT_VC830(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_VOLTCRAFT_VC840(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_TENMA_72_7745(int fd, int revents, void *cb_data);
-SR_PRIV int receive_data_TENMA_72_7750(int fd, int revents, void *cb_data);
-
-#endif
diff --git a/hardware/uni-t-ut32x/api.c b/hardware/uni-t-ut32x/api.c
deleted file mode 100644 (file)
index 81024dc..0000000
+++ /dev/null
@@ -1,385 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Bert Vermeulen <bert@biot.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 "protocol.h"
-
-#include <string.h>
-
-static const int32_t hwcaps[] = {
-       SR_CONF_THERMOMETER,
-       SR_CONF_LIMIT_SAMPLES,
-       SR_CONF_CONTINUOUS,
-       SR_CONF_DATA_SOURCE,
-};
-
-static char *channels[] = {
-       "T1",
-       "T2",
-       "T1-T2",
-};
-
-static const char *data_sources[] = {
-       "Live",
-       "Memory",
-};
-
-SR_PRIV struct sr_dev_driver uni_t_ut32x_driver_info;
-static struct sr_dev_driver *di = &uni_t_ut32x_driver_info;
-
-
-static int init(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, di, LOG_PREFIX);
-}
-
-static GSList *scan(GSList *options)
-{
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       struct sr_dev_inst *sdi;
-       struct sr_channel *ch;
-       struct sr_config *src;
-       GSList *usb_devices, *devices, *l;
-       int i;
-       const char *conn;
-
-       drvc = di->priv;
-       drvc->instances = NULL;
-
-       conn = NULL;
-       for (l = options; l; l = l->next) {
-               src = l->data;
-               switch (src->key) {
-               case SR_CONF_CONN:
-                       conn = g_variant_get_string(src->data, NULL);
-                       break;
-               }
-       }
-       if (!conn)
-               return NULL;
-
-       devices = NULL;
-       if ((usb_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn))) {
-               /* We have a list of sr_usb_dev_inst matching the connection
-                * string. Wrap them in sr_dev_inst and we're done. */
-               for (l = usb_devices; l; l = l->next) {
-                       if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, VENDOR,
-                                       MODEL, NULL)))
-                               return NULL;
-                       sdi->driver = di;
-                       sdi->inst_type = SR_INST_USB;
-                       sdi->conn = l->data;
-                       for (i = 0; i < 3; i++) {
-                               if (!(ch = sr_channel_new(i, SR_CHANNEL_ANALOG, TRUE,
-                                               channels[i]))) {
-                                       sr_dbg("Channel malloc failed.");
-                                       return NULL;
-                               }
-                               sdi->channels = g_slist_append(sdi->channels, ch);
-                       }
-
-                       if (!(devc = g_try_malloc(sizeof(struct dev_context)))) {
-                               sr_dbg("Device context malloc failed.");
-                               return NULL;
-                       }
-                       sdi->priv = devc;
-                       devc->limit_samples = 0;
-                       devc->data_source = DEFAULT_DATA_SOURCE;
-                       drvc->instances = g_slist_append(drvc->instances, sdi);
-                       devices = g_slist_append(devices, sdi);
-               }
-               g_slist_free(usb_devices);
-       } else
-               g_slist_free_full(usb_devices, g_free);
-
-       return devices;
-}
-
-static GSList *dev_list(void)
-{
-       return ((struct drv_context *)(di->priv))->instances;
-}
-
-static int dev_open(struct sr_dev_inst *sdi)
-{
-       struct drv_context *drvc;
-       struct sr_usb_dev_inst *usb;
-       int ret;
-
-       if (!(drvc = di->priv)) {
-               sr_err("Driver was not initialized.");
-               return SR_ERR;
-       }
-
-       usb = sdi->conn;
-
-       if (sr_usb_open(drvc->sr_ctx->libusb_ctx, usb) != SR_OK)
-               return SR_ERR;
-
-/*
- * The libusbx 1.0.9 darwin backend is broken: it can report a kernel
- * driver being active, but detaching it always returns an error.
- */
-#if !defined(__APPLE__)
-       if (libusb_kernel_driver_active(usb->devhdl, USB_INTERFACE) == 1) {
-               if ((ret = libusb_detach_kernel_driver(usb->devhdl, USB_INTERFACE)) < 0) {
-                       sr_err("failed to detach kernel driver: %s",
-                                       libusb_error_name(ret));
-                       return SR_ERR;
-               }
-       }
-#endif
-
-       if ((ret = libusb_set_configuration(usb->devhdl, USB_CONFIGURATION))) {
-               sr_err("Failed to set configuration: %s.", libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-       if ((ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE))) {
-               sr_err("Failed to claim interface: %s.", libusb_error_name(ret));
-               return SR_ERR;
-       }
-       sdi->status = SR_ST_ACTIVE;
-
-       return ret;
-}
-
-static int dev_close(struct sr_dev_inst *sdi)
-{
-       struct sr_usb_dev_inst *usb;
-
-       if (!di->priv) {
-               sr_err("Driver was not initialized.");
-               return SR_ERR;
-       }
-
-       usb = sdi->conn;
-       if (!usb->devhdl)
-               /*  Nothing to do. */
-               return SR_OK;
-
-       libusb_release_interface(usb->devhdl, USB_INTERFACE);
-       libusb_close(usb->devhdl);
-       usb->devhdl = NULL;
-       sdi->status = SR_ST_INACTIVE;
-
-       return SR_OK;
-}
-
-static int cleanup(void)
-{
-       int ret;
-       struct drv_context *drvc;
-
-       if (!(drvc = di->priv))
-               /* Can get called on an unused driver, doesn't matter. */
-               return SR_OK;
-
-
-       ret = std_dev_clear(di, NULL);
-       g_free(drvc);
-       di->priv = NULL;
-
-       return ret;
-}
-
-static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-
-       (void)cg;
-
-       devc = sdi->priv;
-       switch (key) {
-       case SR_CONF_LIMIT_SAMPLES:
-               *data = g_variant_new_uint64(devc->limit_samples);
-               break;
-       case SR_CONF_DATA_SOURCE:
-               if (devc->data_source == DATA_SOURCE_LIVE)
-                       *data = g_variant_new_string("Live");
-               else
-                       *data = g_variant_new_string("Memory");
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       int ret;
-       const char *tmp_str;
-
-       (void)cg;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       if (!di->priv) {
-               sr_err("Driver was not initialized.");
-               return SR_ERR;
-       }
-
-       devc = sdi->priv;
-       ret = SR_OK;
-       switch (key) {
-       case SR_CONF_LIMIT_SAMPLES:
-               devc->limit_samples = g_variant_get_uint64(data);
-               sr_dbg("Setting sample limit to %" PRIu64 ".",
-                      devc->limit_samples);
-               break;
-       case SR_CONF_DATA_SOURCE:
-               tmp_str = g_variant_get_string(data, NULL);
-               if (!strcmp(tmp_str, "Live"))
-                       devc->data_source = DATA_SOURCE_LIVE;
-               else if (!strcmp(tmp_str, "Memory"))
-                       devc->data_source = DATA_SOURCE_MEMORY;
-               else
-                       return SR_ERR;
-               break;
-       default:
-               ret = SR_ERR_NA;
-       }
-
-       return ret;
-}
-
-static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-
-       (void)sdi;
-       (void)cg;
-
-       switch (key) {
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
-               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;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi,
-                                   void *cb_data)
-{
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       struct sr_usb_dev_inst *usb;
-       int len, ret;
-       unsigned char cmd[2];
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       drvc = di->priv;
-       devc = sdi->priv;
-       usb = sdi->conn;
-
-       devc->cb_data = cb_data;
-       devc->num_samples = 0;
-       devc->packet_len = 0;
-
-       /* Configure serial port parameters on USB-UART interface
-        * chip inside the device (just baudrate 2400 actually). */
-       cmd[0] = 0x09;
-       cmd[1] = 0x60;
-       ret = libusb_control_transfer(usb->devhdl, 0x21, 0x09, 0x0300, 0x00,
-                       cmd, 2, 5);
-       if (ret != 2) {
-               sr_dbg("Failed to configure CH9325: %s", libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(cb_data, LOG_PREFIX);
-
-       if (!(devc->xfer = libusb_alloc_transfer(0)))
-               return SR_ERR;
-
-       /* Length of payload to follow. */
-       cmd[0] = 0x01;
-       if (devc->data_source == DATA_SOURCE_LIVE)
-               cmd[1] = CMD_GET_LIVE;
-       else
-               cmd[1] = CMD_GET_STORED;
-
-       ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, cmd, 2, &len, 5);
-       if (ret != 0 || len != 2) {
-               sr_dbg("Failed to start acquisition: %s", libusb_error_name(ret));
-               libusb_free_transfer(devc->xfer);
-               return SR_ERR;
-       }
-
-       libusb_fill_bulk_transfer(devc->xfer, usb->devhdl, EP_IN, devc->buf,
-                       8, uni_t_ut32x_receive_transfer, (void *)sdi, 15);
-       if (libusb_submit_transfer(devc->xfer) != 0) {
-               libusb_free_transfer(devc->xfer);
-               return SR_ERR;
-       }
-
-       usb_source_add(sdi->session, drvc->sr_ctx, 10,
-                       uni_t_ut32x_handle_events, (void *)sdi);
-
-       return SR_OK;
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-
-       (void)cb_data;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       /* Signal USB transfer handler to clean up and stop. */
-       sdi->status = SR_ST_STOPPING;
-
-       return SR_OK;
-}
-
-SR_PRIV struct sr_dev_driver uni_t_ut32x_driver_info = {
-       .name = "uni-t-ut32x",
-       .longname = "UNI-T UT32x",
-       .api_version = 1,
-       .init = init,
-       .cleanup = cleanup,
-       .scan = scan,
-       .dev_list = 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,
-       .priv = NULL,
-};
diff --git a/hardware/uni-t-ut32x/protocol.c b/hardware/uni-t-ut32x/protocol.c
deleted file mode 100644 (file)
index 65cb756..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Bert Vermeulen <bert@biot.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 "protocol.h"
-
-#include <string.h>
-#include <math.h>
-
-extern struct sr_dev_driver uni_t_ut32x_driver_info;
-static struct sr_dev_driver *di = &uni_t_ut32x_driver_info;
-
-static float parse_temperature(unsigned char *buf)
-{
-       float temp;
-       int i;
-       gboolean negative;
-
-       negative = FALSE;
-       temp = 0.0;
-       for (i = 0; i < 4; i++) {
-               if (buf[i] == 0x3a)
-                       continue;
-               if (buf[i] == 0x3b) {
-                       if (negative) {
-                               sr_dbg("Double negative sign!");
-                               return NAN;
-                       } else {
-                               negative = TRUE;
-                               continue;
-                       }
-               }
-               if (buf[i] < 0x30 || buf[i] > 0x39) {
-                       sr_dbg("Invalid digit '%.2x'!", buf[i]);
-                       return NAN;
-               }
-               temp *= 10;
-               temp += (buf[i] - 0x30);
-       }
-       temp /= 10;
-       if (negative)
-               temp = -temp;
-
-       return temp;
-}
-
-static void process_packet(struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_analog analog;
-       GString *spew;
-       float temp;
-       int i;
-       gboolean is_valid;
-
-       devc = sdi->priv;
-       sr_dbg("Received full 19-byte packet.");
-       if (sr_log_loglevel_get() >= SR_LOG_SPEW) {
-               spew = g_string_sized_new(60);
-               for (i = 0; i < devc->packet_len; i++)
-                       g_string_append_printf(spew, "%.2x ", devc->packet[i]);
-               sr_spew("%s", spew->str);
-               g_string_free(spew, TRUE);
-       }
-
-       is_valid = TRUE;
-       if (devc->packet[1] == 0x3b && devc->packet[2] == 0x3b
-                       && devc->packet[3] == 0x3b && devc->packet[4] == 0x3b)
-               /* No measurement: missing channel, empty storage location, ... */
-               is_valid = FALSE;
-
-       temp = parse_temperature(devc->packet + 1);
-       if (isnan(temp))
-               is_valid = FALSE;
-
-       if (is_valid) {
-               memset(&analog, 0, sizeof(struct sr_datafeed_analog));
-               analog.mq = SR_MQ_TEMPERATURE;
-               analog.mqflags = 0;
-               switch (devc->packet[5] - 0x30) {
-               case 1:
-                       analog.unit = SR_UNIT_CELSIUS;
-                       break;
-               case 2:
-                       analog.unit = SR_UNIT_FAHRENHEIT;
-                       break;
-               case 3:
-                       analog.unit = SR_UNIT_KELVIN;
-                       break;
-               default:
-                       /* We can still pass on the measurement, whatever it is. */
-                       sr_dbg("Unknown unit 0x%.2x.", devc->packet[5]);
-               }
-               switch (devc->packet[13] - 0x30) {
-               case 0:
-                       /* Channel T1. */
-                       analog.channels = g_slist_append(NULL, g_slist_nth_data(sdi->channels, 0));
-                       break;
-               case 1:
-                       /* Channel T2. */
-                       analog.channels = g_slist_append(NULL, g_slist_nth_data(sdi->channels, 1));
-                       break;
-               case 2:
-               case 3:
-                       /* Channel T1-T2. */
-                       analog.channels = g_slist_append(NULL, g_slist_nth_data(sdi->channels, 2));
-                       analog.mqflags |= SR_MQFLAG_RELATIVE;
-                       break;
-               default:
-                       sr_err("Unknown channel 0x%.2x.", devc->packet[13]);
-                       is_valid = FALSE;
-               }
-               if (is_valid) {
-                       analog.num_samples = 1;
-                       analog.data = &temp;
-                       packet.type = SR_DF_ANALOG;
-                       packet.payload = &analog;
-                       sr_session_send(devc->cb_data, &packet);
-                       g_slist_free(analog.channels);
-               }
-       }
-
-       /* We count packets even if the temperature was invalid. This way
-        * a sample limit on "Memory" data source still works: unused
-        * memory slots come through as "----" measurements. */
-       devc->num_samples++;
-       if (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
-               sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi,
-                               devc->cb_data);
-       }
-
-}
-
-SR_PRIV void uni_t_ut32x_receive_transfer(struct libusb_transfer *transfer)
-{
-       struct dev_context *devc;
-       struct sr_dev_inst *sdi;
-       int hid_payload_len, ret;
-
-       sdi = transfer->user_data;
-       devc = sdi->priv;
-       if (transfer->actual_length == 8) {
-               /* CH9325 encodes length in low nibble of first byte, with
-                * bytes 1-7 being the (padded) payload. */
-               hid_payload_len = transfer->buffer[0] & 0x0f;
-               memcpy(devc->packet + devc->packet_len, transfer->buffer + 1,
-                               hid_payload_len);
-               devc->packet_len += hid_payload_len;
-               if (devc->packet_len >= 2
-                               && devc->packet[devc->packet_len - 2] == 0x0d
-                               && devc->packet[devc->packet_len - 1] == 0x0a) {
-                       /* Got end of packet, but do we have a complete packet? */
-                       if (devc->packet_len == 19)
-                               process_packet(sdi);
-                       /* Either way, done with it. */
-                       devc->packet_len = 0;
-               } else if (devc->packet_len > 19) {
-                       /* Guard against garbage from the device overrunning
-                        * our packet buffer. */
-                       sr_dbg("Buffer overrun!");
-                       devc->packet_len = 0;
-               }
-       }
-
-       /* Get the next transfer (unless we're shutting down). */
-       if (sdi->status != SR_ST_STOPPING) {
-               if ((ret = libusb_submit_transfer(devc->xfer)) != 0) {
-                       sr_dbg("Failed to resubmit transfer: %s", libusb_error_name(ret));
-                       sdi->status = SR_ST_STOPPING;
-                       libusb_free_transfer(devc->xfer);
-               }
-       } else
-               libusb_free_transfer(devc->xfer);
-
-}
-
-SR_PRIV int uni_t_ut32x_handle_events(int fd, int revents, void *cb_data)
-{
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       struct sr_dev_inst *sdi;
-       struct sr_datafeed_packet packet;
-       struct sr_usb_dev_inst *usb;
-       struct timeval tv;
-       int len, ret;
-       unsigned char cmd[2];
-
-       (void)fd;
-       (void)revents;
-
-       drvc = di->priv;
-
-       if (!(sdi = cb_data))
-               return TRUE;
-
-       if (!(devc = sdi->priv))
-               return TRUE;
-
-       memset(&tv, 0, sizeof(struct timeval));
-       libusb_handle_events_timeout_completed(drvc->sr_ctx->libusb_ctx, &tv,
-                       NULL);
-
-       if (sdi->status == SR_ST_STOPPING) {
-               usb_source_remove(sdi->session, drvc->sr_ctx);
-               packet.type = SR_DF_END;
-               sr_session_send(cb_data, &packet);
-
-               /* Tell the device to stop sending USB packets. */
-               usb = sdi->conn;
-               cmd[0] = 0x01;
-               cmd[1] = CMD_STOP;
-               ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, cmd, 2, &len, 5);
-               if (ret != 0 || len != 2) {
-                       /* Warning only, doesn't matter. */
-                       sr_dbg("Failed to send stop command: %s", libusb_error_name(ret));
-               }
-
-               sdi->status = SR_ST_ACTIVE;
-               return TRUE;
-       }
-
-       return TRUE;
-}
-
diff --git a/hardware/uni-t-ut32x/protocol.h b/hardware/uni-t-ut32x/protocol.h
deleted file mode 100644 (file)
index 8513117..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Bert Vermeulen <bert@biot.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_UNI_T_UT32X_PROTOCOL_H
-#define LIBSIGROK_HARDWARE_UNI_T_UT32X_PROTOCOL_H
-
-#include <stdint.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "uni-t-ut32x"
-
-#define DEFAULT_DATA_SOURCE DATA_SOURCE_LIVE
-#define USB_CONN "1a86.e008"
-#define VENDOR "UNI-T"
-#define MODEL "UT32x"
-#define USB_INTERFACE 0
-#define USB_CONFIGURATION 1
-
-#define EP_IN 0x80 | 2
-#define EP_OUT 2
-
-enum {
-    DATA_SOURCE_LIVE,
-       DATA_SOURCE_MEMORY,
-};
-
-enum {
-       CMD_GET_LIVE = 1,
-       CMD_STOP = 2,
-       CMD_GET_STORED = 7,
-};
-
-/** Private, per-device-instance driver context. */
-struct dev_context {
-       /* Acquisition settings */
-       uint64_t limit_samples;
-       gboolean data_source;
-
-       /* Operational state */
-       uint64_t num_samples;
-       unsigned char buf[8];
-       struct libusb_transfer *xfer;
-       void *cb_data;
-
-       /* Temporary state across callbacks */
-       unsigned char packet[32];
-       int packet_len;
-};
-
-SR_PRIV int uni_t_ut32x_handle_events(int fd, int revents, void *cb_data);
-SR_PRIV void uni_t_ut32x_receive_transfer(struct libusb_transfer *transfer);
-
-#endif
diff --git a/hardware/victor-dmm/api.c b/hardware/victor-dmm/api.c
deleted file mode 100644 (file)
index 56c53e5..0000000
+++ /dev/null
@@ -1,448 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012 Bert Vermeulen <bert@biot.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 <glib.h>
-#include <libusb.h>
-#include <stdlib.h>
-#include <string.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-#include "protocol.h"
-
-#define VICTOR_VID 0x1244
-#define VICTOR_PID 0xd237
-#define VICTOR_VENDOR "Victor"
-#define VICTOR_INTERFACE 0
-#define VICTOR_ENDPOINT LIBUSB_ENDPOINT_IN | 1
-
-SR_PRIV struct sr_dev_driver victor_dmm_driver_info;
-static struct sr_dev_driver *di = &victor_dmm_driver_info;
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data);
-
-static const int32_t hwopts[] = {
-       SR_CONF_CONN,
-};
-
-static const int32_t hwcaps[] = {
-       SR_CONF_MULTIMETER,
-       SR_CONF_LIMIT_MSEC,
-       SR_CONF_LIMIT_SAMPLES,
-       SR_CONF_CONTINUOUS,
-};
-
-static int init(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, di, LOG_PREFIX);
-}
-
-static GSList *scan(GSList *options)
-{
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       struct sr_dev_inst *sdi;
-       struct sr_channel *ch;
-       struct libusb_device_descriptor des;
-       libusb_device **devlist;
-       GSList *devices;
-       int ret, devcnt, i;
-
-       (void)options;
-
-       drvc = di->priv;
-
-       devices = NULL;
-       libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
-       for (i = 0; devlist[i]; i++) {
-               if ((ret = libusb_get_device_descriptor(devlist[i], &des)) != 0) {
-                       sr_warn("Failed to get device descriptor: %s",
-                                       libusb_error_name(ret));
-                       continue;
-               }
-
-               if (des.idVendor != VICTOR_VID || des.idProduct != VICTOR_PID)
-                       continue;
-
-               devcnt = g_slist_length(drvc->instances);
-               if (!(sdi = sr_dev_inst_new(devcnt, SR_ST_INACTIVE,
-                               VICTOR_VENDOR, NULL, NULL)))
-                       return NULL;
-               sdi->driver = di;
-
-               if (!(devc = g_try_malloc0(sizeof(struct dev_context))))
-                       return NULL;
-               sdi->priv = devc;
-
-               if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1")))
-                       return NULL;
-               sdi->channels = g_slist_append(NULL, ch);
-
-               if (!(sdi->conn = sr_usb_dev_inst_new(libusb_get_bus_number(devlist[i]),
-                               libusb_get_device_address(devlist[i]), NULL)))
-                       return NULL;
-               sdi->inst_type = SR_INST_USB;
-
-               drvc->instances = g_slist_append(drvc->instances, sdi);
-               devices = g_slist_append(devices, sdi);
-       }
-       libusb_free_device_list(devlist, 1);
-
-       return devices;
-}
-
-static GSList *dev_list(void)
-{
-       return ((struct drv_context *)(di->priv))->instances;
-}
-
-static int dev_open(struct sr_dev_inst *sdi)
-{
-       struct drv_context *drvc = di->priv;
-       struct sr_usb_dev_inst *usb;
-       libusb_device **devlist;
-       int ret, i;
-
-       if (!di->priv) {
-               sr_err("Driver was not initialized.");
-               return SR_ERR;
-       }
-
-       usb = sdi->conn;
-
-       libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
-       for (i = 0; devlist[i]; i++) {
-               if (libusb_get_bus_number(devlist[i]) != usb->bus
-                               || libusb_get_device_address(devlist[i]) != usb->address)
-                       continue;
-               if ((ret = libusb_open(devlist[i], &usb->devhdl))) {
-                       sr_err("Failed to open device: %s.", libusb_error_name(ret));
-                       return SR_ERR;
-               }
-               break;
-       }
-       libusb_free_device_list(devlist, 1);
-       if (!devlist[i]) {
-               sr_err("Device not found.");
-               return SR_ERR;
-       }
-
-       /* The device reports as HID class, so the kernel would have
-        * claimed it. */
-       if (libusb_kernel_driver_active(usb->devhdl, 0) == 1) {
-               if ((ret = libusb_detach_kernel_driver(usb->devhdl, 0)) < 0) {
-                       sr_err("Failed to detach kernel driver: %s.",
-                              libusb_error_name(ret));
-                       return SR_ERR;
-               }
-       }
-
-       if ((ret = libusb_claim_interface(usb->devhdl,
-                       VICTOR_INTERFACE))) {
-               sr_err("Failed to claim interface: %s.", libusb_error_name(ret));
-               return SR_ERR;
-       }
-       sdi->status = SR_ST_ACTIVE;
-
-       return SR_OK;
-}
-
-static int dev_close(struct sr_dev_inst *sdi)
-{
-       struct sr_usb_dev_inst *usb;
-
-       if (!di->priv) {
-               sr_err("Driver was not initialized.");
-               return SR_ERR;
-       }
-
-       usb = sdi->conn;
-
-       if (!usb->devhdl)
-               /*  Nothing to do. */
-               return SR_OK;
-
-       libusb_release_interface(usb->devhdl, VICTOR_INTERFACE);
-       libusb_close(usb->devhdl);
-       usb->devhdl = NULL;
-       sdi->status = SR_ST_INACTIVE;
-
-       return SR_OK;
-}
-
-static int cleanup(void)
-{
-       int ret;
-       struct drv_context *drvc;
-
-       if (!(drvc = di->priv))
-               /* Can get called on an unused driver, doesn't matter. */
-               return SR_OK;
-
-
-       ret = std_dev_clear(di, NULL);
-       g_free(drvc);
-       di->priv = NULL;
-
-       return ret;
-}
-
-static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct sr_usb_dev_inst *usb;
-       char str[128];
-
-       (void)cg;
-
-       switch (id) {
-       case SR_CONF_CONN:
-               if (!sdi || !sdi->conn)
-                       return SR_ERR_ARG;
-               usb = sdi->conn;
-               snprintf(str, 128, "%d.%d", usb->bus, usb->address);
-               *data = g_variant_new_string(str);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       gint64 now;
-       int ret;
-
-       (void)cg;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       if (!di->priv) {
-               sr_err("Driver was not initialized.");
-               return SR_ERR;
-       }
-
-       devc = sdi->priv;
-       ret = SR_OK;
-       switch (id) {
-       case SR_CONF_LIMIT_MSEC:
-               devc->limit_msec = g_variant_get_uint64(data);
-               now = g_get_monotonic_time() / 1000;
-               devc->end_time = now + devc->limit_msec;
-               sr_dbg("Setting time limit to %" PRIu64 "ms.",
-                      devc->limit_msec);
-               break;
-       case SR_CONF_LIMIT_SAMPLES:
-               devc->limit_samples = g_variant_get_uint64(data);
-               sr_dbg("Setting sample limit to %" PRIu64 ".",
-                      devc->limit_samples);
-               break;
-       default:
-               ret = SR_ERR_NA;
-       }
-
-       return ret;
-}
-
-static int config_list(int 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_INT32,
-                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
-               break;
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static void receive_transfer(struct libusb_transfer *transfer)
-{
-       struct dev_context *devc;
-       struct sr_dev_inst *sdi;
-       int ret;
-
-       sdi = transfer->user_data;
-       devc = sdi->priv;
-       if (transfer->status == LIBUSB_TRANSFER_NO_DEVICE) {
-               /* USB device was unplugged. */
-               dev_acquisition_stop(sdi, sdi);
-       } else if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
-               sr_dbg("Got %d-byte packet.", transfer->actual_length);
-               if (transfer->actual_length == DMM_DATA_SIZE) {
-                       victor_dmm_receive_data(sdi, transfer->buffer);
-                       if (devc->limit_samples) {
-                               if (devc->num_samples >= devc->limit_samples)
-                                       dev_acquisition_stop(sdi, sdi);
-                       }
-               }
-       }
-       /* Anything else is either an error or a timeout, which is fine:
-        * we were just going to send another transfer request anyway. */
-
-       if (sdi->status == SR_ST_ACTIVE) {
-               /* Send the same request again. */
-               if ((ret = libusb_submit_transfer(transfer) != 0)) {
-                       sr_err("Unable to resubmit transfer: %s.",
-                              libusb_error_name(ret));
-                       g_free(transfer->buffer);
-                       libusb_free_transfer(transfer);
-                       dev_acquisition_stop(sdi, sdi);
-               }
-       } else {
-               /* This was the last transfer we're going to receive, so
-                * clean up now. */
-               g_free(transfer->buffer);
-               libusb_free_transfer(transfer);
-       }
-}
-
-static int handle_events(int fd, int revents, void *cb_data)
-{
-       struct dev_context *devc;
-       struct drv_context *drvc = di->priv;
-       struct sr_datafeed_packet packet;
-       struct sr_dev_inst *sdi;
-       struct timeval tv;
-       gint64 now;
-
-       (void)fd;
-       (void)revents;
-
-       sdi = cb_data;
-       devc = sdi->priv;
-
-       if (devc->limit_msec) {
-               now = g_get_monotonic_time() / 1000;
-               if (now > devc->end_time)
-                       dev_acquisition_stop(sdi, sdi);
-       }
-
-       if (sdi->status == SR_ST_STOPPING) {
-               usb_source_remove(sdi->session, drvc->sr_ctx);
-
-               dev_close(sdi);
-
-               packet.type = SR_DF_END;
-               sr_session_send(cb_data, &packet);
-       }
-
-       memset(&tv, 0, sizeof(struct timeval));
-       libusb_handle_events_timeout_completed(drvc->sr_ctx->libusb_ctx, &tv,
-                                              NULL);
-
-       return TRUE;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct dev_context *devc;
-       struct drv_context *drvc = di->priv;
-       struct sr_usb_dev_inst *usb;
-       struct libusb_transfer *transfer;
-       int ret;
-       unsigned char *buf;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       if (!di->priv) {
-               sr_err("Driver was not initialized.");
-               return SR_ERR;
-       }
-
-       devc = sdi->priv;
-       usb = sdi->conn;
-       devc->cb_data = cb_data;
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(cb_data, LOG_PREFIX);
-
-       usb_source_add(sdi->session, drvc->sr_ctx, 100,
-                       handle_events, (void *)sdi);
-
-       buf = g_try_malloc(DMM_DATA_SIZE);
-       transfer = libusb_alloc_transfer(0);
-       /* Each transfer request gets 100ms to arrive before it's restarted.
-        * The device only sends 1 transfer/second no matter how many
-        * times you ask, but we want to keep step with the USB events
-        * handling above. */
-       libusb_fill_interrupt_transfer(transfer, usb->devhdl,
-                       VICTOR_ENDPOINT, buf, DMM_DATA_SIZE, receive_transfer,
-                       cb_data, 100);
-       if ((ret = libusb_submit_transfer(transfer) != 0)) {
-               sr_err("Unable to submit transfer: %s.", libusb_error_name(ret));
-               libusb_free_transfer(transfer);
-               g_free(buf);
-               return SR_ERR;
-       }
-
-       return SR_OK;
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       (void)cb_data;
-
-       if (!di->priv) {
-               sr_err("Driver was not initialized.");
-               return SR_ERR;
-       }
-
-       if (sdi->status != SR_ST_ACTIVE) {
-               sr_err("Device not active, can't stop acquisition.");
-               return SR_ERR;
-       }
-
-       sdi->status = SR_ST_STOPPING;
-
-       return SR_OK;
-}
-
-SR_PRIV struct sr_dev_driver victor_dmm_driver_info = {
-       .name = "victor-dmm",
-       .longname = "Victor DMMs",
-       .api_version = 1,
-       .init = init,
-       .cleanup = cleanup,
-       .scan = scan,
-       .dev_list = 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,
-       .priv = NULL,
-};
diff --git a/hardware/victor-dmm/protocol.c b/hardware/victor-dmm/protocol.c
deleted file mode 100644 (file)
index 6af5141..0000000
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012 Bert Vermeulen <bert@biot.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 <glib.h>
-#include <string.h>
-#include <math.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-#include "protocol.h"
-
-/* Reverse the high nibble into the low nibble */
-static uint8_t decode_digit(uint8_t in)
-{
-       uint8_t out, i;
-
-       out = 0;
-       in >>= 4;
-       for (i = 0x08; i; i >>= 1) {
-               out >>= 1;
-               if (in & i)
-                       out |= 0x08;
-       }
-
-       return out;
-}
-
-static void decode_buf(struct sr_dev_inst *sdi, unsigned char *data)
-{
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_analog analog;
-       struct dev_context *devc;
-       long factor, ivalue;
-       uint8_t digits[4];
-       gboolean is_duty, is_continuity, is_diode, is_ac, is_dc, is_auto;
-       gboolean is_hold, is_max, is_min, is_relative, minus;
-       float fvalue;
-
-       devc = sdi->priv;
-
-       digits[0] = decode_digit(data[12]);
-       digits[1] = decode_digit(data[11]);
-       digits[2] = decode_digit(data[10]);
-       digits[3] = decode_digit(data[9]);
-
-       if (digits[0] == 0x0f && digits[1] == 0x00 && digits[2] == 0x0a &&
-                       digits[3] == 0x0f)
-               /* The "over limit" (OL) display comes through like this */
-               ivalue = -1;
-       else if (digits[0] > 9 || digits[1] > 9 || digits[2] > 9 || digits[3] > 9)
-               /* An invalid digit in any position denotes no value. */
-               ivalue = -2;
-       else {
-               ivalue = digits[0] * 1000;
-               ivalue += digits[1] * 100;
-               ivalue += digits[2] * 10;
-               ivalue += digits[3];
-       }
-
-       /* Decimal point position */
-       factor = 0;
-       switch (data[7] >> 4) {
-       case 0x00:
-               factor = 0;
-               break;
-       case 0x02:
-               factor = 1;
-               break;
-       case 0x04:
-               factor = 2;
-               break;
-       case 0x08:
-               factor = 3;
-               break;
-       default:
-               sr_err("Unknown decimal point byte: 0x%.2x.", data[7]);
-               break;
-       }
-
-       /* Minus flag */
-       minus = data[2] & 0x01;
-
-       /* Mode detail symbols on the right side of the digits */
-       is_duty = is_continuity = is_diode = FALSE;
-       switch (data[4]) {
-       case 0x00:
-               /* None. */
-               break;
-       case 0x01:
-               /* Micro */
-               factor += 6;
-               break;
-       case 0x02:
-               /* Milli */
-               factor += 3;
-               break;
-       case 0x04:
-               /* Kilo */
-               ivalue *= 1000;
-               break;
-       case 0x08:
-               /* Mega */
-               ivalue *= 1000000;
-               break;
-       case 0x10:
-               /* Continuity shows up as Ohm + this bit */
-               is_continuity = TRUE;
-               break;
-       case 0x20:
-               /* Diode tester is Volt + this bit */
-               is_diode = TRUE;
-               break;
-       case 0x40:
-               is_duty = TRUE;
-               break;
-       case 0x80:
-               /* Never seen */
-               sr_dbg("Unknown mode right detail: 0x%.2x.", data[4]);
-               break;
-       default:
-               sr_dbg("Unknown/invalid mode right detail: 0x%.2x.", data[4]);
-               break;
-       }
-
-       /* Scale flags on the right, continued */
-       is_max = is_min = FALSE;
-       if (data[5] & 0x04)
-               is_max = TRUE;
-       if (data[5] & 0x08)
-               is_min = TRUE;
-       if (data[5] & 0x40)
-               /* Nano */
-               factor += 9;
-
-       /* Mode detail symbols on the left side of the digits */
-       is_auto = is_dc = is_ac = is_hold = is_relative = FALSE;
-       if (data[6] & 0x04)
-               is_auto = TRUE;
-       if (data[6] & 0x08)
-               is_dc = TRUE;
-       if (data[6] & 0x10)
-               is_ac = TRUE;
-       if (data[6] & 0x20)
-               is_relative = TRUE;
-       if (data[6] & 0x40)
-               is_hold = TRUE;
-
-       fvalue = (float)ivalue / pow(10, factor);
-       if (minus)
-               fvalue = -fvalue;
-
-       memset(&analog, 0, sizeof(struct sr_datafeed_analog));
-
-       /* Measurement mode */
-       analog.mq = -1;
-       switch (data[3]) {
-       case 0x00:
-               if (is_duty) {
-                       analog.mq = SR_MQ_DUTY_CYCLE;
-                       analog.unit = SR_UNIT_PERCENTAGE;
-               } else
-                       sr_dbg("Unknown measurement mode: %.2x.", data[3]);
-               break;
-       case 0x01:
-               if (is_diode) {
-                       analog.mq = SR_MQ_VOLTAGE;
-                       analog.unit = SR_UNIT_VOLT;
-                       analog.mqflags |= SR_MQFLAG_DIODE;
-                       if (ivalue < 0)
-                               fvalue = NAN;
-               } else {
-                       if (ivalue < 0)
-                               break;
-                       analog.mq = SR_MQ_VOLTAGE;
-                       analog.unit = SR_UNIT_VOLT;
-                       if (is_ac)
-                               analog.mqflags |= SR_MQFLAG_AC;
-                       if (is_dc)
-                               analog.mqflags |= SR_MQFLAG_DC;
-               }
-               break;
-       case 0x02:
-               analog.mq = SR_MQ_CURRENT;
-               analog.unit = SR_UNIT_AMPERE;
-               if (is_ac)
-                       analog.mqflags |= SR_MQFLAG_AC;
-               if (is_dc)
-                       analog.mqflags |= SR_MQFLAG_DC;
-               break;
-       case 0x04:
-               if (is_continuity) {
-                       analog.mq = SR_MQ_CONTINUITY;
-                       analog.unit = SR_UNIT_BOOLEAN;
-                       fvalue = ivalue < 0 ? 0.0 : 1.0;
-               } else {
-                       analog.mq = SR_MQ_RESISTANCE;
-                       analog.unit = SR_UNIT_OHM;
-                       if (ivalue < 0)
-                               fvalue = INFINITY;
-               }
-               break;
-       case 0x08:
-               /* Never seen */
-               sr_dbg("Unknown measurement mode: 0x%.2x.", data[3]);
-               break;
-       case 0x10:
-               analog.mq = SR_MQ_FREQUENCY;
-               analog.unit = SR_UNIT_HERTZ;
-               break;
-       case 0x20:
-               analog.mq = SR_MQ_CAPACITANCE;
-               analog.unit = SR_UNIT_FARAD;
-               break;
-       case 0x40:
-               analog.mq = SR_MQ_TEMPERATURE;
-               analog.unit = SR_UNIT_CELSIUS;
-               break;
-       case 0x80:
-               analog.mq = SR_MQ_TEMPERATURE;
-               analog.unit = SR_UNIT_FAHRENHEIT;
-               break;
-       default:
-               sr_dbg("Unknown/invalid measurement mode: 0x%.2x.", data[3]);
-               break;
-       }
-       if (analog.mq == -1)
-               return;
-
-       if (is_auto)
-               analog.mqflags |= SR_MQFLAG_AUTORANGE;
-       if (is_hold)
-               analog.mqflags |= SR_MQFLAG_HOLD;
-       if (is_max)
-               analog.mqflags |= SR_MQFLAG_MAX;
-       if (is_min)
-               analog.mqflags |= SR_MQFLAG_MIN;
-       if (is_relative)
-               analog.mqflags |= SR_MQFLAG_RELATIVE;
-
-       analog.channels = sdi->channels;
-       analog.num_samples = 1;
-       analog.data = &fvalue;
-       packet.type = SR_DF_ANALOG;
-       packet.payload = &analog;
-       sr_session_send(devc->cb_data, &packet);
-
-       devc->num_samples++;
-}
-
-SR_PRIV int victor_dmm_receive_data(struct sr_dev_inst *sdi, unsigned char *buf)
-{
-       GString *dbg;
-       int i;
-       unsigned char data[DMM_DATA_SIZE];
-       unsigned char obfuscation[DMM_DATA_SIZE] = "jodenxunickxia";
-       unsigned char shuffle[DMM_DATA_SIZE] = {
-               6, 13, 5, 11, 2, 7, 9, 8, 3, 10, 12, 0, 4, 1
-       };
-
-       for (i = 0; i < DMM_DATA_SIZE && buf[i] == 0; i++);
-       if (i == DMM_DATA_SIZE) {
-               /* This DMM outputs all zeroes from time to time, just ignore it. */
-               sr_dbg("Received all zeroes.");
-               return SR_OK;
-       }
-
-       /* Deobfuscate and reorder data. */
-       for (i = 0; i < DMM_DATA_SIZE; i++)
-               data[shuffle[i]] = (buf[i] - obfuscation[i]) & 0xff;
-
-       if (sr_log_loglevel_get() >= SR_LOG_SPEW) {
-               dbg = g_string_sized_new(128);
-               g_string_printf(dbg, "Deobfuscated.");
-               for (i = 0; i < DMM_DATA_SIZE; i++)
-                       g_string_append_printf(dbg, " %.2x", data[i]);
-               sr_spew("%s", dbg->str);
-               g_string_free(dbg, TRUE);
-       }
-
-       decode_buf(sdi, data);
-
-       return SR_OK;
-}
diff --git a/hardware/victor-dmm/protocol.h b/hardware/victor-dmm/protocol.h
deleted file mode 100644 (file)
index 8f12680..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012 Bert Vermeulen <bert@biot.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_VICTOR_DMM_PROTOCOL_H
-#define LIBSIGROK_HARDWARE_VICTOR_DMM_PROTOCOL_H
-
-#include <stdint.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "victor-dmm"
-
-#define DMM_DATA_SIZE 14
-
-/** Private, per-device-instance driver context. */
-struct dev_context {
-       /** The current sampling limit (in number of samples). */
-       uint64_t limit_samples;
-
-       /** The current sampling limit (in ms). */
-       uint64_t limit_msec;
-
-       /** Opaque pointer passed in by the frontend. */
-       void *cb_data;
-
-       /** The current number of already received samples. */
-       uint64_t num_samples;
-       gint64 end_time;
-};
-
-SR_PRIV int victor_dmm_receive_data(struct sr_dev_inst *sdi, unsigned char *buf);
-
-#endif
diff --git a/hardware/zeroplus-logic-cube/analyzer.c b/hardware/zeroplus-logic-cube/analyzer.c
deleted file mode 100644 (file)
index c404a66..0000000
+++ /dev/null
@@ -1,677 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2010 Sven Peter <sven@fail0verflow.com>
- * Copyright (C) 2010 Haxx Enterprises <bushing@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice,
- *   this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright notice,
- *   this list of conditions and the following disclaimer in the documentation
- *   and/or other materials provided with the distribution.
- *
- *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- *  THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <assert.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-#include "analyzer.h"
-#include "gl_usb.h"
-#include "protocol.h"
-
-enum {
-       HARD_DATA_CHECK_SUM             = 0x00,
-       PASS_WORD,
-
-       DEV_ID0                         = 0x10,
-       DEV_ID1,
-
-       START_STATUS                    = 0x20,
-       DEV_STATUS                      = 0x21,
-       FREQUENCY_REG0                  = 0x30,
-       FREQUENCY_REG1,
-       FREQUENCY_REG2,
-       FREQUENCY_REG3,
-       FREQUENCY_REG4,
-       MEMORY_LENGTH,
-       CLOCK_SOURCE,
-
-       TRIGGER_STATUS0                 = 0x40,
-       TRIGGER_STATUS1,
-       TRIGGER_STATUS2,
-       TRIGGER_STATUS3,
-       TRIGGER_STATUS4,
-       TRIGGER_STATUS5,
-       TRIGGER_STATUS6,
-       TRIGGER_STATUS7,
-       TRIGGER_STATUS8,
-
-       TRIGGER_COUNT0                  = 0x50,
-       TRIGGER_COUNT1,
-
-       TRIGGER_LEVEL0                  = 0x55,
-       TRIGGER_LEVEL1,
-       TRIGGER_LEVEL2,
-       TRIGGER_LEVEL3,
-
-       RAMSIZE_TRIGGERBAR_ADDRESS0     = 0x60,
-       RAMSIZE_TRIGGERBAR_ADDRESS1,
-       RAMSIZE_TRIGGERBAR_ADDRESS2,
-       TRIGGERBAR_ADDRESS0,
-       TRIGGERBAR_ADDRESS1,
-       TRIGGERBAR_ADDRESS2,
-       DONT_CARE_TRIGGERBAR,
-
-       FILTER_ENABLE                   = 0x70,
-       FILTER_STATUS,
-
-       ENABLE_DELAY_TIME0              = 0x7a,
-       ENABLE_DELAY_TIME1,
-
-       ENABLE_INSERT_DATA0             = 0x80,
-       ENABLE_INSERT_DATA1,
-       ENABLE_INSERT_DATA2,
-       ENABLE_INSERT_DATA3,
-       COMPRESSION_TYPE0,
-       COMPRESSION_TYPE1,
-
-       TRIGGER_ADDRESS0                = 0x90,
-       TRIGGER_ADDRESS1,
-       TRIGGER_ADDRESS2,
-
-       NOW_ADDRESS0                    = 0x96,
-       NOW_ADDRESS1,
-       NOW_ADDRESS2,
-
-       STOP_ADDRESS0                   = 0x9b,
-       STOP_ADDRESS1,
-       STOP_ADDRESS2,
-
-       READ_RAM_STATUS                 = 0xa0,
-};
-
-static int g_trigger_status[9] = { 0 };
-static int g_trigger_count = 1;
-static int g_filter_status[8] = { 0 };
-static int g_filter_enable = 0;
-
-static int g_freq_value = 1;
-static int g_freq_scale = FREQ_SCALE_MHZ;
-static int g_memory_size = MEMORY_SIZE_8K;
-static int g_ramsize_triggerbar_addr = 2 * 1024;
-static int g_triggerbar_addr = 0;
-static int g_compression = COMPRESSION_NONE;
-static int g_thresh = 0x31; /* 1.5V */
-
-/* Maybe unk specifies an "endpoint" or "register" of sorts. */
-static int analyzer_write_status(libusb_device_handle *devh, unsigned char unk,
-                                unsigned char flags)
-{
-       assert(unk <= 3);
-       return gl_reg_write(devh, START_STATUS, unk << 6 | flags);
-}
-
-#if 0
-static int __analyzer_set_freq(libusb_device_handle *devh, int freq, int scale)
-{
-       int reg0 = 0, divisor = 0, reg2 = 0;
-
-       switch (scale) {
-       case FREQ_SCALE_MHZ: /* MHz */
-               if (freq >= 100 && freq <= 200) {
-                       reg0 = freq * 0.1;
-                       divisor = 1;
-                       reg2 = 0;
-                       break;
-               }
-               if (freq >= 50 && freq < 100) {
-                       reg0 = freq * 0.2;
-                       divisor = 2;
-                       reg2 = 0;
-                       break;
-               }
-               if (freq >= 10 && freq < 50) {
-                       if (freq == 25) {
-                               reg0 = 25;
-                               divisor = 5;
-                               reg2 = 1;
-                               break;
-                       } else {
-                               reg0 = freq * 0.5;
-                               divisor = 5;
-                               reg2 = 1;
-                               break;
-                       }
-               }
-               if (freq >= 2 && freq < 10) {
-                       divisor = 5;
-                       reg0 = freq * 2;
-                       reg2 = 2;
-                       break;
-               }
-               if (freq == 1) {
-                       divisor = 5;
-                       reg2 = 16;
-                       reg0 = 5;
-                       break;
-               }
-               divisor = 5;
-               reg0 = 5;
-               reg2 = 64;
-               break;
-       case FREQ_SCALE_HZ: /* Hz */
-               if (freq >= 500 && freq < 1000) {
-                       reg0 = freq * 0.01;
-                       divisor = 10;
-                       reg2 = 64;
-                       break;
-               }
-               if (freq >= 300 && freq < 500) {
-                       reg0 = freq * 0.005 * 8;
-                       divisor = 5;
-                       reg2 = 67;
-                       break;
-               }
-               if (freq >= 100 && freq < 300) {
-                       reg0 = freq * 0.005 * 16;
-                       divisor = 5;
-                       reg2 = 68;
-                       break;
-               }
-               divisor = 5;
-               reg0 = 5;
-               reg2 = 64;
-               break;
-       case FREQ_SCALE_KHZ: /* kHz */
-               if (freq >= 500 && freq < 1000) {
-                       reg0 = freq * 0.01;
-                       divisor = 5;
-                       reg2 = 17;
-                       break;
-               }
-               if (freq >= 100 && freq < 500) {
-                       reg0 = freq * 0.05;
-                       divisor = 5;
-                       reg2 = 32;
-                       break;
-               }
-               if (freq >= 50 && freq < 100) {
-                       reg0 = freq * 0.1;
-                       divisor = 5;
-                       reg2 = 33;
-                       break;
-               }
-               if (freq >= 10 && freq < 50) {
-                       if (freq == 25) {
-                               reg0 = 25;
-                               divisor = 5;
-                               reg2 = 49;
-                               break;
-                       }
-                       reg0 = freq * 0.5;
-                       divisor = 5;
-                       reg2 = 48;
-                       break;
-               }
-               if (freq >= 2 && freq < 10) {
-                       divisor = 5;
-                       reg0 = freq * 2;
-                       reg2 = 50;
-                       break;
-               }
-               divisor = 5;
-               reg0 = 5;
-               reg2 = 64;
-               break;
-       default:
-               divisor = 5;
-               reg0 = 5;
-               reg2 = 64;
-               break;
-       }
-
-       sr_dbg("Setting samplerate regs (freq=%d, scale=%d): "
-              "reg0: %d, reg1: %d, reg2: %d, reg3: %d.",
-              freq, scale, divisor, reg0, 0x02, reg2);
-
-       if (gl_reg_write(devh, FREQUENCY_REG0, divisor) < 0)
-               return -1; /* Divisor maybe? */
-
-       if (gl_reg_write(devh, FREQUENCY_REG1, reg0) < 0)
-               return -1; /* 10 / 0.2 */
-
-       if (gl_reg_write(devh, FREQUENCY_REG2, 0x02) < 0)
-               return -1; /* Always 2 */
-
-       if (gl_reg_write(devh, FREQUENCY_REG4, reg2) < 0)
-               return -1;
-
-       return 0;
-}
-#endif
-
-/*
- * It seems that ...
- *     FREQUENCT_REG0 - division factor (?)
- *     FREQUENCT_REG1 - multiplication factor (?)
- *     FREQUENCT_REG4 - clock selection (?)
- *
- *     clock selection
- *     0  10MHz  16   1MHz  32 100kHz  48  10kHz  64   1kHz
- *     1   5MHz  17 500kHz  33  50kHz  49   5kHz  65  500Hz
- *     2 2.5MHz   .          .         50 2.5kHz  66  250Hz
- *     .          .          .          .         67  125Hz
- *     .          .          .          .         68 62.5Hz
- */
-static int __analyzer_set_freq(libusb_device_handle *devh, int freq, int scale)
-{
-       struct freq_factor {
-               int freq;
-               int scale;
-               int sel;
-               int div;
-               int mul;
-       };
-
-       static const struct freq_factor f[] = {
-               { 200, FREQ_SCALE_MHZ,  0,  1, 20 },
-               { 150, FREQ_SCALE_MHZ,  0,  1, 15 },
-               { 100, FREQ_SCALE_MHZ,  0,  1, 10 },
-               {  80, FREQ_SCALE_MHZ,  0,  2, 16 },
-               {  50, FREQ_SCALE_MHZ,  0,  2, 10 },
-               {  25, FREQ_SCALE_MHZ,  1,  5, 25 },
-               {  10, FREQ_SCALE_MHZ,  1,  5, 10 },
-               {   1, FREQ_SCALE_MHZ, 16,  5,  5 },
-               { 800, FREQ_SCALE_KHZ, 17,  5,  8 },
-               { 400, FREQ_SCALE_KHZ, 32,  5, 20 },
-               { 200, FREQ_SCALE_KHZ, 32,  5, 10 },
-               { 100, FREQ_SCALE_KHZ, 32,  5,  5 },
-               {  50, FREQ_SCALE_KHZ, 33,  5,  5 },
-               {  25, FREQ_SCALE_KHZ, 49,  5, 25 },
-               {   5, FREQ_SCALE_KHZ, 50,  5, 10 },
-               {   1, FREQ_SCALE_KHZ, 64,  5,  5 },
-               { 500, FREQ_SCALE_HZ,  64, 10,  5 },
-               { 100, FREQ_SCALE_HZ,  68,  5,  8 },
-               {   0, 0,              0,   0,  0 }
-       };
-
-       int i;
-
-       for (i = 0; f[i].freq; i++) {
-               if (scale == f[i].scale && freq == f[i].freq)
-                       break;
-       }
-       if (!f[i].freq)
-               return -1;
-
-       sr_dbg("Setting samplerate regs (freq=%d, scale=%d): "
-              "reg0: %d, reg1: %d, reg2: %d, reg3: %d.",
-              freq, scale, f[i].div, f[i].mul, 0x02, f[i].sel);
-
-       if (gl_reg_write(devh, FREQUENCY_REG0, f[i].div) < 0)
-               return -1;
-
-       if (gl_reg_write(devh, FREQUENCY_REG1, f[i].mul) < 0)
-               return -1;
-
-       if (gl_reg_write(devh, FREQUENCY_REG2, 0x02) < 0)
-               return -1;
-
-       if (gl_reg_write(devh, FREQUENCY_REG4, f[i].sel) < 0)
-               return -1;
-
-       return 0;
-}
-
-static void __analyzer_set_ramsize_trigger_address(libusb_device_handle *devh,
-                                                  unsigned int address)
-{
-       gl_reg_write(devh, RAMSIZE_TRIGGERBAR_ADDRESS0, (address >> 0) & 0xFF);
-       gl_reg_write(devh, RAMSIZE_TRIGGERBAR_ADDRESS1, (address >> 8) & 0xFF);
-       gl_reg_write(devh, RAMSIZE_TRIGGERBAR_ADDRESS2, (address >> 16) & 0xFF);
-}
-
-static void __analyzer_set_triggerbar_address(libusb_device_handle *devh,
-                                             unsigned int address)
-{
-       gl_reg_write(devh, TRIGGERBAR_ADDRESS0, (address >> 0) & 0xFF);
-       gl_reg_write(devh, TRIGGERBAR_ADDRESS1, (address >> 8) & 0xFF);
-       gl_reg_write(devh, TRIGGERBAR_ADDRESS2, (address >> 16) & 0xFF);
-}
-
-static void __analyzer_set_compression(libusb_device_handle *devh,
-                                      unsigned int type)
-{
-       gl_reg_write(devh, COMPRESSION_TYPE0, (type >> 0) & 0xFF);
-       gl_reg_write(devh, COMPRESSION_TYPE1, (type >> 8) & 0xFF);
-}
-
-static void __analyzer_set_trigger_count(libusb_device_handle *devh,
-                                        unsigned int count)
-{
-       gl_reg_write(devh, TRIGGER_COUNT0, (count >> 0) & 0xFF);
-       gl_reg_write(devh, TRIGGER_COUNT1, (count >> 8) & 0xFF);
-}
-
-static void analyzer_write_enable_insert_data(libusb_device_handle *devh)
-{
-       gl_reg_write(devh, ENABLE_INSERT_DATA0, 0x12);
-       gl_reg_write(devh, ENABLE_INSERT_DATA1, 0x34);
-       gl_reg_write(devh, ENABLE_INSERT_DATA2, 0x56);
-       gl_reg_write(devh, ENABLE_INSERT_DATA3, 0x78);
-}
-
-static void analyzer_set_filter(libusb_device_handle *devh)
-{
-       int i;
-       gl_reg_write(devh, FILTER_ENABLE, g_filter_enable);
-       for (i = 0; i < 8; i++)
-               gl_reg_write(devh, FILTER_STATUS + i, g_filter_status[i]);
-}
-
-SR_PRIV void analyzer_reset(libusb_device_handle *devh)
-{
-       analyzer_write_status(devh, 3, STATUS_FLAG_NONE);       // reset device
-       analyzer_write_status(devh, 3, STATUS_FLAG_RESET);      // reset device
-}
-
-SR_PRIV void analyzer_initialize(libusb_device_handle *devh)
-{
-       analyzer_write_status(devh, 1, STATUS_FLAG_NONE);
-       analyzer_write_status(devh, 1, STATUS_FLAG_INIT);
-       analyzer_write_status(devh, 1, STATUS_FLAG_NONE);
-}
-
-SR_PRIV void analyzer_wait(libusb_device_handle *devh, int set, int unset)
-{
-       int status;
-
-       while (1) {
-               status = gl_reg_read(devh, DEV_STATUS);
-               if ((!set || (status & set)) && ((status & unset) == 0))
-                       return;
-       }
-}
-
-SR_PRIV void analyzer_read_start(libusb_device_handle *devh)
-{
-       analyzer_write_status(devh, 3, STATUS_FLAG_20 | STATUS_FLAG_READ);
-
-       /* Prep for bulk reads */
-       gl_reg_read_buf(devh, READ_RAM_STATUS, NULL, 0);
-}
-
-SR_PRIV int analyzer_read_data(libusb_device_handle *devh, void *buffer,
-                      unsigned int size)
-{
-       return gl_read_bulk(devh, buffer, size);
-}
-
-SR_PRIV void analyzer_read_stop(libusb_device_handle *devh)
-{
-       analyzer_write_status(devh, 3, STATUS_FLAG_20);
-       analyzer_write_status(devh, 3, STATUS_FLAG_NONE);
-}
-
-SR_PRIV void analyzer_start(libusb_device_handle *devh)
-{
-       analyzer_write_status(devh, 1, STATUS_FLAG_NONE);
-       analyzer_write_status(devh, 1, STATUS_FLAG_INIT);
-       analyzer_write_status(devh, 1, STATUS_FLAG_NONE);
-       analyzer_write_status(devh, 1, STATUS_FLAG_GO);
-}
-
-SR_PRIV void analyzer_configure(libusb_device_handle *devh)
-{
-       int i;
-
-       /* Write_Start_Status */
-       analyzer_write_status(devh, 1, STATUS_FLAG_RESET);
-       analyzer_write_status(devh, 1, STATUS_FLAG_NONE);
-
-       /* Start_Config_Outside_Device ? */
-       analyzer_write_status(devh, 1, STATUS_FLAG_INIT);
-       analyzer_write_status(devh, 1, STATUS_FLAG_NONE);
-
-       /* SetData_To_Frequence_Reg */
-       __analyzer_set_freq(devh, g_freq_value, g_freq_scale);
-
-       /* SetMemory_Length */
-       gl_reg_write(devh, MEMORY_LENGTH, g_memory_size);
-
-       /* Sele_Inside_Outside_Clock */
-       gl_reg_write(devh, CLOCK_SOURCE, 0x03);
-
-       /* Set_Trigger_Status */
-       for (i = 0; i < 9; i++)
-               gl_reg_write(devh, TRIGGER_STATUS0 + i, g_trigger_status[i]);
-
-       __analyzer_set_trigger_count(devh, g_trigger_count);
-
-       /* Set_Trigger_Level */
-       gl_reg_write(devh, TRIGGER_LEVEL0, g_thresh);
-       gl_reg_write(devh, TRIGGER_LEVEL1, g_thresh);
-       gl_reg_write(devh, TRIGGER_LEVEL2, g_thresh);
-       gl_reg_write(devh, TRIGGER_LEVEL3, g_thresh);
-
-       /* Size of actual memory >> 2 */
-       __analyzer_set_ramsize_trigger_address(devh, g_ramsize_triggerbar_addr);
-       __analyzer_set_triggerbar_address(devh, g_triggerbar_addr);
-
-       /* Set_Dont_Care_TriggerBar */
-       gl_reg_write(devh, DONT_CARE_TRIGGERBAR, 0x01);
-
-       /* Enable_Status */
-       analyzer_set_filter(devh);
-
-       /* Set_Enable_Delay_Time */
-       gl_reg_write(devh, 0x7a, 0x00);
-       gl_reg_write(devh, 0x7b, 0x00);
-       analyzer_write_enable_insert_data(devh);
-       __analyzer_set_compression(devh, g_compression);
-}
-
-SR_PRIV int analyzer_add_triggers(const struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct sr_trigger *trigger;
-       struct sr_trigger_stage *stage;
-       struct sr_trigger_match *match;
-       GSList *l, *m;
-       int channel;
-
-       devc = sdi->priv;
-
-       if (!(trigger = sr_session_trigger_get(sdi->session)))
-               return SR_OK;
-
-       for (l = trigger->stages; l; l = l->next) {
-               stage = l->data;
-               for (m = stage->matches; m; m = m->next) {
-                       match = m->data;
-                       devc->trigger = 1;
-                       if (!match->channel->enabled)
-                               /* Ignore disabled channels with a trigger. */
-                               continue;
-                       channel = match->channel->index;
-                       switch (match->match) {
-                       case SR_TRIGGER_ZERO:
-                               g_trigger_status[channel / 4] |= 2 << (channel % 4 * 2);
-                       case SR_TRIGGER_ONE:
-                               g_trigger_status[channel / 4] |= 1 << (channel % 4 * 2);
-                               break;
-                       default:
-                               sr_err("Unsupported match %d", match->match);
-                               return SR_ERR;
-                       }
-               }
-       }
-
-       return SR_OK;
-}
-
-SR_PRIV void analyzer_add_filter(int channel, int type)
-{
-       int i;
-
-       if (type != FILTER_HIGH && type != FILTER_LOW)
-               return;
-       if ((channel & 0xf) >= 8)
-               return;
-
-       if (channel & CHANNEL_A)
-               i = 0;
-       else if (channel & CHANNEL_B)
-               i = 2;
-       else if (channel & CHANNEL_C)
-               i = 4;
-       else if (channel & CHANNEL_D)
-               i = 6;
-       else
-               return;
-
-       if ((channel & 0xf) >= 4) {
-               i++;
-               channel -= 4;
-       }
-
-       g_filter_status[i] |=
-           1 << ((2 * channel) + (type == FILTER_LOW ? 1 : 0));
-
-       g_filter_enable = 1;
-}
-
-SR_PRIV void analyzer_set_trigger_count(int count)
-{
-       g_trigger_count = count;
-}
-
-SR_PRIV void analyzer_set_freq(int freq, int scale)
-{
-       g_freq_value = freq;
-       g_freq_scale = scale;
-}
-
-SR_PRIV void analyzer_set_memory_size(unsigned int size)
-{
-       g_memory_size = size;
-}
-
-SR_PRIV void analyzer_set_ramsize_trigger_address(unsigned int address)
-{
-       g_ramsize_triggerbar_addr = address;
-}
-
-SR_PRIV unsigned int analyzer_get_ramsize_trigger_address(void)
-{
-       return g_ramsize_triggerbar_addr;
-}
-
-SR_PRIV void analyzer_set_triggerbar_address(unsigned int address)
-{
-       g_triggerbar_addr = address;
-}
-
-SR_PRIV unsigned int analyzer_get_triggerbar_address(void)
-{
-       return g_triggerbar_addr;
-}
-
-SR_PRIV unsigned int analyzer_read_status(libusb_device_handle *devh)
-{
-       return gl_reg_read(devh, DEV_STATUS);
-}
-
-SR_PRIV unsigned int analyzer_read_id(libusb_device_handle *devh)
-{
-       return gl_reg_read(devh, DEV_ID1) << 8 | gl_reg_read(devh, DEV_ID0);
-}
-
-SR_PRIV unsigned int analyzer_get_stop_address(libusb_device_handle *devh)
-{
-       return gl_reg_read(devh, STOP_ADDRESS2) << 16 | gl_reg_read(devh,
-                       STOP_ADDRESS1) << 8 | gl_reg_read(devh, STOP_ADDRESS0);
-}
-
-SR_PRIV unsigned int analyzer_get_now_address(libusb_device_handle *devh)
-{
-       return gl_reg_read(devh, NOW_ADDRESS2) << 16 | gl_reg_read(devh,
-                       NOW_ADDRESS1) << 8 | gl_reg_read(devh, NOW_ADDRESS0);
-}
-
-SR_PRIV unsigned int analyzer_get_trigger_address(libusb_device_handle *devh)
-{
-       return gl_reg_read(devh, TRIGGER_ADDRESS2) << 16 | gl_reg_read(devh,
-               TRIGGER_ADDRESS1) << 8 | gl_reg_read(devh, TRIGGER_ADDRESS0);
-}
-
-SR_PRIV void analyzer_set_compression(unsigned int type)
-{
-       g_compression = type;
-}
-
-SR_PRIV void analyzer_set_voltage_threshold(int thresh)
-{
-       g_thresh = thresh;
-}
-
-SR_PRIV void analyzer_wait_button(libusb_device_handle *devh)
-{
-       analyzer_wait(devh, STATUS_BUTTON_PRESSED, 0);
-}
-
-SR_PRIV void analyzer_wait_data(libusb_device_handle *devh)
-{
-       analyzer_wait(devh, 0, STATUS_BUSY);
-}
-
-SR_PRIV int analyzer_decompress(void *input, unsigned int input_len,
-                               void *output, unsigned int output_len)
-{
-       unsigned char *in = input;
-       unsigned char *out = output;
-       unsigned int A, B, C, count;
-       unsigned int written = 0;
-
-       while (input_len > 0) {
-               A = *in++;
-               B = *in++;
-               C = *in++;
-               count = (*in++) + 1;
-
-               if (count > output_len)
-                       count = output_len;
-               output_len -= count;
-               written += count;
-
-               while (count--) {
-                       *out++ = A;
-                       *out++ = B;
-                       *out++ = C;
-                       *out++ = 0; /* Channel D */
-               }
-
-               input_len -= 4;
-               if (output_len == 0)
-                       break;
-       }
-
-       return written;
-}
diff --git a/hardware/zeroplus-logic-cube/analyzer.h b/hardware/zeroplus-logic-cube/analyzer.h
deleted file mode 100644 (file)
index 9f87259..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2010 Sven Peter <sven@fail0verflow.com>
- * Copyright (C) 2010 Haxx Enterprises <bushing@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice,
- *   this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright notice,
- *   this list of conditions and the following disclaimer in the documentation
- *   and/or other materials provided with the distribution.
- *
- *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- *  THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef LIBSIGROK_HARDWARE_ZEROPLUS_LOGIC_CUBE_ANALYZER_H
-#define LIBSIGROK_HARDWARE_ZEROPLUS_LOGIC_CUBE_ANALYZER_H
-
-#include <libusb.h>
-#include "libsigrok.h"
-
-#define STATUS_FLAG_NONE       0x00
-#define STATUS_FLAG_RESET      0x01
-#define STATUS_FLAG_INIT       0x02
-#define STATUS_FLAG_GO         0x04
-#define STATUS_FLAG_PAUSE      0x08
-#define STATUS_FLAG_READ       0x10
-#define STATUS_FLAG_20         0x20
-
-/* In bytes */
-#define MEMORY_SIZE_8K         0x00
-#define MEMORY_SIZE_64K                0x01
-#define MEMORY_SIZE_128K       0x02
-#define MEMORY_SIZE_256K       0x03
-#define MEMORY_SIZE_512K       0x04
-#define MEMORY_SIZE_1M         0x05
-#define MEMORY_SIZE_2M         0x06
-#define MEMORY_SIZE_4M         0x07
-#define MEMORY_SIZE_8M         0x08
-
-#define STATUS_BUSY            0x01    /* WTF / ??? */
-#define STATUS_READY           0x02
-#define STATUS_BUTTON_PRESSED  0x04
-
-#define CHANNEL_A              0x1000
-#define CHANNEL_B              0x2000
-#define CHANNEL_C              0x3000
-#define CHANNEL_D              0x4000
-
-#define FREQ_SCALE_HZ          0
-#define FREQ_SCALE_KHZ         1
-#define FREQ_SCALE_MHZ         2
-
-#define FILTER_HIGH            0
-#define FILTER_LOW             1
-
-#define COMPRESSION_NONE       0x0001
-#define COMPRESSION_ENABLE     0x8001
-#define COMPRESSION_DOUBLE     0x8002
-
-SR_PRIV void analyzer_set_freq(int freq, int scale);
-SR_PRIV void analyzer_set_ramsize_trigger_address(unsigned int address);
-SR_PRIV void analyzer_set_triggerbar_address(unsigned int address);
-SR_PRIV unsigned int  analyzer_get_ramsize_trigger_address(void );
-SR_PRIV unsigned int analyzer_get_triggerbar_address(void);
-SR_PRIV void analyzer_set_compression(unsigned int type);
-SR_PRIV void analyzer_set_memory_size(unsigned int size);
-SR_PRIV int analyzer_add_triggers(const struct sr_dev_inst *sdi);
-SR_PRIV void analyzer_set_trigger_count(int count);
-SR_PRIV void analyzer_add_filter(int channel, int type);
-SR_PRIV void analyzer_set_voltage_threshold(int thresh);
-
-SR_PRIV unsigned int analyzer_read_status(libusb_device_handle *devh);
-SR_PRIV unsigned int analyzer_read_id(libusb_device_handle *devh);
-SR_PRIV unsigned int analyzer_get_stop_address(libusb_device_handle *devh);
-SR_PRIV unsigned int analyzer_get_now_address(libusb_device_handle *devh);
-SR_PRIV unsigned int analyzer_get_trigger_address(libusb_device_handle *devh);
-SR_PRIV int analyzer_decompress(void *input, unsigned int input_len,
-                               void *output, unsigned int output_len);
-
-SR_PRIV void analyzer_reset(libusb_device_handle *devh);
-SR_PRIV void analyzer_initialize(libusb_device_handle *devh);
-SR_PRIV void analyzer_wait(libusb_device_handle *devh, int set, int unset);
-SR_PRIV void analyzer_read_start(libusb_device_handle *devh);
-SR_PRIV int analyzer_read_data(libusb_device_handle *devh, void *buffer,
-                              unsigned int size);
-SR_PRIV void analyzer_read_stop(libusb_device_handle *devh);
-SR_PRIV void analyzer_start(libusb_device_handle *devh);
-SR_PRIV void analyzer_configure(libusb_device_handle *devh);
-
-SR_PRIV void analyzer_wait_button(libusb_device_handle *devh);
-SR_PRIV void analyzer_wait_data(libusb_device_handle *devh);
-
-#endif
diff --git a/hardware/zeroplus-logic-cube/api.c b/hardware/zeroplus-logic-cube/api.c
deleted file mode 100644 (file)
index a49f074..0000000
+++ /dev/null
@@ -1,752 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.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 "protocol.h"
-
-#define VENDOR_NAME                    "ZEROPLUS"
-#define USB_INTERFACE                  0
-#define USB_CONFIGURATION              1
-#define NUM_TRIGGER_STAGES             4
-#define PACKET_SIZE                    2048    /* ?? */
-
-//#define ZP_EXPERIMENTAL
-
-struct zp_model {
-       uint16_t vid;
-       uint16_t pid;
-       char *model_name;
-       unsigned int channels;
-       unsigned int sample_depth;      /* In Ksamples/channel */
-       unsigned int max_sampling_freq;
-};
-
-/*
- * Note -- 16032, 16064 and 16128 *usually* -- but not always -- have the
- * same 128K sample depth.
- */
-static const struct zp_model zeroplus_models[] = {
-       {0x0c12, 0x7002, "LAP-16128U",    16, 128,  200},
-       {0x0c12, 0x7009, "LAP-C(16064)",  16, 64,   100},
-       {0x0c12, 0x700a, "LAP-C(16128)",  16, 128,  200},
-       {0x0c12, 0x700b, "LAP-C(32128)",  32, 128,  200},
-       {0x0c12, 0x700c, "LAP-C(321000)", 32, 1024, 200},
-       {0x0c12, 0x700d, "LAP-C(322000)", 32, 2048, 200},
-       {0x0c12, 0x700e, "LAP-C(16032)",  16, 32,   100},
-       {0x0c12, 0x7016, "LAP-C(162000)", 16, 2048, 200},
-       { 0, 0, 0, 0, 0, 0 }
-};
-
-static const int32_t hwcaps[] = {
-       SR_CONF_LOGIC_ANALYZER,
-       SR_CONF_SAMPLERATE,
-       SR_CONF_TRIGGER_MATCH,
-       SR_CONF_CAPTURE_RATIO,
-       SR_CONF_VOLTAGE_THRESHOLD,
-       SR_CONF_LIMIT_SAMPLES,
-};
-
-static const int32_t trigger_matches[] = {
-       SR_TRIGGER_ZERO,
-       SR_TRIGGER_ONE,
-};
-
-/*
- * ZEROPLUS LAP-C (16032) numbers the 16 channels A0-A7 and B0-B7.
- * We currently ignore other untested/unsupported devices here.
- */
-static const char *channel_names[] = {
-       "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
-       "B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7",
-       "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7",
-       "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
-       NULL,
-};
-
-SR_PRIV struct sr_dev_driver zeroplus_logic_cube_driver_info;
-static struct sr_dev_driver *di = &zeroplus_logic_cube_driver_info;
-
-/*
- * The hardware supports more samplerates than these, but these are the
- * options hardcoded into the vendor's Windows GUI.
- */
-
-static const uint64_t samplerates_100[] = {
-       SR_HZ(100),
-       SR_HZ(500),
-       SR_KHZ(1),
-       SR_KHZ(5),
-       SR_KHZ(25),
-       SR_KHZ(50),
-       SR_KHZ(100),
-       SR_KHZ(200),
-       SR_KHZ(400),
-       SR_KHZ(800),
-       SR_MHZ(1),
-       SR_MHZ(10),
-       SR_MHZ(25),
-       SR_MHZ(50),
-       SR_MHZ(80),
-       SR_MHZ(100),
-};
-
-const uint64_t samplerates_200[] = {
-       SR_HZ(100),
-       SR_HZ(500),
-       SR_KHZ(1),
-       SR_KHZ(5),
-       SR_KHZ(25),
-       SR_KHZ(50),
-       SR_KHZ(100),
-       SR_KHZ(200),
-       SR_KHZ(400),
-       SR_KHZ(800),
-       SR_MHZ(1),
-       SR_MHZ(10),
-       SR_MHZ(25),
-       SR_MHZ(50),
-       SR_MHZ(80),
-       SR_MHZ(100),
-       SR_MHZ(150),
-       SR_MHZ(200),
-};
-
-static int dev_close(struct sr_dev_inst *sdi);
-
-SR_PRIV int zp_set_samplerate(struct dev_context *devc, uint64_t samplerate)
-{
-       int i;
-
-       for (i = 0; ARRAY_SIZE(samplerates_200); i++)
-               if (samplerate == samplerates_200[i])
-                       break;
-
-       if (i == ARRAY_SIZE(samplerates_200) || samplerate > devc->max_samplerate) {
-               sr_err("Unsupported samplerate: %" PRIu64 "Hz.", samplerate);
-               return SR_ERR_ARG;
-       }
-
-       sr_info("Setting samplerate to %" PRIu64 "Hz.", samplerate);
-
-       if (samplerate >= SR_MHZ(1))
-               analyzer_set_freq(samplerate / SR_MHZ(1), FREQ_SCALE_MHZ);
-       else if (samplerate >= SR_KHZ(1))
-               analyzer_set_freq(samplerate / SR_KHZ(1), FREQ_SCALE_KHZ);
-       else
-               analyzer_set_freq(samplerate, FREQ_SCALE_HZ);
-
-       devc->cur_samplerate = samplerate;
-
-       return SR_OK;
-}
-
-static int init(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, di, LOG_PREFIX);
-}
-
-static GSList *scan(GSList *options)
-{
-       struct sr_dev_inst *sdi;
-       struct sr_channel *ch;
-       struct drv_context *drvc;
-       struct dev_context *devc;
-       const struct zp_model *prof;
-       struct libusb_device_descriptor des;
-       libusb_device **devlist;
-       GSList *devices;
-       int ret, devcnt, i, j;
-
-       (void)options;
-
-       drvc = di->priv;
-
-       devices = NULL;
-
-       /* Find all ZEROPLUS analyzers and add them to device list. */
-       devcnt = 0;
-       libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist); /* TODO: Errors. */
-
-       for (i = 0; devlist[i]; i++) {
-               ret = libusb_get_device_descriptor(devlist[i], &des);
-               if (ret != 0) {
-                       sr_err("Failed to get device descriptor: %s.",
-                              libusb_error_name(ret));
-                       continue;
-               }
-
-               prof = NULL;
-               for (j = 0; j < zeroplus_models[j].vid; j++) {
-                       if (des.idVendor == zeroplus_models[j].vid &&
-                               des.idProduct == zeroplus_models[j].pid) {
-                               prof = &zeroplus_models[j];
-                       }
-               }
-               /* Skip if the device was not found. */
-               if (!prof)
-                       continue;
-               sr_info("Found ZEROPLUS %s.", prof->model_name);
-
-               /* Register the device with libsigrok. */
-               if (!(sdi = sr_dev_inst_new(devcnt, SR_ST_INACTIVE,
-                               VENDOR_NAME, prof->model_name, NULL))) {
-                       sr_err("%s: sr_dev_inst_new failed", __func__);
-                       return NULL;
-               }
-               sdi->driver = di;
-
-               /* Allocate memory for our private driver context. */
-               if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
-                       sr_err("Device context malloc failed.");
-                       return NULL;
-               }
-
-               sdi->priv = devc;
-               devc->prof = prof;
-               devc->num_channels = prof->channels;
-#ifdef ZP_EXPERIMENTAL
-               devc->max_sample_depth = 128 * 1024;
-               devc->max_samplerate = 200;
-#else
-               devc->max_sample_depth = prof->sample_depth * 1024;
-               devc->max_samplerate = prof->max_sampling_freq;
-#endif
-               devc->max_samplerate *= SR_MHZ(1);
-               devc->memory_size = MEMORY_SIZE_8K;
-               // memset(devc->trigger_buffer, 0, NUM_TRIGGER_STAGES);
-
-               /* Fill in channellist according to this device's profile. */
-               for (j = 0; j < devc->num_channels; j++) {
-                       if (!(ch = sr_channel_new(j, SR_CHANNEL_LOGIC, TRUE,
-                                       channel_names[j])))
-                               return NULL;
-                       sdi->channels = g_slist_append(sdi->channels, ch);
-               }
-
-               devices = g_slist_append(devices, sdi);
-               drvc->instances = g_slist_append(drvc->instances, sdi);
-               sdi->inst_type = SR_INST_USB;
-               sdi->conn = sr_usb_dev_inst_new(
-                       libusb_get_bus_number(devlist[i]),
-                       libusb_get_device_address(devlist[i]), NULL);
-               devcnt++;
-
-       }
-       libusb_free_device_list(devlist, 1);
-
-       return devices;
-}
-
-static GSList *dev_list(void)
-{
-       return ((struct drv_context *)(di->priv))->instances;
-}
-
-static int dev_open(struct sr_dev_inst *sdi)
-{
-       struct dev_context *devc;
-       struct drv_context *drvc;
-       struct sr_usb_dev_inst *usb;
-       libusb_device **devlist, *dev;
-       struct libusb_device_descriptor des;
-       int device_count, ret, i;
-
-       drvc = di->priv;
-       usb = sdi->conn;
-
-       if (!(devc = sdi->priv)) {
-               sr_err("%s: sdi->priv was NULL", __func__);
-               return SR_ERR_ARG;
-       }
-
-       device_count = libusb_get_device_list(drvc->sr_ctx->libusb_ctx,
-                                             &devlist);
-       if (device_count < 0) {
-               sr_err("Failed to retrieve device list.");
-               return SR_ERR;
-       }
-
-       dev = NULL;
-       for (i = 0; i < device_count; i++) {
-               if ((ret = libusb_get_device_descriptor(devlist[i], &des))) {
-                       sr_err("Failed to get device descriptor: %s.",
-                              libusb_error_name(ret));
-                       continue;
-               }
-               if (libusb_get_bus_number(devlist[i]) == usb->bus
-                   && libusb_get_device_address(devlist[i]) == usb->address) {
-                       dev = devlist[i];
-                       break;
-               }
-       }
-       if (!dev) {
-               sr_err("Device on bus %d address %d disappeared!",
-                      usb->bus, usb->address);
-               return SR_ERR;
-       }
-
-       if (!(ret = libusb_open(dev, &(usb->devhdl)))) {
-               sdi->status = SR_ST_ACTIVE;
-               sr_info("Opened device %d on %d.%d interface %d.",
-                       sdi->index, usb->bus, usb->address, USB_INTERFACE);
-       } else {
-               sr_err("Failed to open device: %s.", libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-       ret = libusb_set_configuration(usb->devhdl, USB_CONFIGURATION);
-       if (ret < 0) {
-               sr_err("Unable to set USB configuration %d: %s.",
-                      USB_CONFIGURATION, libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-       ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE);
-       if (ret != 0) {
-               sr_err("Unable to claim interface: %s.",
-                      libusb_error_name(ret));
-               return SR_ERR;
-       }
-
-       /* Set default configuration after power on. */
-       if (analyzer_read_status(usb->devhdl) == 0)
-               analyzer_configure(usb->devhdl);
-
-       analyzer_reset(usb->devhdl);
-       analyzer_initialize(usb->devhdl);
-
-       //analyzer_set_memory_size(MEMORY_SIZE_512K);
-       // analyzer_set_freq(g_freq, g_freq_scale);
-       analyzer_set_trigger_count(1);
-       // analyzer_set_ramsize_trigger_address((((100 - g_pre_trigger)
-       // * get_memory_size(g_memory_size)) / 100) >> 2);
-
-#if 0
-       if (g_double_mode == 1)
-               analyzer_set_compression(COMPRESSION_DOUBLE);
-       else if (g_compression == 1)
-               analyzer_set_compression(COMPRESSION_ENABLE);
-       else
-#endif
-       analyzer_set_compression(COMPRESSION_NONE);
-
-       if (devc->cur_samplerate == 0) {
-               /* Samplerate hasn't been set. Default to 1MHz. */
-               analyzer_set_freq(1, FREQ_SCALE_MHZ);
-               devc->cur_samplerate = SR_MHZ(1);
-       }
-
-       if (devc->cur_threshold == 0)
-               set_voltage_threshold(devc, 1.5);
-
-       return SR_OK;
-}
-
-static int dev_close(struct sr_dev_inst *sdi)
-{
-       struct sr_usb_dev_inst *usb;
-
-       usb = sdi->conn;
-
-       if (!usb->devhdl)
-               return SR_ERR;
-
-       sr_info("Closing device %d on %d.%d interface %d.", sdi->index,
-               usb->bus, usb->address, USB_INTERFACE);
-       libusb_release_interface(usb->devhdl, USB_INTERFACE);
-       libusb_reset_device(usb->devhdl);
-       libusb_close(usb->devhdl);
-       usb->devhdl = NULL;
-       sdi->status = SR_ST_INACTIVE;
-
-       return SR_OK;
-}
-
-static int cleanup(void)
-{
-       return std_dev_clear(di, NULL);
-}
-
-static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-
-       (void)cg;
-
-       switch (id) {
-       case SR_CONF_SAMPLERATE:
-               if (sdi) {
-                       devc = sdi->priv;
-                       *data = g_variant_new_uint64(devc->cur_samplerate);
-                       sr_spew("Returning samplerate: %" PRIu64 "Hz.",
-                               devc->cur_samplerate);
-               } else
-                       return SR_ERR_ARG;
-               break;
-       case SR_CONF_CAPTURE_RATIO:
-               if (sdi) {
-                       devc = sdi->priv;
-                       *data = g_variant_new_uint64(devc->capture_ratio);
-               } else
-                       return SR_ERR_ARG;
-               break;
-       case SR_CONF_VOLTAGE_THRESHOLD:
-               if (sdi) {
-                       GVariant *range[2];
-                       devc = sdi->priv;
-                       range[0] = g_variant_new_double(devc->cur_threshold);
-                       range[1] = g_variant_new_double(devc->cur_threshold);
-                       *data = g_variant_new_tuple(range, 2);
-               } else
-                       return SR_ERR_ARG;
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       gdouble low, high;
-
-       (void)cg;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       if (!(devc = sdi->priv)) {
-               sr_err("%s: sdi->priv was NULL", __func__);
-               return SR_ERR_ARG;
-       }
-
-       switch (id) {
-       case SR_CONF_SAMPLERATE:
-               return zp_set_samplerate(devc, g_variant_get_uint64(data));
-       case SR_CONF_LIMIT_SAMPLES:
-               return set_limit_samples(devc, g_variant_get_uint64(data));
-       case SR_CONF_CAPTURE_RATIO:
-               return set_capture_ratio(devc, g_variant_get_uint64(data));
-       case SR_CONF_VOLTAGE_THRESHOLD:
-               g_variant_get(data, "(dd)", &low, &high);
-               return set_voltage_threshold(devc, (low + high) / 2.0);
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct dev_context *devc;
-       GVariant *gvar, *grange[2];
-       GVariantBuilder gvb;
-       double v;
-       GVariant *range[2];
-
-       (void)cg;
-
-       switch (key) {
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
-               break;
-       case SR_CONF_SAMPLERATE:
-               devc = sdi->priv;
-               g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
-               if (devc->prof->max_sampling_freq == 100) {
-                       gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"),
-                                       samplerates_100, ARRAY_SIZE(samplerates_100),
-                                       sizeof(uint64_t));
-               } else if (devc->prof->max_sampling_freq == 200) {
-                       gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"),
-                                       samplerates_200, ARRAY_SIZE(samplerates_200),
-                                       sizeof(uint64_t));
-               } else {
-                       sr_err("Internal error: Unknown max. samplerate: %d.",
-                              devc->prof->max_sampling_freq);
-                       return SR_ERR_ARG;
-               }
-               g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar);
-               *data = g_variant_builder_end(&gvb);
-               break;
-       case SR_CONF_TRIGGER_MATCH:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               trigger_matches, ARRAY_SIZE(trigger_matches),
-                               sizeof(int32_t));
-               break;
-       case SR_CONF_VOLTAGE_THRESHOLD:
-               g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
-               for (v = -6.0; v <= 6.0; v += 0.1) {
-                       range[0] = g_variant_new_double(v);
-                       range[1] = g_variant_new_double(v);
-                       gvar = g_variant_new_tuple(range, 2);
-                       g_variant_builder_add_value(&gvb, gvar);
-               }
-               *data = g_variant_builder_end(&gvb);
-               break;
-       case SR_CONF_LIMIT_SAMPLES:
-               if (!sdi)
-                       return SR_ERR_ARG;
-               devc = sdi->priv;
-               grange[0] = g_variant_new_uint64(0);
-               grange[1] = g_variant_new_uint64(devc->max_sample_depth);
-               *data = g_variant_new_tuple(grange, 2);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi,
-               void *cb_data)
-{
-       struct dev_context *devc;
-       struct sr_usb_dev_inst *usb;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_logic logic;
-       unsigned int samples_read;
-       int res;
-       unsigned int packet_num, n;
-       unsigned char *buf;
-       unsigned int status;
-       unsigned int stop_address;
-       unsigned int now_address;
-       unsigned int trigger_address;
-       unsigned int trigger_offset;
-       unsigned int triggerbar;
-       unsigned int ramsize_trigger;
-       unsigned int memory_size;
-       unsigned int valid_samples;
-       unsigned int discard;
-       int trigger_now;
-
-       if (sdi->status != SR_ST_ACTIVE)
-               return SR_ERR_DEV_CLOSED;
-
-       if (!(devc = sdi->priv)) {
-               sr_err("%s: sdi->priv was NULL", __func__);
-               return SR_ERR_ARG;
-       }
-
-       if (analyzer_add_triggers(sdi) != SR_OK) {
-               sr_err("Failed to configure triggers.");
-               return SR_ERR;
-       }
-
-       usb = sdi->conn;
-
-       set_triggerbar(devc);
-
-       /* Push configured settings to device. */
-       analyzer_configure(usb->devhdl);
-
-       analyzer_start(usb->devhdl);
-       sr_info("Waiting for data.");
-       analyzer_wait_data(usb->devhdl);
-
-       status = analyzer_read_status(usb->devhdl);
-       stop_address = analyzer_get_stop_address(usb->devhdl);
-       now_address = analyzer_get_now_address(usb->devhdl);
-       trigger_address = analyzer_get_trigger_address(usb->devhdl);
-
-       triggerbar = analyzer_get_triggerbar_address();
-       ramsize_trigger = analyzer_get_ramsize_trigger_address();
-
-       n = get_memory_size(devc->memory_size);
-       memory_size = n / 4;
-
-       sr_info("Status = 0x%x.", status);
-       sr_info("Stop address       = 0x%x.", stop_address);
-       sr_info("Now address        = 0x%x.", now_address);
-       sr_info("Trigger address    = 0x%x.", trigger_address);
-       sr_info("Triggerbar address = 0x%x.", triggerbar);
-       sr_info("Ramsize trigger    = 0x%x.", ramsize_trigger);
-       sr_info("Memory size        = 0x%x.", memory_size);
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(cb_data, LOG_PREFIX);
-
-       /* Check for empty capture */
-       if ((status & STATUS_READY) && !stop_address) {
-               packet.type = SR_DF_END;
-               sr_session_send(cb_data, &packet);
-               return SR_OK;
-       }
-
-       if (!(buf = g_try_malloc(PACKET_SIZE))) {
-               sr_err("Packet buffer malloc failed.");
-               return SR_ERR_MALLOC;
-       }
-
-       /* Check if the trigger is in the samples we are throwing away */
-       trigger_now = now_address == trigger_address ||
-               ((now_address + 1) % memory_size) == trigger_address;
-
-       /*
-        * STATUS_READY doesn't clear until now_address advances past
-        * addr 0, but for our logic, clear it in that case
-        */
-       if (!now_address)
-               status &= ~STATUS_READY;
-
-       analyzer_read_start(usb->devhdl);
-
-       /* Calculate how much data to discard */
-       discard = 0;
-       if (status & STATUS_READY) {
-               /*
-                * We haven't wrapped around, we need to throw away data from
-                * our current position to the end of the buffer.
-                * Additionally, the first two samples captured are always
-                * bogus.
-                */
-               discard += memory_size - now_address + 2;
-               now_address = 2;
-       }
-
-       /* If we have more samples than we need, discard them */
-       valid_samples = (stop_address - now_address) % memory_size;
-       if (valid_samples > ramsize_trigger + triggerbar) {
-               discard += valid_samples - (ramsize_trigger + triggerbar);
-               now_address += valid_samples - (ramsize_trigger + triggerbar);
-       }
-
-       sr_info("Need to discard %d samples.", discard);
-
-       /* Calculate how far in the trigger is */
-       if (trigger_now)
-               trigger_offset = 0;
-       else
-               trigger_offset = (trigger_address - now_address) % memory_size;
-
-       /* Recalculate the number of samples available */
-       valid_samples = (stop_address - now_address) % memory_size;
-
-       /* Send the incoming transfer to the session bus. */
-       samples_read = 0;
-       for (packet_num = 0; packet_num < n / PACKET_SIZE; packet_num++) {
-               unsigned int len;
-               unsigned int buf_offset;
-
-               res = analyzer_read_data(usb->devhdl, buf, PACKET_SIZE);
-               sr_info("Tried to read %d bytes, actually read %d bytes.",
-                       PACKET_SIZE, res);
-
-               if (discard >= PACKET_SIZE / 4) {
-                       discard -= PACKET_SIZE / 4;
-                       continue;
-               }
-
-               len = PACKET_SIZE - discard * 4;
-               buf_offset = discard * 4;
-               discard = 0;
-
-               /* Check if we've read all the samples */
-               if (samples_read + len / 4 >= valid_samples)
-                       len = (valid_samples - samples_read) * 4;
-               if (!len)
-                       break;
-
-               if (samples_read < trigger_offset &&
-                   samples_read + len / 4 > trigger_offset) {
-                       /* Send out samples remaining before trigger */
-                       packet.type = SR_DF_LOGIC;
-                       packet.payload = &logic;
-                       logic.length = (trigger_offset - samples_read) * 4;
-                       logic.unitsize = 4;
-                       logic.data = buf + buf_offset;
-                       sr_session_send(cb_data, &packet);
-                       len -= logic.length;
-                       samples_read += logic.length / 4;
-                       buf_offset += logic.length;
-               }
-
-               if (samples_read == trigger_offset) {
-                       /* Send out trigger */
-                       packet.type = SR_DF_TRIGGER;
-                       packet.payload = NULL;
-                       sr_session_send(cb_data, &packet);
-               }
-
-               /* Send out data (or data after trigger) */
-               packet.type = SR_DF_LOGIC;
-               packet.payload = &logic;
-               logic.length = len;
-               logic.unitsize = 4;
-               logic.data = buf + buf_offset;
-               sr_session_send(cb_data, &packet);
-               samples_read += len / 4;
-       }
-       analyzer_read_stop(usb->devhdl);
-       g_free(buf);
-
-       packet.type = SR_DF_END;
-       sr_session_send(cb_data, &packet);
-
-       return SR_OK;
-}
-
-/* TODO: This stops acquisition on ALL devices, ignoring dev_index. */
-static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct dev_context *devc;
-       struct sr_usb_dev_inst *usb;
-       struct sr_datafeed_packet packet;
-
-       packet.type = SR_DF_END;
-       sr_session_send(cb_data, &packet);
-
-       if (!(devc = sdi->priv)) {
-               sr_err("%s: sdi->priv was NULL", __func__);
-               return SR_ERR_BUG;
-       }
-
-       usb = sdi->conn;
-       analyzer_reset(usb->devhdl);
-       /* TODO: Need to cancel and free any queued up transfers. */
-
-       return SR_OK;
-}
-
-SR_PRIV struct sr_dev_driver zeroplus_logic_cube_driver_info = {
-       .name = "zeroplus-logic-cube",
-       .longname = "ZEROPLUS Logic Cube LAP-C series",
-       .api_version = 1,
-       .init = init,
-       .cleanup = cleanup,
-       .scan = scan,
-       .dev_list = 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,
-       .priv = NULL,
-};
diff --git a/hardware/zeroplus-logic-cube/gl_usb.c b/hardware/zeroplus-logic-cube/gl_usb.c
deleted file mode 100644 (file)
index 2099328..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2010 Sven Peter <sven@fail0verflow.com>
- * Copyright (C) 2010 Haxx Enterprises <bushing@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice,
- *   this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright notice,
- *   this list of conditions and the following disclaimer in the documentation
- *   and/or other materials provided with the distribution.
- *
- *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- *  THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <libusb.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-#include "gl_usb.h"
-#include "protocol.h"
-
-#define CTRL_IN                (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN | \
-                        LIBUSB_RECIPIENT_INTERFACE)
-#define CTRL_OUT       (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT | \
-                        LIBUSB_RECIPIENT_INTERFACE)
-#define EP1_BULK_IN    (LIBUSB_ENDPOINT_IN | 1)
-
-#define TIMEOUT                5000    /* Timeout in ms */
-
-enum {
-       REQ_READBULK = 0x82,
-       REQ_WRITEADDR,
-       REQ_READDATA,
-       REQ_WRITEDATA,
-};
-
-static int gl_write_address(libusb_device_handle *devh, unsigned int address)
-{
-       unsigned char packet[8] = { address & 0xFF };
-       int ret;
-
-       ret = libusb_control_transfer(devh, CTRL_OUT, 0xc, REQ_WRITEADDR,
-                                        0, packet, 1, TIMEOUT);
-       if (ret != 1)
-               sr_err("%s: %s.", __func__, libusb_error_name(ret));
-       return ret;
-}
-
-static int gl_write_data(libusb_device_handle *devh, unsigned int val)
-{
-       unsigned char packet[8] = { val & 0xFF };
-       int ret;
-
-       ret = libusb_control_transfer(devh, CTRL_OUT, 0xc, REQ_WRITEDATA,
-                                     0, packet, 1, TIMEOUT);
-       if (ret != 1)
-               sr_err("%s: %s.", __func__, libusb_error_name(ret));
-       return ret;
-}
-
-static int gl_read_data(libusb_device_handle *devh)
-{
-       unsigned char packet[8] = { 0 };
-       int ret;
-
-       ret = libusb_control_transfer(devh, CTRL_IN, 0xc, REQ_READDATA,
-                                     0, packet, 1, TIMEOUT);
-       if (ret != 1)
-               sr_err("%s: %s, val=%hhx.", __func__,
-                      libusb_error_name(ret), packet[0]);
-       return (ret == 1) ? packet[0] : ret;
-}
-
-SR_PRIV int gl_read_bulk(libusb_device_handle *devh, void *buffer,
-                        unsigned int size)
-{
-       unsigned char packet[8] =
-           { 0, 0, 0, 0, size & 0xff, (size & 0xff00) >> 8,
-             (size & 0xff0000) >> 16, (size & 0xff000000) >> 24 };
-       int ret, transferred = 0;
-
-       ret = libusb_control_transfer(devh, CTRL_OUT, 0x4, REQ_READBULK,
-                                     0, packet, 8, TIMEOUT);
-       if (ret != 8)
-               sr_err("%s: libusb_control_transfer: %s.", __func__,
-                      libusb_error_name(ret));
-
-       ret = libusb_bulk_transfer(devh, EP1_BULK_IN, buffer, size,
-                                  &transferred, TIMEOUT);
-       if (ret < 0)
-               sr_err("%s: libusb_bulk_transfer: %s.", __func__,
-                      libusb_error_name(ret));
-       return transferred;
-}
-
-SR_PRIV int gl_reg_write(libusb_device_handle *devh, unsigned int reg,
-                unsigned int val)
-{
-       int ret;
-
-       ret = gl_write_address(devh, reg);
-       if (ret < 0)
-               return ret;
-       ret = gl_write_data(devh, val);
-       return ret;
-}
-
-SR_PRIV int gl_reg_read(libusb_device_handle *devh, unsigned int reg)
-{
-       int ret;
-
-       ret = gl_write_address(devh, reg);
-       if (ret < 0)
-               return ret;
-       ret = gl_read_data(devh);
-       return ret;
-}
-
-SR_PRIV int gl_reg_read_buf(libusb_device_handle *devh, unsigned int reg,
-               unsigned char *buf, unsigned int len)
-{
-       int ret;
-       unsigned int i;
-
-       ret = gl_write_address(devh, reg);
-       if (ret < 0)
-               return ret;
-       for (i = 0; i < len; i++) {
-               ret = gl_read_data(devh);
-               if (ret < 0)
-                       return ret;
-               buf[i] = ret;
-       }
-       return 0;
-}
diff --git a/hardware/zeroplus-logic-cube/gl_usb.h b/hardware/zeroplus-logic-cube/gl_usb.h
deleted file mode 100644 (file)
index c3a33fb..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2010 Sven Peter <sven@fail0verflow.com>
- * Copyright (C) 2010 Haxx Enterprises <bushing@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice,
- *   this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright notice,
- *   this list of conditions and the following disclaimer in the documentation
- *   and/or other materials provided with the distribution.
- *
- *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- *  THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef LIBSIGROK_HARDWARE_ZEROPLUS_LOGIC_CUBE_GL_USB_H
-#define LIBSIGROK_HARDWARE_ZEROPLUS_LOGIC_CUBE_GL_USB_H
-
-#include <libusb.h>
-#include "libsigrok.h"
-
-SR_PRIV int gl_read_bulk(libusb_device_handle *devh, void *buffer,
-                        unsigned int size);
-SR_PRIV int gl_reg_write(libusb_device_handle *devh, unsigned int reg,
-                        unsigned int val);
-SR_PRIV int gl_reg_read(libusb_device_handle *devh, unsigned int reg);
-SR_PRIV int gl_reg_read_buf(libusb_device_handle *devh, unsigned int reg,
-                       unsigned char *buf, unsigned int len);
-#endif
diff --git a/hardware/zeroplus-logic-cube/protocol.c b/hardware/zeroplus-logic-cube/protocol.c
deleted file mode 100644 (file)
index ce20ccf..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.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 <math.h>
-#include "protocol.h"
-
-SR_PRIV unsigned int get_memory_size(int type)
-{
-       if (type == MEMORY_SIZE_8K)
-               return 8 * 1024;
-       else if (type <= MEMORY_SIZE_8M)
-               return (32 * 1024) << type;
-       else
-               return 0;
-}
-
-static int clz(unsigned int x)
-{
-       int n = 0;
-       if (x == 0)
-               return 32;
-       if (!(x & 0xFFFF0000)) {
-               n = n + 16;
-               x = x << 16;
-       }
-       if (!(x & 0xFF000000)) {
-               n = n + 8;
-               x = x << 8;
-       }
-       if (!(x & 0xF0000000)) {
-               n = n + 4;
-               x = x << 4;
-       }
-       if (!(x & 0xC0000000)) {
-               n = n + 2;
-               x = x << 2;
-       }
-       if (!(x & 0x80000000))
-               n = n + 1;
-       return n;
-}
-
-SR_PRIV int set_limit_samples(struct dev_context *devc, uint64_t samples)
-{
-       if (samples > devc->max_sample_depth)
-               samples = devc->max_sample_depth;
-
-       devc->limit_samples = samples;
-
-       if (samples <= 2 * 1024)
-               devc->memory_size = MEMORY_SIZE_8K;
-       else if (samples <= 16 * 1024)
-               devc->memory_size = MEMORY_SIZE_64K;
-       else
-               devc->memory_size = 19 - clz(samples - 1);
-
-       sr_info("Setting memory size to %dK.",
-               get_memory_size(devc->memory_size) / 1024);
-
-       analyzer_set_memory_size(devc->memory_size);
-
-       return SR_OK;
-}
-
-SR_PRIV int set_capture_ratio(struct dev_context *devc, uint64_t ratio)
-{
-       if (ratio > 100) {
-               sr_err("Invalid capture ratio: %" PRIu64 ".", ratio);
-               return SR_ERR_ARG;
-       }
-
-       devc->capture_ratio = ratio;
-
-       sr_info("Setting capture ratio to %d%%.", devc->capture_ratio);
-
-       return SR_OK;
-}
-
-SR_PRIV int set_voltage_threshold(struct dev_context *devc, double thresh)
-{
-       if (thresh > 6.0)
-               thresh = 6.0;
-       if (thresh < -6.0)
-               thresh = -6.0;
-
-       devc->cur_threshold = thresh;
-
-       analyzer_set_voltage_threshold((int) round(-9.1*thresh + 62.6));
-
-       sr_info("Setting voltage threshold to %fV.", devc->cur_threshold);
-
-       return SR_OK;
-}
-
-SR_PRIV void set_triggerbar(struct dev_context *devc)
-{
-       unsigned int trigger_depth, triggerbar, ramsize_trigger;
-
-       trigger_depth = get_memory_size(devc->memory_size) / 4;
-       if (devc->limit_samples < trigger_depth)
-               trigger_depth = devc->limit_samples;
-
-       if (devc->trigger)
-               triggerbar = trigger_depth * devc->capture_ratio / 100;
-       else
-               triggerbar = 0;
-
-       ramsize_trigger = trigger_depth - triggerbar;
-       /* Matches USB packet captures from official app/driver */
-       if (triggerbar > 2)
-               triggerbar -= 2;
-       else {
-               ramsize_trigger -= 1;
-               triggerbar = 0;
-       }
-
-       analyzer_set_triggerbar_address(triggerbar);
-       analyzer_set_ramsize_trigger_address(ramsize_trigger);
-
-       sr_dbg("triggerbar_address = %d(0x%x)", triggerbar, triggerbar);
-       sr_dbg("ramsize_triggerbar_address = %d(0x%x)",
-              ramsize_trigger, ramsize_trigger);
-}
diff --git a/hardware/zeroplus-logic-cube/protocol.h b/hardware/zeroplus-logic-cube/protocol.h
deleted file mode 100644 (file)
index 4b55b33..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#ifndef LIBSIGROK_HARDWARE_ZEROPLUS_LOGIC_CUBE_PROTOCOL_H
-#define LIBSIGROK_HARDWARE_ZEROPLUS_LOGIC_CUBE_PROTOCOL_H
-
-#include <stdint.h>
-#include <glib.h>
-#include <libusb.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-#include "analyzer.h"
-
-#define LOG_PREFIX "zeroplus"
-
-/* Private, per-device-instance driver context. */
-struct dev_context {
-       uint64_t cur_samplerate;
-       uint64_t max_samplerate;
-       uint64_t limit_samples;
-       int num_channels;
-       int memory_size;
-       unsigned int max_sample_depth;
-       //uint8_t channel_mask;
-       //uint8_t trigger_mask[NUM_TRIGGER_STAGES];
-       //uint8_t trigger_value[NUM_TRIGGER_STAGES];
-       // uint8_t trigger_buffer[NUM_TRIGGER_STAGES];
-       int trigger;
-       unsigned int capture_ratio;
-       double cur_threshold;
-       const struct zp_model *prof;
-};
-
-SR_PRIV unsigned int get_memory_size(int type);
-SR_PRIV int zp_set_samplerate(struct dev_context *devc, uint64_t samplerate);
-SR_PRIV int set_limit_samples(struct dev_context *devc, uint64_t samples);
-SR_PRIV int set_capture_ratio(struct dev_context *devc, uint64_t ratio);
-SR_PRIV int set_voltage_threshold(struct dev_context *devc, double thresh);
-SR_PRIV void set_triggerbar(struct dev_context *devc);
-
-#endif
diff --git a/hwdriver.c b/hwdriver.c
deleted file mode 100644 (file)
index 04d877a..0000000
+++ /dev/null
@@ -1,468 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Bert Vermeulen <bert@biot.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 <stdlib.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <dirent.h>
-#include <string.h>
-#include <glib.h>
-#include "config.h" /* Needed for HAVE_LIBUSB_1_0 and others. */
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-/** @cond PRIVATE */
-#define LOG_PREFIX "hwdriver"
-/** @endcond */
-
-extern SR_PRIV struct sr_dev_driver *drivers_list[];
-
-/**
- * @file
- *
- * Hardware driver handling in libsigrok.
- */
-
-/**
- * @defgroup grp_driver Hardware drivers
- *
- * Hardware driver handling in libsigrok.
- *
- * @{
- */
-
-static struct sr_config_info sr_config_info_data[] = {
-       {SR_CONF_CONN, SR_T_STRING, "conn",
-               "Connection", NULL},
-       {SR_CONF_SERIALCOMM, SR_T_STRING, "serialcomm",
-               "Serial communication", NULL},
-       {SR_CONF_SAMPLERATE, SR_T_UINT64, "samplerate",
-               "Sample rate", NULL},
-       {SR_CONF_CAPTURE_RATIO, SR_T_UINT64, "captureratio",
-               "Pre-trigger capture ratio", NULL},
-       {SR_CONF_PATTERN_MODE, SR_T_STRING, "pattern",
-               "Pattern", NULL},
-       {SR_CONF_TRIGGER_MATCH, SR_T_INT32, "triggermatch",
-               "Trigger matches", NULL},
-       {SR_CONF_EXTERNAL_CLOCK, SR_T_BOOL, "external_clock",
-               "External clock mode", NULL},
-       {SR_CONF_SWAP, SR_T_BOOL, "swap",
-               "Swap channel order", NULL},
-       {SR_CONF_RLE, SR_T_BOOL, "rle",
-               "Run Length Encoding", NULL},
-       {SR_CONF_TRIGGER_SLOPE, SR_T_STRING, "triggerslope",
-               "Trigger slope", NULL},
-       {SR_CONF_TRIGGER_SOURCE, SR_T_STRING, "triggersource",
-               "Trigger source", NULL},
-       {SR_CONF_HORIZ_TRIGGERPOS, SR_T_FLOAT, "horiz_triggerpos",
-               "Horizontal trigger position", NULL},
-       {SR_CONF_BUFFERSIZE, SR_T_UINT64, "buffersize",
-               "Buffer size", NULL},
-       {SR_CONF_TIMEBASE, SR_T_RATIONAL_PERIOD, "timebase",
-               "Time base", NULL},
-       {SR_CONF_FILTER, SR_T_STRING, "filter",
-               "Filter targets", NULL},
-       {SR_CONF_VDIV, SR_T_RATIONAL_VOLT, "vdiv",
-               "Volts/div", NULL},
-       {SR_CONF_COUPLING, SR_T_STRING, "coupling",
-               "Coupling", NULL},
-       {SR_CONF_DATALOG, SR_T_BOOL, "datalog",
-               "Datalog", NULL},
-       {SR_CONF_SPL_WEIGHT_FREQ, SR_T_STRING, "spl_weight_freq",
-               "Sound pressure level frequency weighting", NULL},
-       {SR_CONF_SPL_WEIGHT_TIME, SR_T_STRING, "spl_weight_time",
-               "Sound pressure level time weighting", NULL},
-       {SR_CONF_HOLD_MAX, SR_T_BOOL, "hold_max",
-               "Hold max", NULL},
-       {SR_CONF_HOLD_MIN, SR_T_BOOL, "hold_min",
-               "Hold min", NULL},
-       {SR_CONF_SPL_MEASUREMENT_RANGE, SR_T_UINT64_RANGE, "spl_meas_range",
-               "Sound pressure level measurement range", NULL},
-       {SR_CONF_VOLTAGE_THRESHOLD, SR_T_DOUBLE_RANGE, "voltage_threshold",
-               "Voltage threshold", NULL },
-       {SR_CONF_POWER_OFF, SR_T_BOOL, "power_off",
-               "Power off", NULL},
-       {SR_CONF_DATA_SOURCE, SR_T_STRING, "data_source",
-               "Data source", NULL},
-       {SR_CONF_NUM_LOGIC_CHANNELS, SR_T_INT32, "logic_channels",
-               "Number of logic channels", NULL},
-       {SR_CONF_NUM_ANALOG_CHANNELS, SR_T_INT32, "analog_channels",
-               "Number of analog channels", NULL},
-       {SR_CONF_OUTPUT_VOLTAGE, SR_T_FLOAT, "output_voltage",
-               "Current output voltage", NULL},
-       {SR_CONF_OUTPUT_VOLTAGE_MAX, SR_T_FLOAT, "output_voltage_max",
-               "Maximum output voltage", NULL},
-       {SR_CONF_OUTPUT_CURRENT, SR_T_FLOAT, "output_current",
-               "Current output current", NULL},
-       {SR_CONF_OUTPUT_CURRENT_MAX, SR_T_FLOAT, "output_current_max",
-               "Maximum output current", NULL},
-       {SR_CONF_OUTPUT_ENABLED, SR_T_BOOL, "output_enabled",
-               "Output enabled", NULL},
-       {SR_CONF_OUTPUT_CHANNEL, SR_T_STRING, "output_channel",
-               "Output channel modes", NULL},
-       {SR_CONF_OVER_VOLTAGE_PROTECTION, SR_T_BOOL, "ovp",
-               "Over-voltage protection", NULL},
-       {SR_CONF_OVER_CURRENT_PROTECTION, SR_T_BOOL, "ocp",
-               "Over-current protection", NULL},
-       {SR_CONF_LIMIT_SAMPLES, SR_T_UINT64, "limit_samples",
-               "Sample limit", NULL},
-       {SR_CONF_CLOCK_EDGE, SR_T_STRING, "clock_edge",
-               "Clock edge", NULL},
-       {0, 0, NULL, NULL, NULL},
-};
-
-/**
- * Return the list of supported hardware drivers.
- *
- * @return Pointer to the NULL-terminated list of hardware driver pointers.
- *
- * @since 0.1.0
- */
-SR_API struct sr_dev_driver **sr_driver_list(void)
-{
-
-       return drivers_list;
-}
-
-/**
- * Initialize a hardware driver.
- *
- * This usually involves memory allocations and variable initializations
- * within the driver, but _not_ scanning for attached devices.
- * The API call sr_driver_scan() is used for that.
- *
- * @param ctx A libsigrok context object allocated by a previous call to
- *            sr_init(). Must not be NULL.
- * @param driver The driver to initialize. This must be a pointer to one of
- *               the entries returned by sr_driver_list(). Must not be NULL.
- *
- * @retval SR_OK Success
- * @retval SR_ERR_ARG Invalid parameter(s).
- * @retval SR_ERR_BUG Internal errors.
- * @retval other Another negative error code upon other errors.
- *
- * @since 0.2.0
- */
-SR_API int sr_driver_init(struct sr_context *ctx, struct sr_dev_driver *driver)
-{
-       int ret;
-
-       if (!ctx) {
-               sr_err("Invalid libsigrok context, can't initialize.");
-               return SR_ERR_ARG;
-       }
-
-       if (!driver) {
-               sr_err("Invalid driver, can't initialize.");
-               return SR_ERR_ARG;
-       }
-
-       sr_spew("Initializing driver '%s'.", driver->name);
-       if ((ret = driver->init(ctx)) < 0)
-               sr_err("Failed to initialize the driver: %d.", ret);
-
-       return ret;
-}
-
-/**
- * Tell a hardware driver to scan for devices.
- *
- * In addition to the detection, the devices that are found are also
- * initialized automatically. On some devices, this involves a firmware upload,
- * or other such measures.
- *
- * The order in which the system is scanned for devices is not specified. The
- * caller should not assume or rely on any specific order.
- *
- * Before calling sr_driver_scan(), the user must have previously initialized
- * the driver by calling sr_driver_init().
- *
- * @param driver The driver that should scan. This must be a pointer to one of
- *               the entries returned by sr_driver_list(). Must not be NULL.
- * @param options A list of 'struct sr_hwopt' options to pass to the driver's
- *                scanner. Can be NULL/empty.
- *
- * @return A GSList * of 'struct sr_dev_inst', or NULL if no devices were
- *         found (or errors were encountered). This list must be freed by the
- *         caller using g_slist_free(), but without freeing the data pointed
- *         to in the list.
- *
- * @since 0.2.0
- */
-SR_API GSList *sr_driver_scan(struct sr_dev_driver *driver, GSList *options)
-{
-       GSList *l;
-
-       if (!driver) {
-               sr_err("Invalid driver, can't scan for devices.");
-               return NULL;
-       }
-
-       if (!driver->priv) {
-               sr_err("Driver not initialized, can't scan for devices.");
-               return NULL;
-       }
-
-       l = driver->scan(options);
-
-       sr_spew("Scan of '%s' found %d devices.", driver->name,
-               g_slist_length(l));
-
-       return l;
-}
-
-/** Call driver cleanup function for all drivers.
- *  @private */
-SR_PRIV void sr_hw_cleanup_all(void)
-{
-       int i;
-       struct sr_dev_driver **drivers;
-
-       drivers = sr_driver_list();
-       for (i = 0; drivers[i]; i++) {
-               if (drivers[i]->cleanup)
-                       drivers[i]->cleanup();
-       }
-}
-
-/** Allocate struct sr_config.
- *  A floating reference can be passed in for data.
- *  @private
- */
-SR_PRIV struct sr_config *sr_config_new(int key, GVariant *data)
-{
-       struct sr_config *src;
-
-       if (!(src = g_try_malloc(sizeof(struct sr_config))))
-               return NULL;
-       src->key = key;
-       src->data = g_variant_ref_sink(data);
-
-       return src;
-}
-
-/** Free struct sr_config.
- *  @private
- */
-SR_PRIV void sr_config_free(struct sr_config *src)
-{
-
-       if (!src || !src->data) {
-               sr_err("%s: invalid data!", __func__);
-               return;
-       }
-
-       g_variant_unref(src->data);
-       g_free(src);
-
-}
-
-/**
- * Query value of a configuration key at the given driver or device instance.
- *
- * @param[in] driver The sr_dev_driver struct to query.
- * @param[in] sdi (optional) If the key is specific to a device, this must
- *            contain a pointer to the struct sr_dev_inst to be checked.
- *            Otherwise it must be NULL.
- * @param[in] cg The channel group on the device for which to list the
- *                    values, or NULL.
- * @param[in] key The configuration key (SR_CONF_*).
- * @param[in,out] data Pointer to a GVariant where the value will be stored.
- *             Must not be NULL. The caller is given ownership of the GVariant
- *             and must thus decrease the refcount after use. However if
- *             this function returns an error code, the field should be
- *             considered unused, and should not be unreferenced.
- *
- * @retval SR_OK Success.
- * @retval SR_ERR Error.
- * @retval SR_ERR_ARG The driver doesn't know that key, but this is not to be
- *          interpreted as an error by the caller; merely as an indication
- *          that it's not applicable.
- *
- * @since 0.3.0
- */
-SR_API int sr_config_get(const struct sr_dev_driver *driver,
-               const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg,
-               int key, GVariant **data)
-{
-       int ret;
-
-       if (!driver || !data)
-               return SR_ERR;
-
-       if (!driver->config_get)
-               return SR_ERR_ARG;
-
-       if ((ret = driver->config_get(key, data, sdi, cg)) == SR_OK) {
-               /* Got a floating reference from the driver. Sink it here,
-                * caller will need to unref when done with it. */
-               g_variant_ref_sink(*data);
-       }
-
-       return ret;
-}
-
-/**
- * Set value of a configuration key in a device instance.
- *
- * @param[in] sdi The device instance.
- * @param[in] cg The channel group on the device for which to list the
- *                    values, or NULL.
- * @param[in] key The configuration key (SR_CONF_*).
- * @param data The new value for the key, as a GVariant with GVariantType
- *        appropriate to that key. A floating reference can be passed
- *        in; its refcount will be sunk and unreferenced after use.
- *
- * @retval SR_OK Success.
- * @retval SR_ERR Error.
- * @retval SR_ERR_ARG The driver doesn't know that key, but this is not to be
- *          interpreted as an error by the caller; merely as an indication
- *          that it's not applicable.
- *
- * @since 0.3.0
- */
-SR_API int sr_config_set(const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg,
-               int key, GVariant *data)
-{
-       int ret;
-
-       g_variant_ref_sink(data);
-
-       if (!sdi || !sdi->driver || !data)
-               ret = SR_ERR;
-       else if (!sdi->driver->config_set)
-               ret = SR_ERR_ARG;
-       else
-               ret = sdi->driver->config_set(key, data, sdi, cg);
-
-       g_variant_unref(data);
-
-       return ret;
-}
-
-/**
- * Apply configuration settings to the device hardware.
- *
- * @param sdi The device instance.
- *
- * @return SR_OK upon success or SR_ERR in case of error.
- *
- * @since 0.3.0
- */
-SR_API int sr_config_commit(const struct sr_dev_inst *sdi)
-{
-       int ret;
-
-       if (!sdi || !sdi->driver)
-               ret = SR_ERR;
-       else if (!sdi->driver->config_commit)
-               ret = SR_OK;
-       else
-               ret = sdi->driver->config_commit(sdi);
-
-       return ret;
-}
-
-/**
- * List all possible values for a configuration key.
- *
- * @param[in] driver The sr_dev_driver struct to query.
- * @param[in] sdi (optional) If the key is specific to a device, this must
- *            contain a pointer to the struct sr_dev_inst to be checked.
- * @param[in] cg The channel group on the device for which to list the
- *                    values, or NULL.
- * @param[in] key The configuration key (SR_CONF_*).
- * @param[in,out] data A pointer to a GVariant where the list will be stored.
- *             The caller is given ownership of the GVariant and must thus
- *             unref the GVariant after use. However if this function
- *             returns an error code, the field should be considered
- *             unused, and should not be unreferenced.
- *
- * @retval SR_OK Success.
- * @retval SR_ERR Error.
- * @retval SR_ERR_ARG The driver doesn't know that key, but this is not to be
- *          interpreted as an error by the caller; merely as an indication
- *          that it's not applicable.
- *
- * @since 0.3.0
- */
-SR_API int sr_config_list(const struct sr_dev_driver *driver,
-               const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg,
-               int key, GVariant **data)
-{
-       int ret;
-
-       if (!driver || !data)
-               ret = SR_ERR;
-       else if (!driver->config_list)
-               ret = SR_ERR_ARG;
-       else if ((ret = driver->config_list(key, data, sdi, cg)) == SR_OK)
-               g_variant_ref_sink(*data);
-
-       return ret;
-}
-
-/**
- * Get information about a configuration key, by key.
- *
- * @param[in] key The configuration key.
- *
- * @return A pointer to a struct sr_config_info, or NULL if the key
- *         was not found.
- *
- * @since 0.2.0
- */
-SR_API const struct sr_config_info *sr_config_info_get(int key)
-{
-       int i;
-
-       for (i = 0; sr_config_info_data[i].key; i++) {
-               if (sr_config_info_data[i].key == key)
-                       return &sr_config_info_data[i];
-       }
-
-       return NULL;
-}
-
-/**
- * Get information about a configuration key, by name.
- *
- * @param[in] optname The configuration key.
- *
- * @return A pointer to a struct sr_config_info, or NULL if the key
- *         was not found.
- *
- * @since 0.2.0
- */
-SR_API const struct sr_config_info *sr_config_info_name_get(const char *optname)
-{
-       int i;
-
-       for (i = 0; sr_config_info_data[i].key; i++) {
-               if (!strcmp(sr_config_info_data[i].id, optname))
-                       return &sr_config_info_data[i];
-       }
-
-       return NULL;
-}
-
-/** @} */
diff --git a/input/binary.c b/input/binary.c
deleted file mode 100644 (file)
index e0d4c1d..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Bert Vermeulen <bert@biot.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 <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/time.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "input/binary"
-
-#define CHUNKSIZE             (512 * 1024)
-#define DEFAULT_NUM_CHANNELS  8
-
-struct context {
-       uint64_t samplerate;
-};
-
-static int format_match(const char *filename)
-{
-       (void)filename;
-
-       /* This module will handle anything you throw at it. */
-       return TRUE;
-}
-
-static int init(struct sr_input *in, const char *filename)
-{
-       struct sr_channel *ch;
-       int num_channels, i;
-       char name[SR_MAX_CHANNELNAME_LEN + 1];
-       char *param;
-       struct context *ctx;
-
-       (void)filename;
-
-       if (!(ctx = g_try_malloc0(sizeof(*ctx)))) {
-               sr_err("Input format context malloc failed.");
-               return SR_ERR_MALLOC;
-       }
-
-       num_channels = DEFAULT_NUM_CHANNELS;
-       ctx->samplerate = 0;
-
-       if (in->param) {
-               param = g_hash_table_lookup(in->param, "numchannels");
-               if (param) {
-                       num_channels = strtoul(param, NULL, 10);
-                       if (num_channels < 1)
-                               return SR_ERR;
-               }
-
-               param = g_hash_table_lookup(in->param, "samplerate");
-               if (param) {
-                       if (sr_parse_sizestring(param, &ctx->samplerate) != SR_OK)
-                               return SR_ERR;
-               }
-       }
-
-       /* Create a virtual device. */
-       in->sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, NULL, NULL, NULL);
-       in->internal = ctx;
-
-       for (i = 0; i < num_channels; i++) {
-               snprintf(name, SR_MAX_CHANNELNAME_LEN, "%d", i);
-               /* TODO: Check return value. */
-               if (!(ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE, name)))
-                       return SR_ERR;
-               in->sdi->channels = g_slist_append(in->sdi->channels, ch);
-       }
-
-       return SR_OK;
-}
-
-static int loadfile(struct sr_input *in, const char *filename)
-{
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_meta meta;
-       struct sr_datafeed_logic logic;
-       struct sr_config *src;
-       unsigned char buffer[CHUNKSIZE];
-       int fd, size, num_channels;
-       struct context *ctx;
-
-       ctx = in->internal;
-
-       if ((fd = open(filename, O_RDONLY)) == -1)
-               return SR_ERR;
-
-       num_channels = g_slist_length(in->sdi->channels);
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(in->sdi, LOG_PREFIX);
-
-       if (ctx->samplerate) {
-               packet.type = SR_DF_META;
-               packet.payload = &meta;
-               src = sr_config_new(SR_CONF_SAMPLERATE,
-                               g_variant_new_uint64(ctx->samplerate));
-               meta.config = g_slist_append(NULL, src);
-               sr_session_send(in->sdi, &packet);
-               sr_config_free(src);
-       }
-
-       /* Chop up the input file into chunks & send it to the session bus. */
-       packet.type = SR_DF_LOGIC;
-       packet.payload = &logic;
-       logic.unitsize = (num_channels + 7) / 8;
-       logic.data = buffer;
-       while ((size = read(fd, buffer, CHUNKSIZE)) > 0) {
-               logic.length = size;
-               sr_session_send(in->sdi, &packet);
-       }
-       close(fd);
-
-       /* Send end packet to the session bus. */
-       packet.type = SR_DF_END;
-       sr_session_send(in->sdi, &packet);
-
-       g_free(ctx);
-       in->internal = NULL;
-
-       return SR_OK;
-}
-
-SR_PRIV struct sr_input_format input_binary = {
-       .id = "binary",
-       .description = "Raw binary",
-       .format_match = format_match,
-       .init = init,
-       .loadfile = loadfile,
-};
diff --git a/input/chronovu_la8.c b/input/chronovu_la8.c
deleted file mode 100644 (file)
index dcedcf8..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2011 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include <stdlib.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "input/chronovu-la8"
-
-#define NUM_PACKETS            2048
-#define PACKET_SIZE            4096
-#define DEFAULT_NUM_CHANNELS   8
-
-/**
- * Convert the LA8 'divcount' value to the respective samplerate (in Hz).
- *
- * LA8 hardware: sample period = (divcount + 1) * 10ns.
- * Min. value for divcount: 0x00 (10ns sample period, 100MHz samplerate).
- * Max. value for divcount: 0xfe (2550ns sample period, 392.15kHz samplerate).
- *
- * @param divcount The divcount value as needed by the hardware.
- *
- * @return The samplerate in Hz, or 0xffffffffffffffff upon errors.
- */
-static uint64_t divcount_to_samplerate(uint8_t divcount)
-{
-       if (divcount == 0xff)
-               return 0xffffffffffffffffULL;
-
-       return SR_MHZ(100) / (divcount + 1);
-}
-
-static int format_match(const char *filename)
-{
-       struct stat stat_buf;
-       int ret;
-
-       if (!filename) {
-               sr_err("%s: filename was NULL", __func__);
-               // return SR_ERR; /* FIXME */
-               return FALSE;
-       }
-
-       if (!g_file_test(filename, G_FILE_TEST_EXISTS)) {
-               sr_err("%s: input file '%s' does not exist",
-                      __func__, filename);
-               // return SR_ERR; /* FIXME */
-               return FALSE;
-       }
-
-       if (!g_file_test(filename, G_FILE_TEST_IS_REGULAR)) {
-               sr_err("%s: input file '%s' not a regular file",
-                      __func__, filename);
-               // return SR_ERR; /* FIXME */
-               return FALSE;
-       }
-
-       /* Only accept files of length 8MB + 5 bytes. */
-       ret = stat(filename, &stat_buf);
-       if (ret != 0) {
-               sr_err("%s: Error getting file size of '%s'",
-                      __func__, filename);
-               return FALSE;
-       }
-       if (stat_buf.st_size != (8 * 1024 * 1024 + 5)) {
-               sr_dbg("%s: File size must be exactly 8388613 bytes ("
-                      "it actually is %d bytes in size), so this is not a "
-                      "ChronoVu LA8 file.", __func__, stat_buf.st_size);
-               return FALSE;
-       }
-
-       /* TODO: Check for divcount != 0xff. */
-
-       return TRUE;
-}
-
-static int init(struct sr_input *in, const char *filename)
-{
-       struct sr_channel *ch;
-       int num_channels, i;
-       char name[SR_MAX_CHANNELNAME_LEN + 1];
-       char *param;
-
-       (void)filename;
-
-       num_channels = DEFAULT_NUM_CHANNELS;
-
-       if (in->param) {
-               param = g_hash_table_lookup(in->param, "numchannels");
-               if (param) {
-                       num_channels = strtoul(param, NULL, 10);
-                       if (num_channels < 1) {
-                               sr_err("%s: strtoul failed", __func__);
-                               return SR_ERR;
-                       }
-               }
-       }
-
-       /* Create a virtual device. */
-       in->sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, NULL, NULL, NULL);
-
-       for (i = 0; i < num_channels; i++) {
-               snprintf(name, SR_MAX_CHANNELNAME_LEN, "%d", i);
-               /* TODO: Check return value. */
-               if (!(ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE, name)))
-                       return SR_ERR;
-               in->sdi->channels = g_slist_append(in->sdi->channels, ch);
-       }
-
-       return SR_OK;
-}
-
-static int loadfile(struct sr_input *in, const char *filename)
-{
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_meta meta;
-       struct sr_datafeed_logic logic;
-       struct sr_config *src;
-       uint8_t buf[PACKET_SIZE], divcount;
-       int i, fd, size, num_channels;
-       uint64_t samplerate;
-
-       /* TODO: Use glib functions! GIOChannel, g_fopen, etc. */
-       if ((fd = open(filename, O_RDONLY)) == -1) {
-               sr_err("%s: file open failed", __func__);
-               return SR_ERR;
-       }
-
-       num_channels = g_slist_length(in->sdi->channels);
-
-       /* Seek to the end of the file, and read the divcount byte. */
-       divcount = 0x00; /* TODO: Don't hardcode! */
-
-       /* Convert the divcount value to a samplerate. */
-       samplerate = divcount_to_samplerate(divcount);
-       if (samplerate == 0xffffffffffffffffULL) {
-               close(fd); /* FIXME */
-               return SR_ERR;
-       }
-       sr_dbg("%s: samplerate is %" PRIu64, __func__, samplerate);
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(in->sdi, LOG_PREFIX);
-
-       /* Send metadata about the SR_DF_LOGIC packets to come. */
-       packet.type = SR_DF_META;
-       packet.payload = &meta;
-       src = sr_config_new(SR_CONF_SAMPLERATE, g_variant_new_uint64(samplerate));
-       meta.config = g_slist_append(NULL, src);
-       sr_session_send(in->sdi, &packet);
-       sr_config_free(src);
-
-       /* TODO: Handle trigger point. */
-
-       /* Send data packets to the session bus. */
-       sr_dbg("%s: sending SR_DF_LOGIC data packets", __func__);
-       packet.type = SR_DF_LOGIC;
-       packet.payload = &logic;
-       logic.unitsize = (num_channels + 7) / 8;
-       logic.data = buf;
-
-       /* Send 8MB of total data to the session bus in small chunks. */
-       for (i = 0; i < NUM_PACKETS; i++) {
-               /* TODO: Handle errors, handle incomplete reads. */
-               size = read(fd, buf, PACKET_SIZE);
-               logic.length = size;
-               sr_session_send(in->sdi, &packet);
-       }
-       close(fd); /* FIXME */
-
-       /* Send end packet to the session bus. */
-       sr_dbg("%s: sending SR_DF_END", __func__);
-       packet.type = SR_DF_END;
-       packet.payload = NULL;
-       sr_session_send(in->sdi, &packet);
-
-       return SR_OK;
-}
-
-SR_PRIV struct sr_input_format input_chronovu_la8 = {
-       .id = "chronovu-la8",
-       .description = "ChronoVu LA8",
-       .format_match = format_match,
-       .init = init,
-       .loadfile = loadfile,
-};
diff --git a/input/csv.c b/input/csv.c
deleted file mode 100644 (file)
index 6dd06f4..0000000
+++ /dev/null
@@ -1,868 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Marc Schink <sigrok-dev@marcschink.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 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 <stdlib.h>
-#include <string.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "input/csv"
-
-/*
- * The CSV input module has the following options:
- *
- * single-column: Specifies the column number which stores the sample data for
- *                single column mode and enables single column mode. Multi
- *                column mode is used if this parameter is omitted.
- *
- * numchannels:   Specifies the number of channels to use. In multi column mode
- *                the number of channels are the number of columns and in single
- *                column mode the number of bits (LSB first) beginning at
- *                'first-channel'.
- *
- * delimiter:     Specifies the delimiter for columns. Must be at least one
- *                character. Comma is used as default delimiter.
- *
- * format:        Specifies the format of the sample data in single column mode.
- *                Available formats are: 'bin', 'hex' and 'oct'. The binary
- *                format is used by default. This option has no effect in multi
- *                column mode.
- *
- * comment:       Specifies the prefix character(s) for comments. No prefix
- *                characters are used by default which disables removing of
- *                comments.
- *
- * samplerate:    Samplerate which the sample data was captured with. Default
- *                value is 0.
- *
- * first-channel: Column number of the first channel in multi column mode and
- *                position of the bit for the first channel in single column mode.
- *                Default value is 0.
- *
- * header:        Determines if the first line should be treated as header
- *                and used for channel names in multi column mode. Empty header
- *                names will be replaced by the channel number. If enabled in
- *                single column mode the first line will be skipped. Usage of
- *                header is disabled by default.
- *
- * startline:     Line number to start processing sample data. Must be greater
- *                than 0. The default line number to start processing is 1.
- */
-
-/* Single column formats. */
-enum {
-       FORMAT_BIN,
-       FORMAT_HEX,
-       FORMAT_OCT
-};
-
-struct context {
-       /* Current selected samplerate. */
-       uint64_t samplerate;
-
-       /* Number of channels. */
-       gsize num_channels;
-
-       /* Column delimiter character(s). */
-       GString *delimiter;
-
-       /* Comment prefix character(s). */
-       GString *comment;
-
-       /* Determines if sample data is stored in multiple columns. */
-       gboolean multi_column_mode;
-
-       /* Column number of the sample data in single column mode. */
-       gsize single_column;
-
-       /*
-        * Number of the first column to parse. Equivalent to the number of the
-        * first channel in multi column mode and the single column number in
-        * single column mode.
-        */
-       gsize first_column;
-
-       /*
-        * Column number of the first channel in multi column mode and position of
-        * the bit for the first channel in single column mode.
-        */
-       gsize first_channel;
-
-       /* Line number to start processing. */
-       gsize start_line;
-
-       /*
-        * Determines if the first line should be treated as header and used for
-        * channel names in multi column mode.
-        */
-       gboolean header;
-
-       /* Format sample data is stored in single column mode. */
-       int format;
-
-       /* Size of the sample buffer. */
-       gsize sample_buffer_size;
-
-       /* Buffer to store sample data. */
-       uint8_t *sample_buffer;
-
-       GIOChannel *channel;
-
-       /* Buffer for the current line. */
-       GString *buffer;
-
-       /* Current line number. */
-       gsize line_number;
-};
-
-static int format_match(const char *filename)
-{
-       if (!filename) {
-               sr_err("%s: filename was NULL.", __func__);
-               return FALSE;
-       }
-
-       if (!g_file_test(filename, G_FILE_TEST_EXISTS)) {
-               sr_err("Input file '%s' does not exist.", filename);
-               return FALSE;
-       }
-
-       if (!g_file_test(filename, G_FILE_TEST_IS_REGULAR)) {
-               sr_err("Input file '%s' not a regular file.", filename);
-               return FALSE;
-       }
-
-       return TRUE;
-}
-
-static void free_context(struct context *ctx)
-{
-       if (!ctx)
-               return;
-
-       if (ctx->delimiter)
-               g_string_free(ctx->delimiter, TRUE);
-
-       if (ctx->comment)
-               g_string_free(ctx->comment, TRUE);
-
-       if (ctx->channel) {
-               g_io_channel_shutdown(ctx->channel, FALSE, NULL);
-               g_io_channel_unref(ctx->channel);
-       }
-
-       if (ctx->sample_buffer)
-               g_free(ctx->sample_buffer);
-
-       if (ctx->buffer)
-               g_string_free(ctx->buffer, TRUE);
-
-       g_free(ctx);
-}
-
-static void strip_comment(GString *string, const GString *prefix)
-{
-       char *ptr;
-
-       if (!prefix->len)
-               return;
-
-       if (!(ptr = strstr(string->str, prefix->str)))
-               return;
-
-       g_string_truncate(string, ptr - string->str);
-}
-
-static int parse_binstr(const char *str, struct context *ctx)
-{
-       gsize i, j, length;
-
-       length = strlen(str);
-
-       if (!length) {
-               sr_err("Column %zu in line %zu is empty.", ctx->single_column,
-                       ctx->line_number);
-               return SR_ERR;
-       }
-
-       /* Clear buffer in order to set bits only. */
-       memset(ctx->sample_buffer, 0, (ctx->num_channels + 7) >> 3);
-
-       i = ctx->first_channel;
-
-       for (j = 0; i < length && j < ctx->num_channels; i++, j++) {
-               if (str[length - i - 1] == '1') {
-                       ctx->sample_buffer[j / 8] |= (1 << (j % 8));
-               } else if (str[length - i - 1] != '0') {
-                       sr_err("Invalid value '%s' in column %zu in line %zu.",
-                               str, ctx->single_column, ctx->line_number);
-                       return SR_ERR;
-               }
-       }
-
-       return SR_OK;
-}
-
-static int parse_hexstr(const char *str, struct context *ctx)
-{
-       gsize i, j, k, length;
-       uint8_t value;
-       char c;
-
-       length = strlen(str);
-
-       if (!length) {
-               sr_err("Column %zu in line %zu is empty.", ctx->single_column,
-                       ctx->line_number);
-               return SR_ERR;
-       }
-
-       /* Clear buffer in order to set bits only. */
-       memset(ctx->sample_buffer, 0, (ctx->num_channels + 7) >> 3);
-
-       /* Calculate the position of the first hexadecimal digit. */
-       i = ctx->first_channel / 4;
-
-       for (j = 0; i < length && j < ctx->num_channels; i++) {
-               c = str[length - i - 1];
-
-               if (!g_ascii_isxdigit(c)) {
-                       sr_err("Invalid value '%s' in column %zu in line %zu.",
-                               str, ctx->single_column, ctx->line_number);
-                       return SR_ERR;
-               }
-
-               value = g_ascii_xdigit_value(c);
-
-               k = (ctx->first_channel + j) % 4;
-
-               for (; j < ctx->num_channels && k < 4; k++) {
-                       if (value & (1 << k))
-                               ctx->sample_buffer[j / 8] |= (1 << (j % 8));
-
-                       j++;
-               }
-       }
-
-       return SR_OK;
-}
-
-static int parse_octstr(const char *str, struct context *ctx)
-{
-       gsize i, j, k, length;
-       uint8_t value;
-       char c;
-
-       length = strlen(str);
-
-       if (!length) {
-               sr_err("Column %zu in line %zu is empty.", ctx->single_column,
-                       ctx->line_number);
-               return SR_ERR;
-       }
-
-       /* Clear buffer in order to set bits only. */
-       memset(ctx->sample_buffer, 0, (ctx->num_channels + 7) >> 3);
-
-       /* Calculate the position of the first octal digit. */
-       i = ctx->first_channel / 3;
-
-       for (j = 0; i < length && j < ctx->num_channels; i++) {
-               c = str[length - i - 1];
-
-               if (c < '0' || c > '7') {
-                       sr_err("Invalid value '%s' in column %zu in line %zu.",
-                               str, ctx->single_column, ctx->line_number);
-                       return SR_ERR;
-               }
-
-               value = g_ascii_xdigit_value(c);
-
-               k = (ctx->first_channel + j) % 3;
-
-               for (; j < ctx->num_channels && k < 3; k++) {
-                       if (value & (1 << k))
-                               ctx->sample_buffer[j / 8] |= (1 << (j % 8));
-
-                       j++;
-               }
-       }
-
-       return SR_OK;
-}
-
-static char **parse_line(const struct context *ctx, int max_columns)
-{
-       const char *str, *remainder;
-       GSList *list, *l;
-       char **columns;
-       char *column;
-       gsize n, k;
-
-       n = 0;
-       k = 0;
-       list = NULL;
-
-       remainder = ctx->buffer->str;
-       str = strstr(remainder, ctx->delimiter->str);
-
-       while (str && max_columns) {
-               if (n >= ctx->first_column) {
-                       column = g_strndup(remainder, str - remainder);
-                       list = g_slist_prepend(list, g_strstrip(column));
-
-                       max_columns--;
-                       k++;
-               }
-
-               remainder = str + ctx->delimiter->len;
-               str = strstr(remainder, ctx->delimiter->str);
-               n++;
-       }
-
-       if (ctx->buffer->len && max_columns && n >= ctx->first_column) {
-               column = g_strdup(remainder);
-               list = g_slist_prepend(list, g_strstrip(column));
-               k++;
-       }
-
-       if (!(columns = g_try_new(char *, k + 1)))
-               return NULL;
-
-       columns[k--] = NULL;
-
-       for (l = list; l; l = l->next)
-               columns[k--] = l->data;
-
-       g_slist_free(list);
-
-       return columns;
-}
-
-static int parse_multi_columns(char **columns, struct context *ctx)
-{
-       gsize i;
-
-       /* Clear buffer in order to set bits only. */
-       memset(ctx->sample_buffer, 0, (ctx->num_channels + 7) >> 3);
-
-       for (i = 0; i < ctx->num_channels; i++) {
-               if (columns[i][0] == '1') {
-                       ctx->sample_buffer[i / 8] |= (1 << (i % 8));
-               } else if (!strlen(columns[i])) {
-                       sr_err("Column %zu in line %zu is empty.",
-                               ctx->first_channel + i, ctx->line_number);
-                       return SR_ERR;
-               } else if (columns[i][0] != '0') {
-                       sr_err("Invalid value '%s' in column %zu in line %zu.",
-                               columns[i], ctx->first_channel + i,
-                               ctx->line_number);
-                       return SR_ERR;
-               }
-       }
-
-       return SR_OK;
-}
-
-static int parse_single_column(const char *column, struct context *ctx)
-{
-       int res;
-
-       res = SR_ERR;
-
-       switch(ctx->format) {
-       case FORMAT_BIN:
-               res = parse_binstr(column, ctx);
-               break;
-       case FORMAT_HEX:
-               res = parse_hexstr(column, ctx);
-               break;
-       case FORMAT_OCT:
-               res = parse_octstr(column, ctx);
-               break;
-       }
-
-       return res;
-}
-
-static int send_samples(const struct sr_dev_inst *sdi, uint8_t *buffer,
-                       gsize buffer_size, gsize count)
-{
-       int res;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_logic logic;
-       gsize i;
-
-       packet.type = SR_DF_LOGIC;
-       packet.payload = &logic;
-       logic.unitsize = buffer_size;
-       logic.length = buffer_size;
-       logic.data = buffer;
-
-       for (i = 0; i < count; i++) {
-               if ((res = sr_session_send(sdi, &packet)) != SR_OK)
-                       return res;
-       }
-
-       return SR_OK;
-}
-
-static int init(struct sr_input *in, const char *filename)
-{
-       int res;
-       struct context *ctx;
-       const char *param;
-       GIOStatus status;
-       gsize i, term_pos;
-       char channel_name[SR_MAX_CHANNELNAME_LEN + 1];
-       struct sr_channel *ch;
-       char **columns;
-       gsize num_columns;
-       char *ptr;
-
-       if (!(ctx = g_try_malloc0(sizeof(struct context)))) {
-               sr_err("Context malloc failed.");
-               return SR_ERR_MALLOC;
-       }
-
-       /* Create a virtual device. */
-       in->sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, NULL, NULL, NULL);
-       in->internal = ctx;
-
-       /* Set default samplerate. */
-       ctx->samplerate = 0;
-
-       /*
-        * Enable auto-detection of the number of channels in multi column mode
-        * and enforce the specification of the number of channels in single
-        * column mode.
-        */
-       ctx->num_channels = 0;
-
-       /* Set default delimiter. */
-       if (!(ctx->delimiter = g_string_new(","))) {
-               sr_err("Delimiter malloc failed.");
-               free_context(ctx);
-               return SR_ERR_MALLOC;
-       }
-
-       /*
-        * Set default comment prefix. Note that an empty comment prefix
-        * disables removing of comments.
-        */
-       if (!(ctx->comment = g_string_new(""))) {
-               sr_err("Comment malloc failed.");
-               free_context(ctx);
-               return SR_ERR_MALLOC;
-       }
-
-       /* Enable multi column mode by default. */
-       ctx->multi_column_mode = TRUE;
-
-       /* Use first column as default single column number. */
-       ctx->single_column = 0;
-
-       /*
-        * In multi column mode start parsing sample data at the first column
-        * and in single column mode at the first bit.
-        */
-       ctx->first_channel = 0;
-
-       /* Start at the beginning of the file. */
-       ctx->start_line = 1;
-
-       /* Disable the usage of the first line as header by default. */
-       ctx->header = FALSE;
-
-       /* Set default format for single column mode. */
-       ctx->format = FORMAT_BIN;
-
-       if (!(ctx->buffer = g_string_new(""))) {
-               sr_err("Line buffer malloc failed.");
-               free_context(ctx);
-               return SR_ERR_MALLOC;
-       }
-
-       if (in->param) {
-               if ((param = g_hash_table_lookup(in->param, "samplerate"))) {
-                       res = sr_parse_sizestring(param, &ctx->samplerate);
-
-                       if (res != SR_OK) {
-                               sr_err("Invalid samplerate: %s.", param);
-                               free_context(ctx);
-                               return SR_ERR_ARG;
-                       }
-               }
-
-               if ((param = g_hash_table_lookup(in->param, "numchannels")))
-                       ctx->num_channels = g_ascii_strtoull(param, NULL, 10);
-
-               if ((param = g_hash_table_lookup(in->param, "delimiter"))) {
-                       if (!strlen(param)) {
-                               sr_err("Delimiter must be at least one character.");
-                               free_context(ctx);
-                               return SR_ERR_ARG;
-                       }
-
-                       if (!g_ascii_strcasecmp(param, "\\t"))
-                               g_string_assign(ctx->delimiter, "\t");
-                       else
-                               g_string_assign(ctx->delimiter, param);
-               }
-
-               if ((param = g_hash_table_lookup(in->param, "comment")))
-                       g_string_assign(ctx->comment, param);
-
-               if ((param = g_hash_table_lookup(in->param, "single-column"))) {
-                       ctx->single_column = g_ascii_strtoull(param, &ptr, 10);
-                       ctx->multi_column_mode = FALSE;
-
-                       if (param == ptr) {
-                               sr_err("Invalid single-colum number: %s.",
-                                       param);
-                               free_context(ctx);
-                               return SR_ERR_ARG;
-                       }
-               }
-
-               if ((param = g_hash_table_lookup(in->param, "first-channel")))
-                       ctx->first_channel = g_ascii_strtoull(param, NULL, 10);
-
-               if ((param = g_hash_table_lookup(in->param, "startline"))) {
-                       ctx->start_line = g_ascii_strtoull(param, NULL, 10);
-
-                       if (ctx->start_line < 1) {
-                               sr_err("Invalid start line: %s.", param);
-                               free_context(ctx);
-                               return SR_ERR_ARG;
-                       }
-               }
-
-               if ((param = g_hash_table_lookup(in->param, "header")))
-                       ctx->header = sr_parse_boolstring(param);
-
-               if ((param = g_hash_table_lookup(in->param, "format"))) {
-                       if (!g_ascii_strncasecmp(param, "bin", 3)) {
-                               ctx->format = FORMAT_BIN;
-                       } else if (!g_ascii_strncasecmp(param, "hex", 3)) {
-                               ctx->format = FORMAT_HEX;
-                       } else if (!g_ascii_strncasecmp(param, "oct", 3)) {
-                               ctx->format = FORMAT_OCT;
-                       } else {
-                               sr_err("Invalid format: %s.", param);
-                               free_context(ctx);
-                               return SR_ERR;
-                       }
-               }
-       }
-
-       if (ctx->multi_column_mode)
-               ctx->first_column = ctx->first_channel;
-       else
-               ctx->first_column = ctx->single_column;
-
-       if (!ctx->multi_column_mode && !ctx->num_channels) {
-               sr_err("Number of channels needs to be specified in single column mode.");
-               free_context(ctx);
-               return SR_ERR;
-       }
-
-       if (!(ctx->channel = g_io_channel_new_file(filename, "r", NULL))) {
-               sr_err("Input file '%s' could not be opened.", filename);
-               free_context(ctx);
-               return SR_ERR;
-       }
-
-       while (TRUE) {
-               ctx->line_number++;
-               status = g_io_channel_read_line_string(ctx->channel,
-                       ctx->buffer, &term_pos, NULL);
-
-               if (status == G_IO_STATUS_EOF) {
-                       sr_err("Input file is empty.");
-                       free_context(ctx);
-                       return SR_ERR;
-               }
-
-               if (status != G_IO_STATUS_NORMAL) {
-                       sr_err("Error while reading line %zu.",
-                               ctx->line_number);
-                       free_context(ctx);
-                       return SR_ERR;
-               }
-
-               if (ctx->start_line > ctx->line_number) {
-                       sr_spew("Line %zu skipped.", ctx->line_number);
-                       continue;
-               }
-
-               /* Remove line termination character(s). */
-               g_string_truncate(ctx->buffer, term_pos);
-
-               if (!ctx->buffer->len) {
-                       sr_spew("Blank line %zu skipped.", ctx->line_number);
-                       continue;
-               }
-
-               /* Remove trailing comment. */
-               strip_comment(ctx->buffer, ctx->comment);
-
-               if (ctx->buffer->len)
-                       break;
-
-               sr_spew("Comment-only line %zu skipped.", ctx->line_number);
-       }
-
-       /*
-        * In order to determine the number of columns parse the current line
-        * without limiting the number of columns.
-        */
-       if (!(columns = parse_line(ctx, -1))) {
-               sr_err("Error while parsing line %zu.", ctx->line_number);
-               free_context(ctx);
-               return SR_ERR;
-       }
-
-       num_columns = g_strv_length(columns);
-
-       /* Ensure that the first column is not out of bounds. */
-       if (!num_columns) {
-               sr_err("Column %zu in line %zu is out of bounds.",
-                       ctx->first_column, ctx->line_number);
-               g_strfreev(columns);
-               free_context(ctx);
-               return SR_ERR;
-       }
-
-       if (ctx->multi_column_mode) {
-               /*
-                * Detect the number of channels in multi column mode
-                * automatically if not specified.
-                */
-               if (!ctx->num_channels) {
-                       ctx->num_channels = num_columns;
-                       sr_info("Number of auto-detected channels: %zu.",
-                               ctx->num_channels);
-               }
-
-               /*
-                * Ensure that the number of channels does not exceed the number
-                * of columns in multi column mode.
-                */
-               if (num_columns < ctx->num_channels) {
-                       sr_err("Not enough columns for desired number of channels in line %zu.",
-                               ctx->line_number);
-                       g_strfreev(columns);
-                       free_context(ctx);
-                       return SR_ERR;
-               }
-       }
-
-       for (i = 0; i < ctx->num_channels; i++) {
-               if (ctx->header && ctx->multi_column_mode && strlen(columns[i]))
-                       snprintf(channel_name, sizeof(channel_name), "%s",
-                               columns[i]);
-               else
-                       snprintf(channel_name, sizeof(channel_name), "%zu", i);
-
-               ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE, channel_name);
-
-               if (!ch) {
-                       sr_err("Channel creation failed.");
-                       free_context(ctx);
-                       g_strfreev(columns);
-                       return SR_ERR;
-               }
-
-               in->sdi->channels = g_slist_append(in->sdi->channels, ch);
-       }
-
-       g_strfreev(columns);
-
-       /*
-        * Calculate the minimum buffer size to store the sample data of the
-        * channels.
-        */
-       ctx->sample_buffer_size = (ctx->num_channels + 7) >> 3;
-
-       if (!(ctx->sample_buffer = g_try_malloc(ctx->sample_buffer_size))) {
-               sr_err("Sample buffer malloc failed.");
-               free_context(ctx);
-               return SR_ERR_MALLOC;
-       }
-
-       return SR_OK;
-}
-
-static int loadfile(struct sr_input *in, const char *filename)
-{
-       int res;
-       struct context *ctx;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_meta meta;
-       struct sr_config *cfg;
-       GIOStatus status;
-       gboolean read_new_line;
-       gsize term_pos;
-       char **columns;
-       gsize num_columns;
-       int max_columns;
-
-       (void)filename;
-
-       ctx = in->internal;
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(in->sdi, LOG_PREFIX);
-
-       if (ctx->samplerate) {
-               packet.type = SR_DF_META;
-               packet.payload = &meta;
-               cfg = sr_config_new(SR_CONF_SAMPLERATE,
-                       g_variant_new_uint64(ctx->samplerate));
-               meta.config = g_slist_append(NULL, cfg);
-               sr_session_send(in->sdi, &packet);
-               sr_config_free(cfg);
-       }
-
-       read_new_line = FALSE;
-
-       /* Limit the number of columns to parse. */
-       if (ctx->multi_column_mode)
-               max_columns = ctx->num_channels;
-       else
-               max_columns = 1;
-
-       while (TRUE) {
-               /*
-                * Skip reading a new line for the first time if the last read
-                * line was not a header because the sample data is not parsed
-                * yet.
-                */
-               if (read_new_line || ctx->header) {
-                       ctx->line_number++;
-                       status = g_io_channel_read_line_string(ctx->channel,
-                               ctx->buffer, &term_pos, NULL);
-
-                       if (status == G_IO_STATUS_EOF)
-                               break;
-
-                       if (status != G_IO_STATUS_NORMAL) {
-                               sr_err("Error while reading line %zu.",
-                                       ctx->line_number);
-                               free_context(ctx);
-                               return SR_ERR;
-                       }
-
-                       /* Remove line termination character(s). */
-                       g_string_truncate(ctx->buffer, term_pos);
-               }
-
-               read_new_line = TRUE;
-
-               if (!ctx->buffer->len) {
-                       sr_spew("Blank line %zu skipped.", ctx->line_number);
-                       continue;
-               }
-
-               /* Remove trailing comment. */
-               strip_comment(ctx->buffer, ctx->comment);
-
-               if (!ctx->buffer->len) {
-                       sr_spew("Comment-only line %zu skipped.",
-                               ctx->line_number);
-                       continue;
-               }
-
-               if (!(columns = parse_line(ctx, max_columns))) {
-                       sr_err("Error while parsing line %zu.",
-                               ctx->line_number);
-                       free_context(ctx);
-                       return SR_ERR;
-               }
-
-               num_columns = g_strv_length(columns);
-
-               /* Ensure that the first column is not out of bounds. */
-               if (!num_columns) {
-                       sr_err("Column %zu in line %zu is out of bounds.",
-                               ctx->first_column, ctx->line_number);
-                       g_strfreev(columns);
-                       free_context(ctx);
-                       return SR_ERR;
-               }
-
-               /*
-                * Ensure that the number of channels does not exceed the number
-                * of columns in multi column mode.
-                */
-               if (ctx->multi_column_mode && num_columns < ctx->num_channels) {
-                       sr_err("Not enough columns for desired number of channels in line %zu.",
-                               ctx->line_number);
-                       g_strfreev(columns);
-                       free_context(ctx);
-                       return SR_ERR;
-               }
-
-               if (ctx->multi_column_mode)
-                       res = parse_multi_columns(columns, ctx);
-               else
-                       res = parse_single_column(columns[0], ctx);
-
-               if (res != SR_OK) {
-                       g_strfreev(columns);
-                       free_context(ctx);
-                       return SR_ERR;
-               }
-
-               g_strfreev(columns);
-
-               /*
-                * TODO: Parse sample numbers / timestamps and use it for
-                * decompression.
-                */
-
-               /* Send sample data to the session bus. */
-               res = send_samples(in->sdi, ctx->sample_buffer,
-                       ctx->sample_buffer_size, 1);
-
-               if (res != SR_OK) {
-                       sr_err("Sending samples failed.");
-                       free_context(ctx);
-                       return SR_ERR;
-               }
-       }
-
-       /* Send end packet to the session bus. */
-       packet.type = SR_DF_END;
-       sr_session_send(in->sdi, &packet);
-
-       free_context(ctx);
-
-       return SR_OK;
-}
-
-SR_PRIV struct sr_input_format input_csv = {
-       .id = "csv",
-       .description = "Comma-separated values (CSV)",
-       .format_match = format_match,
-       .init = init,
-       .loadfile = loadfile,
-};
diff --git a/input/input.c b/input/input.c
deleted file mode 100644 (file)
index d22b373..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.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 "libsigrok.h"
-#include "libsigrok-internal.h"
-
-/**
- * @file
- *
- * Input file/data format handling.
- */
-
-/**
- * @defgroup grp_input Input formats
- *
- * Input file/data format handling.
- *
- * libsigrok can process acquisition data in several different ways.
- * Aside from acquiring data from a hardware device, it can also take it from
- * a file in various formats (binary, CSV, VCD, and so on).
- *
- * Like everything in libsigrok that handles data, processing is done in a
- * streaming manner -- input should be supplied to libsigrok a chunk at a time.
- * This way anything that processes data can do so in real time, without the
- * user having to wait for the whole thing to be finished.
- *
- * Every input module is "pluggable", meaning it's handled as being separate
- * from the main libsigrok, but linked in to it statically. To keep things
- * modular and separate like this, functions within an input module should be
- * declared static, with only the respective 'struct sr_input_format' being
- * exported for use into the wider libsigrok namespace.
- *
- * @{
- */
-
-/** @cond PRIVATE */
-extern SR_PRIV struct sr_input_format input_chronovu_la8;
-extern SR_PRIV struct sr_input_format input_csv;
-extern SR_PRIV struct sr_input_format input_binary;
-extern SR_PRIV struct sr_input_format input_vcd;
-extern SR_PRIV struct sr_input_format input_wav;
-/* @endcond */
-
-static struct sr_input_format *input_module_list[] = {
-       &input_vcd,
-       &input_chronovu_la8,
-       &input_wav,
-       &input_csv,
-       /* This one has to be last, because it will take any input. */
-       &input_binary,
-       NULL,
-};
-
-/** @since 0.1.0 */
-SR_API struct sr_input_format **sr_input_list(void)
-{
-       return input_module_list;
-}
-
-/** @} */
diff --git a/input/vcd.c b/input/vcd.c
deleted file mode 100644 (file)
index 6759d73..0000000
+++ /dev/null
@@ -1,546 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012 Petteri Aimonen <jpa@sr.mail.kapsi.fi>
- *
- * 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/>.
- */
-
-/* The VCD input module has the following options:
- *
- * numchannels: Maximum number of channels to use. The channels are
- *              detected in the same order as they are listed
- *              in the $var sections of the VCD file.
- *
- * skip:        Allows skipping until given timestamp in the file.
- *              This can speed up analyzing of long captures.
- *            
- *              Value < 0: Skip until first timestamp listed in
- *              the file. (default)
- *
- *              Value = 0: Do not skip, instead generate samples
- *              beginning from timestamp 0.
- *
- *              Value > 0: Start at the given timestamp.
- *
- * downsample:  Divide the samplerate by the given factor.
- *              This can speed up analyzing of long captures.
- *
- * compress:    Compress idle periods longer than this value.
- *              This can speed up analyzing of long captures.
- *              Default 0 = don't compress.
- *
- * Based on Verilog standard IEEE Std 1364-2001 Version C
- *
- * Supported features:
- * - $var with 'wire' and 'reg' types of scalar variables
- * - $timescale definition for samplerate
- * - multiple character variable identifiers
- *
- * Most important unsupported features:
- * - vector variables (bit vectors etc.)
- * - analog, integer and real number variables
- * - $dumpvars initial value declaration
- * - $scope namespaces
- * - more than 64 channels
- */
-
-#include <stdlib.h>
-#include <glib.h>
-#include <stdio.h>
-#include <string.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "input/vcd"
-
-#define DEFAULT_NUM_CHANNELS 8
-#define CHUNKSIZE 1024
-
-struct context {
-       uint64_t samplerate;
-       int maxchannels;
-       int channelcount;
-       int downsample;
-       unsigned compress;
-       int64_t skip;
-       GSList *channels;
-};
-
-struct vcd_channel {
-       gchar *name;
-       gchar *identifier;
-};
-
-
-/* Read until specific type of character occurs in file.
- * Skip input if dest is NULL.
- * Modes:
- * 'W' read until whitespace
- * 'N' read until non-whitespace, and ungetc() the character
- * '$' read until $end
- */
-static gboolean read_until(FILE *file, GString *dest, char mode)
-{
-       int  c;
-       char prev[4] = "";
-
-       for(;;) {
-               c = fgetc(file);
-
-               if (c == EOF) {
-                       if (mode == '$')
-                               sr_err("Unexpected EOF.");
-                       return FALSE;
-               }
-
-               if (mode == 'W' && g_ascii_isspace(c))
-                       return TRUE;
-
-               if (mode == 'N' && !g_ascii_isspace(c)) {
-                       ungetc(c, file);
-                       return TRUE;
-               }
-
-               if (mode == '$') {
-                       prev[0] = prev[1]; prev[1] = prev[2]; prev[2] = prev[3]; prev[3] = c;
-                       if (prev[0] == '$' && prev[1] == 'e' && prev[2] == 'n' && prev[3] == 'd') {
-                               if (dest != NULL)
-                                       g_string_truncate(dest, dest->len - 3);
-
-                               return TRUE;
-                       }
-               }
-
-               if (dest != NULL)
-                       g_string_append_c(dest, c);
-       }
-}
-
-/*
- * Reads a single VCD section from input file and parses it to structure.
- * e.g. $timescale 1ps $end  => "timescale" "1ps"
- */
-static gboolean parse_section(FILE *file, gchar **name, gchar **contents)
-{
-       gboolean status;
-       GString *sname, *scontents;
-
-       /* Skip any initial white-space */
-       if (!read_until(file, NULL, 'N')) return FALSE;
-
-       /* Section tag should start with $. */
-       if (fgetc(file) != '$') {
-               sr_err("Expected $ at beginning of section.");
-               return FALSE;
-       }
-
-       /* Read the section tag */
-       sname = g_string_sized_new(32);
-       status = read_until(file, sname, 'W');
-
-       /* Skip whitespace before content */
-       status = status && read_until(file, NULL, 'N');
-
-       /* Read the content */
-       scontents = g_string_sized_new(128);
-       status = status && read_until(file, scontents, '$');
-       g_strchomp(scontents->str);
-
-       /* Release strings if status is FALSE, return them if status is TRUE */
-       *name = g_string_free(sname, !status);
-       *contents = g_string_free(scontents, !status);
-       return status;
-}
-
-static void free_channel(void *data)
-{
-       struct vcd_channel *vcd_ch = data;
-       g_free(vcd_ch->name);
-       g_free(vcd_ch->identifier);
-       g_free(vcd_ch);
-}
-
-static void release_context(struct context *ctx)
-{
-       g_slist_free_full(ctx->channels, free_channel);
-       g_free(ctx);
-}
-
-/* Remove empty parts from an array returned by g_strsplit. */
-static void remove_empty_parts(gchar **parts)
-{
-       gchar **src = parts;
-       gchar **dest = parts;
-       while (*src != NULL) {
-               if (**src != '\0')
-                       *dest++ = *src;
-               src++;
-       }
-
-       *dest = NULL;
-}
-
-/*
- * Parse VCD header to get values for context structure.
- * The context structure should be zeroed before calling this.
- */
-static gboolean parse_header(FILE *file, struct context *ctx)
-{
-       uint64_t p, q;
-       gchar *name = NULL, *contents = NULL;
-       gboolean status = FALSE;
-       struct vcd_channel *vcd_ch;
-
-       while (parse_section(file, &name, &contents)) {
-               sr_dbg("Section '%s', contents '%s'.", name, contents);
-
-               if (g_strcmp0(name, "enddefinitions") == 0) {
-                       status = TRUE;
-                       break;
-               } else if (g_strcmp0(name, "timescale") == 0) {
-                       /*
-                        * The standard allows for values 1, 10 or 100
-                        * and units s, ms, us, ns, ps and fs.
-                        * */
-                       if (sr_parse_period(contents, &p, &q) == SR_OK) {
-                               ctx->samplerate = q / p;
-                               if (q % p != 0) {
-                                       /* Does not happen unless time value is non-standard */
-                                       sr_warn("Inexact rounding of samplerate, %" PRIu64 " / %" PRIu64 " to %" PRIu64 " Hz.",
-                                               q, p, ctx->samplerate);
-                               }
-
-                               sr_dbg("Samplerate: %" PRIu64, ctx->samplerate);
-                       } else {
-                               sr_err("Parsing timescale failed.");
-                       }
-               } else if (g_strcmp0(name, "var") == 0) {
-                       /* Format: $var type size identifier reference $end */
-                       gchar **parts = g_strsplit_set(contents, " \r\n\t", 0);
-                       remove_empty_parts(parts);
-
-                       if (g_strv_length(parts) != 4)
-                               sr_warn("$var section should have 4 items");
-                       else if (g_strcmp0(parts[0], "reg") != 0 && g_strcmp0(parts[0], "wire") != 0)
-                               sr_info("Unsupported signal type: '%s'", parts[0]);
-                       else if (strtol(parts[1], NULL, 10) != 1)
-                               sr_info("Unsupported signal size: '%s'", parts[1]);
-                       else if (ctx->channelcount >= ctx->maxchannels)
-                               sr_warn("Skipping '%s' because only %d channels requested.", parts[3], ctx->maxchannels);
-                       else {
-                               sr_info("Channel %d is '%s' identified by '%s'.", ctx->channelcount, parts[3], parts[2]);
-                               vcd_ch = g_malloc(sizeof(struct vcd_channel));
-                               vcd_ch->identifier = g_strdup(parts[2]);
-                               vcd_ch->name = g_strdup(parts[3]);
-                               ctx->channels = g_slist_append(ctx->channels, vcd_ch);
-                               ctx->channelcount++;
-                       }
-
-                       g_strfreev(parts);
-               }
-
-               g_free(name); name = NULL;
-               g_free(contents); contents = NULL;
-       }
-
-       g_free(name);
-       g_free(contents);
-
-       return status;
-}
-
-static int format_match(const char *filename)
-{
-       FILE *file;
-       gchar *name = NULL, *contents = NULL;
-       gboolean status;
-
-       file = fopen(filename, "r");
-       if (file == NULL)
-               return FALSE;
-
-       /*
-        * If we can parse the first section correctly,
-        * then it is assumed to be a VCD file.
-        */
-       status = parse_section(file, &name, &contents);
-       status = status && (*name != '\0');
-
-       g_free(name);
-       g_free(contents);
-       fclose(file);
-
-       return status;
-}
-
-static int init(struct sr_input *in, const char *filename)
-{
-       struct sr_channel *ch;
-       int num_channels, i;
-       char name[SR_MAX_CHANNELNAME_LEN + 1];
-       char *param;
-       struct context *ctx;
-
-       (void)filename;
-
-       if (!(ctx = g_try_malloc0(sizeof(*ctx)))) {
-               sr_err("Input format context malloc failed.");
-               return SR_ERR_MALLOC;
-       }
-
-       num_channels = DEFAULT_NUM_CHANNELS;
-       ctx->samplerate = 0;
-       ctx->downsample = 1;
-       ctx->skip = -1;
-
-       if (in->param) {
-               param = g_hash_table_lookup(in->param, "numchannels");
-               if (param) {
-                       num_channels = strtoul(param, NULL, 10);
-                       if (num_channels < 1) {
-                               release_context(ctx);
-                               return SR_ERR;
-                       } else if (num_channels > 64) {
-                               sr_err("No more than 64 channels supported.");
-                               return SR_ERR;
-                       }
-               }
-
-               param = g_hash_table_lookup(in->param, "downsample");
-               if (param) {
-                       ctx->downsample = strtoul(param, NULL, 10);
-                       if (ctx->downsample < 1)
-                               ctx->downsample = 1;
-               }
-
-               param = g_hash_table_lookup(in->param, "compress");
-               if (param)
-                       ctx->compress = strtoul(param, NULL, 10);
-
-               param = g_hash_table_lookup(in->param, "skip");
-               if (param)
-                       ctx->skip = strtoul(param, NULL, 10) / ctx->downsample;
-       }
-
-       /* Maximum number of channels to parse from the VCD */
-       ctx->maxchannels = num_channels;
-
-       /* Create a virtual device. */
-       in->sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, NULL, NULL, NULL);
-       in->internal = ctx;
-
-       for (i = 0; i < num_channels; i++) {
-               snprintf(name, SR_MAX_CHANNELNAME_LEN, "%d", i);
-
-               if (!(ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE, name))) {
-                       release_context(ctx);
-                       return SR_ERR;
-               }
-
-               in->sdi->channels = g_slist_append(in->sdi->channels, ch);
-       }
-
-       return SR_OK;
-}
-
-/* Send N samples of the given value. */
-static void send_samples(const struct sr_dev_inst *sdi, uint64_t sample, uint64_t count)
-{
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_logic logic;
-       uint64_t buffer[CHUNKSIZE];
-       uint64_t i;
-       unsigned chunksize = CHUNKSIZE;
-
-       if (count < chunksize)
-               chunksize = count;
-
-       for (i = 0; i < chunksize; i++)
-               buffer[i] = sample;
-
-       packet.type = SR_DF_LOGIC;
-       packet.payload = &logic;
-       logic.unitsize = sizeof(uint64_t);
-       logic.data = buffer;
-
-       while (count) {
-               if (count < chunksize)
-                       chunksize = count;
-
-               logic.length = sizeof(uint64_t) * chunksize;
-
-               sr_session_send(sdi, &packet);
-               count -= chunksize;
-       }
-}
-
-/* Parse the data section of VCD */
-static void parse_contents(FILE *file, const struct sr_dev_inst *sdi, struct context *ctx)
-{
-       GString *token = g_string_sized_new(32);
-
-       uint64_t prev_timestamp = 0;
-       uint64_t prev_values = 0;
-
-       /* Read one space-delimited token at a time. */
-       while (read_until(file, NULL, 'N') && read_until(file, token, 'W')) {
-               if (token->str[0] == '#' && g_ascii_isdigit(token->str[1])) {
-                       /* Numeric value beginning with # is a new timestamp value */
-                       uint64_t timestamp;
-                       timestamp = strtoull(token->str + 1, NULL, 10);
-
-                       if (ctx->downsample > 1)
-                               timestamp /= ctx->downsample;
-
-                       /*
-                        * Skip < 0 => skip until first timestamp.
-                        * Skip = 0 => don't skip
-                        * Skip > 0 => skip until timestamp >= skip.
-                        */
-                       if (ctx->skip < 0) {
-                               ctx->skip = timestamp;
-                               prev_timestamp = timestamp;
-                       } else if (ctx->skip > 0 && timestamp < (uint64_t)ctx->skip) {
-                               prev_timestamp = ctx->skip;
-                       }
-                       else if (timestamp == prev_timestamp) {
-                               /* Ignore repeated timestamps (e.g. sigrok outputs these) */
-                       }
-                       else {
-                               if (ctx->compress != 0 && timestamp - prev_timestamp > ctx->compress)
-                               {
-                                       /* Compress long idle periods */
-                                       prev_timestamp = timestamp - ctx->compress;
-                               }
-
-                               sr_dbg("New timestamp: %" PRIu64, timestamp);
-
-                               /* Generate samples from prev_timestamp up to timestamp - 1. */
-                               send_samples(sdi, prev_values, timestamp - prev_timestamp);
-                               prev_timestamp = timestamp;
-                       }
-               } else if (token->str[0] == '$' && token->len > 1) {
-                       /* This is probably a $dumpvars, $comment or similar.
-                        * $dump* contain useful data, but other tags will be skipped until $end. */
-                       if (g_strcmp0(token->str, "$dumpvars") == 0
-                                       || g_strcmp0(token->str, "$dumpon") == 0
-                                       || g_strcmp0(token->str, "$dumpoff") == 0
-                                       || g_strcmp0(token->str, "$end") == 0) {
-                               /* Ignore, parse contents as normally. */
-                       } else {
-                               /* Skip until $end */
-                               read_until(file, NULL, '$');
-                       }
-               }
-               else if (strchr("bBrR", token->str[0]) != NULL) {
-                       /* A vector value. Skip it and also the following identifier. */
-                       read_until(file, NULL, 'N');
-                       read_until(file, NULL, 'W');
-               } else if (strchr("01xXzZ", token->str[0]) != NULL) {
-                       /* A new 1-bit sample value */
-                       int i, bit;
-                       GSList *l;
-                       struct vcd_channel *vcd_ch;
-
-                       bit = (token->str[0] == '1');
-
-                       g_string_erase(token, 0, 1);
-                       if (token->len == 0) {
-                               /* There was a space between value and identifier.
-                                * Read in the rest.
-                                */
-                               read_until(file, NULL, 'N');
-                               read_until(file, token, 'W');
-                       }
-
-                       for (i = 0, l = ctx->channels; i < ctx->channelcount && l; i++, l = l->next) {
-                               vcd_ch = l->data;
-
-                               if (g_strcmp0(token->str, vcd_ch->identifier) == 0) {
-                                       /* Found our channel */
-                                       if (bit)
-                                               prev_values |= (uint64_t)1 << i;
-                                       else
-                                               prev_values &= ~((uint64_t)1 << i);
-
-                                       break;
-                               }
-                       }
-
-                       if (i == ctx->channelcount)
-                               sr_dbg("Did not find channel for identifier '%s'.", token->str);
-               } else {
-                       sr_warn("Skipping unknown token '%s'.", token->str);
-               }
-
-               g_string_truncate(token, 0);
-       }
-
-       g_string_free(token, TRUE);
-}
-
-static int loadfile(struct sr_input *in, const char *filename)
-{
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_meta meta;
-       struct sr_config *src;
-       FILE *file;
-       struct context *ctx;
-       uint64_t samplerate;
-
-       ctx = in->internal;
-
-       if ((file = fopen(filename, "r")) == NULL)
-               return SR_ERR;
-
-       if (!parse_header(file, ctx)) {
-               sr_err("VCD parsing failed");
-               fclose(file);
-               return SR_ERR;
-       }
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(in->sdi, LOG_PREFIX);
-
-       /* Send metadata about the SR_DF_LOGIC packets to come. */
-       packet.type = SR_DF_META;
-       packet.payload = &meta;
-       samplerate = ctx->samplerate / ctx->downsample;
-       src = sr_config_new(SR_CONF_SAMPLERATE, g_variant_new_uint64(samplerate));
-       meta.config = g_slist_append(NULL, src);
-       sr_session_send(in->sdi, &packet);
-       sr_config_free(src);
-
-       /* Parse the contents of the VCD file */
-       parse_contents(file, in->sdi, ctx);
-
-       /* Send end packet to the session bus. */
-       packet.type = SR_DF_END;
-       sr_session_send(in->sdi, &packet);
-
-       fclose(file);
-       release_context(ctx);
-       in->internal = NULL;
-
-       return SR_OK;
-}
-
-SR_PRIV struct sr_input_format input_vcd = {
-       .id = "vcd",
-       .description = "Value Change Dump",
-       .format_match = format_match,
-       .init = init,
-       .loadfile = loadfile,
-};
diff --git a/input/wav.c b/input/wav.c
deleted file mode 100644 (file)
index 1c3f050..0000000
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Bert Vermeulen <bert@biot.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 <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <string.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "input/wav"
-
-#define CHUNK_SIZE 4096
-
-struct context {
-       uint64_t samplerate;
-       int samplesize;
-       int num_channels;
-};
-
-static int get_wav_header(const char *filename, char *buf)
-{
-       struct stat st;
-       int fd, l;
-
-       l = strlen(filename);
-       if (l <= 4 || strcasecmp(filename + l - 4, ".wav"))
-               return SR_ERR;
-
-       if (stat(filename, &st) == -1)
-               return SR_ERR;
-       if (st.st_size <= 45)
-               /* Minimum size of header + 1 8-bit mono PCM sample. */
-               return SR_ERR;
-
-       if ((fd = open(filename, O_RDONLY)) == -1)
-               return SR_ERR;
-
-       l = read(fd, buf, 40);
-       close(fd);
-       if (l != 40)
-               return SR_ERR;
-
-       return SR_OK;
-}
-
-static int format_match(const char *filename)
-{
-       char buf[40];
-
-       if (get_wav_header(filename, buf) != SR_OK)
-               return FALSE;
-
-       if (strncmp(buf, "RIFF", 4))
-               return FALSE;
-       if (strncmp(buf + 8, "WAVE", 4))
-               return FALSE;
-       if (strncmp(buf + 12, "fmt ", 4))
-               return FALSE;
-       if (GUINT16_FROM_LE(*(uint16_t *)(buf + 20)) != 1)
-               /* Not PCM. */
-               return FALSE;
-       if (strncmp(buf + 36, "data", 4))
-               return FALSE;
-
-       return TRUE;
-}
-
-static int init(struct sr_input *in, const char *filename)
-{
-       struct sr_channel *ch;
-       struct context *ctx;
-       char buf[40], channelname[8];
-       int i;
-
-       if (get_wav_header(filename, buf) != SR_OK)
-               return SR_ERR;
-
-       if (!(ctx = g_try_malloc0(sizeof(struct context))))
-               return SR_ERR_MALLOC;
-
-       /* Create a virtual device. */
-       in->sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, NULL, NULL, NULL);
-       in->sdi->priv = ctx;
-
-       ctx->samplerate = GUINT32_FROM_LE(*(uint32_t *)(buf + 24));
-       ctx->samplesize = GUINT16_FROM_LE(*(uint16_t *)(buf + 34)) / 8;
-       if (ctx->samplesize != 1 && ctx->samplesize != 2 && ctx->samplesize != 4) {
-               sr_err("only 8, 16 or 32 bits per sample supported.");
-               return SR_ERR;
-       }
-
-       if ((ctx->num_channels = GUINT16_FROM_LE(*(uint16_t *)(buf + 22))) > 20) {
-               sr_err("%d channels seems crazy.", ctx->num_channels);
-               return SR_ERR;
-       }
-
-       for (i = 0; i < ctx->num_channels; i++) {
-               snprintf(channelname, 8, "CH%d", i + 1);
-               if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, channelname)))
-                       return SR_ERR;
-               in->sdi->channels = g_slist_append(in->sdi->channels, ch);
-       }
-
-       return SR_OK;
-}
-
-static int loadfile(struct sr_input *in, const char *filename)
-{
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_meta meta;
-       struct sr_datafeed_analog analog;
-       struct sr_config *src;
-       struct context *ctx;
-       float fdata[CHUNK_SIZE];
-       uint64_t sample;
-       int num_samples, chunk_samples, s, c, fd, l;
-       char buf[CHUNK_SIZE];
-
-       ctx = in->sdi->priv;
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(in->sdi, LOG_PREFIX);
-
-       packet.type = SR_DF_META;
-       packet.payload = &meta;
-       src = sr_config_new(SR_CONF_SAMPLERATE,
-                       g_variant_new_uint64(ctx->samplerate));
-       meta.config = g_slist_append(NULL, src);
-       sr_session_send(in->sdi, &packet);
-       sr_config_free(src);
-
-       if ((fd = open(filename, O_RDONLY)) == -1)
-               return SR_ERR;
-
-       lseek(fd, 40, SEEK_SET);
-       l = read(fd, buf, 4);
-       num_samples = GUINT32_FROM_LE((uint32_t)*(buf));
-       num_samples /= ctx->samplesize / ctx->num_channels;
-       while (TRUE) {
-               if ((l = read(fd, buf, CHUNK_SIZE)) < 1)
-                       break;
-               chunk_samples = l / ctx->samplesize / ctx->num_channels;
-               for (s = 0; s < chunk_samples; s++) {
-                       for (c = 0; c < ctx->num_channels; c++) {
-                               sample = 0;
-                               memcpy(&sample, buf + s * ctx->samplesize + c, ctx->samplesize);
-                               switch (ctx->samplesize) {
-                               case 1:
-                                       /* 8-bit PCM samples are unsigned. */
-                                       fdata[s + c] = (uint8_t)sample / 255.0;
-                                       break;
-                               case 2:
-                                       fdata[s + c] = GINT16_FROM_LE(sample) / 32767.0;
-                                       break;
-                               case 4:
-                                       fdata[s + c] = GINT32_FROM_LE(sample) / 65535.0;
-                                       break;
-                               }
-                       }
-               }
-               packet.type = SR_DF_ANALOG;
-               packet.payload = &analog;
-               analog.channels = in->sdi->channels;
-               analog.num_samples = chunk_samples;
-               analog.mq = 0;
-               analog.unit = 0;
-               analog.data = fdata;
-               sr_session_send(in->sdi, &packet);
-       }
-
-       close(fd);
-       packet.type = SR_DF_END;
-       sr_session_send(in->sdi, &packet);
-
-       return SR_OK;
-}
-
-
-SR_PRIV struct sr_input_format input_wav = {
-       .id = "wav",
-       .description = "WAV file",
-       .format_match = format_match,
-       .init = init,
-       .loadfile = loadfile,
-};
-
diff --git a/libsigrok-internal.h b/libsigrok-internal.h
deleted file mode 100644 (file)
index 8c58bd9..0000000
+++ /dev/null
@@ -1,642 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Bert Vermeulen <bert@biot.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/>.
- */
-
-/** @file
-  * @internal
-  */
-
-#ifndef LIBSIGROK_LIBSIGROK_INTERNAL_H
-#define LIBSIGROK_LIBSIGROK_INTERNAL_H
-
-#include <stdarg.h>
-#include <glib.h>
-#include "config.h" /* Needed for HAVE_LIBUSB_1_0 and others. */
-#ifdef HAVE_LIBUSB_1_0
-#include <libusb.h>
-#endif
-#ifdef HAVE_LIBSERIALPORT
-#include <libserialport.h>
-#endif
-
-/**
- * @file
- *
- * libsigrok private header file, only to be used internally.
- */
-
-/*--- Macros ----------------------------------------------------------------*/
-
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
-#endif
-
-#ifndef ARRAY_AND_SIZE
-#define ARRAY_AND_SIZE(a) (a), ARRAY_SIZE(a)
-#endif
-
-/**
- * Read a 8 bits integer out of memory.
- * @param x a pointer to the input memory
- * @return the corresponding integer
- */
-#define R8(x)     ((unsigned)((const uint8_t*)(x))[0])
-
-/**
- * Read a 16 bits big endian integer out of memory.
- * @param x a pointer to the input memory
- * @return the corresponding integer
- */
-#define RB16(x)  (((unsigned)((const uint8_t*)(x))[0] <<  8) |  \
-                   (unsigned)((const uint8_t*)(x))[1])
-
-/**
- * Read a 16 bits little endian integer out of memory.
- * @param x a pointer to the input memory
- * @return the corresponding integer
- */
-#define RL16(x)  (((unsigned)((const uint8_t*)(x))[1] <<  8) | \
-                   (unsigned)((const uint8_t*)(x))[0])
-
-/**
- * Read a 32 bits big endian integer out of memory.
- * @param x a pointer to the input memory
- * @return the corresponding integer
- */
-#define RB32(x)  (((unsigned)((const uint8_t*)(x))[0] << 24) | \
-                  ((unsigned)((const uint8_t*)(x))[1] << 16) |  \
-                  ((unsigned)((const uint8_t*)(x))[2] <<  8) |  \
-                   (unsigned)((const uint8_t*)(x))[3])
-
-/**
- * Read a 32 bits little endian integer out of memory.
- * @param x a pointer to the input memory
- * @return the corresponding integer
- */
-#define RL32(x)  (((unsigned)((const uint8_t*)(x))[3] << 24) | \
-                  ((unsigned)((const uint8_t*)(x))[2] << 16) |  \
-                  ((unsigned)((const uint8_t*)(x))[1] <<  8) |  \
-                   (unsigned)((const uint8_t*)(x))[0])
-
-/**
- * Write a 8 bits integer to memory.
- * @param p a pointer to the output memory
- * @param x the input integer
- */
-#define W8(p, x)    do { ((uint8_t*)(p))[0] = (uint8_t) (x);      } while(0)
-
-/**
- * Write a 16 bits integer to memory stored as big endian.
- * @param p a pointer to the output memory
- * @param x the input integer
- */
-#define WB16(p, x)  do { ((uint8_t*)(p))[1] = (uint8_t) (x);      \
-                         ((uint8_t*)(p))[0] = (uint8_t)((x)>>8);  } while(0)
-
-/**
- * Write a 16 bits integer to memory stored as little endian.
- * @param p a pointer to the output memory
- * @param x the input integer
- */
-#define WL16(p, x)  do { ((uint8_t*)(p))[0] = (uint8_t) (x);      \
-                         ((uint8_t*)(p))[1] = (uint8_t)((x)>>8);  } while(0)
-
-/**
- * Write a 32 bits integer to memory stored as big endian.
- * @param p a pointer to the output memory
- * @param x the input integer
- */
-#define WB32(p, x)  do { ((uint8_t*)(p))[3] = (uint8_t) (x);      \
-                         ((uint8_t*)(p))[2] = (uint8_t)((x)>>8);  \
-                         ((uint8_t*)(p))[1] = (uint8_t)((x)>>16); \
-                         ((uint8_t*)(p))[0] = (uint8_t)((x)>>24); } while(0)
-
-/**
- * Write a 32 bits integer to memory stored as little endian.
- * @param p a pointer to the output memory
- * @param x the input integer
- */
-#define WL32(p, x)  do { ((uint8_t*)(p))[0] = (uint8_t) (x);      \
-                         ((uint8_t*)(p))[1] = (uint8_t)((x)>>8);  \
-                         ((uint8_t*)(p))[2] = (uint8_t)((x)>>16); \
-                         ((uint8_t*)(p))[3] = (uint8_t)((x)>>24); } while(0)
-
-/* Portability fixes for FreeBSD. */
-#ifdef __FreeBSD__
-#define LIBUSB_CLASS_APPLICATION 0xfe
-#define libusb_handle_events_timeout_completed(ctx, tv, c) \
-       libusb_handle_events_timeout(ctx, tv)
-#endif
-
-struct sr_context {
-#ifdef HAVE_LIBUSB_1_0
-       libusb_context *libusb_ctx;
-       gboolean usb_source_present;
-#ifdef _WIN32
-       GThread *usb_thread;
-       gboolean usb_thread_running;
-       GMutex usb_mutex;
-       HANDLE usb_event;
-       GPollFD usb_pollfd;
-       sr_receive_data_callback usb_cb;
-       void *usb_cb_data;
-#endif
-#endif
-};
-
-#ifdef HAVE_LIBUSB_1_0
-/** USB device instance */
-struct sr_usb_dev_inst {
-       /** USB bus */
-       uint8_t bus;
-       /** Device address on USB bus */
-       uint8_t address;
-       /** libusb device handle */
-       struct libusb_device_handle *devhdl;
-};
-#endif
-
-#ifdef HAVE_LIBSERIALPORT
-#define SERIAL_PARITY_NONE SP_PARITY_NONE
-#define SERIAL_PARITY_EVEN SP_PARITY_EVEN
-#define SERIAL_PARITY_ODD  SP_PARITY_ODD
-struct sr_serial_dev_inst {
-       /** Port name, e.g. '/dev/tty42'. */
-       char *port;
-       /** Comm params for serial_set_paramstr(). */
-       char *serialcomm;
-       /** Port is non-blocking. */
-       int nonblocking;
-       /** libserialport port handle */
-       struct sp_port *data;
-       /** libserialport event set */
-       struct sp_event_set *event_set;
-       /** GPollFDs for event polling */
-       GPollFD *pollfds;
-};
-#endif
-
-struct sr_usbtmc_dev_inst {
-       char *device;
-       int fd;
-};
-
-/* Private driver context. */
-struct drv_context {
-       /** sigrok context */
-       struct sr_context *sr_ctx;
-       GSList *instances;
-};
-
-/*--- log.c -----------------------------------------------------------------*/
-
-SR_PRIV int sr_log(int loglevel, const char *format, ...);
-SR_PRIV int sr_spew(const char *format, ...);
-SR_PRIV int sr_dbg(const char *format, ...);
-SR_PRIV int sr_info(const char *format, ...);
-SR_PRIV int sr_warn(const char *format, ...);
-SR_PRIV int sr_err(const char *format, ...);
-
-/* Message logging helpers with subsystem-specific prefix string. */
-#ifndef NO_LOG_WRAPPERS
-#define sr_log(l, s, args...) sr_log(l, "%s: " s, LOG_PREFIX, ## args)
-#define sr_spew(s, args...) sr_spew("%s: " s, LOG_PREFIX, ## args)
-#define sr_dbg(s, args...) sr_dbg("%s: " s, LOG_PREFIX, ## args)
-#define sr_info(s, args...) sr_info("%s: " s, LOG_PREFIX, ## args)
-#define sr_warn(s, args...) sr_warn("%s: " s, LOG_PREFIX, ## args)
-#define sr_err(s, args...) sr_err("%s: " s, LOG_PREFIX, ## args)
-#endif
-
-/*--- device.c --------------------------------------------------------------*/
-
-/** Values for the changes argument of sr_dev_driver.config_channel_set. */
-enum {
-       /** The enabled state of the channel has been changed. */
-       SR_CHANNEL_SET_ENABLED = 1 << 0,
-};
-
-SR_PRIV struct sr_channel *sr_channel_new(int index, int type,
-               gboolean enabled, const char *name);
-
-/* Generic device instances */
-SR_PRIV struct sr_dev_inst *sr_dev_inst_new(int index, int status,
-               const char *vendor, const char *model, const char *version);
-SR_PRIV void sr_dev_inst_free(struct sr_dev_inst *sdi);
-
-#ifdef HAVE_LIBUSB_1_0
-/* USB-specific instances */
-SR_PRIV struct sr_usb_dev_inst *sr_usb_dev_inst_new(uint8_t bus,
-               uint8_t address, struct libusb_device_handle *hdl);
-SR_PRIV void sr_usb_dev_inst_free(struct sr_usb_dev_inst *usb);
-#endif
-
-#ifdef HAVE_LIBSERIALPORT
-/* Serial-specific instances */
-SR_PRIV struct sr_serial_dev_inst *sr_serial_dev_inst_new(const char *port,
-               const char *serialcomm);
-SR_PRIV void sr_serial_dev_inst_free(struct sr_serial_dev_inst *serial);
-#endif
-
-/* USBTMC-specific instances */
-SR_PRIV struct sr_usbtmc_dev_inst *sr_usbtmc_dev_inst_new(const char *device);
-SR_PRIV void sr_usbtmc_dev_inst_free(struct sr_usbtmc_dev_inst *usbtmc);
-
-/*--- hwdriver.c ------------------------------------------------------------*/
-
-SR_PRIV void sr_hw_cleanup_all(void);
-SR_PRIV struct sr_config *sr_config_new(int key, GVariant *data);
-SR_PRIV void sr_config_free(struct sr_config *src);
-SR_PRIV int sr_source_remove(int fd);
-SR_PRIV int sr_source_remove_pollfd(GPollFD *pollfd);
-SR_PRIV int sr_source_remove_channel(GIOChannel *channel);
-SR_PRIV int sr_source_add(int fd, int events, int timeout,
-               sr_receive_data_callback cb, void *cb_data);
-SR_PRIV int sr_source_add_pollfd(GPollFD *pollfd, int timeout,
-               sr_receive_data_callback cb, void *cb_data);
-SR_PRIV int sr_source_add_channel(GIOChannel *channel, int events, int timeout,
-               sr_receive_data_callback cb, void *cb_data);
-
-/*--- session.c -------------------------------------------------------------*/
-
-struct sr_session {
-       /** List of struct sr_dev pointers. */
-       GSList *devs;
-       /** List of struct datafeed_callback pointers. */
-       GSList *datafeed_callbacks;
-       struct sr_trigger *trigger;
-       GTimeVal starttime;
-       gboolean running;
-
-       unsigned int num_sources;
-
-       /*
-        * Both "sources" and "pollfds" are of the same size and contain pairs
-        * of descriptor and callback function. We can not embed the GPollFD
-        * into the source struct since we want to be able to pass the array
-        * of all poll descriptors to g_poll().
-        */
-       struct source *sources;
-       GPollFD *pollfds;
-       int source_timeout;
-
-       /*
-        * These are our synchronization primitives for stopping the session in
-        * an async fashion. We need to make sure the session is stopped from
-        * within the session thread itself.
-        */
-       /** Mutex protecting access to abort_session. */
-       GMutex stop_mutex;
-       /** Abort current session. See sr_session_stop(). */
-       gboolean abort_session;
-};
-
-SR_PRIV int sr_session_send(const struct sr_dev_inst *sdi,
-               const struct sr_datafeed_packet *packet);
-SR_PRIV int sr_session_stop_sync(struct sr_session *session);
-SR_PRIV int sr_sessionfile_check(const char *filename);
-
-/*--- std.c -----------------------------------------------------------------*/
-
-typedef int (*dev_close_callback)(struct sr_dev_inst *sdi);
-typedef void (*std_dev_clear_callback)(void *priv);
-
-SR_PRIV int std_init(struct sr_context *sr_ctx, struct sr_dev_driver *di,
-               const char *prefix);
-#ifdef HAVE_LIBSERIALPORT
-SR_PRIV int std_serial_dev_open(struct sr_dev_inst *sdi);
-SR_PRIV int std_serial_dev_acquisition_stop(struct sr_dev_inst *sdi,
-               void *cb_data, dev_close_callback dev_close_fn,
-               struct sr_serial_dev_inst *serial, const char *prefix);
-#endif
-SR_PRIV int std_session_send_df_header(const struct sr_dev_inst *sdi,
-               const char *prefix);
-SR_PRIV int std_dev_clear(const struct sr_dev_driver *driver,
-               std_dev_clear_callback clear_private);
-SR_PRIV int std_serial_dev_close(struct sr_dev_inst *sdi);
-
-/*--- strutil.c -------------------------------------------------------------*/
-
-SR_PRIV int sr_atol(const char *str, long *ret);
-SR_PRIV int sr_atoi(const char *str, int *ret);
-SR_PRIV int sr_atod(const char *str, double *ret);
-SR_PRIV int sr_atof(const char *str, float *ret);
-SR_PRIV int sr_atof_ascii(const char *str, float *ret);
-
-/*--- soft-trigger.c --------------------------------------------------------*/
-
-struct soft_trigger_logic {
-       const struct sr_dev_inst *sdi;
-       const struct sr_trigger *trigger;
-       int count;
-       int unitsize;
-       int cur_stage;
-       uint8_t *prev_sample;
-};
-
-SR_PRIV struct soft_trigger_logic *soft_trigger_logic_new(
-               const struct sr_dev_inst *sdi, struct sr_trigger *trigger);
-SR_PRIV void soft_trigger_logic_free(struct soft_trigger_logic *st);
-SR_PRIV int soft_trigger_logic_check(struct soft_trigger_logic *st, uint8_t *buf,
-               int len);
-
-/*--- hardware/common/serial.c ----------------------------------------------*/
-
-#ifdef HAVE_LIBSERIALPORT
-enum {
-       SERIAL_RDWR = 1,
-       SERIAL_RDONLY = 2,
-       SERIAL_NONBLOCK = 4,
-};
-
-typedef gboolean (*packet_valid_callback)(const uint8_t *buf);
-
-SR_PRIV int serial_open(struct sr_serial_dev_inst *serial, int flags);
-SR_PRIV int serial_close(struct sr_serial_dev_inst *serial);
-SR_PRIV int serial_flush(struct sr_serial_dev_inst *serial);
-SR_PRIV int serial_write(struct sr_serial_dev_inst *serial,
-               const void *buf, size_t count);
-SR_PRIV int serial_write_blocking(struct sr_serial_dev_inst *serial,
-               const void *buf, size_t count);
-SR_PRIV int serial_write_nonblocking(struct sr_serial_dev_inst *serial,
-               const void *buf, size_t count);
-SR_PRIV int serial_read(struct sr_serial_dev_inst *serial, void *buf,
-               size_t count);
-SR_PRIV int serial_read_blocking(struct sr_serial_dev_inst *serial, void *buf,
-               size_t count);
-SR_PRIV int serial_read_nonblocking(struct sr_serial_dev_inst *serial, void *buf,
-               size_t count);
-SR_PRIV int serial_set_params(struct sr_serial_dev_inst *serial, int baudrate,
-               int bits, int parity, int stopbits, int flowcontrol, int rts, int dtr);
-SR_PRIV int serial_set_paramstr(struct sr_serial_dev_inst *serial,
-               const char *paramstr);
-SR_PRIV int serial_readline(struct sr_serial_dev_inst *serial, char **buf,
-               int *buflen, gint64 timeout_ms);
-SR_PRIV int serial_stream_detect(struct sr_serial_dev_inst *serial,
-                                uint8_t *buf, size_t *buflen,
-                                size_t packet_size,
-                                packet_valid_callback is_valid,
-                                uint64_t timeout_ms, int baudrate);
-SR_PRIV int sr_serial_extract_options(GSList *options, const char **serial_device,
-                                     const char **serial_options);
-SR_PRIV int serial_source_add(struct sr_session *session,
-               struct sr_serial_dev_inst *serial, int events, int timeout,
-               sr_receive_data_callback cb, void *cb_data);
-SR_PRIV int serial_source_remove(struct sr_session *session,
-               struct sr_serial_dev_inst *serial);
-SR_PRIV GSList *sr_serial_find_usb(uint16_t vendor_id, uint16_t product_id);
-#endif
-
-/*--- hardware/common/ezusb.c -----------------------------------------------*/
-
-#ifdef HAVE_LIBUSB_1_0
-SR_PRIV int ezusb_reset(struct libusb_device_handle *hdl, int set_clear);
-SR_PRIV int ezusb_install_firmware(libusb_device_handle *hdl,
-                                  const char *filename);
-SR_PRIV int ezusb_upload_firmware(libusb_device *dev, int configuration,
-                                 const char *filename);
-#endif
-
-/*--- hardware/common/usb.c -------------------------------------------------*/
-
-#ifdef HAVE_LIBUSB_1_0
-SR_PRIV GSList *sr_usb_find(libusb_context *usb_ctx, const char *conn);
-SR_PRIV int sr_usb_open(libusb_context *usb_ctx, struct sr_usb_dev_inst *usb);
-SR_PRIV int usb_source_add(struct sr_session *session, struct sr_context *ctx,
-               int timeout, sr_receive_data_callback cb, void *cb_data);
-SR_PRIV int usb_source_remove(struct sr_session *session, struct sr_context *ctx);
-#endif
-
-/*--- hardware/common/scpi.c ------------------------------------------------*/
-
-#define SCPI_CMD_IDN "*IDN?"
-#define SCPI_CMD_OPC "*OPC?"
-
-enum {
-       SCPI_CMD_SET_TRIGGER_SOURCE,
-       SCPI_CMD_SET_TIMEBASE,
-       SCPI_CMD_SET_VERTICAL_DIV,
-       SCPI_CMD_SET_TRIGGER_SLOPE,
-       SCPI_CMD_SET_COUPLING,
-       SCPI_CMD_SET_HORIZ_TRIGGERPOS,
-       SCPI_CMD_GET_ANALOG_CHAN_STATE,
-       SCPI_CMD_GET_DIG_CHAN_STATE,
-       SCPI_CMD_GET_TIMEBASE,
-       SCPI_CMD_GET_VERTICAL_DIV,
-       SCPI_CMD_GET_VERTICAL_OFFSET,
-       SCPI_CMD_GET_TRIGGER_SOURCE,
-       SCPI_CMD_GET_HORIZ_TRIGGERPOS,
-       SCPI_CMD_GET_TRIGGER_SLOPE,
-       SCPI_CMD_GET_COUPLING,
-       SCPI_CMD_SET_ANALOG_CHAN_STATE,
-       SCPI_CMD_SET_DIG_CHAN_STATE,
-       SCPI_CMD_GET_DIG_POD_STATE,
-       SCPI_CMD_SET_DIG_POD_STATE,
-       SCPI_CMD_GET_ANALOG_DATA,
-       SCPI_CMD_GET_DIG_DATA,
-       SCPI_CMD_GET_SAMPLE_RATE,
-       SCPI_CMD_GET_SAMPLE_RATE_LIVE,
-};
-
-struct sr_scpi_hw_info {
-       char *manufacturer;
-       char *model;
-       char *serial_number;
-       char *firmware_version;
-};
-
-struct sr_scpi_dev_inst {
-       const char *name;
-       const char *prefix;
-       int priv_size;
-       GSList *(*scan)(struct drv_context *drvc);
-       int (*dev_inst_new)(void *priv, struct drv_context *drvc,
-               const char *resource, char **params, const char *serialcomm);
-       int (*open)(void *priv);
-       int (*source_add)(struct sr_session *session, void *priv, int events,
-               int timeout, sr_receive_data_callback cb, void *cb_data);
-       int (*source_remove)(struct sr_session *session, void *priv);
-       int (*send)(void *priv, const char *command);
-       int (*read_begin)(void *priv);
-       int (*read_data)(void *priv, char *buf, int maxlen);
-       int (*read_complete)(void *priv);
-       int (*close)(void *priv);
-       void (*free)(void *priv);
-       void *priv;
-};
-
-SR_PRIV GSList *sr_scpi_scan(struct drv_context *drvc, GSList *options,
-               struct sr_dev_inst *(*probe_device)(struct sr_scpi_dev_inst *scpi));
-SR_PRIV struct sr_scpi_dev_inst *scpi_dev_inst_new(struct drv_context *drvc,
-               const char *resource, const char *serialcomm);
-SR_PRIV int sr_scpi_open(struct sr_scpi_dev_inst *scpi);
-SR_PRIV int sr_scpi_source_add(struct sr_session *session,
-               struct sr_scpi_dev_inst *scpi, int events, int timeout,
-               sr_receive_data_callback cb, void *cb_data);
-SR_PRIV int sr_scpi_source_remove(struct sr_session *session,
-               struct sr_scpi_dev_inst *scpi);
-SR_PRIV int sr_scpi_send(struct sr_scpi_dev_inst *scpi,
-               const char *format, ...);
-SR_PRIV int sr_scpi_send_variadic(struct sr_scpi_dev_inst *scpi,
-               const char *format, va_list args);
-SR_PRIV int sr_scpi_read_begin(struct sr_scpi_dev_inst *scpi);
-SR_PRIV int sr_scpi_read_data(struct sr_scpi_dev_inst *scpi, char *buf, int maxlen);
-SR_PRIV int sr_scpi_read_complete(struct sr_scpi_dev_inst *scpi);
-SR_PRIV int sr_scpi_close(struct sr_scpi_dev_inst *scpi);
-SR_PRIV void sr_scpi_free(struct sr_scpi_dev_inst *scpi);
-
-SR_PRIV int sr_scpi_get_string(struct sr_scpi_dev_inst *scpi,
-                       const char *command, char **scpi_response);
-SR_PRIV int sr_scpi_get_bool(struct sr_scpi_dev_inst *scpi,
-                       const char *command, gboolean *scpi_response);
-SR_PRIV int sr_scpi_get_int(struct sr_scpi_dev_inst *scpi,
-                       const char *command, int *scpi_response);
-SR_PRIV int sr_scpi_get_float(struct sr_scpi_dev_inst *scpi,
-                       const char *command, float *scpi_response);
-SR_PRIV int sr_scpi_get_double(struct sr_scpi_dev_inst *scpi,
-                       const char *command, double *scpi_response);
-SR_PRIV int sr_scpi_get_opc(struct sr_scpi_dev_inst *scpi);
-SR_PRIV int sr_scpi_get_floatv(struct sr_scpi_dev_inst *scpi,
-                       const char *command, GArray **scpi_response);
-SR_PRIV int sr_scpi_get_uint8v(struct sr_scpi_dev_inst *scpi,
-                       const char *command, GArray **scpi_response);
-SR_PRIV int sr_scpi_get_hw_id(struct sr_scpi_dev_inst *scpi,
-                       struct sr_scpi_hw_info **scpi_response);
-SR_PRIV void sr_scpi_hw_info_free(struct sr_scpi_hw_info *hw_info);
-
-/*--- hardware/common/dmm/es519xx.c -----------------------------------------*/
-
-/**
- * All 11-byte es519xx chips repeat each block twice for each conversion cycle
- * so always read 2 blocks at a time.
- */
-#define ES519XX_11B_PACKET_SIZE (11 * 2)
-#define ES519XX_14B_PACKET_SIZE 14
-
-struct es519xx_info {
-       gboolean is_judge, is_voltage, is_auto, is_micro, is_current;
-       gboolean is_milli, is_resistance, is_continuity, is_diode;
-       gboolean is_frequency, is_rpm, is_capacitance, is_duty_cycle;
-       gboolean is_temperature, is_celsius, is_fahrenheit;
-       gboolean is_adp0, is_adp1, is_adp2, is_adp3;
-       gboolean is_sign, is_batt, is_ol, is_pmax, is_pmin, is_apo;
-       gboolean is_dc, is_ac, is_vahz, is_min, is_max, is_rel, is_hold;
-       gboolean is_digit4, is_ul, is_vasel, is_vbar, is_lpf1, is_lpf0, is_rmr;
-       uint32_t baudrate;
-       int packet_size;
-       gboolean alt_functions, fivedigits, clampmeter, selectable_lpf;
-};
-
-SR_PRIV gboolean sr_es519xx_2400_11b_packet_valid(const uint8_t *buf);
-SR_PRIV int sr_es519xx_2400_11b_parse(const uint8_t *buf, float *floatval,
-               struct sr_datafeed_analog *analog, void *info);
-SR_PRIV gboolean sr_es519xx_2400_11b_altfn_packet_valid(const uint8_t *buf);
-SR_PRIV int sr_es519xx_2400_11b_altfn_parse(const uint8_t *buf,
-               float *floatval, struct sr_datafeed_analog *analog, void *info);
-SR_PRIV gboolean sr_es519xx_19200_11b_5digits_packet_valid(const uint8_t *buf);
-SR_PRIV int sr_es519xx_19200_11b_5digits_parse(const uint8_t *buf,
-               float *floatval, struct sr_datafeed_analog *analog, void *info);
-SR_PRIV gboolean sr_es519xx_19200_11b_clamp_packet_valid(const uint8_t *buf);
-SR_PRIV int sr_es519xx_19200_11b_clamp_parse(const uint8_t *buf,
-               float *floatval, struct sr_datafeed_analog *analog, void *info);
-SR_PRIV gboolean sr_es519xx_19200_11b_packet_valid(const uint8_t *buf);
-SR_PRIV int sr_es519xx_19200_11b_parse(const uint8_t *buf, float *floatval,
-               struct sr_datafeed_analog *analog, void *info);
-SR_PRIV gboolean sr_es519xx_19200_14b_packet_valid(const uint8_t *buf);
-SR_PRIV int sr_es519xx_19200_14b_parse(const uint8_t *buf, float *floatval,
-               struct sr_datafeed_analog *analog, void *info);
-SR_PRIV gboolean sr_es519xx_19200_14b_sel_lpf_packet_valid(const uint8_t *buf);
-SR_PRIV int sr_es519xx_19200_14b_sel_lpf_parse(const uint8_t *buf,
-               float *floatval, struct sr_datafeed_analog *analog, void *info);
-
-/*--- hardware/common/dmm/fs9922.c ------------------------------------------*/
-
-#define FS9922_PACKET_SIZE 14
-
-struct fs9922_info {
-       gboolean is_auto, is_dc, is_ac, is_rel, is_hold, is_bpn, is_z1, is_z2;
-       gboolean is_max, is_min, is_apo, is_bat, is_nano, is_z3, is_micro;
-       gboolean is_milli, is_kilo, is_mega, is_beep, is_diode, is_percent;
-       gboolean is_z4, is_volt, is_ampere, is_ohm, is_hfe, is_hertz, is_farad;
-       gboolean is_celsius, is_fahrenheit;
-       int bargraph_sign, bargraph_value;
-};
-
-SR_PRIV gboolean sr_fs9922_packet_valid(const uint8_t *buf);
-SR_PRIV int sr_fs9922_parse(const uint8_t *buf, float *floatval,
-                           struct sr_datafeed_analog *analog, void *info);
-SR_PRIV void sr_fs9922_z1_diode(struct sr_datafeed_analog *analog, void *info);
-
-/*--- hardware/common/dmm/fs9721.c ------------------------------------------*/
-
-#define FS9721_PACKET_SIZE 14
-
-struct fs9721_info {
-       gboolean is_ac, is_dc, is_auto, is_rs232, is_micro, is_nano, is_kilo;
-       gboolean is_diode, is_milli, is_percent, is_mega, is_beep, is_farad;
-       gboolean is_ohm, is_rel, is_hold, is_ampere, is_volt, is_hz, is_bat;
-       gboolean is_c2c1_11, is_c2c1_10, is_c2c1_01, is_c2c1_00, is_sign;
-};
-
-SR_PRIV gboolean sr_fs9721_packet_valid(const uint8_t *buf);
-SR_PRIV int sr_fs9721_parse(const uint8_t *buf, float *floatval,
-                           struct sr_datafeed_analog *analog, void *info);
-SR_PRIV void sr_fs9721_00_temp_c(struct sr_datafeed_analog *analog, void *info);
-SR_PRIV void sr_fs9721_01_temp_c(struct sr_datafeed_analog *analog, void *info);
-SR_PRIV void sr_fs9721_10_temp_c(struct sr_datafeed_analog *analog, void *info);
-SR_PRIV void sr_fs9721_01_10_temp_f_c(struct sr_datafeed_analog *analog, void *info);
-SR_PRIV void sr_fs9721_max_c_min(struct sr_datafeed_analog *analog, void *info);
-
-/*--- hardware/common/dmm/m2110.c -----------------------------------------*/
-
-#define BBCGM_M2110_PACKET_SIZE 9
-
-SR_PRIV gboolean sr_m2110_packet_valid(const uint8_t *buf);
-SR_PRIV int sr_m2110_parse(const uint8_t *buf, float *floatval,
-                            struct sr_datafeed_analog *analog, void *info);
-
-/*--- hardware/common/dmm/metex14.c -----------------------------------------*/
-
-#define METEX14_PACKET_SIZE 14
-
-struct metex14_info {
-       gboolean is_ac, is_dc, is_resistance, is_capacity, is_temperature;
-       gboolean is_diode, is_frequency, is_ampere, is_volt, is_farad;
-       gboolean is_hertz, is_ohm, is_celsius, is_pico, is_nano, is_micro;
-       gboolean is_milli, is_kilo, is_mega, is_gain, is_decibel, is_hfe;
-       gboolean is_unitless, is_logic;
-};
-
-#ifdef HAVE_LIBSERIALPORT
-SR_PRIV int sr_metex14_packet_request(struct sr_serial_dev_inst *serial);
-#endif
-SR_PRIV gboolean sr_metex14_packet_valid(const uint8_t *buf);
-SR_PRIV int sr_metex14_parse(const uint8_t *buf, float *floatval,
-                            struct sr_datafeed_analog *analog, void *info);
-
-/*--- hardware/common/dmm/rs9lcd.c ------------------------------------------*/
-
-#define RS9LCD_PACKET_SIZE 9
-
-/* Dummy info struct. The parser does not use it. */
-struct rs9lcd_info { int dummy; };
-
-SR_PRIV gboolean sr_rs9lcd_packet_valid(const uint8_t *buf);
-SR_PRIV int sr_rs9lcd_parse(const uint8_t *buf, float *floatval,
-                           struct sr_datafeed_analog *analog, void *info);
-
-#endif
diff --git a/log.c b/log.c
deleted file mode 100644 (file)
index db16c30..0000000
--- a/log.c
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2011-2012 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include <stdarg.h>
-#include <stdio.h>
-#include "libsigrok.h"
-/** @cond PRIVATE */
-#define NO_LOG_WRAPPERS
-/** @endcond */
-#include "libsigrok-internal.h"
-
-/**
- * @file
- *
- * Controlling the libsigrok message logging functionality.
- */
-
-/**
- * @defgroup grp_logging Logging
- *
- * Controlling the libsigrok message logging functionality.
- *
- * @{
- */
-
-/* Currently selected libsigrok loglevel. Default: SR_LOG_WARN. */
-static int cur_loglevel = SR_LOG_WARN; /* Show errors+warnings per default. */
-
-/* Function prototype. */
-static int sr_logv(void *cb_data, int loglevel, const char *format,
-                  va_list args);
-
-/* Pointer to the currently selected log callback. Default: sr_logv(). */
-static sr_log_callback sr_log_cb = sr_logv;
-
-/*
- * Pointer to private data that can be passed to the log callback.
- * This can be used (for example) by C++ GUIs to pass a "this" pointer.
- */
-static void *sr_log_cb_data = NULL;
-
-/* Log domain (a short string that is used as prefix for all messages). */
-/** @cond PRIVATE */
-#define LOGDOMAIN_MAXLEN 30
-#define LOGDOMAIN_DEFAULT "sr: "
-/** @endcond */
-static char sr_log_domain[LOGDOMAIN_MAXLEN + 1] = LOGDOMAIN_DEFAULT;
-
-/**
- * Set the libsigrok loglevel.
- *
- * This influences the amount of log messages (debug messages, error messages,
- * and so on) libsigrok will output. Using SR_LOG_NONE disables all messages.
- *
- * Note that this function itself will also output log messages. After the
- * loglevel has changed, it will output a debug message with SR_LOG_DBG for
- * example. Whether this message is shown depends on the (new) loglevel.
- *
- * @param loglevel The loglevel to set (SR_LOG_NONE, SR_LOG_ERR, SR_LOG_WARN,
- *                 SR_LOG_INFO, SR_LOG_DBG, or SR_LOG_SPEW).
- *
- * @return SR_OK upon success, SR_ERR_ARG upon invalid loglevel.
- *
- * @since 0.1.0
- */
-SR_API int sr_log_loglevel_set(int loglevel)
-{
-       if (loglevel < SR_LOG_NONE || loglevel > SR_LOG_SPEW) {
-               sr_err("Invalid loglevel %d.", loglevel);
-               return SR_ERR_ARG;
-       }
-
-       cur_loglevel = loglevel;
-
-       sr_dbg("libsigrok loglevel set to %d.", loglevel);
-
-       return SR_OK;
-}
-
-/**
- * Get the libsigrok loglevel.
- *
- * @return The currently configured libsigrok loglevel.
- *
- * @since 0.1.0
- */
-SR_API int sr_log_loglevel_get(void)
-{
-       return cur_loglevel;
-}
-
-/**
- * Set the libsigrok logdomain string.
- *
- * @param logdomain The string to use as logdomain for libsigrok log
- *                  messages from now on. Must not be NULL. The maximum
- *                  length of the string is 30 characters (this does not
- *                  include the trailing NUL-byte). Longer strings are
- *                  silently truncated.
- *                  In order to not use a logdomain, pass an empty string.
- *                  The function makes its own copy of the input string, i.e.
- *                  the caller does not need to keep it around.
- *
- * @return SR_OK upon success, SR_ERR_ARG upon invalid logdomain.
- *
- * @since 0.1.0
- */
-SR_API int sr_log_logdomain_set(const char *logdomain)
-{
-       if (!logdomain) {
-               sr_err("log: %s: logdomain was NULL", __func__);
-               return SR_ERR_ARG;
-       }
-
-       /* TODO: Error handling. */
-       snprintf((char *)&sr_log_domain, LOGDOMAIN_MAXLEN, "%s", logdomain);
-
-       sr_dbg("Log domain set to '%s'.", (const char *)&sr_log_domain);
-
-       return SR_OK;
-}
-
-/**
- * Get the currently configured libsigrok logdomain.
- *
- * @return A copy of the currently configured libsigrok logdomain
- *         string. The caller is responsible for g_free()ing the string when
- *         it is no longer needed.
- *
- * @since 0.1.0
- */
-SR_API char *sr_log_logdomain_get(void)
-{
-       return g_strdup((const char *)&sr_log_domain);
-}
-
-/**
- * Set the libsigrok log callback to the specified function.
- *
- * @param cb Function pointer to the log callback function to use.
- *           Must not be NULL.
- * @param cb_data Pointer to private data to be passed on. This can be used by
- *                the caller to pass arbitrary data to the log functions. This
- *                pointer is only stored or passed on by libsigrok, and is
- *                never used or interpreted in any way. The pointer is allowed
- *                to be NULL if the caller doesn't need/want to pass any data.
- *
- * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments.
- *
- * @since 0.3.0
- */
-SR_API int sr_log_callback_set(sr_log_callback cb, void *cb_data)
-{
-       if (!cb) {
-               sr_err("log: %s: cb was NULL", __func__);
-               return SR_ERR_ARG;
-       }
-
-       /* Note: 'cb_data' is allowed to be NULL. */
-
-       sr_log_cb = cb;
-       sr_log_cb_data = cb_data;
-
-       return SR_OK;
-}
-
-/**
- * Set the libsigrok log callback to the default built-in one.
- *
- * Additionally, the internal 'sr_log_cb_data' pointer is set to NULL.
- *
- * @return SR_OK upon success, a negative error code otherwise.
- *
- * @since 0.1.0
- */
-SR_API int sr_log_callback_set_default(void)
-{
-       /*
-        * Note: No log output in this function, as it should safely work
-        * even if the currently set log callback is buggy/broken.
-        */
-       sr_log_cb = sr_logv;
-       sr_log_cb_data = NULL;
-
-       return SR_OK;
-}
-
-static int sr_logv(void *cb_data, int loglevel, const char *format, va_list args)
-{
-       int ret;
-
-       /* This specific log callback doesn't need the void pointer data. */
-       (void)cb_data;
-
-       /* Only output messages of at least the selected loglevel(s). */
-       if (loglevel > cur_loglevel)
-               return SR_OK; /* TODO? */
-
-       if (sr_log_domain[0] != '\0')
-               fprintf(stderr, "%s", sr_log_domain);
-       ret = vfprintf(stderr, format, args);
-       fprintf(stderr, "\n");
-
-       return ret;
-}
-
-/** @private */
-SR_PRIV int sr_log(int loglevel, const char *format, ...)
-{
-       int ret;
-       va_list args;
-
-       va_start(args, format);
-       ret = sr_log_cb(sr_log_cb_data, loglevel, format, args);
-       va_end(args);
-
-       return ret;
-}
-
-/** @private */
-SR_PRIV int sr_spew(const char *format, ...)
-{
-       int ret;
-       va_list args;
-
-       va_start(args, format);
-       ret = sr_log_cb(sr_log_cb_data, SR_LOG_SPEW, format, args);
-       va_end(args);
-
-       return ret;
-}
-
-/** @private */
-SR_PRIV int sr_dbg(const char *format, ...)
-{
-       int ret;
-       va_list args;
-
-       va_start(args, format);
-       ret = sr_log_cb(sr_log_cb_data, SR_LOG_DBG, format, args);
-       va_end(args);
-
-       return ret;
-}
-
-/** @private */
-SR_PRIV int sr_info(const char *format, ...)
-{
-       int ret;
-       va_list args;
-
-       va_start(args, format);
-       ret = sr_log_cb(sr_log_cb_data, SR_LOG_INFO, format, args);
-       va_end(args);
-
-       return ret;
-}
-
-/** @private */
-SR_PRIV int sr_warn(const char *format, ...)
-{
-       int ret;
-       va_list args;
-
-       va_start(args, format);
-       ret = sr_log_cb(sr_log_cb_data, SR_LOG_WARN, format, args);
-       va_end(args);
-
-       return ret;
-}
-
-/** @private */
-SR_PRIV int sr_err(const char *format, ...)
-{
-       int ret;
-       va_list args;
-
-       va_start(args, format);
-       ret = sr_log_cb(sr_log_cb_data, SR_LOG_ERR, format, args);
-       va_end(args);
-
-       return ret;
-}
-
-/** @} */
diff --git a/output/analog.c b/output/analog.c
deleted file mode 100644 (file)
index fbc41d8..0000000
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012 Bert Vermeulen <bert@biot.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 <stdlib.h>
-#include <string.h>
-#include <math.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "output/analog"
-
-struct context {
-       int num_enabled_channels;
-       GPtrArray *channellist;
-};
-
-static int init(struct sr_output *o)
-{
-       struct context *ctx;
-       struct sr_channel *ch;
-       GSList *l;
-
-       sr_spew("Initializing output module.");
-
-       if (!o || !o->sdi)
-               return SR_ERR_ARG;
-
-       if (!(ctx = g_try_malloc0(sizeof(struct context)))) {
-               sr_err("Output module context malloc failed.");
-               return SR_ERR_MALLOC;
-       }
-       o->internal = ctx;
-
-       /* Get the number of channels and their names. */
-       ctx->channellist = g_ptr_array_new();
-       for (l = o->sdi->channels; l; l = l->next) {
-               ch = l->data;
-               if (!ch || !ch->enabled)
-                       continue;
-               g_ptr_array_add(ctx->channellist, ch->name);
-               ctx->num_enabled_channels++;
-       }
-
-       return SR_OK;
-}
-
-static void si_printf(float value, GString *out, char *unitstr)
-{
-       float v;
-
-       if (signbit(value))
-               v = -(value);
-       else
-               v = value;
-
-       if (v < 1e-12 || v > 1e+12)
-               g_string_append_printf(out, "%f %s", value, unitstr);
-       else if (v > 1e+9)
-               g_string_append_printf(out, "%f G%s", value / 1e+9, unitstr);
-       else if (v > 1e+6)
-               g_string_append_printf(out, "%f M%s", value / 1e+6, unitstr);
-       else if (v > 1e+3)
-               g_string_append_printf(out, "%f k%s", value / 1e+3, unitstr);
-       else if (v < 1e-9)
-               g_string_append_printf(out, "%f n%s", value * 1e+9, unitstr);
-       else if (v < 1e-6)
-               g_string_append_printf(out, "%f u%s", value * 1e+6, unitstr);
-       else if (v < 1e-3)
-               g_string_append_printf(out, "%f m%s", value * 1e+3, unitstr);
-       else
-               g_string_append_printf(out, "%f %s", value, unitstr);
-
-}
-
-static void fancyprint(int unit, int mqflags, float value, GString *out)
-{
-       switch (unit) {
-       case SR_UNIT_VOLT:
-               si_printf(value, out, "V");
-               break;
-       case SR_UNIT_AMPERE:
-               si_printf(value, out, "A");
-               break;
-       case SR_UNIT_OHM:
-               si_printf(value, out, "");
-               g_string_append_unichar(out, 0x2126);
-               break;
-       case SR_UNIT_FARAD:
-               si_printf(value, out, "F");
-               break;
-       case SR_UNIT_KELVIN:
-               si_printf(value, out, "K");
-               break;
-       case SR_UNIT_CELSIUS:
-               si_printf(value, out, "");
-               g_string_append_unichar(out, 0x00b0);
-               g_string_append_c(out, 'C');
-               break;
-       case SR_UNIT_FAHRENHEIT:
-               si_printf(value, out, "");
-               g_string_append_unichar(out, 0x00b0);
-               g_string_append_c(out, 'F');
-               break;
-       case SR_UNIT_HERTZ:
-               si_printf(value, out, "Hz");
-               break;
-       case SR_UNIT_PERCENTAGE:
-               g_string_append_printf(out, "%f %%", value);
-               break;
-       case SR_UNIT_BOOLEAN:
-               if (value > 0)
-                       g_string_append_printf(out, "TRUE");
-               else
-                       g_string_append_printf(out, "FALSE");
-               break;
-       case SR_UNIT_SECOND:
-               si_printf(value, out, "s");
-               break;
-       case SR_UNIT_SIEMENS:
-               si_printf(value, out, "S");
-               break;
-       case SR_UNIT_DECIBEL_MW:
-               si_printf(value, out, "dBu");
-               break;
-       case SR_UNIT_DECIBEL_VOLT:
-               si_printf(value, out, "dBV");
-               break;
-       case SR_UNIT_DECIBEL_SPL:
-               if (mqflags & SR_MQFLAG_SPL_FREQ_WEIGHT_A)
-                       si_printf(value, out, "dB(A)");
-               else if (mqflags & SR_MQFLAG_SPL_FREQ_WEIGHT_C)
-                       si_printf(value, out, "dB(C)");
-               else if (mqflags & SR_MQFLAG_SPL_FREQ_WEIGHT_Z)
-                       si_printf(value, out, "dB(Z)");
-               else
-                       /* No frequency weighting, or non-standard "flat" */
-                       si_printf(value, out, "dB(SPL)");
-               if (mqflags & SR_MQFLAG_SPL_TIME_WEIGHT_S)
-                       g_string_append(out, " S");
-               else if (mqflags & SR_MQFLAG_SPL_TIME_WEIGHT_F)
-                       g_string_append(out, " F");
-               if (mqflags & SR_MQFLAG_SPL_LAT)
-                       g_string_append(out, " LAT");
-               else if (mqflags & SR_MQFLAG_SPL_PCT_OVER_ALARM)
-                       /* Not a standard function for SLMs, so this is
-                        * a made-up notation. */
-                       g_string_append(out, " %oA");
-               break;
-       case SR_UNIT_CONCENTRATION:
-               g_string_append_printf(out, "%f ppm", value * 1000000);
-               break;
-       case SR_UNIT_REVOLUTIONS_PER_MINUTE:
-               si_printf(value, out, "RPM");
-               break;
-       case SR_UNIT_VOLT_AMPERE:
-               si_printf(value, out, "VA");
-               break;
-       case SR_UNIT_WATT:
-               si_printf(value, out, "W");
-               break;
-       case SR_UNIT_WATT_HOUR:
-               si_printf(value, out, "Wh");
-               break;
-       case SR_UNIT_METER_SECOND:
-               si_printf(value, out, "m/s");
-               break;
-       case SR_UNIT_HECTOPASCAL:
-               si_printf(value, out, "hPa");
-               break;
-       case SR_UNIT_HUMIDITY_293K:
-               si_printf(value, out, "%rF");
-               break;
-       default:
-               si_printf(value, out, "");
-               break;
-       }
-
-       if (mqflags & SR_MQFLAG_AC)
-               g_string_append_printf(out, " AC");
-       if (mqflags & SR_MQFLAG_DC)
-               g_string_append_printf(out, " DC");
-       if (mqflags & SR_MQFLAG_RMS)
-               g_string_append_printf(out, " RMS");
-       if (mqflags & SR_MQFLAG_DIODE)
-               g_string_append_printf(out, " DIODE");
-       if (mqflags & SR_MQFLAG_HOLD)
-               g_string_append_printf(out, " HOLD");
-       if (mqflags & SR_MQFLAG_MAX)
-               g_string_append_printf(out, " MAX");
-       if (mqflags & SR_MQFLAG_MIN)
-               g_string_append_printf(out, " MIN");
-       if (mqflags & SR_MQFLAG_AUTORANGE)
-               g_string_append_printf(out, " AUTO");
-       if (mqflags & SR_MQFLAG_RELATIVE)
-               g_string_append_printf(out, " REL");
-       if (mqflags & SR_MQFLAG_AVG)
-               g_string_append_printf(out, " AVG");
-       g_string_append_c(out, '\n');
-}
-
-static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
-               GString **out)
-{
-       const struct sr_datafeed_analog *analog;
-       struct sr_channel *ch;
-       GSList *l;
-       const float *fdata;
-       int i, p;
-
-       *out = NULL;
-       if (!o || !o->sdi)
-               return SR_ERR_ARG;
-
-       switch (packet->type) {
-       case SR_DF_FRAME_BEGIN:
-               *out = g_string_new("FRAME-BEGIN\n");
-               break;
-       case SR_DF_FRAME_END:
-               *out = g_string_new("FRAME-END\n");
-               break;
-       case SR_DF_ANALOG:
-               analog = packet->payload;
-               fdata = (const float *)analog->data;
-               *out = g_string_sized_new(512);
-               for (i = 0; i < analog->num_samples; i++) {
-                       for (l = analog->channels, p = 0; l; l = l->next, p++) {
-                               ch = l->data;
-                               g_string_append_printf(*out, "%s: ", ch->name);
-                               fancyprint(analog->unit, analog->mqflags,
-                                               fdata[i + p], *out);
-                       }
-               }
-               break;
-       }
-
-       return SR_OK;
-}
-
-static int cleanup(struct sr_output *o)
-{
-       struct context *ctx;
-
-       if (!o || !o->sdi)
-               return SR_ERR_ARG;
-       ctx = o->internal;
-
-       g_ptr_array_free(ctx->channellist, 1);
-       g_free(ctx);
-       o->internal = NULL;
-
-       return SR_OK;
-}
-
-SR_PRIV struct sr_output_format output_analog = {
-       .id = "analog",
-       .description = "Analog data",
-       .init = init,
-       .receive = receive,
-       .cleanup = cleanup
-};
diff --git a/output/ascii.c b/output/ascii.c
deleted file mode 100644 (file)
index d068942..0000000
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2011 HÃ¥vard Espeland <gus@ping.uio.no>
- * Copyright (C) 2014 Bert Vermeulen <bert@biot.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 <stdlib.h>
-#include <string.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "output/hex"
-
-#define DEFAULT_SAMPLES_PER_LINE 74
-
-struct context {
-       unsigned int num_enabled_channels;
-       int samples_per_line;
-       int bit_cnt;
-       int spl_cnt;
-       int trigger;
-       uint64_t samplerate;
-       int *channel_index;
-       char **channel_names;
-       char **line_values;
-       uint8_t *prev_sample;
-       gboolean header_done;
-       GString **lines;
-       GString *header;
-};
-
-static int init(struct sr_output *o)
-{
-       struct context *ctx;
-       struct sr_channel *ch;
-       GSList *l;
-       GHashTableIter iter;
-       gpointer key, value;
-       unsigned int i, j;
-       int spl;
-
-       if (!o || !o->sdi)
-               return SR_ERR_ARG;
-
-       spl = DEFAULT_SAMPLES_PER_LINE;
-       g_hash_table_iter_init(&iter, o->params);
-       while (g_hash_table_iter_next(&iter, &key, &value)) {
-               if (!strcmp(key, "width")) {
-                       if ((spl = strtoul(value, NULL, 10)) < 1) {
-                               sr_err("Invalid width.");
-                               return SR_ERR_ARG;
-                       }
-               } else {
-                       sr_err("Unknown parameter '%s'.", key);
-                       return SR_ERR_ARG;
-               }
-       }
-
-       ctx = g_malloc0(sizeof(struct context));
-       o->internal = ctx;
-       ctx->trigger = -1;
-       ctx->samples_per_line = spl;
-
-       for (l = o->sdi->channels; l; l = l->next) {
-               ch = l->data;
-               if (ch->type != SR_CHANNEL_LOGIC)
-                       continue;
-               if (!ch->enabled)
-                       continue;
-               ctx->num_enabled_channels++;
-       }
-       ctx->channel_index = g_malloc(sizeof(int) * ctx->num_enabled_channels);
-       ctx->channel_names = g_malloc(sizeof(char *) * ctx->num_enabled_channels);
-       ctx->lines = g_malloc(sizeof(GString *) * ctx->num_enabled_channels);
-       ctx->prev_sample = g_malloc(g_slist_length(o->sdi->channels));
-
-       j = 0;
-       for (i = 0, l = o->sdi->channels; l; l = l->next, i++) {
-               ch = l->data;
-               if (ch->type != SR_CHANNEL_LOGIC)
-                       continue;
-               if (!ch->enabled)
-                       continue;
-               ctx->channel_index[j] = ch->index;
-               ctx->channel_names[j] = ch->name;
-               ctx->lines[j] = g_string_sized_new(80);
-               g_string_printf(ctx->lines[j], "%s:", ch->name);
-               j++;
-       }
-
-       return SR_OK;
-}
-
-static GString *gen_header(struct sr_output *o)
-{
-       struct context *ctx;
-       GVariant *gvar;
-       GString *header;
-       int num_channels;
-       char *samplerate_s;
-
-       ctx = o->internal;
-       if (ctx->samplerate == 0) {
-               if (sr_config_get(o->sdi->driver, o->sdi, NULL, SR_CONF_SAMPLERATE,
-                               &gvar) == SR_OK) {
-                       ctx->samplerate = g_variant_get_uint64(gvar);
-                       g_variant_unref(gvar);
-               }
-       }
-
-       header = g_string_sized_new(512);
-       g_string_printf(header, "%s\n", PACKAGE_STRING);
-       num_channels = g_slist_length(o->sdi->channels);
-       g_string_append_printf(header, "Acquisition with %d/%d channels",
-                       ctx->num_enabled_channels, num_channels);
-       if (ctx->samplerate != 0) {
-               samplerate_s = sr_samplerate_string(ctx->samplerate);
-               g_string_append_printf(header, " at %s", samplerate_s);
-               g_free(samplerate_s);
-       }
-       g_string_append_printf(header, "\n");
-
-       return header;
-}
-
-static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
-               GString **out)
-{
-       const struct sr_datafeed_meta *meta;
-       const struct sr_datafeed_logic *logic;
-       const struct sr_config *src;
-       GSList *l;
-       struct context *ctx;
-       int idx, offset, curbit, prevbit;
-       uint64_t i, j;
-       gchar *p, c;
-
-       *out = NULL;
-       if (!o || !o->sdi)
-               return SR_ERR_ARG;
-       if (!(ctx = o->internal))
-               return SR_ERR_ARG;
-
-       switch (packet->type) {
-       case SR_DF_META:
-               meta = packet->payload;
-               for (l = meta->config; l; l = l->next) {
-                       src = l->data;
-                       if (src->key != SR_CONF_SAMPLERATE)
-                               continue;
-                       ctx->samplerate = g_variant_get_uint64(src->data);
-               }
-               break;
-       case SR_DF_TRIGGER:
-               ctx->trigger = ctx->spl_cnt;
-               break;
-       case SR_DF_LOGIC:
-               if (!ctx->header_done) {
-                       *out = gen_header(o);
-                       ctx->header_done = TRUE;
-               } else
-                       *out = g_string_sized_new(512);
-
-               logic = packet->payload;
-               for (i = 0; i <= logic->length - logic->unitsize; i += logic->unitsize) {
-                       ctx->spl_cnt++;
-                       for (j = 0; j < ctx->num_enabled_channels; j++) {
-                               idx = ctx->channel_index[j];
-                               p = logic->data + i + idx / 8;
-                               curbit = *p & (1 << (idx % 8));
-                               prevbit = (ctx->prev_sample[idx / 8] & ((uint8_t) 1 << (idx % 8)));
-
-                               c = curbit ? '"' : '.';
-                               if (ctx->spl_cnt > 1) {
-                                       if (curbit < prevbit)
-                                               c = '\\';
-                                       else if (curbit > prevbit)
-                                               c = '/';
-                               }
-                               g_string_append_c(ctx->lines[j], c);
-
-                               if (ctx->spl_cnt == ctx->samples_per_line) {
-                                       /* Flush line buffers. */
-                                       g_string_append_len(*out, ctx->lines[j]->str, ctx->lines[j]->len);
-                                       g_string_append_c(*out, '\n');
-                                       if (j == ctx->num_enabled_channels  - 1 && ctx->trigger > -1) {
-                                               offset = ctx->trigger + ctx->trigger / 8;
-                                               g_string_append_printf(*out, "T:%*s^ %d\n", offset, "", ctx->trigger);
-                                               ctx->trigger = -1;
-                                       }
-                                       g_string_printf(ctx->lines[j], "%s:", ctx->channel_names[j]);
-                               }
-                       }
-                       if (ctx->spl_cnt == ctx->samples_per_line)
-                               /* Line buffers were already flushed. */
-                               ctx->spl_cnt = 0;
-                       memcpy(ctx->prev_sample, logic->data + i, logic->unitsize);
-               }
-               break;
-       case SR_DF_END:
-               if (ctx->spl_cnt) {
-                       /* Line buffers need flushing. */
-                       *out = g_string_sized_new(512);
-                       for (i = 0; i < ctx->num_enabled_channels; i++) {
-                               g_string_append_len(*out, ctx->lines[i]->str, ctx->lines[i]->len);
-                               g_string_append_c(*out, '\n');
-                       }
-               }
-               break;
-       }
-
-       return SR_OK;
-}
-
-static int cleanup(struct sr_output *o)
-{
-       struct context *ctx;
-       unsigned int i;
-
-       if (!o)
-               return SR_ERR_ARG;
-
-       if (!(ctx = o->internal))
-               return SR_OK;
-
-       g_free(ctx->channel_index);
-       g_free(ctx->prev_sample);
-       g_free(ctx->channel_names);
-       for (i = 0; i < ctx->num_enabled_channels; i++)
-               g_string_free(ctx->lines[i], TRUE);
-       g_free(ctx->lines);
-       g_free(ctx);
-       o->internal = NULL;
-
-       return SR_OK;
-}
-
-SR_PRIV struct sr_output_format output_ascii = {
-       .id = "ascii",
-       .description = "ASCII",
-       .init = init,
-       .receive = receive,
-       .cleanup = cleanup,
-};
-
-
diff --git a/output/binary.c b/output/binary.c
deleted file mode 100644 (file)
index 6e2531d..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2010 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "output/binary"
-
-static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
-               GString **out)
-{
-       const struct sr_datafeed_logic *logic;
-
-       (void)o;
-
-       *out = NULL;
-       if (packet->type != SR_DF_LOGIC)
-               return SR_OK;
-       logic = packet->payload;
-       *out = g_string_new_len(logic->data, logic->length);
-
-       return SR_OK;
-}
-
-SR_PRIV struct sr_output_format output_binary = {
-       .id = "binary",
-       .description = "Raw binary",
-       .receive = receive,
-};
diff --git a/output/bits.c b/output/bits.c
deleted file mode 100644 (file)
index b44f105..0000000
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2014 Bert Vermeulen <bert@biot.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 <stdlib.h>
-#include <string.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "output/bits"
-
-#define DEFAULT_SAMPLES_PER_LINE 64
-
-struct context {
-       unsigned int num_enabled_channels;
-       int samples_per_line;
-       int spl_cnt;
-       int trigger;
-       uint64_t samplerate;
-       int *channel_index;
-       char **channel_names;
-       gboolean header_done;
-       GString **lines;
-};
-
-static int init(struct sr_output *o)
-{
-       struct context *ctx;
-       struct sr_channel *ch;
-       GSList *l;
-       GHashTableIter iter;
-       gpointer key, value;
-       unsigned int i, j;
-       int spl;
-
-       if (!o || !o->sdi)
-               return SR_ERR_ARG;
-
-       spl = DEFAULT_SAMPLES_PER_LINE;
-       g_hash_table_iter_init(&iter, o->params);
-       while (g_hash_table_iter_next(&iter, &key, &value)) {
-               if (!strcmp(key, "width")) {
-                       if ((spl = strtoul(value, NULL, 10)) < 1) {
-                               sr_err("Invalid width.");
-                               return SR_ERR_ARG;
-                       }
-               } else {
-                       sr_err("Unknown parameter '%s'.", key);
-                       return SR_ERR_ARG;
-               }
-       }
-
-       ctx = g_malloc0(sizeof(struct context));
-       o->internal = ctx;
-       ctx->trigger = -1;
-       ctx->samples_per_line = spl;
-
-       for (l = o->sdi->channels; l; l = l->next) {
-               ch = l->data;
-               if (ch->type != SR_CHANNEL_LOGIC)
-                       continue;
-               if (!ch->enabled)
-                       continue;
-               ctx->num_enabled_channels++;
-       }
-       ctx->channel_index = g_malloc(sizeof(int) * ctx->num_enabled_channels);
-       ctx->channel_names = g_malloc(sizeof(char *) * ctx->num_enabled_channels);
-       ctx->lines = g_malloc(sizeof(GString *) * ctx->num_enabled_channels);
-
-       j = 0;
-       for (i = 0, l = o->sdi->channels; l; l = l->next, i++) {
-               ch = l->data;
-               if (ch->type != SR_CHANNEL_LOGIC)
-                       continue;
-               if (!ch->enabled)
-                       continue;
-               ctx->channel_index[j] = ch->index;
-               ctx->channel_names[j] = ch->name;
-               ctx->lines[j] = g_string_sized_new(80);
-               g_string_printf(ctx->lines[j], "%s:", ch->name);
-               j++;
-       }
-
-       return SR_OK;
-}
-
-static GString *gen_header(struct sr_output *o)
-{
-       struct context *ctx;
-       GVariant *gvar;
-       GString *header;
-       int num_channels;
-       char *samplerate_s;
-
-       ctx = o->internal;
-       if (ctx->samplerate == 0) {
-               if (sr_config_get(o->sdi->driver, o->sdi, NULL, SR_CONF_SAMPLERATE,
-                               &gvar) == SR_OK) {
-                       ctx->samplerate = g_variant_get_uint64(gvar);
-                       g_variant_unref(gvar);
-               }
-       }
-
-       header = g_string_sized_new(512);
-       g_string_printf(header, "%s\n", PACKAGE_STRING);
-       num_channels = g_slist_length(o->sdi->channels);
-       g_string_append_printf(header, "Acquisition with %d/%d channels",
-                       ctx->num_enabled_channels, num_channels);
-       if (ctx->samplerate != 0) {
-               samplerate_s = sr_samplerate_string(ctx->samplerate);
-               g_string_append_printf(header, " at %s", samplerate_s);
-               g_free(samplerate_s);
-       }
-       g_string_append_printf(header, "\n");
-
-       return header;
-}
-
-static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
-               GString **out)
-{
-       const struct sr_datafeed_meta *meta;
-       const struct sr_datafeed_logic *logic;
-       const struct sr_config *src;
-       struct context *ctx;
-       GSList *l;
-       int idx, offset;
-       uint64_t i, j;
-       gchar *p, c;
-
-       *out = NULL;
-       if (!o || !o->sdi)
-               return SR_ERR_ARG;
-       if (!(ctx = o->internal))
-               return SR_ERR_ARG;
-
-       switch (packet->type) {
-       case SR_DF_META:
-               meta = packet->payload;
-               for (l = meta->config; l; l = l->next) {
-                       src = l->data;
-                       if (src->key != SR_CONF_SAMPLERATE)
-                               continue;
-                       ctx->samplerate = g_variant_get_uint64(src->data);
-               }
-               break;
-       case SR_DF_TRIGGER:
-               ctx->trigger = ctx->spl_cnt;
-               break;
-       case SR_DF_LOGIC:
-               if (!ctx->header_done) {
-                       *out = gen_header(o);
-                       ctx->header_done = TRUE;
-               } else
-                       *out = g_string_sized_new(512);
-
-               logic = packet->payload;
-               for (i = 0; i <= logic->length - logic->unitsize; i += logic->unitsize) {
-                       ctx->spl_cnt++;
-                       for (j = 0; j < ctx->num_enabled_channels; j++) {
-                               idx = ctx->channel_index[j];
-                               p = logic->data + i + idx / 8;
-                               c = (*p & (1 << (idx % 8))) ? '1' : '0';
-                               g_string_append_c(ctx->lines[j], c);
-
-                               if (ctx->spl_cnt == ctx->samples_per_line) {
-                                       /* Flush line buffers. */
-                                       g_string_append_len(*out, ctx->lines[j]->str, ctx->lines[j]->len);
-                                       g_string_append_c(*out, '\n');
-                                       if (j == ctx->num_enabled_channels  - 1 && ctx->trigger > -1) {
-                                               offset = ctx->trigger + ctx->trigger / 8;
-                                               g_string_append_printf(*out, "T:%*s^ %d\n", offset, "", ctx->trigger);
-                                               ctx->trigger = -1;
-                                       }
-                                       g_string_printf(ctx->lines[j], "%s:", ctx->channel_names[j]);
-                               } else if ((ctx->spl_cnt & 7) == 0) {
-                                       /* Add a space every 8th bit. */
-                                       g_string_append_c(ctx->lines[j], ' ');
-                               }
-                       }
-                       if (ctx->spl_cnt == ctx->samples_per_line)
-                               /* Line buffers were already flushed. */
-                               ctx->spl_cnt = 0;
-               }
-               break;
-       case SR_DF_END:
-               if (ctx->spl_cnt) {
-                       /* Line buffers need flushing. */
-                       *out = g_string_sized_new(512);
-                       for (i = 0; i < ctx->num_enabled_channels; i++) {
-                               g_string_append_len(*out, ctx->lines[i]->str, ctx->lines[i]->len);
-                               g_string_append_c(*out, '\n');
-                       }
-               }
-               break;
-       }
-
-       return SR_OK;
-}
-
-static int cleanup(struct sr_output *o)
-{
-       struct context *ctx;
-       unsigned int i;
-
-       if (!o)
-               return SR_ERR_ARG;
-
-       if (!(ctx = o->internal))
-               return SR_OK;
-
-       g_free(ctx->channel_index);
-       g_free(ctx->channel_names);
-       for (i = 0; i < ctx->num_enabled_channels; i++)
-               g_string_free(ctx->lines[i], TRUE);
-       g_free(ctx->lines);
-       g_free(ctx);
-       o->internal = NULL;
-
-       return SR_OK;
-}
-
-SR_PRIV struct sr_output_format output_bits = {
-       .id = "bits",
-       .description = "Bits",
-       .init = init,
-       .receive = receive,
-       .cleanup = cleanup,
-};
diff --git a/output/chronovu_la8.c b/output/chronovu_la8.c
deleted file mode 100644 (file)
index ad0b5d3..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2011 Uwe Hermann <uwe@hermann-uwe.de>
- * Copyright (C) 2014 Bert Vermeulen <bert@biot.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 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/>.
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "output/chronovu-la8"
-
-struct context {
-       unsigned int num_enabled_channels;
-       gboolean triggered;
-       uint64_t samplerate;
-       uint64_t samplecount;
-       int *channel_index;
-       GString *pretrig_buf;
-};
-
-/**
- * Check if the given samplerate is supported by the LA8 hardware.
- *
- * @param samplerate The samplerate (in Hz) to check.
- *
- * @return 1 if the samplerate is supported/valid, 0 otherwise.
- */
-static gboolean is_valid_samplerate(uint64_t samplerate)
-{
-       unsigned int i;
-
-       for (i = 0; i < 255; i++) {
-               if (samplerate == (SR_MHZ(100) / (i + 1)))
-                       return TRUE;
-       }
-
-       return FALSE;
-}
-
-/**
- * Convert a samplerate (in Hz) to the 'divcount' value the LA8 wants.
- *
- * LA8 hardware: sample period = (divcount + 1) * 10ns.
- * Min. value for divcount: 0x00 (10ns sample period, 100MHz samplerate).
- * Max. value for divcount: 0xfe (2550ns sample period, 392.15kHz samplerate).
- *
- * @param samplerate The samplerate in Hz.
- *
- * @return The divcount value as needed by the hardware, or 0xff upon errors.
- */
-static uint8_t samplerate_to_divcount(uint64_t samplerate)
-{
-       if (samplerate == 0 || !is_valid_samplerate(samplerate)) {
-               sr_warn("Invalid samplerate (%" PRIu64 "Hz)", samplerate);
-               return 0xff;
-       }
-
-       return (SR_MHZ(100) / samplerate) - 1;
-}
-
-static int init(struct sr_output *o)
-{
-       struct context *ctx;
-       struct sr_channel *ch;
-       GSList *l;
-
-       if (!o || !o->sdi)
-               return SR_ERR_ARG;
-
-       ctx = g_malloc0(sizeof(struct context));
-       o->internal = ctx;
-
-       for (l = o->sdi->channels; l; l = l->next) {
-               ch = l->data;
-               if (ch->type != SR_CHANNEL_LOGIC)
-                       continue;
-               if (!ch->enabled)
-                       continue;
-               ctx->num_enabled_channels++;
-       }
-       ctx->channel_index = g_malloc(sizeof(int) * ctx->num_enabled_channels);
-       ctx->pretrig_buf = g_string_sized_new(1024);
-
-       return SR_OK;
-}
-
-static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
-               GString **out)
-{
-       const struct sr_datafeed_logic *logic;
-       struct context *ctx;
-       GVariant *gvar;
-       uint64_t samplerate;
-       gchar c[4];
-
-       *out = NULL;
-       if (!o || !o->sdi)
-               return SR_ERR_ARG;
-       if (!(ctx = o->internal))
-               return SR_ERR_ARG;
-
-       switch (packet->type) {
-       case SR_DF_HEADER:
-               /* One byte for the 'divcount' value. */
-               if (sr_config_get(o->sdi->driver, o->sdi, NULL, SR_CONF_SAMPLERATE,
-                               &gvar) == SR_OK) {
-                       samplerate = g_variant_get_uint64(gvar);
-                       g_variant_unref(gvar);
-               } else
-                       samplerate = 0;
-               c[0] = samplerate_to_divcount(samplerate);
-               *out = g_string_new_len(c, 1);
-               ctx->triggered = FALSE;
-               break;
-       case SR_DF_TRIGGER:
-               /* Four bytes (little endian) for the trigger point. */
-               c[0] = ctx->samplecount & 0xff;
-               c[1] = (ctx->samplecount >> 8) & 0xff;
-               c[2] = (ctx->samplecount >> 16) & 0xff;
-               c[3] = (ctx->samplecount >> 24) & 0xff;
-               *out = g_string_new_len(c, 4);
-               /* Flush the pre-trigger buffer. */
-               if (ctx->pretrig_buf->len)
-                       g_string_append_len(*out, ctx->pretrig_buf->str,
-                                       ctx->pretrig_buf->len);
-               ctx->triggered = TRUE;
-               break;
-       case SR_DF_LOGIC:
-               logic = packet->payload;
-               if (!ctx->triggered)
-                       g_string_append_len(ctx->pretrig_buf, logic->data, logic->length);
-               else
-                       *out = g_string_new_len(logic->data, logic->length);
-               ctx->samplecount += logic->length / logic->unitsize;
-               break;
-       case SR_DF_END:
-               if (!ctx->triggered && ctx->pretrig_buf->len) {
-                       /* We never got a trigger, submit an empty one. */
-                       *out = g_string_sized_new(ctx->pretrig_buf->len + 4);
-                       g_string_append_len(*out, "\x00\x00\x00\x00", 4);
-                       g_string_append_len(*out, ctx->pretrig_buf->str, ctx->pretrig_buf->len);
-               }
-               break;
-       }
-
-       return SR_OK;
-}
-
-static int cleanup(struct sr_output *o)
-{
-       struct context *ctx;
-
-       if (!o || !o->sdi)
-               return SR_ERR_ARG;
-
-       if (o->internal) {
-               ctx = o->internal;
-               g_string_free(ctx->pretrig_buf, TRUE);
-               g_free(ctx->channel_index);
-               g_free(o->internal);
-               o->internal = NULL;
-       }
-
-       return SR_OK;
-}
-
-SR_PRIV struct sr_output_format output_chronovu_la8 = {
-       .id = "chronovu-la8",
-       .description = "ChronoVu LA8",
-       .init = init,
-       .receive = receive,
-       .cleanup = cleanup,
-};
diff --git a/output/csv.c b/output/csv.c
deleted file mode 100644 (file)
index d17969e..0000000
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2011 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <glib.h>
-#include "config.h" /* Needed for PACKAGE_STRING and others. */
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "output/csv"
-
-struct context {
-       unsigned int num_enabled_channels;
-       uint64_t samplerate;
-       char separator;
-       gboolean header_done;
-       int *channel_index;
-};
-
-/*
- * TODO:
- *  - Option to specify delimiter character and/or string.
- *  - Option to (not) print metadata as comments.
- *  - Option to specify the comment character(s), e.g. # or ; or C/C++-style.
- *  - Option to (not) print samplenumber / time as extra column.
- *  - Option to "compress" output (only print changed samples, VCD-like).
- *  - Option to print comma-separated bits, or whole bytes/words (for 8/16
- *    channel LAs) as ASCII/hex etc. etc.
- *  - Trigger support.
- */
-
-static int init(struct sr_output *o)
-{
-       struct context *ctx;
-       struct sr_channel *ch;
-       GSList *l;
-       int i;
-
-       if (!o || !o->sdi)
-               return SR_ERR_ARG;
-
-       ctx = g_malloc0(sizeof(struct context));
-       o->internal = ctx;
-       ctx->separator = ',';
-
-       /* Get the number of channels, and the unitsize. */
-       for (l = o->sdi->channels; l; l = l->next) {
-               ch = l->data;
-               if (ch->type != SR_CHANNEL_LOGIC)
-                       continue;
-               if (!ch->enabled)
-                       continue;
-               ctx->num_enabled_channels++;
-       }
-       ctx->channel_index = g_malloc(sizeof(int) * ctx->num_enabled_channels);
-
-       /* Once more to map the enabled channels. */
-       for (i = 0, l = o->sdi->channels; l; l = l->next) {
-               ch = l->data;
-               if (ch->type != SR_CHANNEL_LOGIC)
-                       continue;
-               if (!ch->enabled)
-                       continue;
-               ctx->channel_index[i++] = ch->index;
-       }
-
-       return SR_OK;
-}
-
-static GString *gen_header(struct sr_output *o)
-{
-       struct context *ctx;
-       struct sr_channel *ch;
-       GVariant *gvar;
-       GString *header;
-       GSList *l;
-       time_t t;
-       int num_channels, i;
-       char *samplerate_s;
-
-       ctx = o->internal;
-       header = g_string_sized_new(512);
-
-       /* Some metadata */
-       t = time(NULL);
-       g_string_append_printf(header, "; CSV, generated by %s on %s",
-                       PACKAGE_STRING, ctime(&t));
-
-       /* Columns / channels */
-       num_channels = g_slist_length(o->sdi->channels);
-       g_string_append_printf(header, "; Channels (%d/%d):",
-                       ctx->num_enabled_channels, num_channels);
-       for (i = 0, l = o->sdi->channels; l; l = l->next, i++) {
-               ch = l->data;
-               if (ch->type != SR_CHANNEL_LOGIC)
-                       continue;
-               if (!ch->enabled)
-                       continue;
-               g_string_append_printf(header, " %s,", ch->name);
-       }
-       if (o->sdi->channels)
-               /* Drop last separator. */
-               g_string_truncate(header, header->len - 1);
-       g_string_append_printf(header, "\n");
-
-       if (ctx->samplerate == 0) {
-               if (sr_config_get(o->sdi->driver, o->sdi, NULL, SR_CONF_SAMPLERATE,
-                               &gvar) == SR_OK) {
-                       ctx->samplerate = g_variant_get_uint64(gvar);
-                       g_variant_unref(gvar);
-               }
-       }
-       if (ctx->samplerate != 0) {
-               samplerate_s = sr_samplerate_string(ctx->samplerate);
-               g_string_append_printf(header, "; Samplerate: %s\n", samplerate_s);
-               g_free(samplerate_s);
-       }
-
-       return header;
-}
-
-static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
-               GString **out)
-{
-       const struct sr_datafeed_meta *meta;
-       const struct sr_datafeed_logic *logic;
-       const struct sr_config *src;
-       GSList *l;
-       struct context *ctx;
-       int idx;
-       uint64_t i, j;
-       gchar *p, c;
-
-       *out = NULL;
-       if (!o || !o->sdi)
-               return SR_ERR_ARG;
-       if (!(ctx = o->internal))
-               return SR_ERR_ARG;
-
-       switch (packet->type) {
-       case SR_DF_META:
-               meta = packet->payload;
-               for (l = meta->config; l; l = l->next) {
-                       src = l->data;
-                       if (src->key != SR_CONF_SAMPLERATE)
-                               continue;
-                       ctx->samplerate = g_variant_get_uint64(src->data);
-               }
-               break;
-       case SR_DF_LOGIC:
-               logic = packet->payload;
-               if (!ctx->header_done) {
-                       *out = gen_header(o);
-                       ctx->header_done = TRUE;
-               } else {
-                       *out = g_string_sized_new(512);
-               }
-
-               for (i = 0; i <= logic->length - logic->unitsize; i += logic->unitsize) {
-                       for (j = 0; j < ctx->num_enabled_channels; j++) {
-                               idx = ctx->channel_index[j];
-                               p = logic->data + i + idx / 8;
-                               c = *p & (1 << (idx % 8));
-                               g_string_append_c(*out, c ? '1' : '0');
-                               g_string_append_c(*out, ctx->separator);
-                       }
-                       if (j) {
-                               /* Drop last separator. */
-                               g_string_truncate(*out, (*out)->len - 1);
-                       }
-                       g_string_append_printf(*out, "\n");
-               }
-               break;
-       }
-
-       return SR_OK;
-}
-
-static int cleanup(struct sr_output *o)
-{
-       struct context *ctx;
-
-       if (!o || !o->sdi)
-               return SR_ERR_ARG;
-
-       if (o->internal) {
-               ctx = o->internal;
-               g_free(ctx->channel_index);
-               g_free(o->internal);
-               o->internal = NULL;
-       }
-
-       return SR_OK;
-}
-
-SR_PRIV struct sr_output_format output_csv = {
-       .id = "csv",
-       .description = "Comma-separated values (CSV)",
-       .init = init,
-       .receive = receive,
-       .cleanup = cleanup,
-};
diff --git a/output/gnuplot.c b/output/gnuplot.c
deleted file mode 100644 (file)
index a9feec6..0000000
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2010 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <glib.h>
-#include "config.h" /* Needed for PACKAGE_STRING and others. */
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "output/gnuplot"
-
-struct context {
-       unsigned int num_enabled_channels;
-       uint64_t samplerate;
-       uint64_t samplecount;
-       gboolean header_done;
-       uint8_t *prevsample;
-       int *channel_index;
-};
-
-static const char *gnuplot_header = "\
-# Sample data in space-separated columns format usable by gnuplot.\n";
-static const char *gnuplot_header2 = "\
-#\n# Column\tChannel\n\
-# -----------------------------------------------------------------------------\n\
-# 0\t\tSample counter (for internal gnuplot purposes)\n";
-
-
-static int init(struct sr_output *o)
-{
-       struct context *ctx;
-       struct sr_channel *ch;
-       GSList *l;
-       unsigned int i;
-
-       if (!o || !o->sdi)
-               return SR_ERR_ARG;
-
-       ctx = g_malloc0(sizeof(struct context));
-       o->internal = ctx;
-       ctx->num_enabled_channels = 0;
-       for (l = o->sdi->channels; l; l = l->next) {
-               ch = l->data;
-               if (ch->type != SR_CHANNEL_LOGIC)
-                       continue;
-               if (!ch->enabled)
-                       continue;
-               ctx->num_enabled_channels++;
-       }
-       if (ctx->num_enabled_channels <= 0) {
-               sr_err("No logic channel enabled.");
-               return SR_ERR;
-       }
-       ctx->channel_index = g_malloc(sizeof(int) * ctx->num_enabled_channels);
-
-       /* Once more to map the enabled channels. */
-       for (i = 0, l = o->sdi->channels; l; l = l->next) {
-               ch = l->data;
-               if (ch->type != SR_CHANNEL_LOGIC)
-                       continue;
-               if (!ch->enabled)
-                       continue;
-               ctx->channel_index[i++] = ch->index;
-       }
-
-       return SR_OK;
-}
-
-static GString *gen_header(struct sr_output *o)
-{
-       struct context *ctx;
-       struct sr_channel *ch;
-       GVariant *gvar;
-       GString *header;
-       time_t t;
-       unsigned int num_channels, i;
-       char *samplerate_s;
-
-       ctx = o->internal;
-       if (ctx->samplerate == 0) {
-               if (sr_config_get(o->sdi->driver, o->sdi, NULL, SR_CONF_SAMPLERATE,
-                               &gvar) == SR_OK) {
-                       ctx->samplerate = g_variant_get_uint64(gvar);
-                       g_variant_unref(gvar);
-               }
-       }
-
-       t = time(NULL);
-       header = g_string_sized_new(512);
-       g_string_printf(header, "%s", gnuplot_header);
-       g_string_append_printf(header, "# Generated by %s on %s",
-                       PACKAGE_STRING, ctime(&t));
-
-       num_channels = g_slist_length(o->sdi->channels);
-       g_string_append_printf(header, "# Acquisition with %d/%d channels",
-                       ctx->num_enabled_channels, num_channels);
-       if (ctx->samplerate != 0) {
-               samplerate_s = sr_samplerate_string(ctx->samplerate);
-               g_string_append_printf(header, " at %s", samplerate_s);
-               g_free(samplerate_s);
-       }
-       g_string_append_printf(header, "\n");
-
-       g_string_append_printf(header, "%s", gnuplot_header2);
-
-       /* Columns / channels */
-       for (i = 0; i < ctx->num_enabled_channels; i++) {
-               ch = g_slist_nth_data(o->sdi->channels, ctx->channel_index[i]);
-               g_string_append_printf(header, "# %d\t\t%s\n", i + 1, ch->name);
-       }
-
-       return header;
-}
-
-static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
-               GString **out)
-{
-       const struct sr_datafeed_meta *meta;
-       const struct sr_datafeed_logic *logic;
-       const struct sr_config *src;
-       GSList *l;
-       struct context *ctx;
-       const uint8_t *sample;
-       unsigned int curbit, p, idx, i;
-
-       *out = NULL;
-       if (!o || !o->internal)
-               return SR_ERR_BUG;
-       ctx = o->internal;
-
-       if (packet->type == SR_DF_META) {
-               meta = packet->payload;
-               for (l = meta->config; l; l = l->next) {
-                       src = l->data;
-                       if (src->key != SR_CONF_SAMPLERATE)
-                               continue;
-                       ctx->samplerate = g_variant_get_uint64(src->data);
-               }
-       }
-
-       if (packet->type != SR_DF_LOGIC)
-               return SR_OK;
-       logic = packet->payload;
-
-       if (!ctx->prevsample) {
-               /* Can't allocate this until we know the stream's unitsize. */
-               ctx->prevsample = g_malloc0(logic->unitsize);
-       }
-
-       if (!ctx->header_done) {
-               *out = gen_header(o);
-               ctx->header_done = TRUE;
-       } else {
-               *out = g_string_sized_new(512);
-       }
-
-       for (i = 0; i <= logic->length - logic->unitsize; i += logic->unitsize) {
-               sample = logic->data + i;
-               ctx->samplecount++;
-
-               /*
-                * Don't output the same sample multiple times, but make
-                * sure to output at least the first and last sample.
-                */
-               if (i > 0 && i < logic->length - logic->unitsize) {
-                       if (!memcmp(sample, ctx->prevsample, logic->unitsize))
-                               continue;
-               }
-               memcpy(ctx->prevsample, sample, logic->unitsize);
-
-               /* The first column is a counter (needed for gnuplot). */
-               g_string_append_printf(*out, "%" PRIu64 "\t", ctx->samplecount);
-
-               /* The next columns are the values of all channels. */
-               for (p = 0; p < ctx->num_enabled_channels; p++) {
-                       idx = ctx->channel_index[p];
-                       curbit = (sample[idx / 8] & ((uint8_t) (1 << (idx % 8)))) >> (idx % 8);
-                       g_string_append_printf(*out, "%d ", curbit);
-               }
-               g_string_append_printf(*out, "\n");
-       }
-
-       return SR_OK;
-}
-
-static int cleanup(struct sr_output *o)
-{
-       struct context *ctx;
-
-       if (!o || !o->internal)
-               return SR_ERR_BUG;
-       ctx = o->internal;
-       g_free(ctx->channel_index);
-       g_free(ctx->prevsample);
-       g_free(ctx);
-
-       return SR_OK;
-}
-
-SR_PRIV struct sr_output_format output_gnuplot = {
-       .id = "gnuplot",
-       .description = "Gnuplot",
-       .init = init,
-       .receive = receive,
-       .cleanup = cleanup,
-};
diff --git a/output/hex.c b/output/hex.c
deleted file mode 100644 (file)
index 07a430c..0000000
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2014 Bert Vermeulen <bert@biot.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 <stdlib.h>
-#include <string.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "output/hex"
-
-#define DEFAULT_SAMPLES_PER_LINE 192
-
-struct context {
-       unsigned int num_enabled_channels;
-       int samples_per_line;
-       int bit_cnt;
-       int spl_cnt;
-       int trigger;
-       uint64_t samplerate;
-       int *channel_index;
-       char **channel_names;
-       char **line_values;
-       uint8_t *sample_buf;
-       gboolean header_done;
-       GString **lines;
-};
-
-static int init(struct sr_output *o)
-{
-       struct context *ctx;
-       struct sr_channel *ch;
-       GSList *l;
-       GHashTableIter iter;
-       gpointer key, value;
-       unsigned int i, j;
-       int spl;
-
-       if (!o || !o->sdi)
-               return SR_ERR_ARG;
-
-       spl = DEFAULT_SAMPLES_PER_LINE;
-       g_hash_table_iter_init(&iter, o->params);
-       while (g_hash_table_iter_next(&iter, &key, &value)) {
-               if (!strcmp(key, "width")) {
-                       if ((spl = strtoul(value, NULL, 10)) < 1) {
-                               sr_err("Invalid width.");
-                               return SR_ERR_ARG;
-                       }
-               } else {
-                       sr_err("Unknown parameter '%s'.", key);
-                       return SR_ERR_ARG;
-               }
-       }
-
-       ctx = g_malloc0(sizeof(struct context));
-       o->internal = ctx;
-       ctx->trigger = -1;
-       ctx->samples_per_line = spl;
-
-       for (l = o->sdi->channels; l; l = l->next) {
-               ch = l->data;
-               if (ch->type != SR_CHANNEL_LOGIC)
-                       continue;
-               if (!ch->enabled)
-                       continue;
-               ctx->num_enabled_channels++;
-       }
-       ctx->channel_index = g_malloc(sizeof(int) * ctx->num_enabled_channels);
-       ctx->channel_names = g_malloc(sizeof(char *) * ctx->num_enabled_channels);
-       ctx->lines = g_malloc(sizeof(GString *) * ctx->num_enabled_channels);
-       ctx->sample_buf = g_malloc(ctx->num_enabled_channels);
-
-       j = 0;
-       for (i = 0, l = o->sdi->channels; l; l = l->next, i++) {
-               ch = l->data;
-               if (ch->type != SR_CHANNEL_LOGIC)
-                       continue;
-               if (!ch->enabled)
-                       continue;
-               ctx->channel_index[j] = ch->index;
-               ctx->channel_names[j] = ch->name;
-               ctx->lines[j] = g_string_sized_new(80);
-               ctx->sample_buf[j] = 0;
-               g_string_printf(ctx->lines[j], "%s:", ch->name);
-               j++;
-       }
-
-       return SR_OK;
-}
-
-static GString *gen_header(struct sr_output *o)
-{
-       struct context *ctx;
-       GVariant *gvar;
-       GString *header;
-       int num_channels;
-       char *samplerate_s;
-
-       ctx = o->internal;
-       if (ctx->samplerate == 0) {
-               if (sr_config_get(o->sdi->driver, o->sdi, NULL, SR_CONF_SAMPLERATE,
-                               &gvar) == SR_OK) {
-                       ctx->samplerate = g_variant_get_uint64(gvar);
-                       g_variant_unref(gvar);
-               }
-       }
-
-       header = g_string_sized_new(512);
-       g_string_printf(header, "%s\n", PACKAGE_STRING);
-       num_channels = g_slist_length(o->sdi->channels);
-       g_string_append_printf(header, "Acquisition with %d/%d channels",
-                       ctx->num_enabled_channels, num_channels);
-       if (ctx->samplerate != 0) {
-               samplerate_s = sr_samplerate_string(ctx->samplerate);
-               g_string_append_printf(header, " at %s", samplerate_s);
-               g_free(samplerate_s);
-       }
-       g_string_append_printf(header, "\n");
-
-       return header;
-}
-
-static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
-               GString **out)
-{
-       const struct sr_datafeed_meta *meta;
-       const struct sr_datafeed_logic *logic;
-       const struct sr_config *src;
-       GSList *l;
-       struct context *ctx;
-       int idx, pos, offset;
-       uint64_t i, j;
-       gchar *p;
-
-       *out = NULL;
-       if (!o || !o->sdi)
-               return SR_ERR_ARG;
-       if (!(ctx = o->internal))
-               return SR_ERR_ARG;
-
-       switch (packet->type) {
-       case SR_DF_META:
-               meta = packet->payload;
-               for (l = meta->config; l; l = l->next) {
-                       src = l->data;
-                       if (src->key != SR_CONF_SAMPLERATE)
-                               continue;
-                       ctx->samplerate = g_variant_get_uint64(src->data);
-               }
-               break;
-       case SR_DF_TRIGGER:
-               ctx->trigger = ctx->spl_cnt;
-               break;
-       case SR_DF_LOGIC:
-               if (!ctx->header_done) {
-                       *out = gen_header(o);
-                       ctx->header_done = TRUE;
-               } else
-                       *out = g_string_sized_new(512);
-
-               logic = packet->payload;
-               for (i = 0; i <= logic->length - logic->unitsize; i += logic->unitsize) {
-                       ctx->spl_cnt++;
-                       pos = ctx->spl_cnt & 7;
-                       for (j = 0; j < ctx->num_enabled_channels; j++) {
-                               idx = ctx->channel_index[j];
-                               p = logic->data + i + idx / 8;
-                               ctx->sample_buf[j] <<= 1;
-                               if (*p & (1 << (idx % 8)))
-                                       ctx->sample_buf[j] |= 1;
-                               if (ctx->spl_cnt && pos == 0) {
-                                       /* Buffered a byte's worth, output hex. */
-                                       g_string_append_printf(ctx->lines[j], "%.2x ",
-                                                       ctx->sample_buf[j]);
-                                       ctx->sample_buf[j] = 0;
-                               }
-
-                               if (ctx->spl_cnt == ctx->samples_per_line) {
-                                       /* Flush line buffers. */
-                                       g_string_append_len(*out, ctx->lines[j]->str, ctx->lines[j]->len);
-                                       g_string_append_c(*out, '\n');
-                                       if (j == ctx->num_enabled_channels  - 1 && ctx->trigger > -1) {
-                                               offset = ctx->trigger + ctx->trigger / 8;
-                                               g_string_append_printf(*out, "T:%*s^ %d\n", offset, "", ctx->trigger);
-                                               ctx->trigger = -1;
-                                       }
-                                       g_string_printf(ctx->lines[j], "%s:", ctx->channel_names[j]);
-                               }
-                       }
-                       if (ctx->spl_cnt == ctx->samples_per_line)
-                               /* Line buffers were already flushed. */
-                               ctx->spl_cnt = 0;
-               }
-               break;
-       case SR_DF_END:
-               if (ctx->spl_cnt) {
-                       /* Line buffers need flushing. */
-                       *out = g_string_sized_new(512);
-                       for (i = 0; i < ctx->num_enabled_channels; i++) {
-                               if (ctx->spl_cnt & 7)
-                                       g_string_append_printf(ctx->lines[i], "%.2x ",
-                                                       ctx->sample_buf[i] << (8 - (ctx->spl_cnt & 7)));
-                               g_string_append_len(*out, ctx->lines[i]->str, ctx->lines[i]->len);
-                               g_string_append_c(*out, '\n');
-                       }
-               }
-               break;
-       }
-
-       return SR_OK;
-}
-
-static int cleanup(struct sr_output *o)
-{
-       struct context *ctx;
-       unsigned int i;
-
-       if (!o)
-               return SR_ERR_ARG;
-
-       if (!(ctx = o->internal))
-               return SR_OK;
-
-       g_free(ctx->channel_index);
-       g_free(ctx->sample_buf);
-       g_free(ctx->channel_names);
-       for (i = 0; i < ctx->num_enabled_channels; i++)
-               g_string_free(ctx->lines[i], TRUE);
-       g_free(ctx->lines);
-       g_free(ctx);
-       o->internal = NULL;
-
-       return SR_OK;
-}
-
-SR_PRIV struct sr_output_format output_hex = {
-       .id = "hex",
-       .description = "Hexadecimal",
-       .init = init,
-       .receive = receive,
-       .cleanup = cleanup,
-};
-
diff --git a/output/ols.c b/output/ols.c
deleted file mode 100644 (file)
index 78a41bb..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2011 Uwe Hermann <uwe@hermann-uwe.de>
- * Copyright (C) 2013 Bert Vermeulen <bert@biot.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 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-/*
- * This implements version 1.3 of the output format for the OpenBench Logic
- * Sniffer "Alternative" Java client. Details:
- * https://github.com/jawi/ols/wiki/OLS-data-file-format
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "output/ols"
-
-struct context {
-       uint64_t samplerate;
-       uint64_t num_samples;
-};
-
-static int init(struct sr_output *o)
-{
-       struct context *ctx;
-
-       if (!(ctx = g_try_malloc(sizeof(struct context)))) {
-               sr_err("%s: ctx malloc failed", __func__);
-               return SR_ERR_MALLOC;
-       }
-       o->internal = ctx;
-
-       ctx->samplerate = 0;
-       ctx->num_samples = 0;
-
-       return SR_OK;
-}
-
-static GString *gen_header(const struct sr_dev_inst *sdi, struct context *ctx)
-{
-       struct sr_channel *ch;
-       GSList *l;
-       GString *s;
-       GVariant *gvar;
-       int num_enabled_channels;
-
-       if (!ctx->samplerate && sr_config_get(sdi->driver, sdi, NULL,
-                       SR_CONF_SAMPLERATE, &gvar) == SR_OK) {
-               ctx->samplerate = g_variant_get_uint64(gvar);
-               g_variant_unref(gvar);
-       }
-
-       num_enabled_channels = 0;
-       for (l = sdi->channels; l; l = l->next) {
-               ch = l->data;
-               if (ch->type != SR_CHANNEL_LOGIC)
-                       continue;
-               if (!ch->enabled)
-                       continue;
-               num_enabled_channels++;
-       }
-
-       s = g_string_sized_new(512);
-       g_string_append_printf(s, ";Rate: %"PRIu64"\n", ctx->samplerate);
-       g_string_append_printf(s, ";Channels: %d\n", num_enabled_channels);
-       g_string_append_printf(s, ";EnabledChannels: -1\n");
-       g_string_append_printf(s, ";Compressed: true\n");
-       g_string_append_printf(s, ";CursorEnabled: false\n");
-
-       return s;
-}
-
-static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
-               GString **out)
-{
-       struct context *ctx;
-       const struct sr_datafeed_meta *meta;
-       const struct sr_datafeed_logic *logic;
-       const struct sr_config *src;
-       GSList *l;
-       unsigned int i, j;
-       uint8_t c;
-
-       *out = NULL;
-       if (!o || !o->sdi)
-               return SR_ERR_ARG;
-       ctx = o->internal;
-
-       switch (packet->type) {
-       case SR_DF_META:
-               meta = packet->payload;
-               for (l = meta->config; l; l = l->next) {
-                       src = l->data;
-                       if (src->key == SR_CONF_SAMPLERATE)
-                               ctx->samplerate = g_variant_get_uint64(src->data);
-               }
-               break;
-       case SR_DF_LOGIC:
-               logic = packet->payload;
-               if (ctx->num_samples == 0) {
-                       /* First logic packet in the feed. */
-                       *out = gen_header(o->sdi, ctx);
-               } else
-                       *out = g_string_sized_new(512);
-               for (i = 0; i <= logic->length - logic->unitsize; i += logic->unitsize) {
-                       for (j = 0; j < logic->unitsize; j++) {
-                               /* The OLS format wants the samples presented MSB first. */
-                               c = *((uint8_t *)logic->data + i + logic->unitsize - 1 - j);
-                               g_string_append_printf(*out, "%02x", c);
-                       }
-                       g_string_append_printf(*out, "@%"PRIu64"\n", ctx->num_samples++);
-               }
-               break;
-       }
-
-       return SR_OK;
-}
-
-static int cleanup(struct sr_output *o)
-{
-       struct context *ctx;
-
-       if (!o || !o->sdi)
-               return SR_ERR_ARG;
-
-       ctx = o->internal;
-       g_free(ctx);
-       o->internal = NULL;
-
-       return SR_OK;
-}
-
-SR_PRIV struct sr_output_format output_ols = {
-       .id = "ols",
-       .description = "OpenBench Logic Sniffer",
-       .init = init,
-       .receive = receive,
-       .cleanup = cleanup
-};
diff --git a/output/output.c b/output/output.c
deleted file mode 100644 (file)
index 4cf78f6..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.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 "libsigrok.h"
-#include "libsigrok-internal.h"
-
-/**
- * @file
- *
- * Output file/data format handling.
- */
-
-/**
- * @defgroup grp_output Output formats
- *
- * Output file/data format handling.
- *
- * libsigrok supports several output (file) formats, e.g. binary, VCD,
- * gnuplot, and so on. It provides an output API that frontends can use.
- * New output formats can be added/implemented in libsigrok without having
- * to change the frontends at all.
- *
- * All output modules are fed data in a stream. Devices that can stream data
- * into libsigrok, instead of storing and then transferring the whole buffer,
- * can thus generate output live.
- *
- * Output modules generate a newly allocated GString. The caller is then
- * expected to free this with g_string_free() when finished with it.
- *
- * @{
- */
-
-/** @cond PRIVATE */
-extern SR_PRIV struct sr_output_format output_bits;
-extern SR_PRIV struct sr_output_format output_hex;
-extern SR_PRIV struct sr_output_format output_ascii;
-extern SR_PRIV struct sr_output_format output_binary;
-extern SR_PRIV struct sr_output_format output_vcd;
-extern SR_PRIV struct sr_output_format output_ols;
-extern SR_PRIV struct sr_output_format output_gnuplot;
-extern SR_PRIV struct sr_output_format output_chronovu_la8;
-extern SR_PRIV struct sr_output_format output_csv;
-extern SR_PRIV struct sr_output_format output_analog;
-/* @endcond */
-
-static struct sr_output_format *output_module_list[] = {
-       &output_ascii,
-       &output_binary,
-       &output_bits,
-       &output_csv,
-       &output_gnuplot,
-       &output_hex,
-       &output_ols,
-       &output_vcd,
-       &output_chronovu_la8,
-       &output_analog,
-       NULL,
-};
-
-/** @since 0.1.0 */
-SR_API struct sr_output_format **sr_output_list(void)
-{
-       return output_module_list;
-}
-
-/** @since 0.3.0 */
-SR_API struct sr_output *sr_output_new(struct sr_output_format *of,
-               GHashTable *params, const struct sr_dev_inst *sdi)
-{
-       struct sr_output *o;
-
-       o = g_malloc(sizeof(struct sr_output));
-       o->format = of;
-       o->sdi = sdi;
-       o->params = params;
-       if (o->format->init && o->format->init(o) != SR_OK) {
-               g_free(o);
-               o = NULL;
-       }
-
-       return o;
-}
-
-/** @since 0.3.0 */
-SR_API int sr_output_send(struct sr_output *o,
-               const struct sr_datafeed_packet *packet, GString **out)
-{
-       return o->format->receive(o, packet, out);
-}
-
-/** @since 0.3.0 */
-SR_API int sr_output_free(struct sr_output *o)
-{
-       int ret;
-
-       ret = SR_OK;
-       if (o->format->cleanup)
-               ret = o->format->cleanup(o);
-       g_free(o);
-
-       return ret;
-}
-
-/** @} */
diff --git a/output/vcd.c b/output/vcd.c
deleted file mode 100644 (file)
index 87f8049..0000000
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
- * Copyright (C) 2013 Bert Vermeulen <bert@biot.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 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <glib.h>
-#include "config.h" /* Needed for PACKAGE and others. */
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "output/vcd"
-
-struct context {
-       int num_enabled_channels;
-       GArray *channelindices;
-       uint8_t *prevsample;
-       gboolean header_done;
-       int period;
-       int *channel_index;
-       uint64_t samplerate;
-       uint64_t samplecount;
-};
-
-static const char *const vcd_header_comment =
-       "$comment\n  Acquisition with %d/%d channels at %s\n$end\n";
-
-static int init(struct sr_output *o)
-{
-       struct context *ctx;
-       struct sr_channel *ch;
-       GSList *l;
-       int num_enabled_channels, i;
-
-       num_enabled_channels = 0;
-       for (l = o->sdi->channels; l; l = l->next) {
-               ch = l->data;
-               if (ch->type != SR_CHANNEL_LOGIC)
-                       continue;
-               if (!ch->enabled)
-                       continue;
-               num_enabled_channels++;
-       }
-       if (num_enabled_channels > 94) {
-               sr_err("VCD only supports 94 channels.");
-               return SR_ERR;
-       }
-
-       ctx = g_malloc0(sizeof(struct context));
-       o->internal = ctx;
-       ctx->num_enabled_channels = num_enabled_channels;
-       ctx->channel_index = g_malloc(sizeof(int) * ctx->num_enabled_channels);
-
-       /* Once more to map the enabled channels. */
-       for (i = 0, l = o->sdi->channels; l; l = l->next) {
-               ch = l->data;
-               if (ch->type != SR_CHANNEL_LOGIC)
-                       continue;
-               if (!ch->enabled)
-                       continue;
-               ctx->channel_index[i++] = ch->index;
-       }
-
-       return SR_OK;
-}
-
-static GString *gen_header(struct sr_output *o)
-{
-       struct context *ctx;
-       struct sr_channel *ch;
-       GVariant *gvar;
-       GString *header;
-       GSList *l;
-       time_t t;
-       int num_channels, i;
-       char *samplerate_s, *frequency_s, *timestamp;
-
-       ctx = o->internal;
-       header = g_string_sized_new(512);
-       num_channels = g_slist_length(o->sdi->channels);
-
-       /* timestamp */
-       t = time(NULL);
-       timestamp = g_strdup(ctime(&t));
-       timestamp[strlen(timestamp)-1] = 0;
-       g_string_printf(header, "$date %s $end\n", timestamp);
-       g_free(timestamp);
-
-       /* generator */
-       g_string_append_printf(header, "$version %s %s $end\n",
-                       PACKAGE, PACKAGE_VERSION);
-       g_string_append_printf(header, "$comment\n  Acquisition with "
-                       "%d/%d channels", ctx->num_enabled_channels, num_channels);
-
-       if (ctx->samplerate == 0) {
-               if (sr_config_get(o->sdi->driver, o->sdi, NULL, SR_CONF_SAMPLERATE,
-                               &gvar) == SR_OK) {
-                       ctx->samplerate = g_variant_get_uint64(gvar);
-                       g_variant_unref(gvar);
-               }
-       }
-       if (ctx->samplerate != 0) {
-               samplerate_s = sr_samplerate_string(ctx->samplerate);
-               g_string_append_printf(header, " at %s", samplerate_s);
-               g_free(samplerate_s);
-       }
-       g_string_append_printf(header, "\n$end\n");
-
-       /* timescale */
-       /* VCD can only handle 1/10/100 (s - fs), so scale up first */
-       if (ctx->samplerate > SR_MHZ(1))
-               ctx->period = SR_GHZ(1);
-       else if (ctx->samplerate > SR_KHZ(1))
-               ctx->period = SR_MHZ(1);
-       else
-               ctx->period = SR_KHZ(1);
-       frequency_s = sr_period_string(ctx->period);
-       g_string_append_printf(header, "$timescale %s $end\n", frequency_s);
-       g_free(frequency_s);
-
-       /* scope */
-       g_string_append_printf(header, "$scope module %s $end\n", PACKAGE);
-
-       /* Wires / channels */
-       for (i = 0, l = o->sdi->channels; l; l = l->next, i++) {
-               ch = l->data;
-               if (ch->type != SR_CHANNEL_LOGIC)
-                       continue;
-               if (!ch->enabled)
-                       continue;
-               g_string_append_printf(header, "$var wire 1 %c %s $end\n",
-                               (char)('!' + i), ch->name);
-       }
-
-       g_string_append(header, "$upscope $end\n$enddefinitions $end\n");
-
-       return header;
-}
-
-static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
-               GString **out)
-{
-       const struct sr_datafeed_meta *meta;
-       const struct sr_datafeed_logic *logic;
-       const struct sr_config *src;
-       GSList *l;
-       struct context *ctx;
-       unsigned int i;
-       int p, curbit, prevbit, index;
-       uint8_t *sample;
-       gboolean timestamp_written;
-
-       *out = NULL;
-       if (!o || !o->internal)
-               return SR_ERR_BUG;
-       ctx = o->internal;
-
-       switch (packet->type) {
-       case SR_DF_META:
-               meta = packet->payload;
-               for (l = meta->config; l; l = l->next) {
-                       src = l->data;
-                       if (src->key != SR_CONF_SAMPLERATE)
-                               continue;
-                       ctx->samplerate = g_variant_get_uint64(src->data);
-               }
-               break;
-       case SR_DF_LOGIC:
-               logic = packet->payload;
-
-               if (!ctx->header_done) {
-                       *out = gen_header(o);
-                       ctx->header_done = TRUE;
-               } else {
-                       *out = g_string_sized_new(512);
-               }
-
-               if (!ctx->prevsample) {
-                       /* Can't allocate this until we know the stream's unitsize. */
-                       ctx->prevsample = g_malloc0(logic->unitsize);
-               }
-
-               for (i = 0; i <= logic->length - logic->unitsize; i += logic->unitsize) {
-                       sample = logic->data + i;
-                       timestamp_written = FALSE;
-
-                       for (p = 0; p < ctx->num_enabled_channels; p++) {
-                               index = ctx->channel_index[p];
-
-                               curbit = ((unsigned)sample[index / 8]
-                                               >> (index % 8)) & 1;
-                               prevbit = ((unsigned)ctx->prevsample[index / 8]
-                                               >> (index % 8)) & 1;
-
-                               /* VCD only contains deltas/changes of signals. */
-                               if (prevbit == curbit && ctx->samplecount > 0)
-                                       continue;
-
-                               /* Output timestamp of subsequent signal changes. */
-                               if (!timestamp_written)
-                                       g_string_append_printf(*out, "#%.0f",
-                                               (double)ctx->samplecount /
-                                                       ctx->samplerate * ctx->period);
-
-                               /* Output which signal changed to which value. */
-                               g_string_append_c(*out, ' ');
-                               g_string_append_c(*out, '0' + curbit);
-                               g_string_append_c(*out, '!' + p);
-
-                               timestamp_written = TRUE;
-                       }
-
-                       if (timestamp_written)
-                               g_string_append_c(*out, '\n');
-
-                       ctx->samplecount++;
-                       memcpy(ctx->prevsample, sample, logic->unitsize);
-               }
-               break;
-       case SR_DF_END:
-               /* Write final timestamp as length indicator. */
-               *out = g_string_sized_new(512);
-               g_string_printf(*out, "#%.0f\n",
-                               (double)ctx->samplecount / ctx->samplerate * ctx->period);
-               break;
-       }
-
-       return SR_OK;
-}
-
-static int cleanup(struct sr_output *o)
-{
-       struct context *ctx;
-
-       if (!o || !o->internal)
-               return SR_ERR_ARG;
-
-       ctx = o->internal;
-       g_free(ctx->prevsample);
-       g_free(ctx->channel_index);
-       g_free(ctx);
-
-       return SR_OK;
-}
-
-struct sr_output_format output_vcd = {
-       .id = "vcd",
-       .description = "Value Change Dump (VCD)",
-       .init = init,
-       .receive = receive,
-       .cleanup = cleanup,
-};
diff --git a/session.c b/session.c
deleted file mode 100644 (file)
index d8a3b00..0000000
--- a/session.c
+++ /dev/null
@@ -1,910 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-/** @cond PRIVATE */
-#define LOG_PREFIX "session"
-/** @endcond */
-
-/**
- * @file
- *
- * Creating, using, or destroying libsigrok sessions.
- */
-
-/**
- * @defgroup grp_session Session handling
- *
- * Creating, using, or destroying libsigrok sessions.
- *
- * @{
- */
-
-struct source {
-       int timeout;
-       sr_receive_data_callback cb;
-       void *cb_data;
-
-       /* This is used to keep track of the object (fd, pollfd or channel) which is
-        * being polled and will be used to match the source when removing it again.
-        */
-       gintptr poll_object;
-};
-
-struct datafeed_callback {
-       sr_datafeed_callback cb;
-       void *cb_data;
-};
-
-/**
- * Create a new session.
- * Currently, there can be only one session at a time within the same process.
- *
- * @retval SR_OK Success.
- * @retval SR_ERR_BUG A session exists already.
- *
- * @since 0.4.0
- */
-SR_API int sr_session_new(struct sr_session **new_session)
-{
-       struct sr_session *session;
-
-       session = g_malloc0(sizeof(struct sr_session));
-
-       session->source_timeout = -1;
-       session->running = FALSE;
-       session->abort_session = FALSE;
-       g_mutex_init(&session->stop_mutex);
-
-       *new_session = session;
-
-       return SR_OK;
-}
-
-/**
- * Destroy a session.
- * This frees up all memory used by the session.
- *
- * @retval SR_OK Success.
- * @retval SR_ERR_ARG Invalid session passed.
- *
- * @since 0.4.0
- */
-SR_API int sr_session_destroy(struct sr_session *session)
-{
-       if (!session) {
-               sr_err("%s: session was NULL", __func__);
-               return SR_ERR_ARG;
-       }
-
-       sr_session_dev_remove_all(session);
-       g_mutex_clear(&session->stop_mutex);
-       if (session->trigger)
-               sr_trigger_free(session->trigger);
-
-       g_free(session);
-
-       return SR_OK;
-}
-
-/**
- * Remove all the devices from a session.
- *
- * The session itself (i.e., the struct sr_session) is not free'd and still
- * exists after this function returns.
- *
- * @retval SR_OK Success.
- * @retval SR_ERR_BUG Invalid session passed.
- *
- * @since 0.4.0
- */
-SR_API int sr_session_dev_remove_all(struct sr_session *session)
-{
-       struct sr_dev_inst *sdi;
-       GSList *l;
-
-       if (!session) {
-               sr_err("%s: session was NULL", __func__);
-               return SR_ERR_ARG;
-       }
-
-       for (l = session->devs; l; l = l->next) {
-               sdi = (struct sr_dev_inst *) l->data;
-               sdi->session = NULL;
-       }
-
-       g_slist_free(session->devs);
-       session->devs = NULL;
-
-       return SR_OK;
-}
-
-/**
- * Add a device instance to a session.
- *
- * @param sdi The device instance to add to a session. Must not
- *            be NULL. Also, sdi->driver and sdi->driver->dev_open must
- *            not be NULL.
- *
- * @retval SR_OK Success.
- * @retval SR_ERR_ARG Invalid argument.
- *
- * @since 0.4.0
- */
-SR_API int sr_session_dev_add(struct sr_session *session,
-               struct sr_dev_inst *sdi)
-{
-       int ret;
-
-       if (!sdi) {
-               sr_err("%s: sdi was NULL", __func__);
-               return SR_ERR_ARG;
-       }
-
-       if (!session) {
-               sr_err("%s: session was NULL", __func__);
-               return SR_ERR_ARG;
-       }
-
-       /* If sdi->session is not NULL, the device is already in this or
-        * another session. */
-       if (sdi->session) {
-               sr_err("%s: already assigned to session", __func__);
-               return SR_ERR_ARG;
-       }
-
-       /* If sdi->driver is NULL, this is a virtual device. */
-       if (!sdi->driver) {
-               sr_dbg("%s: sdi->driver was NULL, this seems to be "
-                      "a virtual device; continuing", __func__);
-               /* Just add the device, don't run dev_open(). */
-               session->devs = g_slist_append(session->devs, (gpointer)sdi);
-               sdi->session = session;
-               return SR_OK;
-       }
-
-       /* sdi->driver is non-NULL (i.e. we have a real device). */
-       if (!sdi->driver->dev_open) {
-               sr_err("%s: sdi->driver->dev_open was NULL", __func__);
-               return SR_ERR_BUG;
-       }
-
-       session->devs = g_slist_append(session->devs, (gpointer)sdi);
-       sdi->session = session;
-
-       if (session->running) {
-               /* Adding a device to a running session. Commit settings
-                * and start acquisition on that device now. */
-               if ((ret = sr_config_commit(sdi)) != SR_OK) {
-                       sr_err("Failed to commit device settings before "
-                              "starting acquisition in running session (%s)",
-                              sr_strerror(ret));
-                       return ret;
-               }
-               if ((ret = sdi->driver->dev_acquisition_start(sdi,
-                                               (void *)sdi)) != SR_OK) {
-                       sr_err("Failed to start acquisition of device in "
-                              "running session (%s)", sr_strerror(ret));
-                       return ret;
-               }
-       }
-
-       return SR_OK;
-}
-
-/**
- * List all device instances attached to a session.
- *
- * @param devlist A pointer where the device instance list will be
- *                stored on return. If no devices are in the session,
- *                this will be NULL. Each element in the list points
- *                to a struct sr_dev_inst *.
- *                The list must be freed by the caller, but not the
- *                elements pointed to.
- *
- * @retval SR_OK Success.
- * @retval SR_ERR_ARG Invalid argument.
- *
- * @since 0.4.0
- */
-SR_API int sr_session_dev_list(struct sr_session *session, GSList **devlist)
-{
-       if (!session)
-               return SR_ERR_ARG;
-
-       if (!devlist)
-               return SR_ERR_ARG;
-
-       *devlist = g_slist_copy(session->devs);
-
-       return SR_OK;
-}
-
-/**
- * Remove all datafeed callbacks in a session.
- *
- * @retval SR_OK Success.
- * @retval SR_ERR_ARG Invalid session passed.
- *
- * @since 0.4.0
- */
-SR_API int sr_session_datafeed_callback_remove_all(struct sr_session *session)
-{
-       if (!session) {
-               sr_err("%s: session was NULL", __func__);
-               return SR_ERR_ARG;
-       }
-
-       g_slist_free_full(session->datafeed_callbacks, g_free);
-       session->datafeed_callbacks = NULL;
-
-       return SR_OK;
-}
-
-/**
- * Add a datafeed callback to a session.
- *
- * @param cb Function to call when a chunk of data is received.
- *           Must not be NULL.
- * @param cb_data Opaque pointer passed in by the caller.
- *
- * @retval SR_OK Success.
- * @retval SR_ERR_BUG No session exists.
- *
- * @since 0.3.0
- */
-SR_API int sr_session_datafeed_callback_add(struct sr_session *session,
-               sr_datafeed_callback cb, void *cb_data)
-{
-       struct datafeed_callback *cb_struct;
-
-       if (!session) {
-               sr_err("%s: session was NULL", __func__);
-               return SR_ERR_BUG;
-       }
-
-       if (!cb) {
-               sr_err("%s: cb was NULL", __func__);
-               return SR_ERR_ARG;
-       }
-
-       if (!(cb_struct = g_try_malloc0(sizeof(struct datafeed_callback))))
-               return SR_ERR_MALLOC;
-
-       cb_struct->cb = cb;
-       cb_struct->cb_data = cb_data;
-
-       session->datafeed_callbacks =
-           g_slist_append(session->datafeed_callbacks, cb_struct);
-
-       return SR_OK;
-}
-
-SR_API struct sr_trigger *sr_session_trigger_get(struct sr_session *session)
-{
-       return session->trigger;
-}
-
-SR_API int sr_session_trigger_set(struct sr_session *session, struct sr_trigger *trig)
-{
-       session->trigger = trig;
-
-       return SR_OK;
-}
-
-/**
- * Call every device in the current session's callback.
- *
- * For sessions not driven by select loops such as sr_session_run(),
- * but driven by another scheduler, this can be used to poll the devices
- * from within that scheduler.
- *
- * @param block If TRUE, this call will wait for any of the session's
- *              sources to fire an event on the file descriptors, or
- *              any of their timeouts to activate. In other words, this
- *              can be used as a select loop.
- *              If FALSE, all sources have their callback run, regardless
- *              of file descriptor or timeout status.
- *
- * @retval SR_OK Success.
- * @retval SR_ERR Error occured.
- */
-static int sr_session_iteration(struct sr_session *session, gboolean block)
-{
-       unsigned int i;
-       int ret;
-
-       ret = g_poll(session->pollfds, session->num_sources,
-                       block ? session->source_timeout : 0);
-       for (i = 0; i < session->num_sources; i++) {
-               if (session->pollfds[i].revents > 0 || (ret == 0
-                       && session->source_timeout == session->sources[i].timeout)) {
-                       /*
-                        * Invoke the source's callback on an event,
-                        * or if the poll timed out and this source
-                        * asked for that timeout.
-                        */
-                       if (!session->sources[i].cb(session->pollfds[i].fd,
-                                       session->pollfds[i].revents,
-                                       session->sources[i].cb_data))
-                               sr_session_source_remove(session,
-                                               session->sources[i].poll_object);
-               }
-               /*
-                * We want to take as little time as possible to stop
-                * the session if we have been told to do so. Therefore,
-                * we check the flag after processing every source, not
-                * just once per main event loop.
-                */
-               g_mutex_lock(&session->stop_mutex);
-               if (session->abort_session) {
-                       sr_session_stop_sync(session);
-                       /* But once is enough. */
-                       session->abort_session = FALSE;
-               }
-               g_mutex_unlock(&session->stop_mutex);
-       }
-
-       return SR_OK;
-}
-
-
-static int verify_trigger(struct sr_trigger *trigger)
-{
-       struct sr_trigger_stage *stage;
-       struct sr_trigger_match *match;
-       GSList *l, *m;
-
-       if (!trigger->stages) {
-               sr_err("No trigger stages defined.");
-               return SR_ERR;
-       }
-
-       sr_spew("Checking trigger:");
-       for (l = trigger->stages; l; l = l->next) {
-               stage = l->data;
-               if (!stage->matches) {
-                       sr_err("Stage %d has no matches defined.", stage->stage);
-                       return SR_ERR;
-               }
-               for (m = stage->matches; m; m = m->next) {
-                       match = m->data;
-                       if (!match->channel) {
-                               sr_err("Stage %d match has no channel.", stage->stage);
-                               return SR_ERR;
-                       }
-                       if (!match->match) {
-                               sr_err("Stage %d match is not defined.", stage->stage);
-                               return SR_ERR;
-                       }
-                       sr_spew("Stage %d match on channel %s, match %d", stage->stage,
-                                       match->channel->name, match->match);
-               }
-       }
-
-       return SR_OK;
-}
-/**
- * Start a session.
- *
- * @retval SR_OK Success.
- * @retval SR_ERR_ARG Invalid session passed.
- *
- * @since 0.4.0
- */
-SR_API int sr_session_start(struct sr_session *session)
-{
-       struct sr_dev_inst *sdi;
-       GSList *l;
-       int ret;
-
-       if (!session) {
-               sr_err("%s: session was NULL", __func__);
-               return SR_ERR_ARG;
-       }
-
-       if (!session->devs) {
-               sr_err("%s: session->devs was NULL; a session "
-                      "cannot be started without devices.", __func__);
-               return SR_ERR_ARG;
-       }
-
-       if (session->trigger && verify_trigger(session->trigger) != SR_OK)
-               return SR_ERR;
-
-       sr_info("Starting.");
-
-       ret = SR_OK;
-       for (l = session->devs; l; l = l->next) {
-               sdi = l->data;
-               if ((ret = sr_config_commit(sdi)) != SR_OK) {
-                       sr_err("Failed to commit device settings before "
-                              "starting acquisition (%s)", sr_strerror(ret));
-                       break;
-               }
-               if ((ret = sdi->driver->dev_acquisition_start(sdi, sdi)) != SR_OK) {
-                       sr_err("%s: could not start an acquisition "
-                              "(%s)", __func__, sr_strerror(ret));
-                       break;
-               }
-       }
-
-       /* TODO: What if there are multiple devices? Which return code? */
-
-       return ret;
-}
-
-/**
- * Run a session.
- *
- * @retval SR_OK Success.
- * @retval SR_ERR_ARG Invalid session passed.
- *
- * @since 0.4.0
- */
-SR_API int sr_session_run(struct sr_session *session)
-{
-       if (!session) {
-               sr_err("%s: session was NULL", __func__);
-               return SR_ERR_ARG;
-       }
-
-       if (!session->devs) {
-               /* TODO: Actually the case? */
-               sr_err("%s: session->devs was NULL; a session "
-                      "cannot be run without devices.", __func__);
-               return SR_ERR_ARG;
-       }
-       session->running = TRUE;
-
-       sr_info("Running.");
-
-       /* Do we have real sources? */
-       if (session->num_sources == 1 && session->pollfds[0].fd == -1) {
-               /* Dummy source, freewheel over it. */
-               while (session->num_sources)
-                       session->sources[0].cb(-1, 0, session->sources[0].cb_data);
-       } else {
-               /* Real sources, use g_poll() main loop. */
-               while (session->num_sources)
-                       sr_session_iteration(session, TRUE);
-       }
-
-       return SR_OK;
-}
-
-/**
- * Stop a session.
- *
- * The session is stopped immediately, with all acquisition sessions stopped
- * and hardware drivers cleaned up.
- *
- * This must be called from within the session thread, to prevent freeing
- * resources that the session thread will try to use.
- *
- * @retval SR_OK Success.
- * @retval SR_ERR_ARG Invalid session passed.
- *
- * @private
- */
-SR_PRIV int sr_session_stop_sync(struct sr_session *session)
-{
-       struct sr_dev_inst *sdi;
-       GSList *l;
-
-       if (!session) {
-               sr_err("%s: session was NULL", __func__);
-               return SR_ERR_ARG;
-       }
-
-       sr_info("Stopping.");
-
-       for (l = session->devs; l; l = l->next) {
-               sdi = l->data;
-               if (sdi->driver) {
-                       if (sdi->driver->dev_acquisition_stop)
-                               sdi->driver->dev_acquisition_stop(sdi, sdi);
-               }
-       }
-       session->running = FALSE;
-
-       return SR_OK;
-}
-
-/**
- * Stop a session.
- *
- * The session is stopped immediately, with all acquisition sessions being
- * stopped and hardware drivers cleaned up.
- *
- * If the session is run in a separate thread, this function will not block
- * until the session is finished executing. It is the caller's responsibility
- * to wait for the session thread to return before assuming that the session is
- * completely decommissioned.
- *
- * @retval SR_OK Success.
- * @retval SR_ERR_ARG Invalid session passed.
- *
- * @since 0.4.0
- */
-SR_API int sr_session_stop(struct sr_session *session)
-{
-       if (!session) {
-               sr_err("%s: session was NULL", __func__);
-               return SR_ERR_BUG;
-       }
-
-       g_mutex_lock(&session->stop_mutex);
-       session->abort_session = TRUE;
-       g_mutex_unlock(&session->stop_mutex);
-
-       return SR_OK;
-}
-
-/**
- * Debug helper.
- *
- * @param packet The packet to show debugging information for.
- */
-static void datafeed_dump(const struct sr_datafeed_packet *packet)
-{
-       const struct sr_datafeed_logic *logic;
-       const struct sr_datafeed_analog *analog;
-
-       switch (packet->type) {
-       case SR_DF_HEADER:
-               sr_dbg("bus: Received SR_DF_HEADER packet.");
-               break;
-       case SR_DF_TRIGGER:
-               sr_dbg("bus: Received SR_DF_TRIGGER packet.");
-               break;
-       case SR_DF_META:
-               sr_dbg("bus: Received SR_DF_META packet.");
-               break;
-       case SR_DF_LOGIC:
-               logic = packet->payload;
-               sr_dbg("bus: Received SR_DF_LOGIC packet (%" PRIu64 " bytes, "
-                      "unitsize = %d).", logic->length, logic->unitsize);
-               break;
-       case SR_DF_ANALOG:
-               analog = packet->payload;
-               sr_dbg("bus: Received SR_DF_ANALOG packet (%d samples).",
-                      analog->num_samples);
-               break;
-       case SR_DF_END:
-               sr_dbg("bus: Received SR_DF_END packet.");
-               break;
-       case SR_DF_FRAME_BEGIN:
-               sr_dbg("bus: Received SR_DF_FRAME_BEGIN packet.");
-               break;
-       case SR_DF_FRAME_END:
-               sr_dbg("bus: Received SR_DF_FRAME_END packet.");
-               break;
-       default:
-               sr_dbg("bus: Received unknown packet type: %d.", packet->type);
-               break;
-       }
-}
-
-/**
- * Send a packet to whatever is listening on the datafeed bus.
- *
- * Hardware drivers use this to send a data packet to the frontend.
- *
- * @param sdi TODO.
- * @param packet The datafeed packet to send to the session bus.
- *
- * @retval SR_OK Success.
- * @retval SR_ERR_ARG Invalid argument.
- *
- * @private
- */
-SR_PRIV int sr_session_send(const struct sr_dev_inst *sdi,
-                           const struct sr_datafeed_packet *packet)
-{
-       GSList *l;
-       struct datafeed_callback *cb_struct;
-
-       if (!sdi) {
-               sr_err("%s: sdi was NULL", __func__);
-               return SR_ERR_ARG;
-       }
-
-       if (!packet) {
-               sr_err("%s: packet was NULL", __func__);
-               return SR_ERR_ARG;
-       }
-
-       for (l = sdi->session->datafeed_callbacks; l; l = l->next) {
-               if (sr_log_loglevel_get() >= SR_LOG_DBG)
-                       datafeed_dump(packet);
-               cb_struct = l->data;
-               cb_struct->cb(sdi, packet, cb_struct->cb_data);
-       }
-
-       return SR_OK;
-}
-
-/**
- * Add an event source for a file descriptor.
- *
- * @param pollfd The GPollFD.
- * @param[in] timeout Max time to wait before the callback is called,
- *              ignored if 0.
- * @param cb Callback function to add. Must not be NULL.
- * @param cb_data Data for the callback function. Can be NULL.
- * @param poll_object TODO.
- *
- * @retval SR_OK Success.
- * @retval SR_ERR_ARG Invalid argument.
- * @retval SR_ERR_MALLOC Memory allocation error.
- */
-static int _sr_session_source_add(struct sr_session *session, GPollFD *pollfd,
-               int timeout, sr_receive_data_callback cb, void *cb_data, gintptr poll_object)
-{
-       struct source *new_sources, *s;
-       GPollFD *new_pollfds;
-
-       if (!cb) {
-               sr_err("%s: cb was NULL", __func__);
-               return SR_ERR_ARG;
-       }
-
-       /* Note: cb_data can be NULL, that's not a bug. */
-
-       new_pollfds = g_try_realloc(session->pollfds,
-                       sizeof(GPollFD) * (session->num_sources + 1));
-       if (!new_pollfds) {
-               sr_err("%s: new_pollfds malloc failed", __func__);
-               return SR_ERR_MALLOC;
-       }
-
-       new_sources = g_try_realloc(session->sources, sizeof(struct source) *
-                       (session->num_sources + 1));
-       if (!new_sources) {
-               sr_err("%s: new_sources malloc failed", __func__);
-               return SR_ERR_MALLOC;
-       }
-
-       new_pollfds[session->num_sources] = *pollfd;
-       s = &new_sources[session->num_sources++];
-       s->timeout = timeout;
-       s->cb = cb;
-       s->cb_data = cb_data;
-       s->poll_object = poll_object;
-       session->pollfds = new_pollfds;
-       session->sources = new_sources;
-
-       if (timeout != session->source_timeout && timeout > 0
-           && (session->source_timeout == -1 || timeout < session->source_timeout))
-               session->source_timeout = timeout;
-
-       return SR_OK;
-}
-
-/**
- * Add an event source for a file descriptor.
- *
- * @param fd The file descriptor.
- * @param events Events to check for.
- * @param timeout Max time to wait before the callback is called, ignored if 0.
- * @param cb Callback function to add. Must not be NULL.
- * @param cb_data Data for the callback function. Can be NULL.
- *
- * @retval SR_OK Success.
- * @retval SR_ERR_ARG Invalid argument.
- * @retval SR_ERR_MALLOC Memory allocation error.
- *
- * @since 0.3.0
- */
-SR_API int sr_session_source_add(struct sr_session *session, int fd,
-               int events, int timeout, sr_receive_data_callback cb, void *cb_data)
-{
-       GPollFD p;
-
-       (void) session;
-
-       p.fd = fd;
-       p.events = events;
-
-       return _sr_session_source_add(session, &p, timeout, cb, cb_data, (gintptr)fd);
-}
-
-/**
- * Add an event source for a GPollFD.
- *
- * @param pollfd The GPollFD.
- * @param timeout Max time to wait before the callback is called, ignored if 0.
- * @param cb Callback function to add. Must not be NULL.
- * @param cb_data Data for the callback function. Can be NULL.
- *
- * @retval SR_OK Success.
- * @retval SR_ERR_ARG Invalid argument.
- * @retval SR_ERR_MALLOC Memory allocation error.
- *
- * @since 0.3.0
- */
-SR_API int sr_session_source_add_pollfd(struct sr_session *session,
-               GPollFD *pollfd, int timeout, sr_receive_data_callback cb,
-               void *cb_data)
-{
-       (void) session;
-
-       return _sr_session_source_add(session, pollfd, timeout, cb,
-                                     cb_data, (gintptr)pollfd);
-}
-
-/**
- * Add an event source for a GIOChannel.
- *
- * @param channel The GIOChannel.
- * @param events Events to poll on.
- * @param timeout Max time to wait before the callback is called, ignored if 0.
- * @param cb Callback function to add. Must not be NULL.
- * @param cb_data Data for the callback function. Can be NULL.
- *
- * @retval SR_OK Success.
- * @retval SR_ERR_ARG Invalid argument.
- * @retval SR_ERR_MALLOC Memory allocation error.
- *
- * @since 0.3.0
- */
-SR_API int sr_session_source_add_channel(struct sr_session *session,
-               GIOChannel *channel, int events, int timeout,
-               sr_receive_data_callback cb, void *cb_data)
-{
-       GPollFD p;
-
-       (void) session;
-
-#ifdef _WIN32
-       g_io_channel_win32_make_pollfd(channel, events, &p);
-#else
-       p.fd = g_io_channel_unix_get_fd(channel);
-       p.events = events;
-#endif
-
-       return _sr_session_source_add(session, &p, timeout, cb, cb_data, (gintptr)channel);
-}
-
-/**
- * Remove the source belonging to the specified channel.
- *
- * @todo Add more error checks and logging.
- *
- * @param poll_object The channel for which the source should be removed.
- *
- * @retval SR_OK Success
- * @retval SR_ERR_ARG Invalid arguments
- * @retval SR_ERR_MALLOC Memory allocation error
- * @retval SR_ERR_BUG Internal error
- */
-static int _sr_session_source_remove(struct sr_session *session, gintptr poll_object)
-{
-       struct source *new_sources;
-       GPollFD *new_pollfds;
-       unsigned int old;
-
-       if (!session->sources || !session->num_sources) {
-               sr_err("%s: sources was NULL", __func__);
-               return SR_ERR_BUG;
-       }
-
-       for (old = 0; old < session->num_sources; old++) {
-               if (session->sources[old].poll_object == poll_object)
-                       break;
-       }
-
-       /* fd not found, nothing to do */
-       if (old == session->num_sources)
-               return SR_OK;
-
-       session->num_sources -= 1;
-
-       if (old != session->num_sources) {
-               memmove(&session->pollfds[old], &session->pollfds[old+1],
-                       (session->num_sources - old) * sizeof(GPollFD));
-               memmove(&session->sources[old], &session->sources[old+1],
-                       (session->num_sources - old) * sizeof(struct source));
-       }
-
-       new_pollfds = g_try_realloc(session->pollfds, sizeof(GPollFD) * session->num_sources);
-       if (!new_pollfds && session->num_sources > 0) {
-               sr_err("%s: new_pollfds malloc failed", __func__);
-               return SR_ERR_MALLOC;
-       }
-
-       new_sources = g_try_realloc(session->sources, sizeof(struct source) * session->num_sources);
-       if (!new_sources && session->num_sources > 0) {
-               sr_err("%s: new_sources malloc failed", __func__);
-               return SR_ERR_MALLOC;
-       }
-
-       session->pollfds = new_pollfds;
-       session->sources = new_sources;
-
-       return SR_OK;
-}
-
-/**
- * Remove the source belonging to the specified file descriptor.
- *
- * @param fd The file descriptor for which the source should be removed.
- *
- * @retval SR_OK Success
- * @retval SR_ERR_ARG Invalid argument
- * @retval SR_ERR_MALLOC Memory allocation error.
- * @retval SR_ERR_BUG Internal error.
- *
- * @since 0.3.0
- */
-SR_API int sr_session_source_remove(struct sr_session *session, int fd)
-{
-       (void) session;
-
-       return _sr_session_source_remove(session, (gintptr)fd);
-}
-
-/**
- * Remove the source belonging to the specified poll descriptor.
- *
- * @param pollfd The poll descriptor for which the source should be removed.
- *
- * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments, or
- *         SR_ERR_MALLOC upon memory allocation errors, SR_ERR_BUG upon
- *         internal errors.
- *
- * @since 0.2.0
- */
-SR_API int sr_session_source_remove_pollfd(struct sr_session *session,
-               GPollFD *pollfd)
-{
-       (void) session;
-
-       return _sr_session_source_remove(session, (gintptr)pollfd);
-}
-
-/**
- * Remove the source belonging to the specified channel.
- *
- * @param channel The channel for which the source should be removed.
- *
- * @retval SR_OK Success.
- * @retval SR_ERR_ARG Invalid argument.
- * @retval SR_ERR_MALLOC Memory allocation error.
- * @return SR_ERR_BUG Internal error.
- *
- * @since 0.2.0
- */
-SR_API int sr_session_source_remove_channel(struct sr_session *session,
-               GIOChannel *channel)
-{
-       (void) session;
-
-       return _sr_session_source_remove(session, (gintptr)channel);
-}
-
-/** @} */
diff --git a/session_driver.c b/session_driver.c
deleted file mode 100644 (file)
index 9120ea1..0000000
+++ /dev/null
@@ -1,337 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Bert Vermeulen <bert@biot.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 <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/time.h>
-#include <zip.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "virtual-session"
-
-/* size of payloads sent across the session bus */
-/** @cond PRIVATE */
-#define CHUNKSIZE (512 * 1024)
-/** @endcond */
-
-SR_PRIV struct sr_dev_driver session_driver_info;
-static struct sr_dev_driver *di = &session_driver_info;
-
-struct session_vdev {
-       char *sessionfile;
-       char *capturefile;
-       struct zip *archive;
-       struct zip_file *capfile;
-       int bytes_read;
-       uint64_t samplerate;
-       int unitsize;
-       int num_channels;
-       int cur_chunk;
-       gboolean finished;
-};
-
-static const int hwcaps[] = {
-       SR_CONF_CAPTUREFILE,
-       SR_CONF_CAPTURE_UNITSIZE,
-       SR_CONF_SAMPLERATE,
-};
-
-static int receive_data(int fd, int revents, void *cb_data)
-{
-       struct sr_dev_inst *sdi;
-       struct session_vdev *vdev;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_logic logic;
-       struct zip_stat zs;
-       int ret, got_data;
-       char capturefile[16];
-       void *buf;
-
-       (void)fd;
-       (void)revents;
-
-       sdi = cb_data;
-       got_data = FALSE;
-       vdev = sdi->priv;
-       if (!vdev->finished) {
-               if (!vdev->capfile) {
-                       /* No capture file opened yet, or finished with the last
-                        * chunked one. */
-                       if (vdev->cur_chunk == 0) {
-                               /* capturefile is always the unchunked base name. */
-                               if (zip_stat(vdev->archive, vdev->capturefile, 0, &zs) != -1) {
-                                       /* No chunks, just a single capture file. */
-                                       vdev->cur_chunk = 0;
-                                       if (!(vdev->capfile = zip_fopen(vdev->archive,
-                                                       vdev->capturefile, 0)))
-                                               return FALSE;
-                                               sr_dbg("Opened %s.", vdev->capturefile);
-                               } else {
-                                       /* Try as first chunk filename. */
-                                       snprintf(capturefile, 15, "%s-1", vdev->capturefile);
-                                       if (zip_stat(vdev->archive, capturefile, 0, &zs) != -1) {
-                                               vdev->cur_chunk = 1;
-                                               if (!(vdev->capfile = zip_fopen(vdev->archive,
-                                                               capturefile, 0)))
-                                                       return FALSE;
-                                               sr_dbg("Opened %s.", capturefile);
-                                       } else {
-                                               sr_err("No capture file '%s' in " "session file '%s'.",
-                                                               vdev->capturefile, vdev->sessionfile);
-                                               return FALSE;
-                                       }
-                               }
-                       } else {
-                               /* Capture data is chunked, advance to the next chunk. */
-                               vdev->cur_chunk++;
-                               snprintf(capturefile, 15, "%s-%d", vdev->capturefile,
-                                               vdev->cur_chunk);
-                               if (zip_stat(vdev->archive, capturefile, 0, &zs) != -1) {
-                                       if (!(vdev->capfile = zip_fopen(vdev->archive,
-                                                       capturefile, 0)))
-                                               return FALSE;
-                                       sr_dbg("Opened %s.", capturefile);
-                               } else {
-                                       /* We got all the chunks, finish up. */
-                                       vdev->finished = TRUE;
-                                       return TRUE;
-                               }
-                       }
-               }
-
-               if (!(buf = g_try_malloc(CHUNKSIZE))) {
-                       sr_err("%s: buf malloc failed", __func__);
-                       return FALSE;
-               }
-
-               ret = zip_fread(vdev->capfile, buf,
-                               CHUNKSIZE / vdev->unitsize * vdev->unitsize);
-               if (ret > 0) {
-                       if (ret % vdev->unitsize != 0)
-                               sr_warn("Read size %d not a multiple of the"
-                                       " unit size %d.", ret, vdev->unitsize);
-                       got_data = TRUE;
-                       packet.type = SR_DF_LOGIC;
-                       packet.payload = &logic;
-                       logic.length = ret;
-                       logic.unitsize = vdev->unitsize;
-                       logic.data = buf;
-                       vdev->bytes_read += ret;
-                       sr_session_send(sdi, &packet);
-               } else {
-                       /* done with this capture file */
-                       zip_fclose(vdev->capfile);
-                       vdev->capfile = NULL;
-                       if (vdev->cur_chunk == 0) {
-                               /* It was the only file. */
-                               vdev->finished = TRUE;
-                       } else {
-                               /* There might be more chunks, so don't fall through
-                                * to the SR_DF_END here. */
-                               g_free(buf);
-                               return TRUE;
-                       }
-               }
-               g_free(buf);
-       }
-
-       if (!got_data) {
-               packet.type = SR_DF_END;
-               sr_session_send(sdi, &packet);
-               sr_session_source_remove(sdi->session, -1);
-       }
-
-       return TRUE;
-}
-
-/* driver callbacks */
-
-static int init(struct sr_context *sr_ctx)
-{
-       return std_init(sr_ctx, di, LOG_PREFIX);
-}
-
-static int dev_clear(void)
-{
-       struct drv_context *drvc;
-       GSList *l;
-
-       drvc = di->priv;
-       for (l = drvc->instances; l; l = l->next)
-               sr_dev_inst_free(l->data);
-       g_slist_free(drvc->instances);
-       drvc->instances = NULL;
-
-       return SR_OK;
-}
-
-static int dev_open(struct sr_dev_inst *sdi)
-{
-       struct drv_context *drvc;
-       struct session_vdev *vdev;
-
-       drvc = di->priv;
-       vdev = g_malloc0(sizeof(struct session_vdev));
-       sdi->priv = vdev;
-       drvc->instances = g_slist_append(drvc->instances, sdi);
-
-       return SR_OK;
-}
-
-static int dev_close(struct sr_dev_inst *sdi)
-{
-       const struct session_vdev *const vdev = sdi->priv;
-       g_free(vdev->sessionfile);
-       g_free(vdev->capturefile);
-
-       g_free(sdi->priv);
-       sdi->priv = NULL;
-
-       return SR_OK;
-}
-
-static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct session_vdev *vdev;
-
-       (void)cg;
-
-       switch (id) {
-       case SR_CONF_SAMPLERATE:
-               if (sdi) {
-                       vdev = sdi->priv;
-                       *data = g_variant_new_uint64(vdev->samplerate);
-               } else
-                       return SR_ERR;
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       struct session_vdev *vdev;
-
-       (void)cg;
-
-       vdev = sdi->priv;
-
-       switch (id) {
-       case SR_CONF_SAMPLERATE:
-               vdev->samplerate = g_variant_get_uint64(data);
-               sr_info("Setting samplerate to %" PRIu64 ".", vdev->samplerate);
-               break;
-       case SR_CONF_SESSIONFILE:
-               g_free(vdev->sessionfile);
-               vdev->sessionfile = g_strdup(g_variant_get_string(data, NULL));
-               sr_info("Setting sessionfile to '%s'.", vdev->sessionfile);
-               break;
-       case SR_CONF_CAPTUREFILE:
-               g_free(vdev->capturefile);
-               vdev->capturefile = g_strdup(g_variant_get_string(data, NULL));
-               sr_info("Setting capturefile to '%s'.", vdev->capturefile);
-               break;
-       case SR_CONF_CAPTURE_UNITSIZE:
-               vdev->unitsize = g_variant_get_uint64(data);
-               break;
-       case SR_CONF_NUM_LOGIC_CHANNELS:
-               vdev->num_channels = g_variant_get_uint64(data);
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
-               const struct sr_channel_group *cg)
-{
-       (void)sdi;
-       (void)cg;
-
-       switch (key) {
-       case SR_CONF_DEVICE_OPTIONS:
-               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
-                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
-               break;
-       default:
-               return SR_ERR_NA;
-       }
-
-       return SR_OK;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
-{
-       struct session_vdev *vdev;
-       int ret;
-
-       (void)cb_data;
-
-       vdev = sdi->priv;
-       vdev->bytes_read = 0;
-       vdev->cur_chunk = 0;
-       vdev->finished = FALSE;
-
-       sr_info("Opening archive %s file %s", vdev->sessionfile,
-               vdev->capturefile);
-
-       if (!(vdev->archive = zip_open(vdev->sessionfile, 0, &ret))) {
-               sr_err("Failed to open session file '%s': "
-                      "zip error %d.", vdev->sessionfile, ret);
-               return SR_ERR;
-       }
-
-       /* Send header packet to the session bus. */
-       std_session_send_df_header(sdi, LOG_PREFIX);
-
-       /* freewheeling source */
-       sr_session_source_add(sdi->session, -1, 0, 0, receive_data, (void *)sdi);
-
-       return SR_OK;
-}
-
-/** @private */
-SR_PRIV struct sr_dev_driver session_driver = {
-       .name = "virtual-session",
-       .longname = "Session-emulating driver",
-       .api_version = 1,
-       .init = init,
-       .cleanup = dev_clear,
-       .scan = NULL,
-       .dev_list = NULL,
-       .dev_clear = dev_clear,
-       .config_get = config_get,
-       .config_set = config_set,
-       .config_list = config_list,
-       .dev_open = dev_open,
-       .dev_close = dev_close,
-       .dev_acquisition_start = dev_acquisition_start,
-       .dev_acquisition_stop = NULL,
-       .priv = NULL,
-};
diff --git a/session_file.c b/session_file.c
deleted file mode 100644 (file)
index 1c1cee5..0000000
+++ /dev/null
@@ -1,508 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2013 Bert Vermeulen <bert@biot.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 <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <zip.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <glib.h>
-#include <glib/gstdio.h>
-#include "config.h" /* Needed for PACKAGE_VERSION and others. */
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-/** @cond PRIVATE */
-#define LOG_PREFIX "session-file"
-/** @endcond */
-
-/**
- * @file
- *
- * Loading and saving libsigrok session files.
- */
-
-/**
- * @addtogroup grp_session
- *
- * @{
- */
-
-extern struct sr_session *session;
-extern SR_PRIV struct sr_dev_driver session_driver;
-
-/** @private */
-SR_PRIV int sr_sessionfile_check(const char *filename)
-{
-       struct stat st;
-       struct zip *archive;
-       struct zip_file *zf;
-       struct zip_stat zs;
-       int version, ret;
-       char s[11];
-
-       if (!filename)
-               return SR_ERR_ARG;
-
-       if (stat(filename, &st) == -1) {
-               sr_err("Couldn't stat %s: %s", filename, strerror(errno));
-               return SR_ERR;
-       }
-
-       if (!(archive = zip_open(filename, 0, &ret)))
-               /* No logging: this can be used just to check if it's
-                * a sigrok session file or not. */
-               return SR_ERR;
-
-       /* check "version" */
-       version = 0;
-       if (!(zf = zip_fopen(archive, "version", 0))) {
-               sr_dbg("Not a sigrok session file: no version found.");
-               return SR_ERR;
-       }
-       if ((ret = zip_fread(zf, s, 10)) == -1)
-               return SR_ERR;
-       zip_fclose(zf);
-       s[ret] = 0;
-       version = strtoull(s, NULL, 10);
-       if (version > 2) {
-               sr_dbg("Cannot handle sigrok session file version %d.", version);
-               return SR_ERR;
-       }
-       sr_spew("Detected sigrok session file version %d.", version);
-
-       /* read "metadata" */
-       if (zip_stat(archive, "metadata", 0, &zs) == -1) {
-               sr_dbg("Not a valid sigrok session file.");
-               return SR_ERR;
-       }
-
-       return SR_OK;
-}
-
-/**
- * Load the session from the specified filename.
- *
- * @param filename The name of the session file to load. Must not be NULL.
- *
- * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments,
- *         SR_ERR_MALLOC upon memory allocation errors, or SR_ERR upon
- *         other errors.
- */
-SR_API int sr_session_load(const char *filename, struct sr_session **session)
-{
-       GKeyFile *kf;
-       GPtrArray *capturefiles;
-       struct zip *archive;
-       struct zip_file *zf;
-       struct zip_stat zs;
-       struct sr_dev_inst *sdi;
-       struct sr_channel *ch;
-       int devcnt, ret, i, j;
-       uint64_t tmp_u64, total_channels, enabled_channels, p;
-       char **sections, **keys, *metafile, *val;
-       char channelname[SR_MAX_CHANNELNAME_LEN + 1];
-
-       if ((ret = sr_sessionfile_check(filename)) != SR_OK)
-               return ret;
-
-       if (!(archive = zip_open(filename, 0, &ret)))
-               return SR_ERR;
-
-       if (zip_stat(archive, "metadata", 0, &zs) == -1)
-               return SR_ERR;
-
-       if (!(metafile = g_try_malloc(zs.size))) {
-               sr_err("%s: metafile malloc failed", __func__);
-               return SR_ERR_MALLOC;
-       }
-
-       zf = zip_fopen_index(archive, zs.index, 0);
-       zip_fread(zf, metafile, zs.size);
-       zip_fclose(zf);
-
-       kf = g_key_file_new();
-       if (!g_key_file_load_from_data(kf, metafile, zs.size, 0, NULL)) {
-               sr_dbg("Failed to parse metadata.");
-               return SR_ERR;
-       }
-
-       if ((ret = sr_session_new(session)) != SR_OK)
-               return ret;
-
-       devcnt = 0;
-       capturefiles = g_ptr_array_new_with_free_func(g_free);
-       sections = g_key_file_get_groups(kf, NULL);
-       for (i = 0; sections[i]; i++) {
-               if (!strcmp(sections[i], "global"))
-                       /* nothing really interesting in here yet */
-                       continue;
-               if (!strncmp(sections[i], "device ", 7)) {
-                       /* device section */
-                       sdi = NULL;
-                       enabled_channels = total_channels = 0;
-                       keys = g_key_file_get_keys(kf, sections[i], NULL, NULL);
-                       for (j = 0; keys[j]; j++) {
-                               val = g_key_file_get_string(kf, sections[i], keys[j], NULL);
-                               if (!strcmp(keys[j], "capturefile")) {
-                                       sdi = sr_dev_inst_new(devcnt, SR_ST_ACTIVE, NULL, NULL, NULL);
-                                       sdi->driver = &session_driver;
-                                       if (devcnt == 0)
-                                               /* first device, init the driver */
-                                               sdi->driver->init(NULL);
-                                       sr_dev_open(sdi);
-                                       sr_session_dev_add(*session, sdi);
-                                       sdi->driver->config_set(SR_CONF_SESSIONFILE,
-                                                       g_variant_new_string(filename), sdi, NULL);
-                                       sdi->driver->config_set(SR_CONF_CAPTUREFILE,
-                                                       g_variant_new_string(val), sdi, NULL);
-                                       g_ptr_array_add(capturefiles, val);
-                               } else if (!strcmp(keys[j], "samplerate")) {
-                                       sr_parse_sizestring(val, &tmp_u64);
-                                       sdi->driver->config_set(SR_CONF_SAMPLERATE,
-                                                       g_variant_new_uint64(tmp_u64), sdi, NULL);
-                               } else if (!strcmp(keys[j], "unitsize")) {
-                                       tmp_u64 = strtoull(val, NULL, 10);
-                                       sdi->driver->config_set(SR_CONF_CAPTURE_UNITSIZE,
-                                                       g_variant_new_uint64(tmp_u64), sdi, NULL);
-                               } else if (!strcmp(keys[j], "total probes")) {
-                                       total_channels = strtoull(val, NULL, 10);
-                                       sdi->driver->config_set(SR_CONF_NUM_LOGIC_CHANNELS,
-                                                       g_variant_new_uint64(total_channels), sdi, NULL);
-                                       for (p = 0; p < total_channels; p++) {
-                                               snprintf(channelname, SR_MAX_CHANNELNAME_LEN, "%" PRIu64, p);
-                                               if (!(ch = sr_channel_new(p, SR_CHANNEL_LOGIC, TRUE,
-                                                               channelname)))
-                                                       return SR_ERR;
-                                               sdi->channels = g_slist_append(sdi->channels, ch);
-                                       }
-                               } else if (!strncmp(keys[j], "probe", 5)) {
-                                       if (!sdi)
-                                               continue;
-                                       enabled_channels++;
-                                       tmp_u64 = strtoul(keys[j]+5, NULL, 10);
-                                       /* sr_session_save() */
-                                       sr_dev_channel_name_set(sdi, tmp_u64 - 1, val);
-                               }
-                       }
-                       g_strfreev(keys);
-                       /* Disable channels not specifically listed. */
-                       if (total_channels)
-                               for (p = enabled_channels; p < total_channels; p++)
-                                       sr_dev_channel_enable(sdi, p, FALSE);
-               }
-               devcnt++;
-       }
-       g_strfreev(sections);
-       g_key_file_free(kf);
-
-       return SR_OK;
-}
-
-/**
- * Save a session to the specified file.
- *
- * @param filename The name of the filename to save the session as.
- *                 Must not be NULL.
- * @param sdi The device instance from which the data was captured.
- * @param buf The data to be saved.
- * @param unitsize The number of bytes per sample.
- * @param units The number of samples.
- *
- * @retval SR_OK Success
- * @retval SR_ERR_ARG Invalid arguments
- * @retval SR_ERR Other errors
- *
- * @since 0.2.0
- */
-SR_API int sr_session_save(struct sr_session *session, const char *filename,
-               const struct sr_dev_inst *sdi, unsigned char *buf, int unitsize,
-               int units)
-{
-       struct sr_channel *ch;
-       GSList *l;
-       GVariant *gvar;
-       uint64_t samplerate;
-       int cnt, ret;
-       char **channel_names;
-
-       samplerate = 0;
-       if (sr_dev_has_option(sdi, SR_CONF_SAMPLERATE)) {
-               if (sr_config_get(sdi->driver, sdi, NULL,
-                                       SR_CONF_SAMPLERATE, &gvar) == SR_OK) {
-                       samplerate = g_variant_get_uint64(gvar);
-                       g_variant_unref(gvar);
-               }
-       }
-
-       channel_names = g_malloc0(sizeof(char *) * (g_slist_length(sdi->channels) + 1));
-       cnt = 0;
-       for (l = sdi->channels; l; l = l->next) {
-               ch = l->data;
-               if (ch->type != SR_CHANNEL_LOGIC)
-                       continue;
-               if (ch->enabled != TRUE)
-                       continue;
-               if (!ch->name)
-                       continue;
-               /* Just borrowing the ptr. */
-               channel_names[cnt++] = ch->name;
-       }
-
-       if ((ret = sr_session_save_init(session, filename, samplerate,
-                       channel_names)) != SR_OK)
-               return ret;
-
-       ret = sr_session_append(session, filename, buf, unitsize, units);
-
-       return ret;
-}
-
-/**
- * Initialize a saved session file.
- *
- * @param filename The name of the filename to save the session as.
- *                 Must not be NULL.
- * @param samplerate The samplerate to store for this session.
- * @param channels A NULL-terminated array of strings containing the names
- * of all the channels active in this session.
- *
- * @retval SR_OK Success
- * @retval SR_ERR_ARG Invalid arguments
- * @retval SR_ERR Other errors
- *
- * @since 0.3.0
- */
-SR_API int sr_session_save_init(struct sr_session *session,
-               const char *filename, uint64_t samplerate, char **channels)
-{
-       FILE *meta;
-       struct zip *zipfile;
-       struct zip_source *versrc, *metasrc;
-       int tmpfile, cnt, ret, i;
-       char version[1], metafile[32], *s;
-
-       (void) session;
-
-       if (!filename) {
-               sr_err("%s: filename was NULL", __func__);
-               return SR_ERR_ARG;
-       }
-
-       /* Quietly delete it first, libzip wants replace ops otherwise. */
-       unlink(filename);
-       if (!(zipfile = zip_open(filename, ZIP_CREATE, &ret)))
-               return SR_ERR;
-
-       /* "version" */
-       version[0] = '2';
-       if (!(versrc = zip_source_buffer(zipfile, version, 1, 0)))
-               return SR_ERR;
-       if (zip_add(zipfile, "version", versrc) == -1) {
-               sr_info("error saving version into zipfile: %s",
-                       zip_strerror(zipfile));
-               return SR_ERR;
-       }
-
-       /* init "metadata" */
-       strcpy(metafile, "sigrok-meta-XXXXXX");
-       if ((tmpfile = g_mkstemp(metafile)) == -1)
-               return SR_ERR;
-       close(tmpfile);
-       meta = g_fopen(metafile, "wb");
-       fprintf(meta, "[global]\n");
-       fprintf(meta, "sigrok version = %s\n", PACKAGE_VERSION);
-
-       /* metadata */
-       fprintf(meta, "[device 1]\n");
-
-       /* metadata */
-       fprintf(meta, "capturefile = logic-1\n");
-       cnt = 0;
-       for (i = 0; channels[i]; i++)
-               cnt++;
-       fprintf(meta, "total probes = %d\n", cnt);
-       s = sr_samplerate_string(samplerate);
-       fprintf(meta, "samplerate = %s\n", s);
-       g_free(s);
-
-       for (i = 0; channels[i]; i++)
-               fprintf(meta, "probe%d = %s\n", i + 1, channels[i]);
-
-       fclose(meta);
-
-       if (!(metasrc = zip_source_file(zipfile, metafile, 0, -1))) {
-               unlink(metafile);
-               return SR_ERR;
-       }
-       if (zip_add(zipfile, "metadata", metasrc) == -1) {
-               unlink(metafile);
-               return SR_ERR;
-       }
-
-       if ((ret = zip_close(zipfile)) == -1) {
-               sr_info("error saving zipfile: %s", zip_strerror(zipfile));
-               unlink(metafile);
-               return SR_ERR;
-       }
-
-       unlink(metafile);
-
-       return SR_OK;
-}
-
-/**
- * Append data to an existing session file.
- *
- * The session file must have been created with sr_session_save_init()
- * or sr_session_save() beforehand.
- *
- * @param filename The name of the filename to append to. Must not be NULL.
- * @param buf The data to be appended.
- * @param unitsize The number of bytes per sample.
- * @param units The number of samples.
- *
- * @retval SR_OK Success
- * @retval SR_ERR_ARG Invalid arguments
- * @retval SR_ERR Other errors
- *
- * @since 0.3.0
- */
-SR_API int sr_session_append(struct sr_session *session, const char *filename,
-               unsigned char *buf, int unitsize, int units)
-{
-       struct zip *archive;
-       struct zip_source *logicsrc;
-       zip_int64_t num_files;
-       struct zip_file *zf;
-       struct zip_stat zs;
-       struct zip_source *metasrc;
-       GKeyFile *kf;
-       GError *error;
-       gsize len;
-       int chunk_num, next_chunk_num, tmpfile, ret, i;
-       const char *entry_name;
-       char *metafile, tmpname[32], chunkname[16];
-
-       (void) session;
-
-       if ((ret = sr_sessionfile_check(filename)) != SR_OK)
-               return ret;
-
-       if (!(archive = zip_open(filename, 0, &ret)))
-               return SR_ERR;
-
-       if (zip_stat(archive, "metadata", 0, &zs) == -1)
-               return SR_ERR;
-
-       metafile = g_malloc(zs.size);
-       zf = zip_fopen_index(archive, zs.index, 0);
-       zip_fread(zf, metafile, zs.size);
-       zip_fclose(zf);
-
-       /*
-        * If the file was only initialized but doesn't yet have any
-        * data it in, it won't have a unitsize field in metadata yet.
-        */
-       error = NULL;
-       kf = g_key_file_new();
-       if (!g_key_file_load_from_data(kf, metafile, zs.size, 0, &error)) {
-               sr_err("Failed to parse metadata: %s.", error->message);
-               return SR_ERR;
-       }
-       g_free(metafile);
-       tmpname[0] = '\0';
-       if (!g_key_file_has_key(kf, "device 1", "unitsize", &error)) {
-               if (error && error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND) {
-                       sr_err("Failed to check unitsize key: %s", error ? error->message : "?");
-                       return SR_ERR;
-               }
-               /* Add unitsize field. */
-               g_key_file_set_integer(kf, "device 1", "unitsize", unitsize);
-               metafile = g_key_file_to_data(kf, &len, &error);
-               strcpy(tmpname, "sigrok-meta-XXXXXX");
-               if ((tmpfile = g_mkstemp(tmpname)) == -1)
-                       return SR_ERR;
-               if (write(tmpfile, metafile, len) < 0) {
-                       sr_dbg("Failed to create new metadata: %s", strerror(errno));
-                       g_free(metafile);
-                       unlink(tmpname);
-                       return SR_ERR;
-               }
-               close(tmpfile);
-               if (!(metasrc = zip_source_file(archive, tmpname, 0, -1))) {
-                       sr_err("Failed to create zip source for metadata.");
-                       g_free(metafile);
-                       unlink(tmpname);
-                       return SR_ERR;
-               }
-               if (zip_replace(archive, zs.index, metasrc) == -1) {
-                       sr_err("Failed to replace metadata file.");
-                       g_free(metafile);
-                       unlink(tmpname);
-                       return SR_ERR;
-               }
-               g_free(metafile);
-       }
-       g_key_file_free(kf);
-
-       next_chunk_num = 1;
-       num_files = zip_get_num_entries(archive, 0);
-       for (i = 0; i < num_files; i++) {
-               entry_name = zip_get_name(archive, i, 0);
-               if (strncmp(entry_name, "logic-1", 7))
-                       continue;
-               if (strlen(entry_name) == 7) {
-                       /* This file has no extra chunks, just a single "logic-1".
-                        * Rename it to "logic-1-1" * and continue with chunk 2. */
-                       if (zip_rename(archive, i, "logic-1-1") == -1) {
-                               sr_err("Failed to rename 'logic-1' to 'logic-1-1'.");
-                               unlink(tmpname);
-                               return SR_ERR;
-                       }
-                       next_chunk_num = 2;
-                       break;
-               } else if (strlen(entry_name) > 8 && entry_name[7] == '-') {
-                       chunk_num = strtoull(entry_name + 8, NULL, 10);
-                       if (chunk_num >= next_chunk_num)
-                               next_chunk_num = chunk_num + 1;
-               }
-       }
-       snprintf(chunkname, 15, "logic-1-%d", next_chunk_num);
-       if (!(logicsrc = zip_source_buffer(archive, buf, units * unitsize, FALSE))) {
-               unlink(tmpname);
-               return SR_ERR;
-       }
-       if (zip_add(archive, chunkname, logicsrc) == -1) {
-               unlink(tmpname);
-               return SR_ERR;
-       }
-       if ((ret = zip_close(archive)) == -1) {
-               sr_info("error saving session file: %s", zip_strerror(archive));
-               unlink(tmpname);
-               return SR_ERR;
-       }
-       unlink(tmpname);
-
-       return SR_OK;
-}
-
-/** @} */
diff --git a/soft-trigger.c b/soft-trigger.c
deleted file mode 100644 (file)
index 386f8cc..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2014 Bert Vermeulen <bert@biot.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 <string.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-/* @cond PRIVATE */
-#define LOG_PREFIX "soft-trigger"
-/* @endcond */
-
-SR_PRIV struct soft_trigger_logic *soft_trigger_logic_new(
-               const struct sr_dev_inst *sdi, struct sr_trigger *trigger)
-{
-       struct soft_trigger_logic *stl;
-
-       stl = g_malloc0(sizeof(struct soft_trigger_logic));
-       stl->sdi = sdi;
-       stl->trigger = trigger;
-       stl->unitsize = (g_slist_length(sdi->channels) + 7) / 8;
-       stl->prev_sample = g_malloc0(stl->unitsize);
-
-       return stl;
-}
-
-SR_PRIV void soft_trigger_logic_free(struct soft_trigger_logic *stl)
-{
-       g_free(stl->prev_sample);
-       g_free(stl);
-}
-
-static gboolean logic_check_match(struct soft_trigger_logic *stl,
-               uint8_t *sample, struct sr_trigger_match *match)
-{
-       int bit, prev_bit;
-       gboolean result;
-
-       stl->count++;
-       result = FALSE;
-       bit = *(sample + match->channel->index / 8)
-                       & (1 << (match->channel->index % 8));
-       if (match->match == SR_TRIGGER_ZERO)
-               result = bit == 0;
-       else if (match->match == SR_TRIGGER_ONE)
-               result = bit != 0;
-       else {
-               /* Edge matches. */
-               if (stl->count == 1)
-                       /* First sample, don't have enough for an edge match yet. */
-                       return FALSE;
-               prev_bit = *(stl->prev_sample + match->channel->index / 8)
-                               & (1 << (match->channel->index % 8));
-               if (match->match == SR_TRIGGER_RISING)
-                       result = prev_bit == 0 && bit != 0;
-               else if (match->match == SR_TRIGGER_FALLING)
-                       result = prev_bit != 0 && bit == 0;
-               else if (match->match == SR_TRIGGER_EDGE)
-                       result = prev_bit != bit;
-       }
-
-       return result;
-}
-
-/* Returns the offset (in samples) within buf of where the trigger
- * occurred, or -1 if not triggered. */
-SR_PRIV int soft_trigger_logic_check(struct soft_trigger_logic *stl,
-               uint8_t *buf, int len)
-{
-       struct sr_datafeed_packet packet;
-       struct sr_trigger_stage *stage;
-       struct sr_trigger_match *match;
-       GSList *l, *l_stage;
-       int offset;
-       int i;
-       gboolean match_found;
-
-       offset = -1;
-       for (i = 0; i < len; i += stl->unitsize) {
-               l_stage = g_slist_nth(stl->trigger->stages, stl->cur_stage);
-               stage = l_stage->data;
-               if (!stage->matches)
-                       /* No matches supplied, client error. */
-                       return SR_ERR_ARG;
-
-               match_found = TRUE;
-               for (l = stage->matches; l; l = l->next) {
-                       match = l->data;
-                       if (!match->channel->enabled)
-                               /* Ignore disabled channels with a trigger. */
-                               continue;
-                       if (!logic_check_match(stl, buf + i, match)) {
-                               match_found = FALSE;
-                               break;
-                       }
-               }
-               memcpy(stl->prev_sample, buf + i, stl->unitsize);
-               if (match_found) {
-                       /* Matched on the current stage. */
-                       if (l_stage->next) {
-                               /* Advance to next stage. */
-                               stl->cur_stage++;
-                       } else {
-                               /* Matched on last stage, fire trigger. */
-                               offset = i / stl->unitsize;
-
-                               packet.type = SR_DF_TRIGGER;
-                               packet.payload = NULL;
-                               sr_session_send(stl->sdi, &packet);
-                               break;
-                       }
-               } else if (stl->cur_stage > 0) {
-                       /*
-                        * We had a match at an earlier stage, but failed on the
-                        * current stage. However, we may have a match on this
-                        * stage in the next bit -- trigger on 0001 will fail on
-                        * seeing 00001, so we need to go back to stage 0 -- but
-                        * at the next sample from the one that matched originally,
-                        * which the counter increment at the end of the loop
-                        * takes care of.
-                        */
-                       i -= stl->cur_stage * stl->unitsize;
-                       if (i < -1)
-                               i = -1; /* Oops, went back past this buffer. */
-                       /* Reset trigger stage. */
-                       stl->cur_stage = 0;
-               }
-       }
-
-       return offset;
-}
-
diff --git a/src/backend.c b/src/backend.c
new file mode 100644 (file)
index 0000000..f650fe1
--- /dev/null
@@ -0,0 +1,397 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com>
+ * Copyright (C) 2012 Peter Stuge <peter@stuge.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 <glib.h>
+#include "config.h" /* Needed for HAVE_LIBUSB_1_0 and others. */
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+/** @cond PRIVATE */
+#define LOG_PREFIX "backend"
+/** @endcond */
+
+/**
+ * @mainpage libsigrok API
+ *
+ * @section sec_intro Introduction
+ *
+ * The <a href="http://sigrok.org">sigrok</a> project aims at creating a
+ * portable, cross-platform, Free/Libre/Open-Source signal analysis software
+ * suite that supports various device types (such as logic analyzers,
+ * oscilloscopes, multimeters, and more).
+ *
+ * <a href="http://sigrok.org/wiki/Libsigrok">libsigrok</a> is a shared
+ * library written in C which provides the basic API for talking to
+ * <a href="http://sigrok.org/wiki/Supported_hardware">supported hardware</a>
+ * and reading/writing the acquired data into various
+ * <a href="http://sigrok.org/wiki/Input_output_formats">input/output
+ * file formats</a>.
+ *
+ * @section sec_api API reference
+ *
+ * See the "Modules" page for an introduction to various libsigrok
+ * related topics and the detailed API documentation of the respective
+ * functions.
+ *
+ * You can also browse the API documentation by file, or review all
+ * data structures.
+ *
+ * @section sec_mailinglists Mailing lists
+ *
+ * There are two mailing lists for sigrok/libsigrok: <a href="https://lists.sourceforge.net/lists/listinfo/sigrok-devel">sigrok-devel</a> and <a href="https://lists.sourceforge.net/lists/listinfo/sigrok-commits">sigrok-commits</a>.
+ *
+ * @section sec_irc IRC
+ *
+ * You can find the sigrok developers in the
+ * <a href="irc://chat.freenode.net/sigrok">\#sigrok</a>
+ * IRC channel on Freenode.
+ *
+ * @section sec_website Website
+ *
+ * <a href="http://sigrok.org/wiki/Libsigrok">sigrok.org/wiki/Libsigrok</a>
+ */
+
+/**
+ * @file
+ *
+ * Initializing and shutting down libsigrok.
+ */
+
+/**
+ * @defgroup grp_init Initialization
+ *
+ * Initializing and shutting down libsigrok.
+ *
+ * Before using any of the libsigrok functionality (except
+ * sr_log_loglevel_set() and sr_log_opts_set()), sr_init() must
+ * be called to initialize the library, which will return a struct sr_context
+ * when the initialization was successful.
+ *
+ * When libsigrok functionality is no longer needed, sr_exit() should be
+ * called, which will (among other things) free the struct sr_context.
+ *
+ * Example for a minimal program using libsigrok:
+ *
+ * @code{.c}
+ *   #include <stdio.h>
+ *   #include <libsigrok/libsigrok.h>
+ *
+ *   int main(int argc, char **argv)
+ *   {
+ *     int ret;
+ *     struct sr_context *sr_ctx;
+ *
+ *     if ((ret = sr_init(&sr_ctx)) != SR_OK) {
+ *             printf("Error initializing libsigrok (%s): %s.\n",
+ *                    sr_strerror_name(ret), sr_strerror(ret));
+ *             return 1;
+ *     }
+ *
+ *     // Use libsigrok functions here...
+ *
+ *     if ((ret = sr_exit(sr_ctx)) != SR_OK) {
+ *             printf("Error shutting down libsigrok (%s): %s.\n",
+ *                    sr_strerror_name(ret), sr_strerror(ret));
+ *             return 1;
+ *     }
+ *
+ *     return 0;
+ *   }
+ * @endcode
+ *
+ * @{
+ */
+
+/**
+ * Sanity-check all libsigrok drivers.
+ *
+ * @retval SR_OK All drivers are OK
+ * @retval SR_ERR One or more drivers have issues.
+ */
+static int sanity_check_all_drivers(void)
+{
+       int i, errors, ret = SR_OK;
+       struct sr_dev_driver **drivers;
+       const char *d;
+
+       sr_spew("Sanity-checking all drivers.");
+
+       drivers = sr_driver_list();
+       for (i = 0; drivers[i]; i++) {
+               errors = 0;
+
+               d = (drivers[i]->name) ? drivers[i]->name : "NULL";
+
+               if (!drivers[i]->name) {
+                       sr_err("No name in driver %d ('%s').", i, d);
+                       errors++;
+               }
+               if (!drivers[i]->longname) {
+                       sr_err("No longname in driver %d ('%s').", i, d);
+                       errors++;
+               }
+               if (drivers[i]->api_version < 1) {
+                       sr_err("API version in driver %d ('%s') < 1.", i, d);
+                       errors++;
+               }
+               if (!drivers[i]->init) {
+                       sr_err("No init in driver %d ('%s').", i, d);
+                       errors++;
+               }
+               if (!drivers[i]->cleanup) {
+                       sr_err("No cleanup in driver %d ('%s').", i, d);
+                       errors++;
+               }
+               if (!drivers[i]->scan) {
+                       sr_err("No scan in driver %d ('%s').", i, d);
+                       errors++;
+               }
+               if (!drivers[i]->dev_list) {
+                       sr_err("No dev_list in driver %d ('%s').", i, d);
+                       errors++;
+               }
+               /* Note: config_get() is optional. */
+               if (!drivers[i]->config_set) {
+                       sr_err("No config_set in driver %d ('%s').", i, d);
+                       errors++;
+               }
+               if (!drivers[i]->config_list) {
+                       sr_err("No config_list in driver %d ('%s').", i, d);
+                       errors++;
+               }
+               if (!drivers[i]->dev_open) {
+                       sr_err("No dev_open in driver %d ('%s').", i, d);
+                       errors++;
+               }
+               if (!drivers[i]->dev_close) {
+                       sr_err("No dev_close in driver %d ('%s').", i, d);
+                       errors++;
+               }
+               if (!drivers[i]->dev_acquisition_start) {
+                       sr_err("No dev_acquisition_start in driver %d ('%s').",
+                              i, d);
+                       errors++;
+               }
+               if (!drivers[i]->dev_acquisition_stop) {
+                       sr_err("No dev_acquisition_stop in driver %d ('%s').",
+                              i, d);
+                       errors++;
+               }
+
+               /* Note: 'priv' is allowed to be NULL. */
+
+               if (errors == 0)
+                       continue;
+
+               ret = SR_ERR;
+       }
+
+       return ret;
+}
+
+/**
+ * Sanity-check all libsigrok input modules.
+ *
+ * @retval SR_OK All modules are OK
+ * @retval SR_ERR One or more modules have issues.
+ */
+static int sanity_check_all_input_modules(void)
+{
+       int i, errors, ret = SR_OK;
+       struct sr_input_format **inputs;
+       const char *d;
+
+       sr_spew("Sanity-checking all input modules.");
+
+       inputs = sr_input_list();
+       for (i = 0; inputs[i]; i++) {
+               errors = 0;
+
+               d = (inputs[i]->id) ? inputs[i]->id : "NULL";
+
+               if (!inputs[i]->id) {
+                       sr_err("No ID in module %d ('%s').", i, d);
+                       errors++;
+               }
+               if (!inputs[i]->description) {
+                       sr_err("No description in module %d ('%s').", i, d);
+                       errors++;
+               }
+               if (!inputs[i]->format_match) {
+                       sr_err("No format_match in module %d ('%s').", i, d);
+                       errors++;
+               }
+               if (!inputs[i]->init) {
+                       sr_err("No init in module %d ('%s').", i, d);
+                       errors++;
+               }
+               if (!inputs[i]->loadfile) {
+                       sr_err("No loadfile in module %d ('%s').", i, d);
+                       errors++;
+               }
+
+               if (errors == 0)
+                       continue;
+
+               ret = SR_ERR;
+       }
+
+       return ret;
+}
+
+/**
+ * Sanity-check all libsigrok output modules.
+ *
+ * @retval SR_OK All modules are OK
+ * @retval SR_ERR One or more modules have issues.
+ */
+static int sanity_check_all_output_modules(void)
+{
+       int i, errors, ret = SR_OK;
+       struct sr_output_format **outputs;
+       const char *d;
+
+       sr_spew("Sanity-checking all output modules.");
+
+       outputs = sr_output_list();
+       for (i = 0; outputs[i]; i++) {
+               errors = 0;
+
+               d = (outputs[i]->id) ? outputs[i]->id : "NULL";
+
+               if (!outputs[i]->id) {
+                       sr_err("No ID in module %d ('%s').", i, d);
+                       errors++;
+               }
+               if (!outputs[i]->description) {
+                       sr_err("No description in module '%s'.", d);
+                       errors++;
+               }
+               if (!outputs[i]->receive) {
+                       sr_err("No receive in module '%s'.", d);
+                       errors++;
+               }
+
+               if (errors == 0)
+                       continue;
+
+               ret = SR_ERR;
+       }
+
+       return ret;
+}
+
+/**
+ * Initialize libsigrok.
+ *
+ * This function must be called before any other libsigrok function.
+ *
+ * @param ctx Pointer to a libsigrok context struct pointer. Must not be NULL.
+ *            This will be a pointer to a newly allocated libsigrok context
+ *            object upon success, and is undefined upon errors.
+ *
+ * @return SR_OK upon success, a (negative) error code otherwise. Upon errors
+ *         the 'ctx' pointer is undefined and should not be used. Upon success,
+ *         the context will be free'd by sr_exit() as part of the libsigrok
+ *         shutdown.
+ *
+ * @since 0.2.0
+ */
+SR_API int sr_init(struct sr_context **ctx)
+{
+       int ret = SR_ERR;
+       struct sr_context *context;
+
+       if (!ctx) {
+               sr_err("%s(): libsigrok context was NULL.", __func__);
+               return SR_ERR;
+       }
+
+       if (sanity_check_all_drivers() < 0) {
+               sr_err("Internal driver error(s), aborting.");
+               return ret;
+       }
+
+       if (sanity_check_all_input_modules() < 0) {
+               sr_err("Internal input module error(s), aborting.");
+               return ret;
+       }
+
+       if (sanity_check_all_output_modules() < 0) {
+               sr_err("Internal output module error(s), aborting.");
+               return ret;
+       }
+
+       /* + 1 to handle when struct sr_context has no members. */
+       context = g_try_malloc0(sizeof(struct sr_context) + 1);
+
+       if (!context) {
+               ret = SR_ERR_MALLOC;
+               goto done;
+       }
+
+#ifdef HAVE_LIBUSB_1_0
+       ret = libusb_init(&context->libusb_ctx);
+       if (LIBUSB_SUCCESS != ret) {
+               sr_err("libusb_init() returned %s.", libusb_error_name(ret));
+               ret = SR_ERR;
+               goto done;
+       }
+#endif
+
+       *ctx = context;
+       context = NULL;
+       ret = SR_OK;
+
+done:
+       if (context)
+               g_free(context);
+       return ret;
+}
+
+/**
+ * Shutdown libsigrok.
+ *
+ * @param ctx Pointer to a libsigrok context struct. Must not be NULL.
+ *
+ * @retval SR_OK Success
+ * @retval other Error code SR_ERR, ...
+ *
+ * @since 0.2.0
+ */
+SR_API int sr_exit(struct sr_context *ctx)
+{
+       if (!ctx) {
+               sr_err("%s(): libsigrok context was NULL.", __func__);
+               return SR_ERR;
+       }
+
+       sr_hw_cleanup_all();
+
+#ifdef HAVE_LIBUSB_1_0
+       libusb_exit(ctx->libusb_ctx);
+#endif
+
+       g_free(ctx);
+
+       return SR_OK;
+}
+
+/** @} */
diff --git a/src/device.c b/src/device.c
new file mode 100644 (file)
index 0000000..434d106
--- /dev/null
@@ -0,0 +1,474 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <glib.h>
+#include "config.h" /* Needed for HAVE_LIBUSB_1_0 and others. */
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+/** @cond PRIVATE */
+#define LOG_PREFIX "device"
+/** @endcond */
+
+/**
+ * @file
+ *
+ * Device handling in libsigrok.
+ */
+
+/**
+ * @defgroup grp_devices Devices
+ *
+ * Device handling in libsigrok.
+ *
+ * @{
+ */
+
+/** @private
+ *  Allocate and initialize new struct sr_channel
+ *  @param[in]  index @copydoc sr_channel::index
+ *  @param[in]  type @copydoc sr_channel::type
+ *  @param[in]  enabled @copydoc sr_channel::enabled
+ *  @param[in]  name @copydoc sr_channel::name
+ *
+ *  @return NULL (failure) or new struct sr_channel*.
+ */
+SR_PRIV struct sr_channel *sr_channel_new(int index, int type,
+               gboolean enabled, const char *name)
+{
+       struct sr_channel *ch;
+
+       if (!(ch = g_try_malloc0(sizeof(struct sr_channel)))) {
+               sr_err("Channel malloc failed.");
+               return NULL;
+       }
+
+       ch->index = index;
+       ch->type = type;
+       ch->enabled = enabled;
+       if (name)
+               ch->name = g_strdup(name);
+
+       return ch;
+}
+
+/**
+ * Set the name of the specified channel in the specified device.
+ *
+ * If the channel already has a different name assigned to it, it will be
+ * removed, and the new name will be saved instead.
+ *
+ * @param sdi The device instance the channel is connected to.
+ * @param[in] channelnum The number of the channel whose name to set.
+ *                 Note that the channel numbers start at 0.
+ * @param[in] name The new name that the specified channel should get. A copy
+ *             of the string is made.
+ *
+ * @return SR_OK on success, or SR_ERR_ARG on invalid arguments.
+ *
+ * @since 0.3.0
+ */
+SR_API int sr_dev_channel_name_set(const struct sr_dev_inst *sdi,
+               int channelnum, const char *name)
+{
+       GSList *l;
+       struct sr_channel *ch;
+       int ret;
+
+       if (!sdi) {
+               sr_err("%s: sdi was NULL", __func__);
+               return SR_ERR_ARG;
+       }
+
+       ret = SR_ERR_ARG;
+       for (l = sdi->channels; l; l = l->next) {
+               ch = l->data;
+               if (ch->index == channelnum) {
+                       g_free(ch->name);
+                       ch->name = g_strdup(name);
+                       ret = SR_OK;
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+/**
+ * Enable or disable a channel on the specified device.
+ *
+ * @param sdi The device instance the channel is connected to.
+ * @param channelnum The channel number, starting from 0.
+ * @param state TRUE to enable the channel, FALSE to disable.
+ *
+ * @return SR_OK on success or SR_ERR on failure.  In case of invalid
+ *         arguments, SR_ERR_ARG is returned and the channel enabled state
+ *         remains unchanged.
+ *
+ * @since 0.3.0
+ */
+SR_API int sr_dev_channel_enable(const struct sr_dev_inst *sdi, int channelnum,
+               gboolean state)
+{
+       GSList *l;
+       struct sr_channel *ch;
+       int ret;
+       gboolean was_enabled;
+
+       if (!sdi)
+               return SR_ERR_ARG;
+
+       ret = SR_ERR_ARG;
+       for (l = sdi->channels; l; l = l->next) {
+               ch = l->data;
+               if (ch->index == channelnum) {
+                       was_enabled = ch->enabled;
+                       ch->enabled = state;
+                       ret = SR_OK;
+                       if (!state != !was_enabled && sdi->driver
+                                       && sdi->driver->config_channel_set) {
+                               ret = sdi->driver->config_channel_set(
+                                       sdi, ch, SR_CHANNEL_SET_ENABLED);
+                               /* Roll back change if it wasn't applicable. */
+                               if (ret == SR_ERR_ARG)
+                                       ch->enabled = was_enabled;
+                       }
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+/**
+ * Determine whether the specified device instance has the specified
+ * capability.
+ *
+ * @param sdi Pointer to the device instance to be checked. Must not be NULL.
+ *            If the device's 'driver' field is NULL (virtual device), this
+ *            function will always return FALSE (virtual devices don't have
+ *            a hardware capabilities list).
+ * @param[in] key The option that should be checked for is supported by the
+ *            specified device.
+ *
+ * @retval TRUE Device has the specified option
+ * @retval FALSE Device does not have the specified option, invalid input
+ *         parameters or other error conditions.
+ *
+ * @since 0.2.0
+ */
+SR_API gboolean sr_dev_has_option(const struct sr_dev_inst *sdi, int key)
+{
+       GVariant *gvar;
+       const int *devopts;
+       gsize num_opts, i;
+       int ret;
+
+       if (!sdi || !sdi->driver || !sdi->driver->config_list)
+               return FALSE;
+
+       if (sdi->driver->config_list(SR_CONF_DEVICE_OPTIONS,
+                               &gvar, sdi, NULL) != SR_OK)
+               return FALSE;
+
+       ret = FALSE;
+       devopts = g_variant_get_fixed_array(gvar, &num_opts, sizeof(int32_t));
+       for (i = 0; i < num_opts; i++) {
+               if (devopts[i] == key) {
+                       ret = TRUE;
+                       break;
+               }
+       }
+       g_variant_unref(gvar);
+
+       return ret;
+}
+
+/** @private
+ *  Allocate and init new device instance struct.
+ *  @param[in]  index   @copydoc sr_dev_inst::index
+ *  @param[in]  status  @copydoc sr_dev_inst::status
+ *  @param[in]  vendor  @copydoc sr_dev_inst::vendor
+ *  @param[in]  model   @copydoc sr_dev_inst::model
+ *  @param[in]  version @copydoc sr_dev_inst::version
+ *
+ *  @retval NULL Error
+ *  @retval struct sr_dev_inst *. Dynamically allocated, free using
+ *              sr_dev_inst_free().
+ */
+SR_PRIV struct sr_dev_inst *sr_dev_inst_new(int index, int status,
+               const char *vendor, const char *model, const char *version)
+{
+       struct sr_dev_inst *sdi;
+
+       if (!(sdi = g_try_malloc(sizeof(struct sr_dev_inst)))) {
+               sr_err("Device instance malloc failed.");
+               return NULL;
+       }
+
+       sdi->driver = NULL;
+       sdi->index = index;
+       sdi->status = status;
+       sdi->inst_type = -1;
+       sdi->vendor = vendor ? g_strdup(vendor) : NULL;
+       sdi->model = model ? g_strdup(model) : NULL;
+       sdi->version = version ? g_strdup(version) : NULL;
+       sdi->channels = NULL;
+       sdi->channel_groups = NULL;
+       sdi->session = NULL;
+       sdi->conn = NULL;
+       sdi->priv = NULL;
+
+       return sdi;
+}
+
+/** @private
+ *  Free device instance struct created by sr_dev_inst().
+ *  @param sdi  struct* to free.
+ */
+SR_PRIV void sr_dev_inst_free(struct sr_dev_inst *sdi)
+{
+       struct sr_channel *ch;
+       GSList *l;
+
+       for (l = sdi->channels; l; l = l->next) {
+               ch = l->data;
+               g_free(ch->name);
+               g_free(ch);
+       }
+       g_slist_free(sdi->channels);
+
+       if (sdi->channel_groups)
+               g_slist_free(sdi->channel_groups);
+
+       g_free(sdi->vendor);
+       g_free(sdi->model);
+       g_free(sdi->version);
+       g_free(sdi);
+}
+
+#ifdef HAVE_LIBUSB_1_0
+
+/** @private
+ *  Allocate and init struct for USB device instance.
+ *  @param[in]  bus @copydoc sr_usb_dev_inst::bus
+ *  @param[in]  address @copydoc sr_usb_dev_inst::address
+ *  @param[in]  hdl @copydoc sr_usb_dev_inst::devhdl
+ *
+ *  @retval NULL Error
+ *  @retval other struct sr_usb_dev_inst * for USB device instance.
+ */
+SR_PRIV struct sr_usb_dev_inst *sr_usb_dev_inst_new(uint8_t bus,
+                       uint8_t address, struct libusb_device_handle *hdl)
+{
+       struct sr_usb_dev_inst *udi;
+
+       if (!(udi = g_try_malloc(sizeof(struct sr_usb_dev_inst)))) {
+               sr_err("USB device instance malloc failed.");
+               return NULL;
+       }
+
+       udi->bus = bus;
+       udi->address = address;
+       udi->devhdl = hdl;
+
+       return udi;
+}
+
+/** @private
+ *  Free struct * allocated by sr_usb_dev_inst().
+ *  @param usb  struct* to free. Must not be NULL.
+ */
+SR_PRIV void sr_usb_dev_inst_free(struct sr_usb_dev_inst *usb)
+{
+       g_free(usb);
+}
+
+#endif
+
+#ifdef HAVE_LIBSERIALPORT
+
+/**
+ * @private
+ *
+ * Both parameters are copied to newly allocated strings, and freed
+ * automatically by sr_serial_dev_inst_free().
+ *
+ * @param[in] port OS-specific serial port specification. Examples:
+ *                 "/dev/ttyUSB0", "/dev/ttyACM1", "/dev/tty.Modem-0", "COM1".
+ * @param[in] serialcomm A serial communication parameters string, in the form
+ *              of \<speed\>/\<data bits\>\<parity\>\<stopbits\>, for example
+ *              "9600/8n1" or "600/7o2". This is an optional parameter;
+ *              it may be filled in later.
+ *
+ * @return A pointer to a newly initialized struct sr_serial_dev_inst,
+ *         or NULL on error.
+ */
+SR_PRIV struct sr_serial_dev_inst *sr_serial_dev_inst_new(const char *port,
+               const char *serialcomm)
+{
+       struct sr_serial_dev_inst *serial;
+
+       if (!port) {
+               sr_err("Serial port required.");
+               return NULL;
+       }
+
+       if (!(serial = g_try_malloc0(sizeof(struct sr_serial_dev_inst)))) {
+               sr_err("Serial device instance malloc failed.");
+               return NULL;
+       }
+
+       serial->port = g_strdup(port);
+       if (serialcomm)
+               serial->serialcomm = g_strdup(serialcomm);
+
+       return serial;
+}
+
+/** @private
+ *  Free struct sr_serial_dev_inst * allocated by sr_serial_dev_inst().
+ *  @param serial   struct sr_serial_dev_inst * to free. Must not be NULL.
+ */
+SR_PRIV void sr_serial_dev_inst_free(struct sr_serial_dev_inst *serial)
+{
+       g_free(serial->port);
+       g_free(serial->serialcomm);
+       g_free(serial);
+}
+#endif
+
+/** @private */
+SR_PRIV struct sr_usbtmc_dev_inst *sr_usbtmc_dev_inst_new(const char *device)
+{
+       struct sr_usbtmc_dev_inst *usbtmc;
+
+       if (!device) {
+               sr_err("Device name required.");
+               return NULL;
+       }
+
+       if (!(usbtmc = g_try_malloc0(sizeof(struct sr_usbtmc_dev_inst)))) {
+               sr_err("USBTMC device instance malloc failed.");
+               return NULL;
+       }
+
+       usbtmc->device = g_strdup(device);
+       usbtmc->fd = -1;
+
+       return usbtmc;
+}
+
+/** @private */
+SR_PRIV void sr_usbtmc_dev_inst_free(struct sr_usbtmc_dev_inst *usbtmc)
+{
+       g_free(usbtmc->device);
+       g_free(usbtmc);
+}
+
+/**
+ * Get the list of devices/instances of the specified driver.
+ *
+ * @param driver The driver to use. Must not be NULL.
+ *
+ * @return The list of devices/instances of this driver, or NULL upon errors
+ *         or if the list is empty.
+ *
+ * @since 0.2.0
+ */
+SR_API GSList *sr_dev_list(const struct sr_dev_driver *driver)
+{
+       if (driver && driver->dev_list)
+               return driver->dev_list();
+       else
+               return NULL;
+}
+
+/**
+ * Clear the list of device instances a driver knows about.
+ *
+ * @param driver The driver to use. This must be a pointer to one of
+ *               the entries returned by sr_driver_list(). Must not be NULL.
+ *
+ * @retval SR_OK Success
+ * @retval SR_ERR_ARG Invalid driver
+ *
+ * @since 0.2.0
+ */
+SR_API int sr_dev_clear(const struct sr_dev_driver *driver)
+{
+       int ret;
+
+       if (!driver) {
+               sr_err("Invalid driver.");
+               return SR_ERR_ARG;
+       }
+
+       if (driver->dev_clear)
+               ret = driver->dev_clear();
+       else
+               ret = std_dev_clear(driver, NULL);
+
+       return ret;
+}
+
+/**
+ * Open the specified device.
+ *
+ * @param sdi Device instance to use. Must not be NULL.
+ *
+ * @return SR_OK upon success, a negative error code upon errors.
+ *
+ * @since 0.2.0
+ */
+SR_API int sr_dev_open(struct sr_dev_inst *sdi)
+{
+       int ret;
+
+       if (!sdi || !sdi->driver || !sdi->driver->dev_open)
+               return SR_ERR;
+
+       ret = sdi->driver->dev_open(sdi);
+
+       return ret;
+}
+
+/**
+ * Close the specified device.
+ *
+ * @param sdi Device instance to use. Must not be NULL.
+ *
+ * @return SR_OK upon success, a negative error code upon errors.
+ *
+ * @since 0.2.0
+ */
+SR_API int sr_dev_close(struct sr_dev_inst *sdi)
+{
+       int ret;
+
+       if (!sdi || !sdi->driver || !sdi->driver->dev_close)
+               return SR_ERR;
+
+       ret = sdi->driver->dev_close(sdi);
+
+       return ret;
+}
+
+/** @} */
diff --git a/src/dmm/es519xx.c b/src/dmm/es519xx.c
new file mode 100644 (file)
index 0000000..075587c
--- /dev/null
@@ -0,0 +1,828 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Uwe Hermann <uwe@hermann-uwe.de>
+ * Copyright (C) 2013 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 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/*
+ * Cyrustek ES519XX protocol parser.
+ *
+ * Communication parameters: Unidirectional, 2400/7o1 or 19230/7o1
+ */
+
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "es519xx"
+
+/* Factors for the respective measurement mode (0 means "invalid"). */
+static const float factors_2400_11b[9][8] = {
+       {1e-4,  1e-3,  1e-2,  1e-1, 1,    0,    0,    0   }, /* V */
+       {1e-7,  1e-6,  0,     0,    0,    0,    0,    0   }, /* uA */
+       {1e-5,  1e-4,  0,     0,    0,    0,    0,    0   }, /* mA */
+       {1e-2,  0,     0,     0,    0,    0,    0,    0   }, /* A */
+       {1e1,   1e2,   1e3,   1e4,  1e5,  1e6,  0,    0   }, /* RPM */
+       {1e-1,  1,     1e1,   1e2,  1e3,  1e4,  0,    0   }, /* Resistance */
+       {1,     1e1,   1e2,   1e3,  1e4,  1e5,  0,    0   }, /* Frequency */
+       {1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5}, /* Capacitance */
+       {1e-3,  0,     0,     0,    0,    0,    0,    0   }, /* Diode */
+};
+static const float factors_19200_11b_5digits[9][8] = {
+       {1e-4,  1e-3,  1e-2,  1e-1, 1e-5, 0,    0,    0},    /* V */
+       {1e-8,  1e-7,  0,     0,    0,    0,    0,    0},    /* uA */
+       {1e-6,  1e-5,  0,     0,    0,    0,    0,    0},    /* mA */
+       {0,     1e-3,  0,     0,    0,    0,    0,    0},    /* A */
+       {1e-4,  1e-3,  1e-2,  1e-1, 1,    0,    0,    0},    /* Manual A */
+       {1e-2,  1e-1,  1,     1e1,  1e2,  1e3,  1e4,  0},    /* Resistance */
+       {1e-1,  0,     1,     1e1,  1e2,  1e3,  1e4,  0},    /* Frequency */
+       {1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5}, /* Capacitance */
+       {1e-4,  0,     0,     0,    0,    0,    0,    0   }, /* Diode */
+};
+static const float factors_19200_11b_clampmeter[9][8] = {
+       {1e-3,  1e-2,  1e-1,  1,    1e-4, 0,    0,    0},    /* V */
+       {1e-7,  1e-6,  0,     0,    0,    0,    0,    0},    /* uA */
+       {1e-5,  1e-4,  0,     0,    0,    0,    0,    0},    /* mA */
+       {1e-2,  0,     0,     0,    0,    0,    0,    0},    /* A */
+       {1e-3,  1e-2,  1e-1,  1,    0,    0,    0,    0},    /* Manual A */
+       {1e-1,  1,     1e1,   1e2,  1e3,  1e4,  0,    0},    /* Resistance */
+       {1e-1,  0,     1,     1e1,  1e2,  1e3,  1e4,  0},    /* Frequency */
+       {1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5}, /* Capacitance */
+       {1e-3,  0,     0,     0,    0,    0,    0,    0   }, /* Diode */
+};
+static const float factors_19200_11b[9][8] = {
+       {1e-3,  1e-2,  1e-1,  1,    1e-4, 0,    0,    0},    /* V */
+       {1e-7,  1e-6,  0,     0,    0,    0,    0,    0},    /* uA */
+       {1e-5,  1e-4,  0,     0,    0,    0,    0,    0},    /* mA */
+       {1e-3,  1e-2,  0,     0,    0,    0,    0,    0},    /* A */
+       {0,     0,     0,     0,    0,    0,    0,    0},    /* Manual A */
+       {1e-1,  1,     1e1,   1e2,  1e3,  1e4,  0,    0},    /* Resistance */
+       {1,     1e1,   1e2,   1e3,  1e4,  0,    0,    0},    /* Frequency */
+       {1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 0},    /* Capacitance */
+       {1e-3,  0,     0,     0,    0,    0,    0,    0},    /* Diode */
+};
+static const float factors_19200_14b[9][8] = {
+       {1e-4,  1e-3,  1e-2,  1e-1, 1e-5, 0,    0,    0},    /* V */
+       {1e-8,  1e-7,  0,     0,    0,    0,    0,    0},    /* uA */
+       {1e-6,  1e-5,  0,     0,    0,    0,    0,    0},    /* mA */
+       {1e-3,  0,     0,     0,    0,    0,    0,    0},    /* A */
+       {1e-4,  1e-3,  1e-2,  1e-1, 1,    0,    0,    0},    /* Manual A */
+       {1e-2,  1e-1,  1,     1e1,  1e2,  1e3,  1e4,  0},    /* Resistance */
+       {1e-2,  1e-1,  0,     1,    1e1,  1e2,  1e3,  1e4},  /* Frequency */
+       {1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5}, /* Capacitance */
+       {1e-4,  0,     0,     0,    0,    0,    0,    0   }, /* Diode */
+};
+
+static int parse_value(const uint8_t *buf, struct es519xx_info *info,
+                       float *result)
+{
+       int i, intval, num_digits;
+       float floatval;
+
+       num_digits = 4 + ((info->packet_size == 14) ? 1 : 0);
+
+       /* Bytes 1-4 (or 5): Value (4 or 5 decimal digits) */
+       if (info->is_ol) {
+               sr_spew("Over limit.");
+               *result = INFINITY;
+               return SR_OK;
+       } else if (info->is_ul) {
+               sr_spew("Under limit.");
+               *result = INFINITY;
+               return SR_OK;
+       } else if (!isdigit(buf[1]) || !isdigit(buf[2]) ||
+                  !isdigit(buf[3]) || !isdigit(buf[4]) ||
+                  (num_digits == 5 && !isdigit(buf[5]))) {
+               sr_dbg("Value contained invalid digits: %02x %02x %02x %02x "
+                      "(%c %c %c %c).", buf[1], buf[2], buf[3], buf[4],
+                      buf[1], buf[2], buf[3], buf[4]);
+               return SR_ERR;
+       }
+       intval = (info->is_digit4) ? 1 : 0;
+       for (i = 0; i < num_digits; i++)
+               intval = 10 * intval + (buf[i + 1] - '0');
+
+       /* Apply sign. */
+       intval *= info->is_sign ? -1 : 1;
+
+       floatval = (float)intval;
+
+       /* Note: The decimal point position will be parsed later. */
+
+       sr_spew("The display value is %f.", floatval);
+
+       *result = floatval;
+
+       return SR_OK;
+}
+
+static int parse_range(uint8_t b, float *floatval,
+                       const struct es519xx_info *info)
+{
+       int idx, mode;
+       float factor = 0;
+
+       idx = b - '0';
+
+       if (idx < 0 || idx > 7) {
+               sr_dbg("Invalid range byte / index: 0x%02x / 0x%02x.", b, idx);
+               return SR_ERR;
+       }
+
+       /* Parse range byte (depends on the measurement mode). */
+       if (info->is_voltage)
+               mode = 0; /* V */
+       else if (info->is_current && info->is_micro)
+               mode = 1; /* uA */
+       else if (info->is_current && info->is_milli)
+               mode = 2; /* mA */
+       else if (info->is_current && info->is_auto)
+               mode = 3; /* A */
+       else if (info->is_current && !info->is_auto)
+               mode = 4; /* Manual A */
+       else if (info->is_rpm)
+               /* Not a typo, it's really index 4 in factors_2400_11b[][]. */
+               mode = 4; /* RPM */
+       else if (info->is_resistance || info->is_continuity)
+               mode = 5; /* Resistance */
+       else if (info->is_frequency)
+               mode = 6; /* Frequency */
+       else if (info->is_capacitance)
+               mode = 7; /* Capacitance */
+       else if (info->is_diode)
+               mode = 8; /* Diode */
+       else if (info->is_duty_cycle)
+               mode = 0; /* Dummy, unused */
+       else {
+               sr_dbg("Invalid mode, range byte was: 0x%02x.", b);
+               return SR_ERR;
+       }
+
+       if (info->is_vbar) {
+               if (info->is_micro)
+                       factor = (const float[]){1e-1, 1}[idx];
+               else if (info->is_milli)
+                       factor = (const float[]){1e-2, 1e-1}[idx];
+       }
+       else if (info->is_duty_cycle)
+               factor = 1e-1;
+       else if (info->baudrate == 2400)
+               factor = factors_2400_11b[mode][idx];
+       else if (info->fivedigits)
+               factor = factors_19200_11b_5digits[mode][idx];
+       else if (info->clampmeter)
+               factor = factors_19200_11b_clampmeter[mode][idx];
+       else if (info->packet_size == 11)
+               factor = factors_19200_11b[mode][idx];
+       else if (info->packet_size == 14)
+               factor = factors_19200_14b[mode][idx];
+
+       if (factor == 0) {
+               sr_dbg("Invalid factor for range byte: 0x%02x.", b);
+               return SR_ERR;
+       }
+
+       /* Apply respective factor (mode-dependent) on the value. */
+       *floatval *= factor;
+       sr_dbg("Applying factor %f, new value is %f.", factor, *floatval);
+
+       return SR_OK;
+}
+
+static void parse_flags(const uint8_t *buf, struct es519xx_info *info)
+{
+       int function, status;
+
+       function = 5 + ((info->packet_size == 14) ? 1 : 0);
+       status = function + 1;
+
+       /* Status byte */
+       if (info->alt_functions) {
+               info->is_sign  = (buf[status] & (1 << 3)) != 0;
+               info->is_batt  = (buf[status] & (1 << 2)) != 0; /* Bat. low */
+               info->is_ol    = (buf[status] & (1 << 1)) != 0; /* Overflow */
+               info->is_ol   |= (buf[status] & (1 << 0)) != 0; /* Overflow */
+       } else {
+               info->is_judge = (buf[status] & (1 << 3)) != 0;
+               info->is_sign  = (buf[status] & (1 << 2)) != 0;
+               info->is_batt  = (buf[status] & (1 << 1)) != 0; /* Bat. low */
+               info->is_ol    = (buf[status] & (1 << 0)) != 0; /* Overflow */
+       }
+
+       if (info->packet_size == 14) {
+               /* Option 1 byte */
+               info->is_max  = (buf[8] & (1 << 3)) != 0;
+               info->is_min  = (buf[8] & (1 << 2)) != 0;
+               info->is_rel  = (buf[8] & (1 << 1)) != 0;
+               info->is_rmr  = (buf[8] & (1 << 0)) != 0;
+
+               /* Option 2 byte */
+               info->is_ul   = (buf[9] & (1 << 3)) != 0; /* Underflow */
+               info->is_pmax = (buf[9] & (1 << 2)) != 0; /* Max. peak value */
+               info->is_pmin = (buf[9] & (1 << 1)) != 0; /* Min. peak value */
+
+               /* Option 3 byte */
+               info->is_dc   = (buf[10] & (1 << 3)) != 0;
+               info->is_ac   = (buf[10] & (1 << 2)) != 0;
+               info->is_auto = (buf[10] & (1 << 1)) != 0;
+               info->is_vahz = (buf[10] & (1 << 0)) != 0;
+
+               /* LPF: Low-pass filter(s) */
+               if (info->selectable_lpf) {
+                       /* Option 4 byte */
+                       info->is_hold = (buf[11] & (1 << 3)) != 0;
+                       info->is_vbar = (buf[11] & (1 << 2)) != 0;
+                       info->is_lpf1 = (buf[11] & (1 << 1)) != 0;
+                       info->is_lpf0 = (buf[11] & (1 << 0)) != 0;
+               } else {
+                       /* Option 4 byte */
+                       info->is_vbar = (buf[11] & (1 << 2)) != 0;
+                       info->is_hold = (buf[11] & (1 << 1)) != 0;
+                       info->is_lpf1 = (buf[11] & (1 << 0)) != 0;
+               }
+       } else if (info->alt_functions) {
+               /* Option 2 byte */
+               info->is_dc   = (buf[8] & (1 << 3)) != 0;
+               info->is_auto = (buf[8] & (1 << 2)) != 0;
+               info->is_apo  = (buf[8] & (1 << 0)) != 0;
+               info->is_ac   = !info->is_dc;
+       } else {
+               /* Option 1 byte */
+               if (info->baudrate == 2400) {
+                       info->is_pmax   = (buf[7] & (1 << 3)) != 0;
+                       info->is_pmin   = (buf[7] & (1 << 2)) != 0;
+                       info->is_vahz   = (buf[7] & (1 << 0)) != 0;
+               } else if (info->fivedigits) {
+                       info->is_ul     = (buf[7] & (1 << 3)) != 0;
+                       info->is_pmax   = (buf[7] & (1 << 2)) != 0;
+                       info->is_pmin   = (buf[7] & (1 << 1)) != 0;
+                       info->is_digit4 = (buf[7] & (1 << 0)) != 0;
+               } else if (info->clampmeter) {
+                       info->is_ul     = (buf[7] & (1 << 3)) != 0;
+                       info->is_vasel  = (buf[7] & (1 << 2)) != 0;
+                       info->is_vbar   = (buf[7] & (1 << 1)) != 0;
+               } else {
+                       info->is_hold   = (buf[7] & (1 << 3)) != 0;
+                       info->is_max    = (buf[7] & (1 << 2)) != 0;
+                       info->is_min    = (buf[7] & (1 << 1)) != 0;
+               }
+
+               /* Option 2 byte */
+               info->is_dc   = (buf[8] & (1 << 3)) != 0;
+               info->is_ac   = (buf[8] & (1 << 2)) != 0;
+               info->is_auto = (buf[8] & (1 << 1)) != 0;
+               if (info->baudrate == 2400)
+                       info->is_apo  = (buf[8] & (1 << 0)) != 0;
+               else
+                       info->is_vahz = (buf[8] & (1 << 0)) != 0;
+       }
+
+       /* Function byte */
+       if (info->alt_functions) {
+               switch (buf[function]) {
+               case 0x3f: /* A */
+                       info->is_current = info->is_auto = TRUE;
+                       break;
+               case 0x3e: /* uA */
+                       info->is_current = info->is_micro = info->is_auto = TRUE;
+                       break;
+               case 0x3d: /* mA */
+                       info->is_current = info->is_milli = info->is_auto = TRUE;
+                       break;
+               case 0x3c: /* V */
+                       info->is_voltage = TRUE;
+                       break;
+               case 0x37: /* Resistance */
+                       info->is_resistance = TRUE;
+                       break;
+               case 0x36: /* Continuity */
+                       info->is_continuity = TRUE;
+                       break;
+               case 0x3b: /* Diode */
+                       info->is_diode = TRUE;
+                       break;
+               case 0x3a: /* Frequency */
+                       info->is_frequency = TRUE;
+                       break;
+               case 0x34: /* ADP0 */
+               case 0x35: /* ADP0 */
+                       info->is_adp0 = TRUE;
+                       break;
+               case 0x38: /* ADP1 */
+               case 0x39: /* ADP1 */
+                       info->is_adp1 = TRUE;
+                       break;
+               case 0x32: /* ADP2 */
+               case 0x33: /* ADP2 */
+                       info->is_adp2 = TRUE;
+                       break;
+               case 0x30: /* ADP3 */
+               case 0x31: /* ADP3 */
+                       info->is_adp3 = TRUE;
+                       break;
+               default:
+                       sr_dbg("Invalid function byte: 0x%02x.", buf[function]);
+                       break;
+               }
+       } else {
+               /* Note: Some of these mappings are fixed up later. */
+               switch (buf[function]) {
+               case 0x3b: /* V */
+                       info->is_voltage = TRUE;
+                       break;
+               case 0x3d: /* uA */
+                       info->is_current = info->is_micro = info->is_auto = TRUE;
+                       break;
+               case 0x3f: /* mA */
+                       info->is_current = info->is_milli = info->is_auto = TRUE;
+                       break;
+               case 0x30: /* A */
+                       info->is_current = info->is_auto = TRUE;
+                       break;
+               case 0x39: /* Manual A */
+                       info->is_current = TRUE;
+                       info->is_auto = FALSE; /* Manual mode */
+                       break;
+               case 0x33: /* Resistance */
+                       info->is_resistance = TRUE;
+                       break;
+               case 0x35: /* Continuity */
+                       info->is_continuity = TRUE;
+                       break;
+               case 0x31: /* Diode */
+                       info->is_diode = TRUE;
+                       break;
+               case 0x32: /* Frequency / RPM / duty cycle */
+                       if (info->packet_size == 14) {
+                               if (info->is_judge)
+                                       info->is_duty_cycle = TRUE;
+                               else
+                                       info->is_frequency = TRUE;
+                       } else {
+                               if (info->is_judge)
+                                       info->is_rpm = TRUE;
+                               else
+                                       info->is_frequency = TRUE;
+                       }
+                       break;
+               case 0x36: /* Capacitance */
+                       info->is_capacitance = TRUE;
+                       break;
+               case 0x34: /* Temperature */
+                       info->is_temperature = TRUE;
+                       if (info->is_judge)
+                               info->is_celsius = TRUE;
+                       else
+                               info->is_fahrenheit = TRUE;
+                       /* IMPORTANT: The digits always represent Celsius! */
+                       break;
+               case 0x3e: /* ADP0 */
+                       info->is_adp0 = TRUE;
+                       break;
+               case 0x3c: /* ADP1 */
+                       info->is_adp1 = TRUE;
+                       break;
+               case 0x38: /* ADP2 */
+                       info->is_adp2 = TRUE;
+                       break;
+               case 0x3a: /* ADP3 */
+                       info->is_adp3 = TRUE;
+                       break;
+               default:
+                       sr_dbg("Invalid function byte: 0x%02x.", buf[function]);
+                       break;
+               }
+       }
+
+       if (info->is_vahz && (info->is_voltage || info->is_current)) {
+               info->is_voltage = FALSE;
+               info->is_current = FALSE;
+               info->is_milli = info->is_micro = FALSE;
+               if (info->packet_size == 14) {
+                       if (info->is_judge)
+                               info->is_duty_cycle = TRUE;
+                       else
+                               info->is_frequency = TRUE;
+               } else {
+                       if (info->is_judge)
+                               info->is_rpm = TRUE;
+                       else
+                               info->is_frequency = TRUE;
+               }
+       }
+
+       if (info->is_current && (info->is_micro || info->is_milli) && info->is_vasel) {
+               info->is_current = info->is_auto = FALSE;
+               info->is_voltage = TRUE;
+       }
+
+       if (info->baudrate == 2400) {
+               /* Inverted mapping between mA and A, and no manual A. */
+               if (info->is_current && (info->is_milli || !info->is_auto)) {
+                       info->is_milli = !info->is_milli;
+                       info->is_auto = TRUE;
+               }
+       }
+}
+
+static void handle_flags(struct sr_datafeed_analog *analog,
+                        float *floatval, const struct es519xx_info *info)
+{
+       /*
+        * Note: is_micro etc. are not used directly to multiply/divide
+        * floatval, this is handled via parse_range() and factors[][].
+        */
+
+       /* Measurement modes */
+       if (info->is_voltage) {
+               analog->mq = SR_MQ_VOLTAGE;
+               analog->unit = SR_UNIT_VOLT;
+       }
+       if (info->is_current) {
+               analog->mq = SR_MQ_CURRENT;
+               analog->unit = SR_UNIT_AMPERE;
+       }
+       if (info->is_resistance) {
+               analog->mq = SR_MQ_RESISTANCE;
+               analog->unit = SR_UNIT_OHM;
+       }
+       if (info->is_frequency) {
+               analog->mq = SR_MQ_FREQUENCY;
+               analog->unit = SR_UNIT_HERTZ;
+       }
+       if (info->is_capacitance) {
+               analog->mq = SR_MQ_CAPACITANCE;
+               analog->unit = SR_UNIT_FARAD;
+       }
+       if (info->is_temperature && info->is_celsius) {
+               analog->mq = SR_MQ_TEMPERATURE;
+               analog->unit = SR_UNIT_CELSIUS;
+       }
+       if (info->is_temperature && info->is_fahrenheit) {
+               analog->mq = SR_MQ_TEMPERATURE;
+               analog->unit = SR_UNIT_FAHRENHEIT;
+       }
+       if (info->is_continuity) {
+               analog->mq = SR_MQ_CONTINUITY;
+               analog->unit = SR_UNIT_BOOLEAN;
+               *floatval = (*floatval < 0.0 || *floatval > 25.0) ? 0.0 : 1.0;
+       }
+       if (info->is_diode) {
+               analog->mq = SR_MQ_VOLTAGE;
+               analog->unit = SR_UNIT_VOLT;
+       }
+       if (info->is_rpm) {
+               analog->mq = SR_MQ_FREQUENCY;
+               analog->unit = SR_UNIT_REVOLUTIONS_PER_MINUTE;
+       }
+       if (info->is_duty_cycle) {
+               analog->mq = SR_MQ_DUTY_CYCLE;
+               analog->unit = SR_UNIT_PERCENTAGE;
+       }
+
+       /* Measurement related flags */
+       if (info->is_ac)
+               analog->mqflags |= SR_MQFLAG_AC;
+       if (info->is_dc)
+               analog->mqflags |= SR_MQFLAG_DC;
+       if (info->is_auto)
+               analog->mqflags |= SR_MQFLAG_AUTORANGE;
+       if (info->is_diode)
+               analog->mqflags |= SR_MQFLAG_DIODE;
+       if (info->is_hold)
+               /*
+               * Note: HOLD only affects the number displayed on the LCD,
+               * but not the value sent via the protocol! It also does not
+               * affect the bargraph on the LCD.
+               */
+               analog->mqflags |= SR_MQFLAG_HOLD;
+       if (info->is_max)
+               analog->mqflags |= SR_MQFLAG_MAX;
+       if (info->is_min)
+               analog->mqflags |= SR_MQFLAG_MIN;
+       if (info->is_rel)
+               analog->mqflags |= SR_MQFLAG_RELATIVE;
+
+       /* Other flags */
+       if (info->is_judge)
+               sr_spew("Judge bit is set.");
+       if (info->is_batt)
+               sr_spew("Battery is low.");
+       if (info->is_ol)
+               sr_spew("Input overflow.");
+       if (info->is_ul)
+               sr_spew("Input underflow.");
+       if (info->is_pmax)
+               sr_spew("pMAX active, LCD shows max. peak value.");
+       if (info->is_pmin)
+               sr_spew("pMIN active, LCD shows min. peak value.");
+       if (info->is_vahz)
+               sr_spew("VAHZ active.");
+       if (info->is_apo)
+               sr_spew("Auto-Power-Off enabled.");
+       if (info->is_vbar)
+               sr_spew("VBAR active.");
+       if ((!info->selectable_lpf && info->is_lpf1) ||
+           (info->selectable_lpf && (!info->is_lpf0 || !info->is_lpf1)))
+               sr_spew("Low-pass filter feature is active.");
+}
+
+static gboolean flags_valid(const struct es519xx_info *info)
+{
+       int count;
+
+       /* Does the packet have more than one multiplier? */
+       count  = (info->is_micro) ? 1 : 0;
+       count += (info->is_milli) ? 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  = (info->is_voltage) ? 1 : 0;
+       count += (info->is_current) ? 1 : 0;
+       count += (info->is_resistance) ? 1 : 0;
+       count += (info->is_frequency) ? 1 : 0;
+       count += (info->is_capacitance) ? 1 : 0;
+       count += (info->is_temperature) ? 1 : 0;
+       count += (info->is_continuity) ? 1 : 0;
+       count += (info->is_diode) ? 1 : 0;
+       count += (info->is_rpm) ? 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;
+}
+
+static gboolean sr_es519xx_packet_valid(const uint8_t *buf,
+                                        struct es519xx_info *info)
+{
+       int s;
+
+       s = info->packet_size;
+
+       if (s == 11 && memcmp(buf, buf + s, s))
+               return FALSE;
+
+       if (buf[s - 2] != '\r' || buf[s - 1] != '\n')
+               return FALSE;
+
+       parse_flags(buf, info);
+
+       if (!flags_valid(info))
+               return FALSE;
+
+       return TRUE;
+}
+
+static int sr_es519xx_parse(const uint8_t *buf, float *floatval,
+                            struct sr_datafeed_analog *analog,
+                            struct es519xx_info *info)
+{
+       int ret;
+
+       if (!sr_es519xx_packet_valid(buf, info))
+               return SR_ERR;
+
+       if ((ret = parse_value(buf, info, floatval)) != SR_OK) {
+               sr_dbg("Error parsing value: %d.", ret);
+               return ret;
+       }
+
+       if ((ret = parse_range(buf[0], floatval, info)) != SR_OK)
+               return ret;
+
+       handle_flags(analog, floatval, info);
+       return SR_OK;
+}
+
+/*
+ * Functions for 2400 baud / 11 bytes protocols.
+ * This includes ES51962, ES51971, ES51972, ES51978 and ES51989.
+ */
+SR_PRIV gboolean sr_es519xx_2400_11b_packet_valid(const uint8_t *buf)
+{
+       struct es519xx_info info;
+
+       memset(&info, 0, sizeof(struct es519xx_info));
+       info.baudrate = 2400;
+       info.packet_size = 11;
+
+       return sr_es519xx_packet_valid(buf, &info);
+}
+
+SR_PRIV int sr_es519xx_2400_11b_parse(const uint8_t *buf, float *floatval,
+                               struct sr_datafeed_analog *analog, void *info)
+{
+       struct es519xx_info *info_local;
+
+       info_local = info;
+       memset(info_local, 0, sizeof(struct es519xx_info));
+       info_local->baudrate = 2400;
+       info_local->packet_size = 11;
+
+       return sr_es519xx_parse(buf, floatval, analog, info);
+}
+
+/*
+ * Functions for 2400 baud / 11 byte protocols.
+ * This includes ES51960, ES51977 and ES51988.
+ */
+SR_PRIV gboolean sr_es519xx_2400_11b_altfn_packet_valid(const uint8_t *buf)
+{
+       struct es519xx_info info;
+
+       memset(&info, 0, sizeof(struct es519xx_info));
+       info.baudrate = 2400;
+       info.packet_size = 11;
+       info.alt_functions = TRUE;
+
+       return sr_es519xx_packet_valid(buf, &info);
+}
+
+SR_PRIV int sr_es519xx_2400_11b_altfn_parse(const uint8_t *buf,
+               float *floatval, struct sr_datafeed_analog *analog, void *info)
+{
+       struct es519xx_info *info_local;
+
+       info_local = info;
+       memset(info_local, 0, sizeof(struct es519xx_info));
+       info_local->baudrate = 2400;
+       info_local->packet_size = 11;
+       info_local->alt_functions = TRUE;
+
+       return sr_es519xx_parse(buf, floatval, analog, info);
+}
+
+/*
+ * Functions for 19200 baud / 11 bytes protocols with 5 digits display.
+ * This includes ES51911, ES51916 and ES51918.
+ */
+SR_PRIV gboolean sr_es519xx_19200_11b_5digits_packet_valid(const uint8_t *buf)
+{
+       struct es519xx_info info;
+
+       memset(&info, 0, sizeof(struct es519xx_info));
+       info.baudrate = 19200;
+       info.packet_size = 11;
+       info.fivedigits = TRUE;
+
+       return sr_es519xx_packet_valid(buf, &info);
+}
+
+SR_PRIV int sr_es519xx_19200_11b_5digits_parse(const uint8_t *buf,
+               float *floatval, struct sr_datafeed_analog *analog, void *info)
+{
+       struct es519xx_info *info_local;
+
+       info_local = info;
+       memset(info_local, 0, sizeof(struct es519xx_info));
+       info_local->baudrate = 19200;
+       info_local->packet_size = 11;
+       info_local->fivedigits = TRUE;
+
+       return sr_es519xx_parse(buf, floatval, analog, info);
+}
+
+/*
+ * Functions for 19200 baud / 11 bytes protocols with clamp meter support.
+ * This includes ES51967 and ES51969.
+ */
+SR_PRIV gboolean sr_es519xx_19200_11b_clamp_packet_valid(const uint8_t *buf)
+{
+       struct es519xx_info info;
+
+       memset(&info, 0, sizeof(struct es519xx_info));
+       info.baudrate = 19200;
+       info.packet_size = 11;
+       info.clampmeter = TRUE;
+
+       return sr_es519xx_packet_valid(buf, &info);
+}
+
+SR_PRIV int sr_es519xx_19200_11b_clamp_parse(const uint8_t *buf,
+               float *floatval, struct sr_datafeed_analog *analog, void *info)
+{
+       struct es519xx_info *info_local;
+
+       info_local = info;
+       memset(info_local, 0, sizeof(struct es519xx_info));
+       info_local->baudrate = 19200;
+       info_local->packet_size = 11;
+       info_local->clampmeter = TRUE;
+
+       return sr_es519xx_parse(buf, floatval, analog, info);
+}
+
+/*
+ * Functions for 19200 baud / 11 bytes protocols.
+ * This includes ES51981, ES51982, ES51983, ES51984 and ES51986.
+ */
+SR_PRIV gboolean sr_es519xx_19200_11b_packet_valid(const uint8_t *buf)
+{
+       struct es519xx_info info;
+
+       memset(&info, 0, sizeof(struct es519xx_info));
+       info.baudrate = 19200;
+       info.packet_size = 11;
+
+       return sr_es519xx_packet_valid(buf, &info);
+}
+
+SR_PRIV int sr_es519xx_19200_11b_parse(const uint8_t *buf, float *floatval,
+                       struct sr_datafeed_analog *analog, void *info)
+{
+       struct es519xx_info *info_local;
+
+       info_local = info;
+       memset(info_local, 0, sizeof(struct es519xx_info));
+       info_local->baudrate = 19200;
+       info_local->packet_size = 11;
+
+       return sr_es519xx_parse(buf, floatval, analog, info);
+}
+
+/*
+ * Functions for 19200 baud / 14 bytes protocols.
+ * This includes ES51921 and ES51922.
+ */
+SR_PRIV gboolean sr_es519xx_19200_14b_packet_valid(const uint8_t *buf)
+{
+       struct es519xx_info info;
+
+       memset(&info, 0, sizeof(struct es519xx_info));
+       info.baudrate = 19200;
+       info.packet_size = 14;
+
+       return sr_es519xx_packet_valid(buf, &info);
+}
+
+SR_PRIV int sr_es519xx_19200_14b_parse(const uint8_t *buf, float *floatval,
+                       struct sr_datafeed_analog *analog, void *info)
+{
+       struct es519xx_info *info_local;
+
+       info_local = info;
+       memset(info_local, 0, sizeof(struct es519xx_info));
+       info_local->baudrate = 19200;
+       info_local->packet_size = 14;
+
+       return sr_es519xx_parse(buf, floatval, analog, info);
+}
+
+/*
+ * Functions for 19200 baud / 14 bytes protocols with selectable LPF.
+ * This includes ES51931 and ES51932.
+ */
+SR_PRIV gboolean sr_es519xx_19200_14b_sel_lpf_packet_valid(const uint8_t *buf)
+{
+       struct es519xx_info info;
+
+       memset(&info, 0, sizeof(struct es519xx_info));
+       info.baudrate = 19200;
+       info.packet_size = 14;
+       info.selectable_lpf = TRUE;
+
+       return sr_es519xx_packet_valid(buf, &info);
+}
+
+SR_PRIV int sr_es519xx_19200_14b_sel_lpf_parse(const uint8_t *buf,
+               float *floatval, struct sr_datafeed_analog *analog, void *info)
+{
+       struct es519xx_info *info_local;
+
+       info_local = info;
+       memset(info_local, 0, sizeof(struct es519xx_info));
+       info_local->baudrate = 19200;
+       info_local->packet_size = 14;
+       info_local->selectable_lpf = TRUE;
+
+       return sr_es519xx_parse(buf, floatval, analog, info);
+}
diff --git a/src/dmm/fs9721.c b/src/dmm/fs9721.c
new file mode 100644 (file)
index 0000000..f3101f8
--- /dev/null
@@ -0,0 +1,445 @@
+/*
+ * 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>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/*
+ * Fortune Semiconductor FS9721_LP3/FS9721B protocol parser.
+ *
+ * FS9721_LP3: 4000 counts (3 3/4 digits)
+ * FS9721B/Q100: 2400 counts (3 2/3 digits)
+ *
+ * Same for both chips:
+ *  - Packages: Bare die (78 pins) or QFP-100
+ *  - Communication parameters: Unidirectional, 2400/8n1
+ *  - The protocol seems to be exactly the same.
+ */
+
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "fs9721"
+
+static int parse_digit(uint8_t b)
+{
+       switch (b) {
+       case 0x7d:
+               return 0;
+       case 0x05:
+               return 1;
+       case 0x5b:
+               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 digit byte: 0x%02x.", b);
+               return -1;
+       }
+}
+
+static gboolean sync_nibbles_valid(const uint8_t *buf)
+{
+       int i;
+
+       /* Check the synchronization nibbles, and make sure they all match. */
+       for (i = 0; i < FS9721_PACKET_SIZE; i++) {
+               if (((buf[i] >> 4) & 0x0f) != (i + 1)) {
+                       sr_dbg("Sync nibble in byte %d (0x%02x) is invalid.",
+                              i, buf[i]);
+                       return FALSE;
+               }
+       }
+
+       return TRUE;
+}
+
+static gboolean flags_valid(const struct fs9721_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;
+       count += (info->is_percent) ? 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 not set? */
+       if (!info->is_rs232) {
+               sr_dbg("No RS232 flag detected in packet.");
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+static int parse_value(const uint8_t *buf, float *result)
+{
+       int i, sign, intval = 0, digits[4];
+       uint8_t digit_bytes[4];
+       float floatval;
+
+       /* Byte 1: LCD SEG2 */
+       sign = ((buf[1] & (1 << 3)) != 0) ? -1 : 1;
+
+       /*
+        * Bytes 1-8: Value (4 decimal digits, sign, decimal point)
+        *
+        * Over limit: "0L" (LCD), 0x00 0x7d 0x68 0x00 (digit bytes).
+        */
+
+       /* Merge the two nibbles for a digit into one byte. */
+       for (i = 0; i < 4; i++) {
+               digit_bytes[i] = ((buf[1 + (i * 2)] & 0x0f) << 4);
+               digit_bytes[i] |= (buf[1 + (i * 2) + 1] & 0x0f);
+
+               /* Bit 7 in the byte is not part of the digit. */
+               digit_bytes[i] &= ~(1 << 7);
+       }
+
+       /* Check for "OL". */
+       if (digit_bytes[0] == 0x00 && digit_bytes[1] == 0x7d &&
+           digit_bytes[2] == 0x68 && digit_bytes[3] == 0x00) {
+               sr_spew("Over limit.");
+               *result = INFINITY;
+               return SR_OK;
+       }
+
+       /* Parse the digits. */
+       for (i = 0; i < 4; i++)
+               digits[i] = parse_digit(digit_bytes[i]);
+       sr_spew("Digits: %02x %02x %02x %02x (%d%d%d%d).",
+               digit_bytes[0], digit_bytes[1], digit_bytes[2], digit_bytes[3],
+               digits[0], digits[1], digits[2], digits[3]);
+
+       /* Merge all digits into an integer value. */
+       for (i = 0; i < 4; i++) {
+               intval *= 10;
+               intval += digits[i];
+       }
+
+       floatval = (float)intval;
+
+       /* Decimal point position. */
+       if ((buf[3] & (1 << 3)) != 0) {
+               floatval /= 1000;
+               sr_spew("Decimal point after first digit.");
+       } else if ((buf[5] & (1 << 3)) != 0) {
+               floatval /= 100;
+               sr_spew("Decimal point after second digit.");
+       } else if ((buf[7] & (1 << 3)) != 0) {
+               floatval /= 10;
+               sr_spew("Decimal point after third digit.");
+       } else {
+               sr_spew("No decimal point in the number.");
+       }
+
+       /* Apply sign. */
+       floatval *= sign;
+
+       sr_spew("The display value is %f.", floatval);
+
+       *result = floatval;
+
+       return SR_OK;
+}
+
+static void parse_flags(const uint8_t *buf, struct fs9721_info *info)
+{
+       /* Byte 0: LCD SEG1 */
+       info->is_ac         = (buf[0] & (1 << 3)) != 0;
+       info->is_dc         = (buf[0] & (1 << 2)) != 0;
+       info->is_auto       = (buf[0] & (1 << 1)) != 0;
+       info->is_rs232      = (buf[0] & (1 << 0)) != 0;
+
+       /* Byte 1: LCD SEG2 */
+       info->is_sign       = (buf[1] & (1 << 3)) != 0;
+
+       /* Byte 9: LCD SEG10 */
+       info->is_micro      = (buf[9] & (1 << 3)) != 0;
+       info->is_nano       = (buf[9] & (1 << 2)) != 0;
+       info->is_kilo       = (buf[9] & (1 << 1)) != 0;
+       info->is_diode      = (buf[9] & (1 << 0)) != 0;
+
+       /* Byte 10: LCD SEG11 */
+       info->is_milli      = (buf[10] & (1 << 3)) != 0;
+       info->is_percent    = (buf[10] & (1 << 2)) != 0;
+       info->is_mega       = (buf[10] & (1 << 1)) != 0;
+       info->is_beep       = (buf[10] & (1 << 0)) != 0;
+
+       /* Byte 11: LCD SEG12 */
+       info->is_farad      = (buf[11] & (1 << 3)) != 0;
+       info->is_ohm        = (buf[11] & (1 << 2)) != 0;
+       info->is_rel        = (buf[11] & (1 << 1)) != 0;
+       info->is_hold       = (buf[11] & (1 << 0)) != 0;
+
+       /* Byte 12: LCD SEG13 */
+       info->is_ampere     = (buf[12] & (1 << 3)) != 0;
+       info->is_volt       = (buf[12] & (1 << 2)) != 0;
+       info->is_hz         = (buf[12] & (1 << 1)) != 0;
+       info->is_bat        = (buf[12] & (1 << 0)) != 0;
+
+       /* Byte 13: LCD SEG14 */
+       info->is_c2c1_11    = (buf[13] & (1 << 3)) != 0;
+       info->is_c2c1_10    = (buf[13] & (1 << 2)) != 0;
+       info->is_c2c1_01    = (buf[13] & (1 << 1)) != 0;
+       info->is_c2c1_00    = (buf[13] & (1 << 0)) != 0;
+}
+
+static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
+                        const struct fs9721_info *info)
+{
+       /* Factors */
+       if (info->is_nano)
+               *floatval /= 1000000000;
+       if (info->is_micro)
+               *floatval /= 1000000;
+       if (info->is_milli)
+               *floatval /= 1000;
+       if (info->is_kilo)
+               *floatval *= 1000;
+       if (info->is_mega)
+               *floatval *= 1000000;
+
+       /* Measurement modes */
+       if (info->is_volt) {
+               analog->mq = SR_MQ_VOLTAGE;
+               analog->unit = SR_UNIT_VOLT;
+       }
+       if (info->is_ampere) {
+               analog->mq = SR_MQ_CURRENT;
+               analog->unit = SR_UNIT_AMPERE;
+       }
+       if (info->is_ohm) {
+               analog->mq = SR_MQ_RESISTANCE;
+               analog->unit = SR_UNIT_OHM;
+       }
+       if (info->is_hz) {
+               analog->mq = SR_MQ_FREQUENCY;
+               analog->unit = SR_UNIT_HERTZ;
+       }
+       if (info->is_farad) {
+               analog->mq = SR_MQ_CAPACITANCE;
+               analog->unit = SR_UNIT_FARAD;
+       }
+       if (info->is_beep) {
+               analog->mq = SR_MQ_CONTINUITY;
+               analog->unit = SR_UNIT_BOOLEAN;
+               *floatval = (*floatval == INFINITY) ? 0.0 : 1.0;
+       }
+       if (info->is_diode) {
+               analog->mq = SR_MQ_VOLTAGE;
+               analog->unit = SR_UNIT_VOLT;
+       }
+       if (info->is_percent) {
+               analog->mq = SR_MQ_DUTY_CYCLE;
+               analog->unit = SR_UNIT_PERCENTAGE;
+       }
+
+       /* Measurement related flags */
+       if (info->is_ac)
+               analog->mqflags |= SR_MQFLAG_AC;
+       if (info->is_dc)
+               analog->mqflags |= SR_MQFLAG_DC;
+       if (info->is_auto)
+               analog->mqflags |= SR_MQFLAG_AUTORANGE;
+       if (info->is_diode)
+               analog->mqflags |= SR_MQFLAG_DIODE;
+       if (info->is_hold)
+               analog->mqflags |= SR_MQFLAG_HOLD;
+       if (info->is_rel)
+               analog->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_c2c1_00)
+               sr_spew("User-defined LCD symbol 0 is active.");
+       if (info->is_c2c1_01)
+               sr_spew("User-defined LCD symbol 1 is active.");
+       if (info->is_c2c1_10)
+               sr_spew("User-defined LCD symbol 2 is active.");
+       if (info->is_c2c1_11)
+               sr_spew("User-defined LCD symbol 3 is active.");
+}
+
+SR_PRIV gboolean sr_fs9721_packet_valid(const uint8_t *buf)
+{
+       struct fs9721_info info;
+
+       parse_flags(buf, &info);
+
+       return (sync_nibbles_valid(buf) && flags_valid(&info));
+}
+
+/**
+ * Parse a protocol packet.
+ *
+ * @param buf Buffer containing the 14-byte protocol packet. Must not be NULL.
+ * @param floatval Pointer to a float variable. That variable will contain the
+ *                 result value upon parsing success. Mut 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 fs9721_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_fs9721_parse(const uint8_t *buf, float *floatval,
+                           struct sr_datafeed_analog *analog, void *info)
+{
+       int ret;
+       struct fs9721_info *info_local;
+
+       info_local = (struct fs9721_info *)info;
+
+       if ((ret = parse_value(buf, floatval)) != SR_OK) {
+               sr_dbg("Error parsing value: %d.", ret);
+               return ret;
+       }
+
+       parse_flags(buf, info_local);
+       handle_flags(analog, floatval, info_local);
+
+       return SR_OK;
+}
+
+SR_PRIV void sr_fs9721_00_temp_c(struct sr_datafeed_analog *analog, void *info)
+{
+       struct fs9721_info *info_local;
+
+       info_local = (struct fs9721_info *)info;
+
+       /* User-defined FS9721_LP3 flag 'c2c1_00' means temperature (C). */
+       if (info_local->is_c2c1_00) {
+               analog->mq = SR_MQ_TEMPERATURE;
+               analog->unit = SR_UNIT_CELSIUS;
+       }
+}
+
+SR_PRIV void sr_fs9721_01_temp_c(struct sr_datafeed_analog *analog, void *info)
+{
+       struct fs9721_info *info_local;
+
+       info_local = (struct fs9721_info *)info;
+
+       /* User-defined FS9721_LP3 flag 'c2c1_01' means temperature (C). */
+       if (info_local->is_c2c1_01) {
+               analog->mq = SR_MQ_TEMPERATURE;
+               analog->unit = SR_UNIT_CELSIUS;
+       }
+}
+
+SR_PRIV void sr_fs9721_10_temp_c(struct sr_datafeed_analog *analog, void *info)
+{
+       struct fs9721_info *info_local;
+
+       info_local = (struct fs9721_info *)info;
+
+       /* User-defined FS9721_LP3 flag 'c2c1_10' means temperature (C). */
+       if (info_local->is_c2c1_10) {
+               analog->mq = SR_MQ_TEMPERATURE;
+               analog->unit = SR_UNIT_CELSIUS;
+       }
+}
+
+SR_PRIV void sr_fs9721_01_10_temp_f_c(struct sr_datafeed_analog *analog, void *info)
+{
+       struct fs9721_info *info_local;
+
+       info_local = (struct fs9721_info *)info;
+
+       /* User-defined FS9721_LP3 flag 'c2c1_01' means temperature (F). */
+       if (info_local->is_c2c1_01) {
+               analog->mq = SR_MQ_TEMPERATURE;
+               analog->unit = SR_UNIT_FAHRENHEIT;
+       }
+
+       /* User-defined FS9721_LP3 flag 'c2c1_10' means temperature (C). */
+       if (info_local->is_c2c1_10) {
+               analog->mq = SR_MQ_TEMPERATURE;
+               analog->unit = SR_UNIT_CELSIUS;
+       }
+}
+
+SR_PRIV void sr_fs9721_max_c_min(struct sr_datafeed_analog *analog, void *info)
+{
+       struct fs9721_info *info_local;
+
+       info_local = (struct fs9721_info *)info;
+
+       /* User-defined FS9721_LP3 flag 'c2c1_00' means MAX. */
+       if (info_local->is_c2c1_00)
+               analog->mqflags |= SR_MQFLAG_MAX;
+
+       /* User-defined FS9721_LP3 flag 'c2c1_01' means temperature (C). */
+       if (info_local->is_c2c1_01) {
+               analog->mq = SR_MQ_TEMPERATURE;
+               analog->unit = SR_UNIT_CELSIUS;
+       }
+
+       /* User-defined FS9721_LP3 flag 'c2c1_11' means MIN. */
+       if (info_local->is_c2c1_11)
+               analog->mqflags |= SR_MQFLAG_MIN;
+
+}
diff --git a/src/dmm/fs9922.c b/src/dmm/fs9922.c
new file mode 100644 (file)
index 0000000..caaa51c
--- /dev/null
@@ -0,0 +1,384 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/*
+ * Fortune Semiconductor FS9922-DMM3/FS9922-DMM4 protocol parser.
+ */
+
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "fs9922"
+
+static gboolean flags_valid(const struct fs9922_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?
+        *
+        * Note: In "diode mode", both is_diode and is_volt will be set.
+        * That is a valid use-case, so we don't want to error out below
+        * if it happens. Thus, we don't check for is_diode here.
+        */
+       count = 0;
+       // count += (info->is_diode) ? 1 : 0;
+       count += (info->is_percent) ? 1 : 0;
+       count += (info->is_volt) ? 1 : 0;
+       count += (info->is_ampere) ? 1 : 0;
+       count += (info->is_ohm) ? 1 : 0;
+       count += (info->is_hfe) ? 1 : 0;
+       count += (info->is_hertz) ? 1 : 0;
+       count += (info->is_farad) ? 1 : 0;
+       count += (info->is_celsius) ? 1 : 0;
+       count += (info->is_fahrenheit) ? 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;
+       }
+
+       /* Both Celsius and Fahrenheit set? */
+       if (info->is_celsius && info->is_fahrenheit) {
+               sr_dbg("Both Celsius and Fahrenheit flags detected in packet.");
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+static int parse_value(const uint8_t *buf, float *result)
+{
+       int sign, intval;
+       float floatval;
+
+       /* Byte 0: Sign ('+' or '-') */
+       if (buf[0] == '+') {
+               sign = 1;
+       } else if (buf[0] == '-') {
+               sign = -1;
+       } else {
+               sr_dbg("Invalid sign byte: 0x%02x.", buf[0]);
+               return SR_ERR;
+       }
+
+       /*
+        * Bytes 1-4: Value (4 decimal digits)
+        *
+        * Over limit: "0.L" on the display, "?0:?" as protocol "digits".
+        */
+       if (buf[1] == '?' && buf[2] == '0' && buf[3] == ':' && buf[4] == '?') {
+               sr_spew("Over limit.");
+               *result = INFINITY;
+               return SR_OK;
+       } else if (!isdigit(buf[1]) || !isdigit(buf[2]) ||
+                  !isdigit(buf[3]) || !isdigit(buf[4])) {
+               sr_dbg("Value contained invalid digits: %02x %02x %02x %02x ("
+                      "%c %c %c %c).", buf[1], buf[2], buf[3], buf[4]);
+               return SR_ERR;
+       }
+       intval = 0;
+       intval += (buf[1] - '0') * 1000;
+       intval += (buf[2] - '0') * 100;
+       intval += (buf[3] - '0') * 10;
+       intval += (buf[4] - '0') * 1;
+
+       floatval = (float)intval;
+
+       /* Byte 5: Always ' ' (space, 0x20) */
+
+       /*
+        * Byte 6: Decimal point position ('0', '1', '2', or '4')
+        *
+        * Note: The Fortune Semiconductor FS9922-DMM3/4 datasheets both have
+        * an error/typo here. They claim that the values '0'/'1'/'2'/'3' are
+        * used, but '0'/'1'/'2'/'4' is actually correct.
+        */
+       if (buf[6] != '0' && buf[6] != '1' && buf[6] != '2' && buf[6] != '4') {
+               sr_dbg("Invalid decimal point value: 0x%02x.", buf[6]);
+               return SR_ERR;
+       }
+       if (buf[6] == '0')
+               floatval /= 1;
+       else if (buf[6] == '1')
+               floatval /= 1000;
+       else if (buf[6] == '2')
+               floatval /= 100;
+       else if (buf[6] == '4')
+               floatval /= 10;
+
+       /* Apply sign. */
+       floatval *= sign;
+
+       sr_spew("The display value is %f.", floatval);
+
+       *result = floatval;
+
+       return SR_OK;
+}
+
+static void parse_flags(const uint8_t *buf, struct fs9922_info *info)
+{
+       /* Z1/Z2/Z3/Z4 are bits for user-defined LCD symbols (on/off). */
+
+       /* Byte 7 */
+       /* Bit 7: Always 0 */
+       /* Bit 6: Always 0 */
+       info->is_auto       = (buf[7] & (1 << 5)) != 0;
+       info->is_dc         = (buf[7] & (1 << 4)) != 0;
+       info->is_ac         = (buf[7] & (1 << 3)) != 0;
+       info->is_rel        = (buf[7] & (1 << 2)) != 0;
+       info->is_hold       = (buf[7] & (1 << 1)) != 0;
+       info->is_bpn        = (buf[7] & (1 << 0)) != 0; /* Bargraph shown */
+
+       /* Byte 8 */
+       info->is_z1         = (buf[8] & (1 << 7)) != 0; /* User symbol 1 */
+       info->is_z2         = (buf[8] & (1 << 6)) != 0; /* User symbol 2 */
+       info->is_max        = (buf[8] & (1 << 5)) != 0;
+       info->is_min        = (buf[8] & (1 << 4)) != 0;
+       info->is_apo        = (buf[8] & (1 << 3)) != 0; /* Auto-poweroff on */
+       info->is_bat        = (buf[8] & (1 << 2)) != 0; /* Battery low */
+       info->is_nano       = (buf[8] & (1 << 1)) != 0;
+       info->is_z3         = (buf[8] & (1 << 0)) != 0; /* User symbol 3 */
+
+       /* Byte 9 */
+       info->is_micro      = (buf[9] & (1 << 7)) != 0;
+       info->is_milli      = (buf[9] & (1 << 6)) != 0;
+       info->is_kilo       = (buf[9] & (1 << 5)) != 0;
+       info->is_mega       = (buf[9] & (1 << 4)) != 0;
+       info->is_beep       = (buf[9] & (1 << 3)) != 0;
+       info->is_diode      = (buf[9] & (1 << 2)) != 0;
+       info->is_percent    = (buf[9] & (1 << 1)) != 0;
+       info->is_z4         = (buf[9] & (1 << 0)) != 0; /* User symbol 4 */
+
+       /* Byte 10 */
+       info->is_volt       = (buf[10] & (1 << 7)) != 0;
+       info->is_ampere     = (buf[10] & (1 << 6)) != 0;
+       info->is_ohm        = (buf[10] & (1 << 5)) != 0;
+       info->is_hfe        = (buf[10] & (1 << 4)) != 0;
+       info->is_hertz      = (buf[10] & (1 << 3)) != 0;
+       info->is_farad      = (buf[10] & (1 << 2)) != 0;
+       info->is_celsius    = (buf[10] & (1 << 1)) != 0; /* Only FS9922-DMM4 */
+       info->is_fahrenheit = (buf[10] & (1 << 0)) != 0; /* Only FS9922-DMM4 */
+
+       /*
+        * Byte 11: Bar graph
+        *
+        * Bit 7 contains the sign of the bargraph number (if the bit is set,
+        * the number is negative), bits 6..0 contain the actual number.
+        * Valid range: 0-40 (FS9922-DMM3), 0-60 (FS9922-DMM4).
+        *
+        * Upon "over limit" the bargraph value is 1 count above the highest
+        * valid number (i.e. 41 or 61, depending on chip).
+        */
+       if (info->is_bpn) {
+               info->bargraph_sign = ((buf[11] & (1 << 7)) != 0) ? -1 : 1;
+               info->bargraph_value = (buf[11] & 0x7f);
+               info->bargraph_value *= info->bargraph_sign;
+       }
+
+       /* Byte 12: Always '\r' (carriage return, 0x0d, 13) */
+
+       /* Byte 13: Always '\n' (newline, 0x0a, 10) */
+}
+
+static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
+                        const struct fs9922_info *info)
+{
+       /* Factors */
+       if (info->is_nano)
+               *floatval /= 1000000000;
+       if (info->is_micro)
+               *floatval /= 1000000;
+       if (info->is_milli)
+               *floatval /= 1000;
+       if (info->is_kilo)
+               *floatval *= 1000;
+       if (info->is_mega)
+               *floatval *= 1000000;
+
+       /* Measurement modes */
+       if (info->is_volt || info->is_diode) {
+               /* Note: In "diode mode" both is_diode and is_volt are set. */
+               analog->mq = SR_MQ_VOLTAGE;
+               analog->unit = SR_UNIT_VOLT;
+       }
+       if (info->is_ampere) {
+               analog->mq = SR_MQ_CURRENT;
+               analog->unit = SR_UNIT_AMPERE;
+       }
+       if (info->is_ohm) {
+               analog->mq = SR_MQ_RESISTANCE;
+               analog->unit = SR_UNIT_OHM;
+       }
+       if (info->is_hfe) {
+               analog->mq = SR_MQ_GAIN;
+               analog->unit = SR_UNIT_UNITLESS;
+       }
+       if (info->is_hertz) {
+               analog->mq = SR_MQ_FREQUENCY;
+               analog->unit = SR_UNIT_HERTZ;
+       }
+       if (info->is_farad) {
+               analog->mq = SR_MQ_CAPACITANCE;
+               analog->unit = SR_UNIT_FARAD;
+       }
+       if (info->is_celsius) {
+               analog->mq = SR_MQ_TEMPERATURE;
+               analog->unit = SR_UNIT_CELSIUS;
+       }
+       if (info->is_fahrenheit) {
+               analog->mq = SR_MQ_TEMPERATURE;
+               analog->unit = SR_UNIT_FAHRENHEIT;
+       }
+       if (info->is_beep) {
+               analog->mq = SR_MQ_CONTINUITY;
+               analog->unit = SR_UNIT_BOOLEAN;
+               *floatval = (*floatval == INFINITY) ? 0.0 : 1.0;
+       }
+       if (info->is_percent) {
+               analog->mq = SR_MQ_DUTY_CYCLE;
+               analog->unit = SR_UNIT_PERCENTAGE;
+       }
+
+       /* Measurement related flags */
+       if (info->is_ac)
+               analog->mqflags |= SR_MQFLAG_AC;
+       if (info->is_dc)
+               analog->mqflags |= SR_MQFLAG_DC;
+       if (info->is_auto)
+               analog->mqflags |= SR_MQFLAG_AUTORANGE;
+       if (info->is_diode)
+               analog->mqflags |= SR_MQFLAG_DIODE;
+       if (info->is_hold)
+               analog->mqflags |= SR_MQFLAG_HOLD;
+       if (info->is_max)
+               analog->mqflags |= SR_MQFLAG_MAX;
+       if (info->is_min)
+               analog->mqflags |= SR_MQFLAG_MIN;
+       if (info->is_rel)
+               analog->mqflags |= SR_MQFLAG_RELATIVE;
+
+       /* Other flags */
+       if (info->is_apo)
+               sr_spew("Automatic power-off function is active.");
+       if (info->is_bat)
+               sr_spew("Battery is low.");
+       if (info->is_z1)
+               sr_spew("User-defined LCD symbol 1 is active.");
+       if (info->is_z2)
+               sr_spew("User-defined LCD symbol 2 is active.");
+       if (info->is_z3)
+               sr_spew("User-defined LCD symbol 3 is active.");
+       if (info->is_z4)
+               sr_spew("User-defined LCD symbol 4 is active.");
+       if (info->is_bpn)
+               sr_spew("The bargraph value is %d.", info->bargraph_value);
+       else
+               sr_spew("The bargraph is not active.");
+
+}
+
+SR_PRIV gboolean sr_fs9922_packet_valid(const uint8_t *buf)
+{
+       struct fs9922_info info;
+
+       /* Byte 0: Sign (must be '+' or '-') */
+       if (buf[0] != '+' && buf[0] != '-')
+               return FALSE;
+
+       /* Byte 12: Always '\r' (carriage return, 0x0d, 13) */
+       /* Byte 13: Always '\n' (newline, 0x0a, 10) */
+       if (buf[12] != '\r' || buf[13] != '\n')
+               return FALSE;
+
+       parse_flags(buf, &info);
+
+       return flags_valid(&info);
+}
+
+/**
+ * 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 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 fs9922_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_fs9922_parse(const uint8_t *buf, float *floatval,
+                           struct sr_datafeed_analog *analog, void *info)
+{
+       int ret;
+       struct fs9922_info *info_local;
+
+       info_local = (struct fs9922_info *)info;
+
+       if ((ret = parse_value(buf, floatval)) != SR_OK) {
+               sr_dbg("Error parsing value: %d.", ret);
+               return ret;
+       }
+
+       parse_flags(buf, info_local);
+       handle_flags(analog, floatval, info_local);
+
+       return SR_OK;
+}
+
+SR_PRIV void sr_fs9922_z1_diode(struct sr_datafeed_analog *analog, void *info)
+{
+       struct fs9922_info *info_local;
+
+       info_local = (struct fs9922_info *)info;
+
+       /* User-defined z1 flag means "diode mode". */
+       if (info_local->is_z1) {
+               analog->mq = SR_MQ_VOLTAGE;
+               analog->unit = SR_UNIT_VOLT;
+               analog->mqflags |= SR_MQFLAG_DIODE;
+       }
+}
diff --git a/src/dmm/m2110.c b/src/dmm/m2110.c
new file mode 100644 (file)
index 0000000..5863cef
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Matthias Heidbrink <m-sigrok@heidbrink.biz>
+ *
+ * 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
+ *
+ * BBC Goerz Metrawatt M2110 ASCII protocol parser.
+ *
+ * Most probably the simplest multimeter protocol ever ;-) .
+ */
+
+#include <string.h>
+#include <math.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "m2110"
+
+SR_PRIV gboolean sr_m2110_packet_valid(const uint8_t *buf)
+{
+       float val;
+
+       if ((buf[7] != '\r') || (buf[8] != '\n'))
+               return FALSE;
+
+       if (!strncmp((const char *)buf, "OVERRNG", 7))
+               return TRUE;
+
+       if (sscanf((const char *)buf, "%f", &val) == 1)
+               return TRUE;
+       else
+               return FALSE;
+}
+
+SR_PRIV int sr_m2110_parse(const uint8_t *buf, float *floatval,
+                               struct sr_datafeed_analog *analog, void *info)
+{
+       float val;
+
+       (void)info;
+
+       /* We don't know the unit, so that's the best we can do. */
+       analog->mq = SR_MQ_GAIN;
+       analog->unit = SR_UNIT_UNITLESS;
+       analog->mqflags = 0;
+
+       if (!strncmp((const char *)buf, "OVERRNG", 7))
+               *floatval = INFINITY;
+       else if (sscanf((const char *)buf, "%f", &val) == 1)
+               *floatval = val;
+
+       return SR_OK;
+}
diff --git a/src/dmm/metex14.c b/src/dmm/metex14.c
new file mode 100644 (file)
index 0000000..8151aa9
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012-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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/**
+ * @file
+ *
+ * Metex 14-bytes ASCII protocol parser.
+ *
+ * @internal
+ * This should work for various multimeters which use this kind of protocol,
+ * even though there is some variation in which modes each DMM supports.
+ *
+ * It does _not_ work for all Metex DMMs, some use a quite different protocol.
+ */
+
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "metex14"
+
+/** Parse value from buf, byte 2-8. */
+static int parse_value(const uint8_t *buf, struct metex14_info *info,
+                       float *result)
+{
+       int i, is_ol, cnt;
+       char valstr[7 + 1];
+
+       /* Strip all spaces from bytes 2-8. */
+       memset(&valstr, 0, 7 + 1);
+       for (i = 0, cnt = 0; i < 7; i++) {
+               if (buf[2 + i] != ' ')
+                       valstr[cnt++] = buf[2 + i];
+       }
+
+       /* Bytes 5-7: Over limit (various forms) */
+       is_ol = 0;
+       is_ol += (!strcasecmp((const char *)&valstr, ".OL")) ? 1 : 0;
+       is_ol += (!strcasecmp((const char *)&valstr, "O.L")) ? 1 : 0;
+       is_ol += (!strcasecmp((const char *)&valstr, "OL.")) ? 1 : 0;
+       is_ol += (!strcasecmp((const char *)&valstr, "OL")) ? 1 : 0;
+       is_ol += (!strcasecmp((const char *)&valstr, "-.OL")) ? 1 : 0;
+       is_ol += (!strcasecmp((const char *)&valstr, "-O.L")) ? 1 : 0;
+       is_ol += (!strcasecmp((const char *)&valstr, "-OL.")) ? 1 : 0;
+       is_ol += (!strcasecmp((const char *)&valstr, "-OL")) ? 1 : 0;
+       if (is_ol != 0) {
+               sr_spew("Over limit.");
+               *result = INFINITY;
+               return SR_OK;
+       }
+
+       /* Logic functions */
+       if (!strcmp((const char *)&valstr, "READY") ||
+                       !strcmp((const char *)&valstr, "FLOAT")) {
+               *result = INFINITY;
+               info->is_logic = TRUE;
+       } else if (!strcmp((const char *)&valstr, "Hi")) {
+               *result = 1.0;
+               info->is_logic = TRUE;
+       } else if (!strcmp((const char *)&valstr, "Lo")) {
+               *result = 0.0;
+               info->is_logic = TRUE;
+       }
+       if (info->is_logic)
+               return SR_OK;
+
+       /* Bytes 2-8: Sign, value (up to 5 digits) and decimal point */
+       sscanf((const char *)&valstr, "%f", result);
+
+       sr_spew("The display value is %f.", *result);
+
+       return SR_OK;
+}
+
+static void parse_flags(const char *buf, struct metex14_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 2-8: See parse_value(). */
+
+       /* Strip all spaces from bytes 9-12. */
+       memset(&unit, 0, 4 + 1);
+       for (i = 0, cnt = 0; i < 4; i++) {
+               if (buf[9 + i] != ' ')
+                       unit[cnt++] = buf[9 + i];
+       }
+
+       /* Bytes 9-12: Unit */
+       u = (const char *)&unit;
+       if (!strcasecmp(u, "A"))
+               info->is_ampere = TRUE;
+       else if (!strcasecmp(u, "mA"))
+               info->is_milli = info->is_ampere = TRUE;
+       else if (!strcasecmp(u, "uA"))
+               info->is_micro = info->is_ampere = TRUE;
+       else if (!strcasecmp(u, "V"))
+               info->is_volt = TRUE;
+       else if (!strcasecmp(u, "mV"))
+               info->is_milli = info->is_volt = TRUE;
+       else if (!strcasecmp(u, "Ohm"))
+               info->is_ohm = TRUE;
+       else if (!strcasecmp(u, "KOhm"))
+               info->is_kilo = info->is_ohm = TRUE;
+       else if (!strcasecmp(u, "MOhm"))
+               info->is_mega = info->is_ohm = TRUE;
+       else if (!strcasecmp(u, "pF"))
+               info->is_pico = info->is_farad = TRUE;
+       else if (!strcasecmp(u, "nF"))
+               info->is_nano = info->is_farad = TRUE;
+       else if (!strcasecmp(u, "uF"))
+               info->is_micro = info->is_farad = TRUE;
+       else if (!strcasecmp(u, "KHz"))
+               info->is_kilo = info->is_hertz = TRUE;
+       else if (!strcasecmp(u, "C"))
+               info->is_celsius = TRUE;
+       else if (!strcasecmp(u, "DB"))
+               info->is_decibel = TRUE;
+       else if (!strcasecmp(u, ""))
+               info->is_unitless = TRUE;
+
+       /* Bytes 0-1: Measurement mode, except AC/DC */
+       info->is_resistance  = !strncmp(buf, "OH", 2) ||
+               (!strncmp(buf, "  ", 2) && info->is_ohm);
+       info->is_capacity    = !strncmp(buf, "CA", 2) ||
+               (!strncmp(buf, "  ", 2) && info->is_farad);
+       info->is_temperature = !strncmp(buf, "TE", 2);
+       info->is_diode       = !strncmp(buf, "DI", 2) ||
+               (!strncmp(buf, "  ", 2) && info->is_volt && info->is_milli);
+       info->is_frequency   = !strncmp(buf, "FR", 2) ||
+               (!strncmp(buf, "  ", 2) && info->is_hertz);
+       info->is_gain        = !strncmp(buf, "DB", 2);
+       info->is_hfe         = !strncmp(buf, "HF", 2) ||
+               (!strncmp(buf, "  ", 2) && !info->is_volt && !info->is_ohm &&
+                !info->is_logic && !info->is_farad && !info->is_hertz);
+       /*
+        * Note:
+        * - Protocol doesn't distinguish "resistance" from "beep" mode.
+        * - "DB" shows the logarithmic ratio of input voltage to a
+        *   pre-stored (user-changeable) value in the DMM.
+        */
+
+       /* Byte 13: Always '\r' (carriage return, 0x0d, 13) */
+}
+
+static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
+                        const struct metex14_info *info)
+{
+       /* Factors */
+       if (info->is_pico)
+               *floatval /= 1000000000000ULL;
+       if (info->is_nano)
+               *floatval /= 1000000000;
+       if (info->is_micro)
+               *floatval /= 1000000;
+       if (info->is_milli)
+               *floatval /= 1000;
+       if (info->is_kilo)
+               *floatval *= 1000;
+       if (info->is_mega)
+               *floatval *= 1000000;
+
+       /* Measurement modes */
+       if (info->is_volt) {
+               analog->mq = SR_MQ_VOLTAGE;
+               analog->unit = SR_UNIT_VOLT;
+       }
+       if (info->is_ampere) {
+               analog->mq = SR_MQ_CURRENT;
+               analog->unit = SR_UNIT_AMPERE;
+       }
+       if (info->is_ohm) {
+               analog->mq = SR_MQ_RESISTANCE;
+               analog->unit = SR_UNIT_OHM;
+       }
+       if (info->is_hertz) {
+               analog->mq = SR_MQ_FREQUENCY;
+               analog->unit = SR_UNIT_HERTZ;
+       }
+       if (info->is_farad) {
+               analog->mq = SR_MQ_CAPACITANCE;
+               analog->unit = SR_UNIT_FARAD;
+       }
+       if (info->is_celsius) {
+               analog->mq = SR_MQ_TEMPERATURE;
+               analog->unit = SR_UNIT_CELSIUS;
+       }
+       if (info->is_diode) {
+               analog->mq = SR_MQ_VOLTAGE;
+               analog->unit = SR_UNIT_VOLT;
+       }
+       if (info->is_gain) {
+               analog->mq = SR_MQ_GAIN;
+               analog->unit = SR_UNIT_DECIBEL_VOLT;
+       }
+       if (info->is_hfe) {
+               analog->mq = SR_MQ_GAIN;
+               analog->unit = SR_UNIT_UNITLESS;
+       }
+       if (info->is_logic) {
+               analog->mq = SR_MQ_GAIN;
+               analog->unit = SR_UNIT_UNITLESS;
+       }
+
+       /* Measurement related flags */
+       if (info->is_ac)
+               analog->mqflags |= SR_MQFLAG_AC;
+       if (info->is_dc)
+               analog->mqflags |= SR_MQFLAG_DC;
+       if (info->is_diode)
+               analog->mqflags |= SR_MQFLAG_DIODE;
+}
+
+static gboolean flags_valid(const struct metex14_info *info)
+{
+       int count;
+
+       /* Does the packet have more than one multiplier? */
+       count = 0;
+       count += (info->is_pico) ? 1 : 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_ac) ? 1 : 0;
+       count += (info->is_dc) ? 1 : 0;
+       count += (info->is_resistance) ? 1 : 0;
+       count += (info->is_capacity) ? 1 : 0;
+       count += (info->is_temperature) ? 1 : 0;
+       count += (info->is_diode) ? 1 : 0;
+       count += (info->is_frequency) ? 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;
+}
+
+#ifdef HAVE_LIBSERIALPORT
+SR_PRIV int sr_metex14_packet_request(struct sr_serial_dev_inst *serial)
+{
+       const uint8_t wbuf = 'D';
+
+       sr_spew("Requesting DMM packet.");
+
+       return (serial_write(serial, &wbuf, 1) == 1) ? SR_OK : SR_ERR;
+}
+#endif
+
+SR_PRIV gboolean sr_metex14_packet_valid(const uint8_t *buf)
+{
+       struct metex14_info info;
+
+       memset(&info, 0x00, sizeof(struct metex14_info));
+       parse_flags((const char *)buf, &info);
+
+       if (!flags_valid(&info))
+               return FALSE;
+
+       if (buf[13] != '\r')
+               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 metex14_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_metex14_parse(const uint8_t *buf, float *floatval,
+                            struct sr_datafeed_analog *analog, void *info)
+{
+       int ret;
+       struct metex14_info *info_local;
+
+       info_local = (struct metex14_info *)info;
+
+       /* Don't print byte 13. That one contains the carriage return. */
+       sr_dbg("DMM packet: \"%.13s\"", buf);
+
+       memset(info_local, 0x00, sizeof(struct metex14_info));
+
+       if ((ret = parse_value(buf, info_local, floatval)) != SR_OK) {
+               sr_dbg("Error parsing value: %d.", ret);
+               return ret;
+       }
+
+       parse_flags((const char *)buf, info_local);
+       handle_flags(analog, floatval, info_local);
+
+       return SR_OK;
+}
diff --git a/src/dmm/rs9lcd.c b/src/dmm/rs9lcd.c
new file mode 100644 (file)
index 0000000..539c233
--- /dev/null
@@ -0,0 +1,437 @@
+/*
+ * 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/>.
+ */
+
+/*
+ * RadioShack 22-812 protocol parser.
+ *
+ * This protocol is currently encountered on the RadioShack 22-812 DMM.
+ * It is a 9-byte packet representing a 1:1 mapping of the LCD segments, hence
+ * the name rs9lcd.
+ *
+ * The chip is a bare die covered by a plastic blob. It is unclear if this chip
+ * and protocol is used on any other device.
+ */
+
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "rs9lcd"
+
+/* Byte 1 of the packet, and the modes it represents */
+#define IND1_HZ                (1 << 7)
+#define IND1_OHM       (1 << 6)
+#define IND1_KILO      (1 << 5)
+#define IND1_MEGA      (1 << 4)
+#define IND1_FARAD     (1 << 3)
+#define IND1_AMP       (1 << 2)
+#define IND1_VOLT      (1 << 1)
+#define IND1_MILI      (1 << 0)
+/* Byte 2 of the packet, and the modes it represents */
+#define IND2_MICRO     (1 << 7)
+#define IND2_NANO      (1 << 6)
+#define IND2_DBM       (1 << 5)
+#define IND2_SEC       (1 << 4)
+#define IND2_DUTY      (1 << 3)
+#define IND2_HFE       (1 << 2)
+#define IND2_REL       (1 << 1)
+#define IND2_MIN       (1 << 0)
+/* Byte 7 of the packet, and the modes it represents */
+#define INFO_BEEP      (1 << 7)
+#define INFO_DIODE     (1 << 6)
+#define INFO_BAT       (1 << 5)
+#define INFO_HOLD      (1 << 4)
+#define INFO_NEG       (1 << 3)
+#define INFO_AC                (1 << 2)
+#define INFO_RS232     (1 << 1)
+#define INFO_AUTO      (1 << 0)
+/* Instead of a decimal point, digit 4 carries the MAX flag */
+#define DIG4_MAX       (1 << 3)
+/* Mask to remove the decimal point from a digit */
+#define DP_MASK                (1 << 3)
+
+/* What the LCD values represent */
+#define LCD_0          0xd7
+#define LCD_1          0x50
+#define LCD_2          0xb5
+#define LCD_3          0xf1
+#define LCD_4          0x72
+#define LCD_5          0xe3
+#define LCD_6          0xe7
+#define LCD_7          0x51
+#define LCD_8          0xf7
+#define LCD_9          0xf3
+
+#define LCD_C          0x87
+#define LCD_E
+#define LCD_F
+#define LCD_h          0x66
+#define LCD_H          0x76
+#define LCD_I
+#define LCD_n
+#define LCD_P          0x37
+#define LCD_r
+
+enum {
+       MODE_DC_V       = 0,
+       MODE_AC_V       = 1,
+       MODE_DC_UA      = 2,
+       MODE_DC_MA      = 3,
+       MODE_DC_A       = 4,
+       MODE_AC_UA      = 5,
+       MODE_AC_MA      = 6,
+       MODE_AC_A       = 7,
+       MODE_OHM        = 8,
+       MODE_FARAD      = 9,
+       MODE_HZ         = 10,
+       MODE_VOLT_HZ    = 11,   /* Dial set to V, Hz selected by Hz button */
+       MODE_AMP_HZ     = 12,   /* Dial set to A, Hz selected by Hz button */
+       MODE_DUTY       = 13,
+       MODE_VOLT_DUTY  = 14,   /* Dial set to V, duty cycle selected */
+       MODE_AMP_DUTY   = 15,   /* Dial set to A, duty cycle selected */
+       MODE_WIDTH      = 16,
+       MODE_VOLT_WIDTH = 17,   /* Dial set to V, pulse width selected */
+       MODE_AMP_WIDTH  = 18,   /* Dial set to A, pulse width selected */
+       MODE_DIODE      = 19,
+       MODE_CONT       = 20,
+       MODE_HFE        = 21,
+       MODE_LOGIC      = 22,
+       MODE_DBM        = 23,
+       /* MODE_EF      = 24, */ /* Not encountered on any DMM */
+       MODE_TEMP       = 25,
+       MODE_INVALID    = 26,
+};
+
+enum {
+       READ_ALL,
+       READ_TEMP,
+};
+
+struct rs9lcd_packet {
+       uint8_t mode;
+       uint8_t indicatrix1;
+       uint8_t indicatrix2;
+       uint8_t digit4;
+       uint8_t digit3;
+       uint8_t digit2;
+       uint8_t digit1;
+       uint8_t info;
+       uint8_t checksum;
+};
+
+static gboolean checksum_valid(const struct rs9lcd_packet *rs_packet)
+{
+       uint8_t *raw;
+       uint8_t sum = 0;
+       int i;
+
+       raw = (void *)rs_packet;
+
+       for (i = 0; i < RS9LCD_PACKET_SIZE - 1; i++)
+               sum += raw[i];
+
+       /* This is just a funky constant added to the checksum. */
+       sum += 57;
+       sum -= rs_packet->checksum;
+       return (sum == 0);
+}
+
+static gboolean selection_good(const struct rs9lcd_packet *rs_packet)
+{
+       int count;
+
+       /* Does the packet have more than one multiplier? */
+       count = 0;
+       count += (rs_packet->indicatrix1 & IND1_KILO)  ? 1 : 0;
+       count += (rs_packet->indicatrix1 & IND1_MEGA)  ? 1 : 0;
+       count += (rs_packet->indicatrix1 & IND1_MILI)  ? 1 : 0;
+       count += (rs_packet->indicatrix2 & IND2_MICRO) ? 1 : 0;
+       count += (rs_packet->indicatrix2 & IND2_NANO)  ? 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 += (rs_packet->indicatrix1 & IND1_HZ)    ? 1 : 0;
+       count += (rs_packet->indicatrix1 & IND1_OHM)   ? 1 : 0;
+       count += (rs_packet->indicatrix1 & IND1_FARAD) ? 1 : 0;
+       count += (rs_packet->indicatrix1 & IND1_AMP)   ? 1 : 0;
+       count += (rs_packet->indicatrix1 & IND1_VOLT)  ? 1 : 0;
+       count += (rs_packet->indicatrix2 & IND2_DBM)   ? 1 : 0;
+       count += (rs_packet->indicatrix2 & IND2_SEC)   ? 1 : 0;
+       count += (rs_packet->indicatrix2 & IND2_DUTY)  ? 1 : 0;
+       count += (rs_packet->indicatrix2 & IND2_HFE)   ? 1 : 0;
+       if (count > 1) {
+               sr_dbg("More than one measurement type detected in packet.");
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+/*
+ * Since the 22-812 does not identify itself in any way, shape, or form,
+ * we really don't know for sure who is sending the data. We must use every
+ * possible check to filter out bad packets, especially since detection of the
+ * 22-812 depends on how well we can filter the packets.
+ */
+SR_PRIV gboolean sr_rs9lcd_packet_valid(const uint8_t *buf)
+{
+       const struct rs9lcd_packet *rs_packet = (void *)buf;
+
+       /*
+        * Check for valid mode first, before calculating the checksum. No
+        * point calculating the checksum, if we know we'll reject the packet.
+        */
+       if (!(rs_packet->mode < MODE_INVALID))
+               return FALSE;
+
+       if (!checksum_valid(rs_packet)) {
+               sr_spew("Packet with invalid checksum. Discarding.");
+               return FALSE;
+       }
+
+       if (!selection_good(rs_packet)) {
+               sr_spew("Packet with invalid selection bits. Discarding.");
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+static uint8_t decode_digit(uint8_t raw_digit)
+{
+       /* Take out the decimal point, so we can use a simple switch(). */
+       raw_digit &= ~DP_MASK;
+
+       switch (raw_digit) {
+       case 0x00:
+       case LCD_0:
+               return 0;
+       case LCD_1:
+               return 1;
+       case LCD_2:
+               return 2;
+       case LCD_3:
+               return 3;
+       case LCD_4:
+               return 4;
+       case LCD_5:
+               return 5;
+       case LCD_6:
+               return 6;
+       case LCD_7:
+               return 7;
+       case LCD_8:
+               return 8;
+       case LCD_9:
+               return 9;
+       default:
+               sr_dbg("Invalid digit byte: 0x%02x.", raw_digit);
+               return 0xff;
+       }
+}
+
+static double lcd_to_double(const struct rs9lcd_packet *rs_packet, int type)
+{
+       double rawval = 0, multiplier = 1;
+       uint8_t digit, raw_digit;
+       gboolean dp_reached = FALSE;
+       int i, end;
+
+       /* end = 1: Don't parse last digit. end = 0: Parse all digits. */
+       end = (type == READ_TEMP) ? 1 : 0;
+
+       /* We have 4 digits, and we start from the most significant. */
+       for (i = 3; i >= end; i--) {
+               raw_digit = *(&(rs_packet->digit4) + i);
+               digit = decode_digit(raw_digit);
+               if (digit == 0xff) {
+                       rawval = NAN;
+                       break;
+               }
+               /*
+                * Digit 1 does not have a decimal point. Instead, the decimal
+                * point is used to indicate MAX, so we must avoid testing it.
+                */
+               if ((i < 3) && (raw_digit & DP_MASK))
+                       dp_reached = TRUE;
+               if (dp_reached)
+                       multiplier /= 10;
+               rawval = rawval * 10 + digit;
+       }
+       rawval *= multiplier;
+       if (rs_packet->info & INFO_NEG)
+               rawval *= -1;
+
+       /* See if we need to multiply our raw value by anything. */
+       if (rs_packet->indicatrix1 & IND2_NANO)
+               rawval *= 1E-9;
+       else if (rs_packet->indicatrix2 & IND2_MICRO)
+               rawval *= 1E-6;
+       else if (rs_packet->indicatrix1 & IND1_MILI)
+               rawval *= 1E-3;
+       else if (rs_packet->indicatrix1 & IND1_KILO)
+               rawval *= 1E3;
+       else if (rs_packet->indicatrix1 & IND1_MEGA)
+               rawval *= 1E6;
+
+       return rawval;
+}
+
+static gboolean is_celsius(const struct rs9lcd_packet *rs_packet)
+{
+       return ((rs_packet->digit4 & ~DP_MASK) == LCD_C);
+}
+
+static gboolean is_shortcirc(const struct rs9lcd_packet *rs_packet)
+{
+       return ((rs_packet->digit2 & ~DP_MASK) == LCD_h);
+}
+
+static gboolean is_logic_high(const struct rs9lcd_packet *rs_packet)
+{
+       sr_spew("Digit 2: 0x%02x.", rs_packet->digit2 & ~DP_MASK);
+       return ((rs_packet->digit2 & ~DP_MASK) == LCD_H);
+}
+
+SR_PRIV int sr_rs9lcd_parse(const uint8_t *buf, float *floatval,
+                           struct sr_datafeed_analog *analog, void *info)
+{
+       const struct rs9lcd_packet *rs_packet = (void *)buf;
+       double rawval;
+
+       (void)info;
+
+       rawval = lcd_to_double(rs_packet, READ_ALL);
+
+       switch (rs_packet->mode) {
+       case MODE_DC_V:
+               analog->mq = SR_MQ_VOLTAGE;
+               analog->unit = SR_UNIT_VOLT;
+               analog->mqflags |= SR_MQFLAG_DC;
+               break;
+       case MODE_AC_V:
+               analog->mq = SR_MQ_VOLTAGE;
+               analog->unit = SR_UNIT_VOLT;
+               analog->mqflags |= SR_MQFLAG_AC;
+               break;
+       case MODE_DC_UA:        /* Fall through */
+       case MODE_DC_MA:        /* Fall through */
+       case MODE_DC_A:
+               analog->mq = SR_MQ_CURRENT;
+               analog->unit = SR_UNIT_AMPERE;
+               analog->mqflags |= SR_MQFLAG_DC;
+               break;
+       case MODE_AC_UA:        /* Fall through */
+       case MODE_AC_MA:        /* Fall through */
+       case MODE_AC_A:
+               analog->mq = SR_MQ_CURRENT;
+               analog->unit = SR_UNIT_AMPERE;
+               analog->mqflags |= SR_MQFLAG_AC;
+               break;
+       case MODE_OHM:
+               analog->mq = SR_MQ_RESISTANCE;
+               analog->unit = SR_UNIT_OHM;
+               break;
+       case MODE_FARAD:
+               analog->mq = SR_MQ_CAPACITANCE;
+               analog->unit = SR_UNIT_FARAD;
+               break;
+       case MODE_CONT:
+               analog->mq = SR_MQ_CONTINUITY;
+               analog->unit = SR_UNIT_BOOLEAN;
+               rawval = is_shortcirc(rs_packet);
+               break;
+       case MODE_DIODE:
+               analog->mq = SR_MQ_VOLTAGE;
+               analog->unit = SR_UNIT_VOLT;
+               analog->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
+               break;
+       case MODE_HZ:           /* Fall through */
+       case MODE_VOLT_HZ:      /* Fall through */
+       case MODE_AMP_HZ:
+               analog->mq = SR_MQ_FREQUENCY;
+               analog->unit = SR_UNIT_HERTZ;
+               break;
+       case MODE_LOGIC:
+               /*
+                * No matter whether or not we have an actual voltage reading,
+                * we are measuring voltage, so we set our MQ as VOLTAGE.
+                */
+               analog->mq = SR_MQ_VOLTAGE;
+               if (!isnan(rawval)) {
+                       /* We have an actual voltage. */
+                       analog->unit = SR_UNIT_VOLT;
+               } else {
+                       /* We have either HI or LOW. */
+                       analog->unit = SR_UNIT_BOOLEAN;
+                       rawval = is_logic_high(rs_packet);
+               }
+               break;
+       case MODE_HFE:
+               analog->mq = SR_MQ_GAIN;
+               analog->unit = SR_UNIT_UNITLESS;
+               break;
+       case MODE_DUTY:         /* Fall through */
+       case MODE_VOLT_DUTY:    /* Fall through */
+       case MODE_AMP_DUTY:
+               analog->mq = SR_MQ_DUTY_CYCLE;
+               analog->unit = SR_UNIT_PERCENTAGE;
+               break;
+       case MODE_WIDTH:        /* Fall through */
+       case MODE_VOLT_WIDTH:   /* Fall through */
+       case MODE_AMP_WIDTH:
+               analog->mq = SR_MQ_PULSE_WIDTH;
+               analog->unit = SR_UNIT_SECOND;
+               break;
+       case MODE_TEMP:
+               analog->mq = SR_MQ_TEMPERATURE;
+               /* We need to reparse. */
+               rawval = lcd_to_double(rs_packet, READ_TEMP);
+               analog->unit = is_celsius(rs_packet) ?
+                               SR_UNIT_CELSIUS : SR_UNIT_FAHRENHEIT;
+               break;
+       case MODE_DBM:
+               analog->mq = SR_MQ_POWER;
+               analog->unit = SR_UNIT_DECIBEL_MW;
+               analog->mqflags |= SR_MQFLAG_AC;
+               break;
+       default:
+               sr_dbg("Unknown mode: %d.", rs_packet->mode);
+               break;
+       }
+
+       if (rs_packet->info & INFO_HOLD)
+               analog->mqflags |= SR_MQFLAG_HOLD;
+       if (rs_packet->digit4 & DIG4_MAX)
+               analog->mqflags |= SR_MQFLAG_MAX;
+       if (rs_packet->indicatrix2 & IND2_MIN)
+               analog->mqflags |= SR_MQFLAG_MIN;
+       if (rs_packet->info & INFO_AUTO)
+               analog->mqflags |= SR_MQFLAG_AUTORANGE;
+
+       *floatval = rawval;
+       return SR_OK;
+}
diff --git a/src/drivers.c b/src/drivers.c
new file mode 100644 (file)
index 0000000..f93214d
--- /dev/null
@@ -0,0 +1,359 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Bert Vermeulen <bert@biot.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 "libsigrok.h"
+#include "libsigrok-internal.h"
+
+/** @cond PRIVATE */
+#ifdef HAVE_HW_AGILENT_DMM
+extern SR_PRIV struct sr_dev_driver agdmm_driver_info;
+#endif
+#ifdef HAVE_HW_APPA_55II
+extern SR_PRIV struct sr_dev_driver appa_55ii_driver_info;
+#endif
+#ifdef HAVE_HW_ASIX_SIGMA
+extern SR_PRIV struct sr_dev_driver asix_sigma_driver_info;
+#endif
+#ifdef HAVE_HW_ATTEN_PPS3XXX
+extern SR_PRIV struct sr_dev_driver atten_pps3203_driver_info;
+#endif
+#ifdef HAVE_HW_BEAGLELOGIC
+extern SR_PRIV struct sr_dev_driver beaglelogic_driver_info;
+#endif
+#ifdef HAVE_HW_BRYMEN_BM86X
+extern SR_PRIV struct sr_dev_driver brymen_bm86x_driver_info;
+#endif
+#ifdef HAVE_HW_BRYMEN_DMM
+extern SR_PRIV struct sr_dev_driver brymen_bm857_driver_info;
+#endif
+#ifdef HAVE_HW_CEM_DT_885X
+extern SR_PRIV struct sr_dev_driver cem_dt_885x_driver_info;
+#endif
+#ifdef HAVE_HW_CENTER_3XX
+extern SR_PRIV struct sr_dev_driver center_309_driver_info;
+extern SR_PRIV struct sr_dev_driver voltcraft_k204_driver_info;
+#endif
+#ifdef HAVE_HW_CHRONOVU_LA
+extern SR_PRIV struct sr_dev_driver chronovu_la_driver_info;
+#endif
+#ifdef HAVE_HW_COLEAD_SLM
+extern SR_PRIV struct sr_dev_driver colead_slm_driver_info;
+#endif
+#ifdef HAVE_HW_CONRAD_DIGI_35_CPU
+extern SR_PRIV struct sr_dev_driver conrad_digi_35_cpu_driver_info;
+#endif
+#ifdef HAVE_HW_DEMO
+extern SR_PRIV struct sr_dev_driver demo_driver_info;
+#endif
+#ifdef HAVE_HW_FLUKE_DMM
+extern SR_PRIV struct sr_dev_driver flukedmm_driver_info;
+#endif
+#ifdef HAVE_HW_FX2LAFW
+extern SR_PRIV struct sr_dev_driver fx2lafw_driver_info;
+#endif
+#ifdef HAVE_HW_GMC_MH_1X_2X
+extern SR_PRIV struct sr_dev_driver gmc_mh_1x_2x_rs232_driver_info;
+extern SR_PRIV struct sr_dev_driver gmc_mh_2x_bd232_driver_info;
+#endif
+#ifdef HAVE_HW_HAMEG_HMO
+extern SR_PRIV struct sr_dev_driver hameg_hmo_driver_info;
+#endif
+#ifdef HAVE_HW_HANTEK_DSO
+extern SR_PRIV struct sr_dev_driver hantek_dso_driver_info;
+#endif
+#ifdef HAVE_HW_IKALOGIC_SCANALOGIC2
+extern SR_PRIV struct sr_dev_driver ikalogic_scanalogic2_driver_info;
+#endif
+#ifdef HAVE_HW_IKALOGIC_SCANAPLUS
+extern SR_PRIV struct sr_dev_driver ikalogic_scanaplus_driver_info;
+#endif
+#ifdef HAVE_HW_KECHENG_KC_330B
+extern SR_PRIV struct sr_dev_driver kecheng_kc_330b_driver_info;
+#endif
+#ifdef HAVE_HW_LASCAR_EL_USB
+extern SR_PRIV struct sr_dev_driver lascar_el_usb_driver_info;
+#endif
+#ifdef HAVE_HW_LINK_MSO19
+extern SR_PRIV struct sr_dev_driver link_mso19_driver_info;
+#endif
+#ifdef HAVE_HW_MANSON_HCS_3XXX
+extern SR_PRIV struct sr_dev_driver manson_hcs_3xxx_driver_info;
+#endif
+#ifdef HAVE_HW_MIC_985XX
+extern SR_PRIV struct sr_dev_driver mic_98581_driver_info;
+extern SR_PRIV struct sr_dev_driver mic_98583_driver_info;
+#endif
+#ifdef HAVE_HW_MOTECH_LPS_30X
+extern SR_PRIV struct sr_dev_driver motech_lps_301_driver_info;
+#endif
+#ifdef HAVE_HW_NORMA_DMM
+extern SR_PRIV struct sr_dev_driver norma_dmm_driver_info;
+extern SR_PRIV struct sr_dev_driver siemens_b102x_driver_info;
+#endif
+#ifdef HAVE_HW_OPENBENCH_LOGIC_SNIFFER
+extern SR_PRIV struct sr_dev_driver ols_driver_info;
+#endif
+#ifdef HAVE_HW_RIGOL_DS
+extern SR_PRIV struct sr_dev_driver rigol_ds_driver_info;
+#endif
+#ifdef HAVE_HW_SALEAE_LOGIC16
+extern SR_PRIV struct sr_dev_driver saleae_logic16_driver_info;
+#endif
+#ifdef HAVE_HW_SERIAL_DMM
+extern SR_PRIV struct sr_dev_driver bbcgm_m2110_driver_info;
+extern SR_PRIV struct sr_dev_driver digitek_dt4000zc_driver_info;
+extern SR_PRIV struct sr_dev_driver tekpower_tp4000zc_driver_info;
+extern SR_PRIV struct sr_dev_driver metex_me31_driver_info;
+extern SR_PRIV struct sr_dev_driver peaktech_3410_driver_info;
+extern SR_PRIV struct sr_dev_driver mastech_mas345_driver_info;
+extern SR_PRIV struct sr_dev_driver va_va18b_driver_info;
+extern SR_PRIV struct sr_dev_driver va_va40b_driver_info;
+extern SR_PRIV struct sr_dev_driver metex_m3640d_driver_info;
+extern SR_PRIV struct sr_dev_driver metex_m4650cr_driver_info;
+extern SR_PRIV struct sr_dev_driver peaktech_4370_driver_info;
+extern SR_PRIV struct sr_dev_driver pce_pce_dm32_driver_info;
+extern SR_PRIV struct sr_dev_driver radioshack_22_168_driver_info;
+extern SR_PRIV struct sr_dev_driver radioshack_22_805_driver_info;
+extern SR_PRIV struct sr_dev_driver radioshack_22_812_driver_info;
+extern SR_PRIV struct sr_dev_driver tecpel_dmm_8061_ser_driver_info;
+extern SR_PRIV struct sr_dev_driver voltcraft_m3650cr_driver_info;
+extern SR_PRIV struct sr_dev_driver voltcraft_m3650d_driver_info;
+extern SR_PRIV struct sr_dev_driver voltcraft_m4650cr_driver_info;
+extern SR_PRIV struct sr_dev_driver voltcraft_me42_driver_info;
+extern SR_PRIV struct sr_dev_driver voltcraft_vc820_ser_driver_info;
+extern SR_PRIV struct sr_dev_driver voltcraft_vc830_ser_driver_info;
+extern SR_PRIV struct sr_dev_driver voltcraft_vc840_ser_driver_info;
+extern SR_PRIV struct sr_dev_driver uni_t_ut60a_ser_driver_info;
+extern SR_PRIV struct sr_dev_driver uni_t_ut60e_ser_driver_info;
+extern SR_PRIV struct sr_dev_driver uni_t_ut60g_ser_driver_info;
+extern SR_PRIV struct sr_dev_driver uni_t_ut61b_ser_driver_info;
+extern SR_PRIV struct sr_dev_driver uni_t_ut61c_ser_driver_info;
+extern SR_PRIV struct sr_dev_driver uni_t_ut61d_ser_driver_info;
+extern SR_PRIV struct sr_dev_driver uni_t_ut61e_ser_driver_info;
+extern SR_PRIV struct sr_dev_driver iso_tech_idm103n_driver_info;
+extern SR_PRIV struct sr_dev_driver tenma_72_7745_ser_driver_info;
+extern SR_PRIV struct sr_dev_driver tenma_72_7750_ser_driver_info;
+#endif
+#ifdef HAVE_HW_SYSCLK_LWLA
+extern SR_PRIV struct sr_dev_driver sysclk_lwla_driver_info;
+#endif
+#ifdef HAVE_HW_TELEINFO
+extern SR_PRIV struct sr_dev_driver teleinfo_driver_info;
+#endif
+#ifdef HAVE_HW_TESTO
+extern SR_PRIV struct sr_dev_driver testo_driver_info;
+#endif
+#ifdef HAVE_HW_TONDAJ_SL_814
+extern SR_PRIV struct sr_dev_driver tondaj_sl_814_driver_info;
+#endif
+#ifdef HAVE_HW_UNI_T_DMM
+extern SR_PRIV struct sr_dev_driver tecpel_dmm_8061_driver_info;
+extern SR_PRIV struct sr_dev_driver uni_t_ut60a_driver_info;
+extern SR_PRIV struct sr_dev_driver uni_t_ut60e_driver_info;
+extern SR_PRIV struct sr_dev_driver uni_t_ut60g_driver_info;
+extern SR_PRIV struct sr_dev_driver uni_t_ut61b_driver_info;
+extern SR_PRIV struct sr_dev_driver uni_t_ut61c_driver_info;
+extern SR_PRIV struct sr_dev_driver uni_t_ut61d_driver_info;
+extern SR_PRIV struct sr_dev_driver uni_t_ut61e_driver_info;
+extern SR_PRIV struct sr_dev_driver voltcraft_vc820_driver_info;
+extern SR_PRIV struct sr_dev_driver voltcraft_vc830_driver_info;
+extern SR_PRIV struct sr_dev_driver voltcraft_vc840_driver_info;
+extern SR_PRIV struct sr_dev_driver tenma_72_7745_driver_info;
+extern SR_PRIV struct sr_dev_driver tenma_72_7750_driver_info;
+#endif
+#ifdef HAVE_HW_UNI_T_UT32X
+extern SR_PRIV struct sr_dev_driver uni_t_ut32x_driver_info;
+#endif
+#ifdef HAVE_HW_VICTOR_DMM
+extern SR_PRIV struct sr_dev_driver victor_dmm_driver_info;
+#endif
+#ifdef HAVE_HW_ZEROPLUS_LOGIC_CUBE
+extern SR_PRIV struct sr_dev_driver zeroplus_logic_cube_driver_info;
+#endif
+
+SR_PRIV struct sr_dev_driver *drivers_list[] = {
+#ifdef HAVE_HW_AGILENT_DMM
+       &agdmm_driver_info,
+#endif
+#ifdef HAVE_HW_APPA_55II
+       &appa_55ii_driver_info,
+#endif
+#ifdef HAVE_HW_ASIX_SIGMA
+       &asix_sigma_driver_info,
+#endif
+#ifdef HAVE_HW_ATTEN_PPS3XXX
+       &atten_pps3203_driver_info,
+#endif
+#ifdef HAVE_HW_BEAGLELOGIC
+       &beaglelogic_driver_info,
+#endif
+#ifdef HAVE_HW_BRYMEN_BM86X
+       &brymen_bm86x_driver_info,
+#endif
+#ifdef HAVE_HW_BRYMEN_DMM
+       &brymen_bm857_driver_info,
+#endif
+#ifdef HAVE_HW_CEM_DT_885X
+       &cem_dt_885x_driver_info,
+#endif
+#ifdef HAVE_HW_CENTER_3XX
+       &center_309_driver_info,
+       &voltcraft_k204_driver_info,
+#endif
+#ifdef HAVE_HW_CHRONOVU_LA
+       &chronovu_la_driver_info,
+#endif
+#ifdef HAVE_HW_COLEAD_SLM
+       &colead_slm_driver_info,
+#endif
+#ifdef HAVE_HW_CONRAD_DIGI_35_CPU
+       &conrad_digi_35_cpu_driver_info,
+#endif
+#ifdef HAVE_HW_DEMO
+       &demo_driver_info,
+#endif
+#ifdef HAVE_HW_FLUKE_DMM
+       &flukedmm_driver_info,
+#endif
+#ifdef HAVE_HW_FX2LAFW
+       &fx2lafw_driver_info,
+#endif
+#ifdef HAVE_HW_GMC_MH_1X_2X
+       &gmc_mh_1x_2x_rs232_driver_info,
+       &gmc_mh_2x_bd232_driver_info,
+#endif
+#ifdef HAVE_HW_HAMEG_HMO
+       &hameg_hmo_driver_info,
+#endif
+#ifdef HAVE_HW_HANTEK_DSO
+       &hantek_dso_driver_info,
+#endif
+#ifdef HAVE_HW_IKALOGIC_SCANALOGIC2
+       &ikalogic_scanalogic2_driver_info,
+#endif
+#ifdef HAVE_HW_IKALOGIC_SCANAPLUS
+       &ikalogic_scanaplus_driver_info,
+#endif
+#ifdef HAVE_HW_KECHENG_KC_330B
+       &kecheng_kc_330b_driver_info,
+#endif
+#ifdef HAVE_HW_LASCAR_EL_USB
+       &lascar_el_usb_driver_info,
+#endif
+#ifdef HAVE_HW_LINK_MSO19
+       &link_mso19_driver_info,
+#endif
+#ifdef HAVE_HW_MANSON_HCS_3XXX
+       &manson_hcs_3xxx_driver_info,
+#endif
+#ifdef HAVE_HW_MIC_985XX
+       &mic_98581_driver_info,
+       &mic_98583_driver_info,
+#endif
+#ifdef HAVE_HW_MOTECH_LPS_30X
+       &motech_lps_301_driver_info,
+#endif
+#ifdef HAVE_HW_NORMA_DMM
+       &norma_dmm_driver_info,
+       &siemens_b102x_driver_info,
+#endif
+#ifdef HAVE_HW_OPENBENCH_LOGIC_SNIFFER
+       &ols_driver_info,
+#endif
+#ifdef HAVE_HW_RIGOL_DS
+       &rigol_ds_driver_info,
+#endif
+#ifdef HAVE_HW_SALEAE_LOGIC16
+       &saleae_logic16_driver_info,
+#endif
+#ifdef HAVE_HW_SERIAL_DMM
+       &bbcgm_m2110_driver_info,
+       &digitek_dt4000zc_driver_info,
+       &tekpower_tp4000zc_driver_info,
+       &metex_me31_driver_info,
+       &peaktech_3410_driver_info,
+       &mastech_mas345_driver_info,
+       &va_va18b_driver_info,
+       &va_va40b_driver_info,
+       &metex_m3640d_driver_info,
+       &metex_m4650cr_driver_info,
+       &peaktech_4370_driver_info,
+       &pce_pce_dm32_driver_info,
+       &radioshack_22_168_driver_info,
+       &radioshack_22_805_driver_info,
+       &radioshack_22_812_driver_info,
+       &tecpel_dmm_8061_ser_driver_info,
+       &voltcraft_m3650cr_driver_info,
+       &voltcraft_m3650d_driver_info,
+       &voltcraft_m4650cr_driver_info,
+       &voltcraft_me42_driver_info,
+       &voltcraft_vc820_ser_driver_info,
+       &voltcraft_vc830_ser_driver_info,
+       &voltcraft_vc840_ser_driver_info,
+       &uni_t_ut60a_ser_driver_info,
+       &uni_t_ut60e_ser_driver_info,
+       &uni_t_ut60g_ser_driver_info,
+       &uni_t_ut61b_ser_driver_info,
+       &uni_t_ut61c_ser_driver_info,
+       &uni_t_ut61d_ser_driver_info,
+       &uni_t_ut61e_ser_driver_info,
+       &iso_tech_idm103n_driver_info,
+       &tenma_72_7745_ser_driver_info,
+       &tenma_72_7750_ser_driver_info,
+#endif
+#ifdef HAVE_HW_SYSCLK_LWLA
+       &sysclk_lwla_driver_info,
+#endif
+#ifdef HAVE_HW_TELEINFO
+       &teleinfo_driver_info,
+#endif
+#ifdef HAVE_HW_TESTO
+       &testo_driver_info,
+#endif
+#ifdef HAVE_HW_TONDAJ_SL_814
+       &tondaj_sl_814_driver_info,
+#endif
+#ifdef HAVE_HW_UNI_T_DMM
+       &tecpel_dmm_8061_driver_info,
+       &uni_t_ut60a_driver_info,
+       &uni_t_ut60e_driver_info,
+       &uni_t_ut60g_driver_info,
+       &uni_t_ut61b_driver_info,
+       &uni_t_ut61c_driver_info,
+       &uni_t_ut61d_driver_info,
+       &uni_t_ut61e_driver_info,
+       &voltcraft_vc820_driver_info,
+       &voltcraft_vc830_driver_info,
+       &voltcraft_vc840_driver_info,
+       &tenma_72_7745_driver_info,
+       &tenma_72_7750_driver_info,
+#endif
+#ifdef HAVE_HW_UNI_T_UT32X
+       &uni_t_ut32x_driver_info,
+#endif
+#ifdef HAVE_HW_VICTOR_DMM
+       &victor_dmm_driver_info,
+#endif
+#ifdef HAVE_HW_ZEROPLUS_LOGIC_CUBE
+       &zeroplus_logic_cube_driver_info,
+#endif
+       NULL,
+};
+/** @endcond */
+
diff --git a/src/error.c b/src/error.c
new file mode 100644 (file)
index 0000000..f877975
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "libsigrok.h"
+
+/**
+ * @file
+ *
+ * Error handling in libsigrok.
+ */
+
+/**
+ * @defgroup grp_error Error handling
+ *
+ * Error handling in libsigrok.
+ *
+ * libsigrok functions usually return @ref SR_OK upon success, or a negative
+ * error code on failure.
+ *
+ * @{
+ */
+
+/**
+ * Return a human-readable error string for the given libsigrok error code.
+ *
+ * @param error_code A libsigrok error code number, such as SR_ERR_MALLOC.
+ *
+ * @return A const string containing a short, human-readable (English)
+ *         description of the error, such as "memory allocation error".
+ *         The string must NOT be free'd by the caller!
+ *
+ * @see sr_strerror_name
+ *
+ * @since 0.2.0
+ */
+SR_API const char *sr_strerror(int error_code)
+{
+       /*
+        * Note: All defined SR_* error macros from libsigrok.h must have
+        * an entry in this function, as well as in sr_strerror_name().
+        */
+
+       switch (error_code) {
+       case SR_OK:
+               return "no error";
+       case SR_ERR:
+               return "generic/unspecified error";
+       case SR_ERR_MALLOC:
+               return "memory allocation error";
+       case SR_ERR_ARG:
+               return "invalid argument";
+       case SR_ERR_BUG:
+               return "internal error";
+       case SR_ERR_SAMPLERATE:
+               return "invalid samplerate";
+       case SR_ERR_NA:
+               return "not applicable";
+       case SR_ERR_DEV_CLOSED:
+               return "device closed but should be open";
+       case SR_ERR_TIMEOUT:
+               return "timeout occurred";
+       case SR_ERR_CHANNEL_GROUP:
+               return "no channel group specified";
+       default:
+               return "unknown error";
+       }
+}
+
+/**
+ * Return the "name" string of the given libsigrok error code.
+ *
+ * For example, the "name" of the SR_ERR_MALLOC error code is "SR_ERR_MALLOC",
+ * the name of the SR_OK code is "SR_OK", and so on.
+ *
+ * This function can be used for various purposes where the "name" string of
+ * a libsigrok error code is useful.
+ *
+ * @param error_code A libsigrok error code number, such as SR_ERR_MALLOC.
+ *
+ * @return A const string containing the "name" of the error code as string.
+ *         The string must NOT be free'd by the caller!
+ *
+ * @see sr_strerror
+ *
+ * @since 0.2.0
+ */
+SR_API const char *sr_strerror_name(int error_code)
+{
+       /*
+        * Note: All defined SR_* error macros from libsigrok.h must have
+        * an entry in this function, as well as in sr_strerror().
+        */
+
+       switch (error_code) {
+       case SR_OK:
+               return "SR_OK";
+       case SR_ERR:
+               return "SR_ERR";
+       case SR_ERR_MALLOC:
+               return "SR_ERR_MALLOC";
+       case SR_ERR_ARG:
+               return "SR_ERR_ARG";
+       case SR_ERR_BUG:
+               return "SR_ERR_BUG";
+       case SR_ERR_SAMPLERATE:
+               return "SR_ERR_SAMPLERATE";
+       case SR_ERR_NA:
+               return "SR_ERR_NA";
+       case SR_ERR_DEV_CLOSED:
+               return "SR_ERR_DEV_CLOSED";
+       case SR_ERR_TIMEOUT:
+               return "SR_ERR_TIMEOUT";
+       case SR_ERR_CHANNEL_GROUP:
+               return "SR_ERR_CHANNEL_GROUP";
+       default:
+               return "unknown error code";
+       }
+}
+
+/** @} */
diff --git a/src/ezusb.c b/src/ezusb.c
new file mode 100644 (file)
index 0000000..044b464
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.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/>.
+ */
+
+/*
+ * Helper functions for the Cypress EZ-USB / FX2 series chips.
+ */
+
+#include <libusb.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "ezusb"
+
+SR_PRIV int ezusb_reset(struct libusb_device_handle *hdl, int set_clear)
+{
+       int ret;
+       unsigned char buf[1];
+
+       sr_info("setting CPU reset mode %s...",
+               set_clear ? "on" : "off");
+       buf[0] = set_clear ? 1 : 0;
+       ret = libusb_control_transfer(hdl, LIBUSB_REQUEST_TYPE_VENDOR, 0xa0,
+                                     0xe600, 0x0000, buf, 1, 100);
+       if (ret < 0)
+               sr_err("Unable to send control request: %s.",
+                               libusb_error_name(ret));
+
+       return ret;
+}
+
+SR_PRIV int ezusb_install_firmware(libusb_device_handle *hdl,
+                                  const char *filename)
+{
+       FILE *fw;
+       int offset, chunksize, ret, result;
+       unsigned char buf[4096];
+
+       sr_info("Uploading firmware at %s", filename);
+       if ((fw = g_fopen(filename, "rb")) == NULL) {
+               sr_err("Unable to open firmware file %s for reading: %s",
+                      filename, strerror(errno));
+               return SR_ERR;
+       }
+
+       result = SR_OK;
+       offset = 0;
+       while (1) {
+               chunksize = fread(buf, 1, 4096, fw);
+               if (chunksize == 0)
+                       break;
+               ret = libusb_control_transfer(hdl, LIBUSB_REQUEST_TYPE_VENDOR |
+                                             LIBUSB_ENDPOINT_OUT, 0xa0, offset,
+                                             0x0000, buf, chunksize, 100);
+               if (ret < 0) {
+                       sr_err("Unable to send firmware to device: %s.",
+                                       libusb_error_name(ret));
+                       result = SR_ERR;
+                       break;
+               }
+               sr_info("Uploaded %d bytes", chunksize);
+               offset += chunksize;
+       }
+       fclose(fw);
+       sr_info("Firmware upload done");
+
+       return result;
+}
+
+SR_PRIV int ezusb_upload_firmware(libusb_device *dev, int configuration,
+                                 const char *filename)
+{
+       struct libusb_device_handle *hdl;
+       int ret;
+
+       sr_info("uploading firmware to device on %d.%d",
+               libusb_get_bus_number(dev), libusb_get_device_address(dev));
+
+       if ((ret = libusb_open(dev, &hdl)) < 0) {
+               sr_err("failed to open device: %s.", libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+/*
+ * The libusbx darwin backend is broken: it can report a kernel driver being
+ * active, but detaching it always returns an error.
+ */
+#if !defined(__APPLE__)
+       if (libusb_kernel_driver_active(hdl, 0) == 1) {
+               if ((ret = libusb_detach_kernel_driver(hdl, 0)) < 0) {
+                       sr_err("failed to detach kernel driver: %s",
+                                       libusb_error_name(ret));
+                       return SR_ERR;
+               }
+       }
+#endif
+
+       if ((ret = libusb_set_configuration(hdl, configuration)) < 0) {
+               sr_err("Unable to set configuration: %s",
+                               libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+       if ((ezusb_reset(hdl, 1)) < 0)
+               return SR_ERR;
+
+       if (ezusb_install_firmware(hdl, filename) < 0)
+               return SR_ERR;
+
+       if ((ezusb_reset(hdl, 0)) < 0)
+               return SR_ERR;
+
+       libusb_close(hdl);
+
+       return SR_OK;
+}
diff --git a/src/hardware/agilent-dmm/agilent-dmm.h b/src/hardware/agilent-dmm/agilent-dmm.h
new file mode 100644 (file)
index 0000000..2277111
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert@biot.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_AGILENT_DMM_AGILENT_DMM_H
+#define LIBSIGROK_HARDWARE_AGILENT_DMM_AGILENT_DMM_H
+
+#define LOG_PREFIX "agilent-dmm"
+
+#define AGDMM_BUFSIZE  256
+
+/* Supported models */
+enum {
+       AGILENT_U1231A = 1,
+       AGILENT_U1232A,
+       AGILENT_U1233A,
+       AGILENT_U1251A,
+       AGILENT_U1252A,
+       AGILENT_U1253A,
+};
+
+/* Supported device profiles */
+struct agdmm_profile {
+       int model;
+       const char *modelname;
+       const struct agdmm_job *jobs;
+       const struct agdmm_recv *recvs;
+};
+
+/* Private, per-device-instance driver context. */
+struct dev_context {
+       const struct agdmm_profile *profile;
+       uint64_t limit_samples;
+       uint64_t limit_msec;
+
+       /* Opaque pointer passed in by the frontend. */
+       void *cb_data;
+
+       /* Runtime. */
+       uint64_t num_samples;
+       int64_t jobqueue[8];
+       unsigned char buf[AGDMM_BUFSIZE];
+       int buflen;
+       int cur_mq;
+       int cur_unit;
+       int cur_mqflags;
+       int cur_divider;
+       int cur_acdc;
+       int mode_tempaux;
+       int mode_continuity;
+};
+
+struct agdmm_job {
+       int interval;
+       int (*send) (const struct sr_dev_inst *sdi);
+};
+
+struct agdmm_recv {
+       const char *recv_regex;
+       int (*recv) (const struct sr_dev_inst *sdi, GMatchInfo *match);
+};
+
+SR_PRIV int agdmm_receive_data(int fd, int revents, void *cb_data);
+
+#endif
diff --git a/src/hardware/agilent-dmm/api.c b/src/hardware/agilent-dmm/api.c
new file mode 100644 (file)
index 0000000..cb7baa6
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert@biot.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 <glib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "agilent-dmm.h"
+
+static const int32_t hwopts[] = {
+       SR_CONF_CONN,
+       SR_CONF_SERIALCOMM,
+};
+
+static const int32_t hwcaps[] = {
+       SR_CONF_MULTIMETER,
+       SR_CONF_LIMIT_SAMPLES,
+       SR_CONF_LIMIT_MSEC,
+       SR_CONF_CONTINUOUS,
+};
+
+extern const struct agdmm_job agdmm_jobs_u123x[];
+extern const struct agdmm_recv agdmm_recvs_u123x[];
+extern const struct agdmm_job agdmm_jobs_u125x[];
+extern const struct agdmm_recv agdmm_recvs_u125x[];
+
+/* This works on all the Agilent U12xxA series, although the
+ * U127xA can apparently also run at 19200/8n1. */
+#define SERIALCOMM "9600/8n1"
+
+static const struct agdmm_profile supported_agdmm[] = {
+       { AGILENT_U1231A, "U1231A", agdmm_jobs_u123x, agdmm_recvs_u123x },
+       { AGILENT_U1232A, "U1232A", agdmm_jobs_u123x, agdmm_recvs_u123x },
+       { AGILENT_U1233A, "U1233A", agdmm_jobs_u123x, agdmm_recvs_u123x },
+       { AGILENT_U1251A, "U1251A", agdmm_jobs_u125x, agdmm_recvs_u125x },
+       { AGILENT_U1252A, "U1252A", agdmm_jobs_u125x, agdmm_recvs_u125x },
+       { AGILENT_U1253A, "U1253A", agdmm_jobs_u125x, agdmm_recvs_u125x },
+       { 0, NULL, NULL, NULL }
+};
+
+SR_PRIV struct sr_dev_driver agdmm_driver_info;
+static struct sr_dev_driver *di = &agdmm_driver_info;
+
+static int init(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+       struct sr_dev_inst *sdi;
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       struct sr_config *src;
+       struct sr_channel *ch;
+       struct sr_serial_dev_inst *serial;
+       GSList *l, *devices;
+       int len, i;
+       const char *conn, *serialcomm;
+       char *buf, **tokens;
+
+       drvc = di->priv;
+       drvc->instances = NULL;
+
+       devices = NULL;
+       conn = serialcomm = NULL;
+       for (l = options; l; l = l->next) {
+               src = l->data;
+               switch (src->key) {
+               case SR_CONF_CONN:
+                       conn = g_variant_get_string(src->data, NULL);
+                       break;
+               case SR_CONF_SERIALCOMM:
+                       serialcomm = g_variant_get_string(src->data, NULL);
+                       break;
+               }
+       }
+       if (!conn)
+               return NULL;
+       if (!serialcomm)
+               serialcomm = SERIALCOMM;
+
+       if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
+               return NULL;
+
+       if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
+               return NULL;
+
+       serial_flush(serial);
+       if (serial_write(serial, "*IDN?\r\n", 7) == -1) {
+               sr_err("Unable to send identification string: %s.",
+                      strerror(errno));
+               return NULL;
+       }
+
+       len = 128;
+       if (!(buf = g_try_malloc(len))) {
+               sr_err("Serial buffer malloc failed.");
+               return NULL;
+       }
+       serial_readline(serial, &buf, &len, 150);
+       if (!len)
+               return NULL;
+
+       tokens = g_strsplit(buf, ",", 4);
+       if (!strcmp("Agilent Technologies", tokens[0])
+                       && tokens[1] && tokens[2] && tokens[3]) {
+               for (i = 0; supported_agdmm[i].model; i++) {
+                       if (strcmp(supported_agdmm[i].modelname, tokens[1]))
+                               continue;
+                       if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "Agilent",
+                                       tokens[1], tokens[3])))
+                               return NULL;
+                       if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+                               sr_err("Device context malloc failed.");
+                               return NULL;
+                       }
+                       devc->profile = &supported_agdmm[i];
+                       devc->cur_mq = -1;
+                       sdi->inst_type = SR_INST_SERIAL;
+                       sdi->conn = serial;
+                       sdi->priv = devc;
+                       sdi->driver = di;
+                       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1")))
+                               return NULL;
+                       sdi->channels = g_slist_append(sdi->channels, ch);
+                       drvc->instances = g_slist_append(drvc->instances, sdi);
+                       devices = g_slist_append(devices, sdi);
+                       break;
+               }
+       }
+       g_strfreev(tokens);
+       g_free(buf);
+
+       serial_close(serial);
+       if (!devices)
+               sr_serial_dev_inst_free(serial);
+
+       return devices;
+}
+
+static GSList *dev_list(void)
+{
+       return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int cleanup(void)
+{
+       return std_dev_clear(di, NULL);
+}
+
+static int config_set(int id, 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;
+
+       if (!(devc = sdi->priv)) {
+               sr_err("sdi->priv was NULL.");
+               return SR_ERR_BUG;
+       }
+
+       switch (id) {
+       case SR_CONF_LIMIT_MSEC:
+               /* TODO: not yet implemented */
+               if (g_variant_get_uint64(data) == 0) {
+                       sr_err("LIMIT_MSEC can't be 0.");
+                       return SR_ERR;
+               }
+               devc->limit_msec = g_variant_get_uint64(data);
+               sr_dbg("Setting time limit to %" PRIu64 "ms.",
+                      devc->limit_msec);
+               break;
+       case SR_CONF_LIMIT_SAMPLES:
+               devc->limit_samples = g_variant_get_uint64(data);
+               sr_dbg("Setting sample limit to %" PRIu64 ".",
+                      devc->limit_samples);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_list(int 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_INT32,
+                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+               break;
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       if (!(devc = sdi->priv)) {
+               sr_err("sdi->priv was NULL.");
+               return SR_ERR_BUG;
+       }
+
+       devc->cb_data = cb_data;
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(cb_data, LOG_PREFIX);
+
+       /* Poll every 100ms, or whenever some data comes in. */
+       serial = sdi->conn;
+       serial_source_add(sdi->session, serial, G_IO_IN, 100,
+                       agdmm_receive_data, (void *)sdi);
+
+       return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       return std_serial_dev_acquisition_stop(sdi, cb_data, std_serial_dev_close,
+                       sdi->conn, LOG_PREFIX);
+}
+
+SR_PRIV struct sr_dev_driver agdmm_driver_info = {
+       .name = "agilent-dmm",
+       .longname = "Agilent U12xx series DMMs",
+       .api_version = 1,
+       .init = init,
+       .cleanup = cleanup,
+       .scan = scan,
+       .dev_list = 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 = dev_acquisition_stop,
+       .priv = NULL,
+};
diff --git a/src/hardware/agilent-dmm/sched.c b/src/hardware/agilent-dmm/sched.c
new file mode 100644 (file)
index 0000000..bd9cb38
--- /dev/null
@@ -0,0 +1,474 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert@biot.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 <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "agilent-dmm.h"
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <math.h>
+
+static void dispatch(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       const struct agdmm_job *jobs;
+       int64_t now;
+       int i;
+
+       devc = sdi->priv;
+       jobs = devc->profile->jobs;
+       now = g_get_monotonic_time() / 1000;
+       for (i = 0; (&jobs[i])->interval; i++) {
+               if (now - devc->jobqueue[i] > (&jobs[i])->interval) {
+                       sr_spew("Running job %d.", i);
+                       (&jobs[i])->send(sdi);
+                       devc->jobqueue[i] = now;
+               }
+       }
+}
+
+static void receive_line(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       const struct agdmm_recv *recvs, *recv;
+       GRegex *reg;
+       GMatchInfo *match;
+       int i;
+
+       devc = sdi->priv;
+
+       /* Strip CRLF */
+       while (devc->buflen) {
+               if (*(devc->buf + devc->buflen - 1) == '\r'
+                               || *(devc->buf + devc->buflen - 1) == '\n')
+                       *(devc->buf + --devc->buflen) = '\0';
+               else
+                       break;
+       }
+       sr_spew("Received '%s'.", devc->buf);
+
+       recv = NULL;
+       recvs = devc->profile->recvs;
+       for (i = 0; (&recvs[i])->recv_regex; i++) {
+               reg = g_regex_new((&recvs[i])->recv_regex, 0, 0, NULL);
+               if (g_regex_match(reg, (char *)devc->buf, 0, &match)) {
+                       recv = &recvs[i];
+                       break;
+               }
+               g_match_info_unref(match);
+               g_regex_unref(reg);
+       }
+       if (recv) {
+               recv->recv(sdi, match);
+               g_match_info_unref(match);
+               g_regex_unref(reg);
+       } else
+               sr_dbg("Unknown line '%s'.", devc->buf);
+
+       /* Done with this. */
+       devc->buflen = 0;
+}
+
+SR_PRIV int agdmm_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 len;
+
+       (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. */
+               while(AGDMM_BUFSIZE - devc->buflen - 1 > 0) {
+                       len = serial_read(serial, devc->buf + devc->buflen, 1);
+                       if (len < 1)
+                               break;
+                       devc->buflen += len;
+                       *(devc->buf + devc->buflen) = '\0';
+                       if (*(devc->buf + devc->buflen - 1) == '\n') {
+                               /* End of line */
+                               receive_line(sdi);
+                               break;
+                       }
+               }
+       }
+
+       dispatch(sdi);
+
+       if (devc->limit_samples && devc->num_samples >= devc->limit_samples)
+               sdi->driver->dev_acquisition_stop(sdi, cb_data);
+
+       return TRUE;
+}
+
+static int agdmm_send(const struct sr_dev_inst *sdi, const char *cmd)
+{
+       struct sr_serial_dev_inst *serial;
+       char buf[32];
+
+       serial = sdi->conn;
+
+       sr_spew("Sending '%s'.", cmd);
+       strncpy(buf, cmd, 28);
+       if (!strncmp(buf, "*IDN?", 5))
+               strncat(buf, "\r\n", 32);
+       else
+               strncat(buf, "\n\r\n", 32);
+       if (serial_write(serial, buf, strlen(buf)) == -1) {
+               sr_err("Failed to send: %s.", strerror(errno));
+               return SR_ERR;
+       }
+
+       return SR_OK;
+}
+
+static int send_stat(const struct sr_dev_inst *sdi)
+{
+       return agdmm_send(sdi, "STAT?");
+}
+
+static int recv_stat_u123x(const struct sr_dev_inst *sdi, GMatchInfo *match)
+{
+       struct dev_context *devc;
+       char *s;
+
+       devc = sdi->priv;
+       s = g_match_info_fetch(match, 1);
+       sr_spew("STAT response '%s'.", s);
+
+       /* Max, Min or Avg mode -- no way to tell which, so we'll
+        * set both flags to denote it's not a normal measurement. */
+       if (s[0] == '1')
+               devc->cur_mqflags |= SR_MQFLAG_MAX | SR_MQFLAG_MIN;
+       else
+               devc->cur_mqflags &= ~(SR_MQFLAG_MAX | SR_MQFLAG_MIN);
+
+       if (s[1] == '1')
+               devc->cur_mqflags |= SR_MQFLAG_RELATIVE;
+       else
+               devc->cur_mqflags &= ~SR_MQFLAG_RELATIVE;
+
+       /* Triggered or auto hold modes. */
+       if (s[2] == '1' || s[3] == '1')
+               devc->cur_mqflags |= SR_MQFLAG_HOLD;
+       else
+               devc->cur_mqflags &= ~SR_MQFLAG_HOLD;
+
+       /* Temp/aux mode. */
+       if (s[7] == '1')
+               devc->mode_tempaux = TRUE;
+       else
+               devc->mode_tempaux = FALSE;
+
+       /* Continuity mode. */
+       if (s[16] == '1')
+               devc->mode_continuity = TRUE;
+       else
+               devc->mode_continuity = FALSE;
+
+       g_free(s);
+
+       return SR_OK;
+}
+
+static int recv_stat_u125x(const struct sr_dev_inst *sdi, GMatchInfo *match)
+{
+       struct dev_context *devc;
+       char *s;
+
+       devc = sdi->priv;
+       s = g_match_info_fetch(match, 1);
+       sr_spew("STAT response '%s'.", s);
+
+       /* Peak hold mode. */
+       if (s[4] == '1')
+               devc->cur_mqflags |= SR_MQFLAG_MAX;
+       else
+               devc->cur_mqflags &= ~SR_MQFLAG_MAX;
+
+       /* Triggered hold mode. */
+       if (s[7] == '1')
+               devc->cur_mqflags |= SR_MQFLAG_HOLD;
+       else
+               devc->cur_mqflags &= ~SR_MQFLAG_HOLD;
+
+       g_free(s);
+
+       return SR_OK;
+}
+
+static int send_fetc(const struct sr_dev_inst *sdi)
+{
+       return agdmm_send(sdi, "FETC?");
+}
+
+static int recv_fetc(const struct sr_dev_inst *sdi, GMatchInfo *match)
+{
+       struct dev_context *devc;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_analog analog;
+       float fvalue;
+       char *mstr;
+
+       sr_spew("FETC reply '%s'.", g_match_info_get_string(match));
+       devc = sdi->priv;
+
+       if (devc->cur_mq == -1)
+               /* Haven't seen configuration yet, so can't know what
+                * the fetched float means. Not really an error, we'll
+                * get metadata soon enough. */
+               return SR_OK;
+
+       if (!strcmp(g_match_info_get_string(match), "+9.90000000E+37")) {
+               /* An invalid measurement shows up on the display as "O.L", but
+                * comes through like this. Since comparing 38-digit floats
+                * is rather problematic, we'll cut through this here. */
+               fvalue = NAN;
+       } else {
+               mstr = g_match_info_fetch(match, 1);
+               if (sr_atof_ascii(mstr, &fvalue) != SR_OK || fvalue == 0.0) {
+                       g_free(mstr);
+                       sr_err("Invalid float.");
+                       return SR_ERR;
+               }
+               g_free(mstr);
+               if (devc->cur_divider > 0)
+                       fvalue /= devc->cur_divider;
+       }
+
+       memset(&analog, 0, sizeof(struct sr_datafeed_analog));
+       analog.mq = devc->cur_mq;
+       analog.unit = devc->cur_unit;
+       analog.mqflags = devc->cur_mqflags;
+       analog.channels = sdi->channels;
+       analog.num_samples = 1;
+       analog.data = &fvalue;
+       packet.type = SR_DF_ANALOG;
+       packet.payload = &analog;
+       sr_session_send(devc->cb_data, &packet);
+
+       devc->num_samples++;
+
+       return SR_OK;
+}
+
+static int send_conf(const struct sr_dev_inst *sdi)
+{
+       return agdmm_send(sdi, "CONF?");
+}
+
+static int recv_conf_u123x(const struct sr_dev_inst *sdi, GMatchInfo *match)
+{
+       struct dev_context *devc;
+       char *mstr;
+
+       sr_spew("CONF? response '%s'.", g_match_info_get_string(match));
+       devc = sdi->priv;
+       mstr = g_match_info_fetch(match, 1);
+       if (!strcmp(mstr, "V")) {
+               devc->cur_mq = SR_MQ_VOLTAGE;
+               devc->cur_unit = SR_UNIT_VOLT;
+               devc->cur_mqflags = 0;
+               devc->cur_divider = 0;
+       } else if(!strcmp(mstr, "MV")) {
+               if (devc->mode_tempaux) {
+                       devc->cur_mq = SR_MQ_TEMPERATURE;
+                       /* No way to detect whether Fahrenheit or Celcius
+                        * is used, so we'll just default to Celcius. */
+                       devc->cur_unit = SR_UNIT_CELSIUS;
+               devc->cur_mqflags = 0;
+               devc->cur_divider = 0;
+               } else {
+                       devc->cur_mq = SR_MQ_VOLTAGE;
+                       devc->cur_unit = SR_UNIT_VOLT;
+                       devc->cur_mqflags = 0;
+                       devc->cur_divider = 1000;
+               }
+       } else if(!strcmp(mstr, "A")) {
+               devc->cur_mq = SR_MQ_CURRENT;
+               devc->cur_unit = SR_UNIT_AMPERE;
+               devc->cur_mqflags = 0;
+               devc->cur_divider = 0;
+       } else if(!strcmp(mstr, "UA")) {
+               devc->cur_mq = SR_MQ_CURRENT;
+               devc->cur_unit = SR_UNIT_AMPERE;
+               devc->cur_mqflags = 0;
+               devc->cur_divider = 1000000;
+       } else if(!strcmp(mstr, "FREQ")) {
+               devc->cur_mq = SR_MQ_FREQUENCY;
+               devc->cur_unit = SR_UNIT_HERTZ;
+               devc->cur_mqflags = 0;
+               devc->cur_divider = 0;
+       } else if(!strcmp(mstr, "RES")) {
+               if (devc->mode_continuity) {
+                       devc->cur_mq = SR_MQ_CONTINUITY;
+                       devc->cur_unit = SR_UNIT_BOOLEAN;
+               } else {
+                       devc->cur_mq = SR_MQ_RESISTANCE;
+                       devc->cur_unit = SR_UNIT_OHM;
+               }
+               devc->cur_mqflags = 0;
+               devc->cur_divider = 0;
+       } else if(!strcmp(mstr, "CAP")) {
+               devc->cur_mq = SR_MQ_CAPACITANCE;
+               devc->cur_unit = SR_UNIT_FARAD;
+               devc->cur_mqflags = 0;
+               devc->cur_divider = 0;
+       } else
+               sr_dbg("Unknown first argument.");
+       g_free(mstr);
+
+       if (g_match_info_get_match_count(match) == 4) {
+               mstr = g_match_info_fetch(match, 3);
+               /* Third value, if present, is always AC or DC. */
+               if (!strcmp(mstr, "AC"))
+                       devc->cur_mqflags |= SR_MQFLAG_AC;
+               else if (!strcmp(mstr, "DC"))
+                       devc->cur_mqflags |= SR_MQFLAG_DC;
+               else
+                       sr_dbg("Unknown third argument.");
+               g_free(mstr);
+       } else
+               devc->cur_mqflags &= ~(SR_MQFLAG_AC | SR_MQFLAG_DC);
+
+       return SR_OK;
+}
+
+static int recv_conf_u125x(const struct sr_dev_inst *sdi, GMatchInfo *match)
+{
+       struct dev_context *devc;
+       char *mstr;
+
+       sr_spew("CONF? response '%s'.", g_match_info_get_string(match));
+       devc = sdi->priv;
+       mstr = g_match_info_fetch(match, 1);
+       if (!strncmp(mstr, "VOLT", 4)) {
+               devc->cur_mq = SR_MQ_VOLTAGE;
+               devc->cur_unit = SR_UNIT_VOLT;
+               devc->cur_mqflags = 0;
+               devc->cur_divider = 0;
+               if (mstr[4] == ':') {
+                       if (!strcmp(mstr + 4, "AC"))
+                               devc->cur_mqflags |= SR_MQFLAG_AC;
+                       else if (!strcmp(mstr + 4, "DC"))
+                               devc->cur_mqflags |= SR_MQFLAG_DC;
+                       else
+                               /* "ACDC" appears as well, no idea what it means. */
+                               devc->cur_mqflags &= ~(SR_MQFLAG_AC | SR_MQFLAG_DC);
+               } else
+                       devc->cur_mqflags &= ~(SR_MQFLAG_AC | SR_MQFLAG_DC);
+       } else if(!strcmp(mstr, "CURR")) {
+               devc->cur_mq = SR_MQ_CURRENT;
+               devc->cur_unit = SR_UNIT_AMPERE;
+               devc->cur_mqflags = 0;
+               devc->cur_divider = 0;
+       } else if(!strcmp(mstr, "RES")) {
+               if (devc->mode_continuity) {
+                       devc->cur_mq = SR_MQ_CONTINUITY;
+                       devc->cur_unit = SR_UNIT_BOOLEAN;
+               } else {
+                       devc->cur_mq = SR_MQ_RESISTANCE;
+                       devc->cur_unit = SR_UNIT_OHM;
+               }
+               devc->cur_mqflags = 0;
+               devc->cur_divider = 0;
+       } else
+               sr_dbg("Unknown first argument.");
+       g_free(mstr);
+
+       return SR_OK;
+}
+
+/* At least the 123x and 125x appear to have this. */
+static int recv_conf(const struct sr_dev_inst *sdi, GMatchInfo *match)
+{
+       struct dev_context *devc;
+       char *mstr;
+
+       sr_spew("CONF? response '%s'.", g_match_info_get_string(match));
+       devc = sdi->priv;
+       mstr = g_match_info_fetch(match, 1);
+       if(!strcmp(mstr, "DIOD")) {
+               devc->cur_mq = SR_MQ_VOLTAGE;
+               devc->cur_unit = SR_UNIT_VOLT;
+               devc->cur_mqflags = SR_MQFLAG_DIODE;
+               devc->cur_divider = 0;
+       } else
+               sr_dbg("Unknown single argument.");
+       g_free(mstr);
+
+       return SR_OK;
+}
+
+/* This comes in whenever the rotary switch is changed to a new position.
+ * We could use it to determine the major measurement mode, but we already
+ * have the output of CONF? for that, which is more detailed. However
+ * we do need to catch this here, or it'll show up in some other output. */
+static int recv_switch(const struct sr_dev_inst *sdi, GMatchInfo *match)
+{
+       (void)sdi;
+
+       sr_spew("Switch '%s'.", g_match_info_get_string(match));
+
+       return SR_OK;
+}
+
+SR_PRIV const struct agdmm_job agdmm_jobs_u123x[] = {
+       { 143, send_stat },
+       { 1000, send_conf },
+       { 143, send_fetc },
+       { 0, NULL }
+};
+
+SR_PRIV const struct agdmm_recv agdmm_recvs_u123x[] = {
+       { "^\"(\\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|UA|FREQ),(\\d),(AC|DC)\"$", recv_conf_u123x },
+       { "^\"(RES|CAP),(\\d)\"$", recv_conf_u123x},
+       { "^\"(DIOD)\"$", recv_conf },
+       { NULL, NULL }
+};
+
+SR_PRIV const struct agdmm_job agdmm_jobs_u125x[] = {
+       { 143, send_stat },
+       { 1000, send_conf },
+       { 143, send_fetc },
+       { 0, NULL }
+};
+
+SR_PRIV const struct agdmm_recv agdmm_recvs_u125x[] = {
+       { "^\"(\\d\\d.{18}\\d)\"$", recv_stat_u125x },
+       { "^\\*([0-9])$", recv_switch },
+       { "^([-+][0-9]\\.[0-9]{8}E[-+][0-9]{2})$", recv_fetc },
+       { "^(VOLT|CURR|RES|CAP) ([-+][0-9\\.E\\-+]+),([-+][0-9\\.E\\-+]+)$", recv_conf_u125x },
+       { "^(VOLT:[ACD]+) ([-+][0-9\\.E\\-+]+),([-+][0-9\\.E\\-+]+)$", recv_conf_u125x },
+       { "^\"(DIOD)\"$", recv_conf },
+       { NULL, NULL }
+};
diff --git a/src/hardware/appa-55ii/api.c b/src/hardware/appa-55ii/api.c
new file mode 100644 (file)
index 0000000..de71e33
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 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 <string.h>
+#include "protocol.h"
+
+static const int32_t hwopts[] = {
+       SR_CONF_CONN,
+       SR_CONF_SERIALCOMM,
+};
+
+static const int32_t hwcaps[] = {
+       SR_CONF_THERMOMETER,
+       SR_CONF_LIMIT_SAMPLES,
+       SR_CONF_LIMIT_MSEC,
+       SR_CONF_CONTINUOUS,
+       SR_CONF_DATA_SOURCE,
+};
+
+static const char *data_sources[] = {
+       "Live",
+       "Memory",
+};
+
+SR_PRIV struct sr_dev_driver appa_55ii_driver_info;
+static struct sr_dev_driver *di = &appa_55ii_driver_info;
+
+static int init(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+       struct sr_dev_inst *sdi;
+       struct sr_channel *ch;
+       struct sr_config *src;
+       GSList *devices, *l;
+       const char *conn, *serialcomm;
+       uint8_t buf[50];
+       size_t len;
+
+       len = sizeof(buf);
+       devices = NULL;
+       conn = serialcomm = NULL;
+       for (l = options; l; l = l->next) {
+               src = l->data;
+               switch (src->key) {
+               case SR_CONF_CONN:
+                       conn = g_variant_get_string(src->data, NULL);
+                       break;
+               case SR_CONF_SERIALCOMM:
+                       serialcomm = g_variant_get_string(src->data, NULL);
+                       break;
+               }
+       }
+       if (!conn)
+               return NULL;
+       if (!serialcomm)
+               serialcomm = "9600/8n1";
+
+       if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
+               return NULL;
+       if (serial_open(serial, SERIAL_RDONLY | SERIAL_NONBLOCK) != SR_OK)
+               return NULL;
+
+       sr_info("Probing serial port %s.", conn);
+
+       drvc = di->priv;
+       drvc->instances = NULL;
+       serial_flush(serial);
+
+       /* Let's get a bit of data and see if we can find a packet. */
+       if (serial_stream_detect(serial, buf, &len, 25,
+                       appa_55ii_packet_valid, 500, 9600) != SR_OK)
+               goto scan_cleanup;
+
+       sr_info("Found device on port %s.", conn);
+
+       if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "APPA", "55II", NULL)))
+               goto scan_cleanup;
+
+       if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+               sr_err("Device context malloc failed.");
+               goto scan_cleanup;
+       }
+
+       devc->data_source = DEFAULT_DATA_SOURCE;
+
+       sdi->inst_type = SR_INST_SERIAL;
+       sdi->conn = serial;
+       sdi->priv = devc;
+       sdi->driver = di;
+
+       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "T1")))
+               goto scan_cleanup;
+       sdi->channels = g_slist_append(sdi->channels, ch);
+       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "T2")))
+               goto scan_cleanup;
+       sdi->channels = g_slist_append(sdi->channels, ch);
+
+       drvc->instances = g_slist_append(drvc->instances, sdi);
+       devices = g_slist_append(devices, sdi);
+
+scan_cleanup:
+       serial_close(serial);
+
+       return devices;
+}
+
+static GSList *dev_list(void)
+{
+       return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int cleanup(void)
+{
+       return std_dev_clear(di, NULL);
+}
+
+static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc = sdi->priv;
+
+       (void)cg;
+
+       switch (key) {
+       case SR_CONF_LIMIT_SAMPLES:
+               *data = g_variant_new_uint64(devc->limit_samples);
+               break;
+       case SR_CONF_LIMIT_MSEC:
+               *data = g_variant_new_uint64(devc->limit_msec);
+               break;
+       case SR_CONF_DATA_SOURCE:
+               *data = g_variant_new_string(data_sources[devc->data_source]);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       const char *tmp_str;
+       unsigned int i;
+
+       (void)cg;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       if (!(devc = sdi->priv)) {
+               sr_err("sdi->priv was NULL.");
+               return SR_ERR_BUG;
+       }
+
+       switch (key) {
+       case SR_CONF_LIMIT_SAMPLES:
+               devc->limit_samples = g_variant_get_uint64(data);
+               sr_dbg("Setting sample limit to %" PRIu64 ".", devc->limit_samples);
+               break;
+       case SR_CONF_LIMIT_MSEC:
+               devc->limit_msec = g_variant_get_uint64(data);
+               sr_dbg("Setting time limit to %" PRIu64 "ms.", devc->limit_msec);
+               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:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_list(int 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_INT32,
+                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+               break;
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+               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;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi,
+               void *cb_data)
+{
+       struct sr_serial_dev_inst *serial;
+       struct dev_context *devc;
+
+       serial = sdi->conn;
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       if (!(devc = sdi->priv)) {
+               sr_err("sdi->priv was NULL.");
+               return SR_ERR_BUG;
+       }
+
+       devc->session_cb_data = cb_data;
+
+       /*
+        * Reset the number of samples to take. If we've already collected our
+        * quota, but we start a new session, and don't reset this, we'll just
+        * quit without acquiring any new samples.
+        */
+       devc->num_samples = 0;
+       devc->start_time = g_get_monotonic_time();
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(cb_data, LOG_PREFIX);
+
+       /* Poll every 50ms, or whenever some data comes in. */
+       serial_source_add(sdi->session, serial, G_IO_IN, 50,
+                       appa_55ii_receive_data, (void *)sdi);
+
+       return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       return std_serial_dev_acquisition_stop(sdi, cb_data,
+                       std_serial_dev_close, sdi->conn, LOG_PREFIX);
+}
+
+SR_PRIV struct sr_dev_driver appa_55ii_driver_info = {
+       .name = "appa-55ii",
+       .longname = "APPA 55II",
+       .api_version = 1,
+       .init = init,
+       .cleanup = cleanup,
+       .scan = scan,
+       .dev_list = dev_list,
+       .dev_clear = NULL,
+       .config_get = config_get,
+       .config_set = config_set,
+       .config_list = config_list,
+       .dev_open = std_serial_dev_open,
+       .dev_close = std_serial_dev_close,
+       .dev_acquisition_start = dev_acquisition_start,
+       .dev_acquisition_stop = dev_acquisition_stop,
+       .priv = NULL,
+};
diff --git a/src/hardware/appa-55ii/protocol.c b/src/hardware/appa-55ii/protocol.c
new file mode 100644 (file)
index 0000000..708262b
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 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 <string.h>
+#include <math.h>
+#include "protocol.h"
+
+typedef enum {
+    LIVE_DATA    = 0x00,
+    LOG_METADATA = 0x11,
+    LOG_DATA     = 0x14,
+    LOG_START    = 0x18,
+    LOG_END      = 0x19,
+} packet_type;
+
+static gboolean appa_55ii_checksum(const uint8_t *buf)
+{
+       int i, size, checksum;
+
+       size = buf[3] + 4;
+       checksum = 0;
+       for (i = 0; i < size; i++)
+               checksum += buf[i];
+
+       return buf[size] == (checksum & 0xFF);
+}
+
+SR_PRIV gboolean appa_55ii_packet_valid(const uint8_t *buf)
+{
+       if (buf[0] == 0x55 && buf[1] == 0x55 && buf[3] <= 32
+                       && appa_55ii_checksum(buf))
+               return TRUE;
+
+       return FALSE;
+}
+
+static uint64_t appa_55ii_flags(const uint8_t *buf)
+{
+       uint8_t disp_mode;
+       uint64_t flags;
+
+       disp_mode = buf[4 + 13];
+       flags = 0;
+       if ((disp_mode & 0xF0) == 0x20)
+               flags |= SR_MQFLAG_HOLD;
+       if ((disp_mode & 0x0C) == 0x04)
+               flags |= SR_MQFLAG_MAX;
+       if ((disp_mode & 0x0C) == 0x08)
+               flags |= SR_MQFLAG_MIN;
+       if ((disp_mode & 0x0C) == 0x0C)
+               flags |= SR_MQFLAG_AVG;
+
+       return flags;
+}
+
+static float appa_55ii_temp(const uint8_t *buf, int ch)
+{
+       const uint8_t *ptr;
+       int16_t temp;
+       uint8_t flags;
+
+       ptr = buf + 4 + 14 + 3 * ch;
+       temp = RL16(ptr);
+       flags = ptr[2];
+
+       if (flags & 0x60)
+               return INFINITY;
+       else if (flags & 1)
+               return (float)temp / 10;
+       else
+               return (float)temp;
+}
+
+static void appa_55ii_live_data(struct sr_dev_inst *sdi, const uint8_t *buf)
+{
+       struct dev_context *devc;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_analog analog;
+       struct sr_channel *ch;
+       float values[APPA_55II_NUM_CHANNELS], *val_ptr;
+       int i;
+
+       devc = sdi->priv;
+
+       if (devc->data_source != DATA_SOURCE_LIVE)
+               return;
+
+       val_ptr = values;
+       memset(&analog, 0, sizeof(analog));
+       analog.num_samples = 1;
+       analog.mq = SR_MQ_TEMPERATURE;
+       analog.unit = SR_UNIT_CELSIUS;
+       analog.mqflags = appa_55ii_flags(buf);
+       analog.data = values;
+
+       for (i = 0; i < APPA_55II_NUM_CHANNELS; i++) {
+               ch = g_slist_nth_data(sdi->channels, i);
+               if (!ch->enabled)
+                       continue;
+               analog.channels = g_slist_append(analog.channels, ch);
+               *val_ptr++ = appa_55ii_temp(buf, i);
+       }
+
+       packet.type = SR_DF_ANALOG;
+       packet.payload = &analog;
+       sr_session_send(devc->session_cb_data, &packet);
+       g_slist_free(analog.channels);
+
+       devc->num_samples++;
+}
+
+static void appa_55ii_log_metadata(struct sr_dev_inst *sdi, const uint8_t *buf)
+{
+       struct dev_context *devc;
+
+       devc = sdi->priv;
+       devc->num_log_records = (buf[5] << 8) + buf[4];
+}
+
+static void appa_55ii_log_data_parse(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_analog analog;
+       struct sr_channel *ch;
+       float values[APPA_55II_NUM_CHANNELS], *val_ptr;
+       const uint8_t *buf;
+       int16_t temp;
+       int offset, i;
+
+       devc = sdi->priv;
+       offset = 0;
+
+       while (devc->log_buf_len >= 20 && devc->num_log_records > 0) {
+               buf = devc->log_buf + offset;
+               val_ptr = values;
+
+               /* FIXME: Timestamp should be sent in the packet. */
+               sr_dbg("Timestamp: %02d:%02d:%02d", buf[2], buf[3], buf[4]);
+
+               memset(&analog, 0, sizeof(analog));
+               analog.num_samples = 1;
+               analog.mq = SR_MQ_TEMPERATURE;
+               analog.unit = SR_UNIT_CELSIUS;
+               analog.data = values;
+
+               for (i = 0; i < APPA_55II_NUM_CHANNELS; i++) {
+                       temp = RL16(buf + 12 + 2 * i);
+                       ch = g_slist_nth_data(sdi->channels, i);
+                       if (!ch->enabled)
+                               continue;
+                       analog.channels = g_slist_append(analog.channels, ch);
+                       *val_ptr++ = temp == 0x7FFF ? INFINITY : (float)temp / 10;
+               }
+
+               packet.type = SR_DF_ANALOG;
+               packet.payload = &analog;
+               sr_session_send(devc->session_cb_data, &packet);
+               g_slist_free(analog.channels);
+
+               devc->num_samples++;
+               devc->log_buf_len -= 20;
+               offset += 20;
+               devc->num_log_records--;
+       }
+
+       memmove(devc->log_buf, devc->log_buf + offset, devc->log_buf_len);
+}
+
+static void appa_55ii_log_data(struct sr_dev_inst *sdi, const uint8_t *buf)
+{
+       struct dev_context *devc;
+       const uint8_t *ptr;
+       unsigned int size;
+       int s;
+
+       devc = sdi->priv;
+       if (devc->data_source != DATA_SOURCE_MEMORY)
+               return;
+
+       ptr = buf + 4;
+       size = buf[3];
+       while (size > 0) {
+               s = MIN(size, sizeof(devc->log_buf) - devc->log_buf_len);
+               memcpy(devc->log_buf + devc->log_buf_len, ptr, s);
+               devc->log_buf_len += s;
+               size -= s;
+               ptr += s;
+
+               appa_55ii_log_data_parse(sdi);
+       }
+}
+
+static void appa_55ii_log_end(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+
+       devc = sdi->priv;
+       if (devc->data_source != DATA_SOURCE_MEMORY)
+               return;
+
+       sdi->driver->dev_acquisition_stop(sdi, devc->session_cb_data);
+}
+
+static const uint8_t *appa_55ii_parse_data(struct sr_dev_inst *sdi,
+               const uint8_t *buf, int len)
+{
+       if (len < 5)
+               /* Need more data. */
+               return NULL;
+
+       if (buf[0] != 0x55 || buf[1] != 0x55)
+               /* Try to re-synchronize on a packet start. */
+               return buf + 1;
+
+       if (len < 5 + buf[3])
+               /* Need more data. */
+               return NULL;
+
+       if (!appa_55ii_checksum(buf))
+               /* Skip broken packet. */
+               return buf + 4 + buf[3] + 1;
+
+       switch ((packet_type)buf[2]) {
+       case LIVE_DATA:
+               appa_55ii_live_data(sdi, buf);
+               break;
+       case LOG_METADATA:
+               appa_55ii_log_metadata(sdi, buf);
+               break;
+       case LOG_DATA:
+               appa_55ii_log_data(sdi, buf);
+               break;
+       case LOG_START:
+               break;
+       case LOG_END:
+               appa_55ii_log_end(sdi);
+               break;
+       default:
+               sr_warn("Invalid packet type: 0x%02x.", buf[2]);
+               break;
+       }
+
+       return buf + 4 + buf[3] + 1;
+}
+
+SR_PRIV int appa_55ii_receive_data(int fd, int revents, void *cb_data)
+{
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+       int64_t time;
+       const uint8_t *ptr, *next_ptr, *end_ptr;
+       int len;
+
+       (void)fd;
+
+       if (!(sdi = cb_data) || !(devc = sdi->priv) || revents != G_IO_IN)
+               return TRUE;
+       serial = sdi->conn;
+
+       /* Try to get as much data as the buffer can hold. */
+       len = sizeof(devc->buf) - devc->buf_len;
+       len = serial_read(serial, devc->buf + devc->buf_len, len);
+       if (len < 1) {
+               sr_err("Serial port read error: %d.", len);
+               return FALSE;
+       }
+       devc->buf_len += len;
+
+       /* Now look for packets in that data. */
+       ptr = devc->buf;
+       end_ptr = ptr + devc->buf_len;
+       while ((next_ptr = appa_55ii_parse_data(sdi, ptr, end_ptr - ptr)))
+               ptr = next_ptr;
+
+       /* If we have any data left, move it to the beginning of our buffer. */
+       memmove(devc->buf, ptr, end_ptr - ptr);
+       devc->buf_len -= ptr - devc->buf;
+
+       /* If buffer is full and no valid packet was found, wipe buffer. */
+       if (devc->buf_len >= sizeof(devc->buf)) {
+               devc->buf_len = 0;
+               return FALSE;
+       }
+
+       if (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
+               sr_info("Requested number of samples reached.");
+               sdi->driver->dev_acquisition_stop(sdi, devc->session_cb_data);
+               return TRUE;
+       }
+
+       if (devc->limit_msec) {
+               time = (g_get_monotonic_time() - devc->start_time) / 1000;
+               if (time > (int64_t)devc->limit_msec) {
+                       sr_info("Requested time limit reached.");
+                       sdi->driver->dev_acquisition_stop(sdi,
+                                       devc->session_cb_data);
+                       return TRUE;
+               }
+       }
+
+       return TRUE;
+}
diff --git a/src/hardware/appa-55ii/protocol.h b/src/hardware/appa-55ii/protocol.h
new file mode 100644 (file)
index 0000000..fa3c247
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Aurelien Jacobs <aurel@gnuage.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_APPA_55II_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_APPA_55II_PROTOCOL_H
+
+#include <stdint.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "appa-55ii"
+
+#define APPA_55II_NUM_CHANNELS  2
+#define APPA_55II_BUF_SIZE    (4 + 32 + 1)
+#define DEFAULT_DATA_SOURCE   DATA_SOURCE_LIVE
+
+enum {
+       DATA_SOURCE_LIVE,
+       DATA_SOURCE_MEMORY,
+};
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+       /* Acquisition settings */
+       uint64_t limit_samples;   /**< The sampling limit (in number of samples). */
+       uint64_t limit_msec;      /**< The time limit (in milliseconds). */
+       gboolean data_source;     /**< Whether to read live samples or memory */
+       void *session_cb_data;    /**< Opaque pointer passed in by the frontend. */
+
+       /* Operational state */
+       uint64_t num_samples;     /**< The number of already received samples. */
+       int64_t start_time;       /**< The time at which sampling started. */
+
+       /* Temporary state across callbacks */
+       uint8_t buf[APPA_55II_BUF_SIZE];
+       unsigned int buf_len;
+       uint8_t log_buf[64];
+       unsigned int log_buf_len;
+       unsigned int num_log_records;
+};
+
+SR_PRIV gboolean appa_55ii_packet_valid(const uint8_t *buf);
+SR_PRIV int appa_55ii_receive_data(int fd, int revents, void *cb_data);
+
+#endif
diff --git a/src/hardware/asix-sigma/asix-sigma.c b/src/hardware/asix-sigma/asix-sigma.c
new file mode 100644 (file)
index 0000000..bfd6948
--- /dev/null
@@ -0,0 +1,1553 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010-2012 HÃ¥vard Espeland <gus@ping.uio.no>,
+ * Copyright (C) 2010 Martin StensgÃ¥rd <mastensg@ping.uio.no>
+ * Copyright (C) 2010 Carl Henrik Lunde <chlunde@ping.uio.no>
+ *
+ * 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/>.
+ */
+
+/*
+ * ASIX SIGMA/SIGMA2 logic analyzer driver
+ */
+
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <ftdi.h>
+#include <string.h>
+#include <unistd.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "asix-sigma.h"
+
+#define USB_VENDOR                     0xa600
+#define USB_PRODUCT                    0xa000
+#define USB_DESCRIPTION                        "ASIX SIGMA"
+#define USB_VENDOR_NAME                        "ASIX"
+#define USB_MODEL_NAME                 "SIGMA"
+
+SR_PRIV struct sr_dev_driver asix_sigma_driver_info;
+static struct sr_dev_driver *di = &asix_sigma_driver_info;
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data);
+
+/*
+ * The ASIX Sigma supports arbitrary integer frequency divider in
+ * the 50MHz mode. The divider is in range 1...256 , allowing for
+ * very precise sampling rate selection. This driver supports only
+ * a subset of the sampling rates.
+ */
+static const uint64_t samplerates[] = {
+       SR_KHZ(200),    /* div=250 */
+       SR_KHZ(250),    /* div=200 */
+       SR_KHZ(500),    /* div=100 */
+       SR_MHZ(1),      /* div=50  */
+       SR_MHZ(5),      /* div=10  */
+       SR_MHZ(10),     /* div=5   */
+       SR_MHZ(25),     /* div=2   */
+       SR_MHZ(50),     /* div=1   */
+       SR_MHZ(100),    /* Special FW needed */
+       SR_MHZ(200),    /* Special FW needed */
+};
+
+/*
+ * Channel numbers seem to go from 1-16, according to this image:
+ * http://tools.asix.net/img/sigma_sigmacab_pins_720.jpg
+ * (the cable has two additional GND pins, and a TI and TO pin)
+ */
+static const char *channel_names[] = {
+       "1", "2", "3", "4", "5", "6", "7", "8",
+       "9", "10", "11", "12", "13", "14", "15", "16",
+};
+
+static const int32_t hwcaps[] = {
+       SR_CONF_LOGIC_ANALYZER,
+       SR_CONF_SAMPLERATE,
+       SR_CONF_TRIGGER_MATCH,
+       SR_CONF_CAPTURE_RATIO,
+       SR_CONF_LIMIT_MSEC,
+};
+
+static const int32_t trigger_matches[] = {
+       SR_TRIGGER_ZERO,
+       SR_TRIGGER_ONE,
+       SR_TRIGGER_RISING,
+       SR_TRIGGER_FALLING,
+};
+
+static const char *sigma_firmware_files[] = {
+       /* 50 MHz, supports 8 bit fractions */
+       FIRMWARE_DIR "/asix-sigma-50.fw",
+       /* 100 MHz */
+       FIRMWARE_DIR "/asix-sigma-100.fw",
+       /* 200 MHz */
+       FIRMWARE_DIR "/asix-sigma-200.fw",
+       /* Synchronous clock from pin */
+       FIRMWARE_DIR "/asix-sigma-50sync.fw",
+       /* Frequency counter */
+       FIRMWARE_DIR "/asix-sigma-phasor.fw",
+};
+
+static int sigma_read(void *buf, size_t size, struct dev_context *devc)
+{
+       int ret;
+
+       ret = ftdi_read_data(&devc->ftdic, (unsigned char *)buf, size);
+       if (ret < 0) {
+               sr_err("ftdi_read_data failed: %s",
+                      ftdi_get_error_string(&devc->ftdic));
+       }
+
+       return ret;
+}
+
+static int sigma_write(void *buf, size_t size, struct dev_context *devc)
+{
+       int ret;
+
+       ret = ftdi_write_data(&devc->ftdic, (unsigned char *)buf, size);
+       if (ret < 0) {
+               sr_err("ftdi_write_data failed: %s",
+                      ftdi_get_error_string(&devc->ftdic));
+       } else if ((size_t) ret != size) {
+               sr_err("ftdi_write_data did not complete write.");
+       }
+
+       return ret;
+}
+
+static int sigma_write_register(uint8_t reg, uint8_t *data, size_t len,
+                               struct dev_context *devc)
+{
+       size_t i;
+       uint8_t buf[len + 2];
+       int idx = 0;
+
+       buf[idx++] = REG_ADDR_LOW | (reg & 0xf);
+       buf[idx++] = REG_ADDR_HIGH | (reg >> 4);
+
+       for (i = 0; i < len; ++i) {
+               buf[idx++] = REG_DATA_LOW | (data[i] & 0xf);
+               buf[idx++] = REG_DATA_HIGH_WRITE | (data[i] >> 4);
+       }
+
+       return sigma_write(buf, idx, devc);
+}
+
+static int sigma_set_register(uint8_t reg, uint8_t value, struct dev_context *devc)
+{
+       return sigma_write_register(reg, &value, 1, devc);
+}
+
+static int sigma_read_register(uint8_t reg, uint8_t *data, size_t len,
+                              struct dev_context *devc)
+{
+       uint8_t buf[3];
+
+       buf[0] = REG_ADDR_LOW | (reg & 0xf);
+       buf[1] = REG_ADDR_HIGH | (reg >> 4);
+       buf[2] = REG_READ_ADDR;
+
+       sigma_write(buf, sizeof(buf), devc);
+
+       return sigma_read(data, len, devc);
+}
+
+static uint8_t sigma_get_register(uint8_t reg, struct dev_context *devc)
+{
+       uint8_t value;
+
+       if (1 != sigma_read_register(reg, &value, 1, devc)) {
+               sr_err("sigma_get_register: 1 byte expected");
+               return 0;
+       }
+
+       return value;
+}
+
+static int sigma_read_pos(uint32_t *stoppos, uint32_t *triggerpos,
+                         struct dev_context *devc)
+{
+       uint8_t buf[] = {
+               REG_ADDR_LOW | READ_TRIGGER_POS_LOW,
+
+               REG_READ_ADDR | NEXT_REG,
+               REG_READ_ADDR | NEXT_REG,
+               REG_READ_ADDR | NEXT_REG,
+               REG_READ_ADDR | NEXT_REG,
+               REG_READ_ADDR | NEXT_REG,
+               REG_READ_ADDR | NEXT_REG,
+       };
+       uint8_t result[6];
+
+       sigma_write(buf, sizeof(buf), devc);
+
+       sigma_read(result, sizeof(result), devc);
+
+       *triggerpos = result[0] | (result[1] << 8) | (result[2] << 16);
+       *stoppos = result[3] | (result[4] << 8) | (result[5] << 16);
+
+       /* Not really sure why this must be done, but according to spec. */
+       if ((--*stoppos & 0x1ff) == 0x1ff)
+               stoppos -= 64;
+
+       if ((*--triggerpos & 0x1ff) == 0x1ff)
+               triggerpos -= 64;
+
+       return 1;
+}
+
+static int sigma_read_dram(uint16_t startchunk, size_t numchunks,
+                          uint8_t *data, struct dev_context *devc)
+{
+       size_t i;
+       uint8_t buf[4096];
+       int idx = 0;
+
+       /* Send the startchunk. Index start with 1. */
+       buf[0] = startchunk >> 8;
+       buf[1] = startchunk & 0xff;
+       sigma_write_register(WRITE_MEMROW, buf, 2, devc);
+
+       /* Read the DRAM. */
+       buf[idx++] = REG_DRAM_BLOCK;
+       buf[idx++] = REG_DRAM_WAIT_ACK;
+
+       for (i = 0; i < numchunks; ++i) {
+               /* Alternate bit to copy from DRAM to cache. */
+               if (i != (numchunks - 1))
+                       buf[idx++] = REG_DRAM_BLOCK | (((i + 1) % 2) << 4);
+
+               buf[idx++] = REG_DRAM_BLOCK_DATA | ((i % 2) << 4);
+
+               if (i != (numchunks - 1))
+                       buf[idx++] = REG_DRAM_WAIT_ACK;
+       }
+
+       sigma_write(buf, idx, devc);
+
+       return sigma_read(data, numchunks * CHUNK_SIZE, devc);
+}
+
+/* Upload trigger look-up tables to Sigma. */
+static int sigma_write_trigger_lut(struct triggerlut *lut, struct dev_context *devc)
+{
+       int i;
+       uint8_t tmp[2];
+       uint16_t bit;
+
+       /* Transpose the table and send to Sigma. */
+       for (i = 0; i < 16; ++i) {
+               bit = 1 << i;
+
+               tmp[0] = tmp[1] = 0;
+
+               if (lut->m2d[0] & bit)
+                       tmp[0] |= 0x01;
+               if (lut->m2d[1] & bit)
+                       tmp[0] |= 0x02;
+               if (lut->m2d[2] & bit)
+                       tmp[0] |= 0x04;
+               if (lut->m2d[3] & bit)
+                       tmp[0] |= 0x08;
+
+               if (lut->m3 & bit)
+                       tmp[0] |= 0x10;
+               if (lut->m3s & bit)
+                       tmp[0] |= 0x20;
+               if (lut->m4 & bit)
+                       tmp[0] |= 0x40;
+
+               if (lut->m0d[0] & bit)
+                       tmp[1] |= 0x01;
+               if (lut->m0d[1] & bit)
+                       tmp[1] |= 0x02;
+               if (lut->m0d[2] & bit)
+                       tmp[1] |= 0x04;
+               if (lut->m0d[3] & bit)
+                       tmp[1] |= 0x08;
+
+               if (lut->m1d[0] & bit)
+                       tmp[1] |= 0x10;
+               if (lut->m1d[1] & bit)
+                       tmp[1] |= 0x20;
+               if (lut->m1d[2] & bit)
+                       tmp[1] |= 0x40;
+               if (lut->m1d[3] & bit)
+                       tmp[1] |= 0x80;
+
+               sigma_write_register(WRITE_TRIGGER_SELECT0, tmp, sizeof(tmp),
+                                    devc);
+               sigma_set_register(WRITE_TRIGGER_SELECT1, 0x30 | i, devc);
+       }
+
+       /* Send the parameters */
+       sigma_write_register(WRITE_TRIGGER_SELECT0, (uint8_t *) &lut->params,
+                            sizeof(lut->params), devc);
+
+       return SR_OK;
+}
+
+static void clear_helper(void *priv)
+{
+       struct dev_context *devc;
+
+       devc = priv;
+
+       ftdi_deinit(&devc->ftdic);
+}
+
+static int dev_clear(void)
+{
+       return std_dev_clear(di, clear_helper);
+}
+
+static int init(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+       struct sr_dev_inst *sdi;
+       struct sr_channel *ch;
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       GSList *devices;
+       struct ftdi_device_list *devlist;
+       char serial_txt[10];
+       uint32_t serial;
+       int ret;
+       unsigned int i;
+
+       (void)options;
+
+       drvc = di->priv;
+
+       devices = NULL;
+
+       if (!(devc = g_try_malloc(sizeof(struct dev_context)))) {
+               sr_err("%s: devc malloc failed", __func__);
+               return NULL;
+       }
+
+       ftdi_init(&devc->ftdic);
+
+       /* Look for SIGMAs. */
+
+       if ((ret = ftdi_usb_find_all(&devc->ftdic, &devlist,
+           USB_VENDOR, USB_PRODUCT)) <= 0) {
+               if (ret < 0)
+                       sr_err("ftdi_usb_find_all(): %d", ret);
+               goto free;
+       }
+
+       /* 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);
+
+       if (serial < 0xa6010000 || serial > 0xa602ffff) {
+               sr_err("Only SIGMA and SIGMA2 are supported "
+                      "in this version of libsigrok.");
+               goto free;
+       }
+
+       sr_info("Found ASIX SIGMA - Serial: %s", serial_txt);
+
+       devc->cur_samplerate = samplerates[0];
+       devc->period_ps = 0;
+       devc->limit_msec = 0;
+       devc->cur_firmware = -1;
+       devc->num_channels = 0;
+       devc->samples_per_event = 0;
+       devc->capture_ratio = 50;
+       devc->use_triggers = 0;
+
+       /* Register SIGMA device. */
+       if (!(sdi = sr_dev_inst_new(0, SR_ST_INITIALIZING, USB_VENDOR_NAME,
+                                   USB_MODEL_NAME, NULL))) {
+               sr_err("%s: sdi was NULL", __func__);
+               goto free;
+       }
+       sdi->driver = di;
+
+       for (i = 0; i < ARRAY_SIZE(channel_names); i++) {
+               ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE,
+                                   channel_names[i]);
+               if (!ch)
+                       return NULL;
+               sdi->channels = g_slist_append(sdi->channels, ch);
+       }
+
+       devices = g_slist_append(devices, sdi);
+       drvc->instances = g_slist_append(drvc->instances, sdi);
+       sdi->priv = devc;
+
+       /* We will open the device again when we need it. */
+       ftdi_list_free(&devlist);
+
+       return devices;
+
+free:
+       ftdi_deinit(&devc->ftdic);
+       g_free(devc);
+       return NULL;
+}
+
+static GSList *dev_list(void)
+{
+       return ((struct drv_context *)(di->priv))->instances;
+}
+
+/*
+ * Configure the FPGA for bitbang mode.
+ * This sequence is documented in section 2. of the ASIX Sigma programming
+ * manual. This sequence is necessary to configure the FPGA in the Sigma
+ * into Bitbang mode, in which it can be programmed with the firmware.
+ */
+static int sigma_fpga_init_bitbang(struct dev_context *devc)
+{
+       uint8_t suicide[] = {
+               0x84, 0x84, 0x88, 0x84, 0x88, 0x84, 0x88, 0x84,
+       };
+       uint8_t init_array[] = {
+               0x01, 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01,
+               0x01, 0x01,
+       };
+       int i, ret, timeout = 10000;
+       uint8_t data;
+
+       /* Section 2. part 1), do the FPGA suicide. */
+       sigma_write(suicide, sizeof(suicide), devc);
+       sigma_write(suicide, sizeof(suicide), devc);
+       sigma_write(suicide, sizeof(suicide), devc);
+       sigma_write(suicide, sizeof(suicide), devc);
+
+       /* Section 2. part 2), do pulse on D1. */
+       sigma_write(init_array, sizeof(init_array), devc);
+       ftdi_usb_purge_buffers(&devc->ftdic);
+
+       /* Wait until the FPGA asserts D6/INIT_B. */
+       for (i = 0; i < timeout; i++) {
+               ret = sigma_read(&data, 1, devc);
+               if (ret < 0)
+                       return ret;
+               /* Test if pin D6 got asserted. */
+               if (data & (1 << 5))
+                       return 0;
+               /* The D6 was not asserted yet, wait a bit. */
+               usleep(10000);
+       }
+
+       return SR_ERR_TIMEOUT;
+}
+
+/*
+ * Configure the FPGA for logic-analyzer mode.
+ */
+static int sigma_fpga_init_la(struct dev_context *devc)
+{
+       /* Initialize the logic analyzer mode. */
+       uint8_t logic_mode_start[] = {
+               REG_ADDR_LOW  | (READ_ID & 0xf),
+               REG_ADDR_HIGH | (READ_ID >> 8),
+               REG_READ_ADDR,  /* Read ID register. */
+
+               REG_ADDR_LOW | (WRITE_TEST & 0xf),
+               REG_DATA_LOW | 0x5,
+               REG_DATA_HIGH_WRITE | 0x5,
+               REG_READ_ADDR,  /* Read scratch register. */
+
+               REG_DATA_LOW | 0xa,
+               REG_DATA_HIGH_WRITE | 0xa,
+               REG_READ_ADDR,  /* Read scratch register. */
+
+               REG_ADDR_LOW | (WRITE_MODE & 0xf),
+               REG_DATA_LOW | 0x0,
+               REG_DATA_HIGH_WRITE | 0x8,
+       };
+
+       uint8_t result[3];
+       int ret;
+
+       /* Initialize the logic analyzer mode. */
+       sigma_write(logic_mode_start, sizeof(logic_mode_start), devc);
+
+       /* Expect a 3 byte reply since we issued three READ requests. */
+       ret = sigma_read(result, 3, devc);
+       if (ret != 3)
+               goto err;
+
+       if (result[0] != 0xa6 || result[1] != 0x55 || result[2] != 0xaa)
+               goto err;
+
+       return SR_OK;
+err:
+       sr_err("Configuration failed. Invalid reply received.");
+       return SR_ERR;
+}
+
+/*
+ * Read the firmware from a file and transform it into a series of bitbang
+ * pulses used to program the FPGA. Note that the *bb_cmd must be free()'d
+ * by the caller of this function.
+ */
+static int sigma_fw_2_bitbang(const char *filename,
+                             uint8_t **bb_cmd, gsize *bb_cmd_size)
+{
+       GMappedFile *file;
+       GError *error;
+       gsize i, file_size, bb_size;
+       gchar *firmware;
+       uint8_t *bb_stream, *bbs;
+       uint32_t imm;
+       int bit, v;
+       int ret = SR_OK;
+
+       /*
+        * Map the file and make the mapped buffer writable.
+        * NOTE: Using writable=TRUE does _NOT_ mean that file that is mapped
+        *       will be modified. It will not be modified until someone uses
+        *       g_file_set_contents() on it.
+        */
+       error = NULL;
+       file = g_mapped_file_new(filename, TRUE, &error);
+       g_assert_no_error(error);
+
+       file_size = g_mapped_file_get_length(file);
+       firmware = g_mapped_file_get_contents(file);
+       g_assert(firmware);
+
+       /* Weird magic transformation below, I have no idea what it does. */
+       imm = 0x3f6df2ab;
+       for (i = 0; i < file_size; i++) {
+               imm = (imm + 0xa853753) % 177 + (imm * 0x8034052);
+               firmware[i] ^= imm & 0xff;
+       }
+
+       /*
+        * Now that the firmware is "transformed", we will transcribe the
+        * firmware blob into a sequence of toggles of the Dx wires. This
+        * sequence will be fed directly into the Sigma, which must be in
+        * the FPGA bitbang programming mode.
+        */
+
+       /* Each bit of firmware is transcribed as two toggles of Dx wires. */
+       bb_size = file_size * 8 * 2;
+       bb_stream = (uint8_t *)g_try_malloc(bb_size);
+       if (!bb_stream) {
+               sr_err("%s: Failed to allocate bitbang stream", __func__);
+               ret = SR_ERR_MALLOC;
+               goto exit;
+       }
+
+       bbs = bb_stream;
+       for (i = 0; i < file_size; i++) {
+               for (bit = 7; bit >= 0; bit--) {
+                       v = (firmware[i] & (1 << bit)) ? 0x40 : 0x00;
+                       *bbs++ = v | 0x01;
+                       *bbs++ = v;
+               }
+       }
+
+       /* The transformation completed successfully, return the result. */
+       *bb_cmd = bb_stream;
+       *bb_cmd_size = bb_size;
+
+exit:
+       g_mapped_file_unref(file);
+       return ret;
+}
+
+static int upload_firmware(int firmware_idx, struct dev_context *devc)
+{
+       int ret;
+       unsigned char *buf;
+       unsigned char pins;
+       size_t buf_size;
+       const char *firmware = sigma_firmware_files[firmware_idx];
+       struct ftdi_context *ftdic = &devc->ftdic;
+
+       /* Make sure it's an ASIX SIGMA. */
+       ret = ftdi_usb_open_desc(ftdic, USB_VENDOR, USB_PRODUCT,
+                                USB_DESCRIPTION, NULL);
+       if (ret < 0) {
+               sr_err("ftdi_usb_open failed: %s",
+                      ftdi_get_error_string(ftdic));
+               return 0;
+       }
+
+       ret = ftdi_set_bitmode(ftdic, 0xdf, BITMODE_BITBANG);
+       if (ret < 0) {
+               sr_err("ftdi_set_bitmode failed: %s",
+                      ftdi_get_error_string(ftdic));
+               return 0;
+       }
+
+       /* Four times the speed of sigmalogan - Works well. */
+       ret = ftdi_set_baudrate(ftdic, 750000);
+       if (ret < 0) {
+               sr_err("ftdi_set_baudrate failed: %s",
+                      ftdi_get_error_string(ftdic));
+               return 0;
+       }
+
+       /* Initialize the FPGA for firmware upload. */
+       ret = sigma_fpga_init_bitbang(devc);
+       if (ret)
+               return ret;
+
+       /* Prepare firmware. */
+       ret = sigma_fw_2_bitbang(firmware, &buf, &buf_size);
+       if (ret != SR_OK) {
+               sr_err("An error occured while reading the firmware: %s",
+                      firmware);
+               return ret;
+       }
+
+       /* Upload firmare. */
+       sr_info("Uploading firmware file '%s'.", firmware);
+       sigma_write(buf, buf_size, devc);
+
+       g_free(buf);
+
+       ret = ftdi_set_bitmode(ftdic, 0x00, BITMODE_RESET);
+       if (ret < 0) {
+               sr_err("ftdi_set_bitmode failed: %s",
+                      ftdi_get_error_string(ftdic));
+               return SR_ERR;
+       }
+
+       ftdi_usb_purge_buffers(ftdic);
+
+       /* Discard garbage. */
+       while (sigma_read(&pins, 1, devc) == 1)
+               ;
+
+       /* Initialize the FPGA for logic-analyzer mode. */
+       ret = sigma_fpga_init_la(devc);
+       if (ret != SR_OK)
+               return ret;
+
+       devc->cur_firmware = firmware_idx;
+
+       sr_info("Firmware uploaded.");
+
+       return SR_OK;
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       int ret;
+
+       devc = sdi->priv;
+
+       /* Make sure it's an ASIX SIGMA. */
+       if ((ret = ftdi_usb_open_desc(&devc->ftdic,
+               USB_VENDOR, USB_PRODUCT, USB_DESCRIPTION, NULL)) < 0) {
+
+               sr_err("ftdi_usb_open failed: %s",
+                      ftdi_get_error_string(&devc->ftdic));
+
+               return 0;
+       }
+
+       sdi->status = SR_ST_ACTIVE;
+
+       return SR_OK;
+}
+
+static int set_samplerate(const struct sr_dev_inst *sdi, uint64_t samplerate)
+{
+       struct dev_context *devc;
+       unsigned int i;
+       int ret;
+
+       devc = sdi->priv;
+       ret = SR_OK;
+
+       for (i = 0; i < ARRAY_SIZE(samplerates); i++) {
+               if (samplerates[i] == samplerate)
+                       break;
+       }
+       if (samplerates[i] == 0)
+               return SR_ERR_SAMPLERATE;
+
+       if (samplerate <= SR_MHZ(50)) {
+               ret = upload_firmware(0, devc);
+               devc->num_channels = 16;
+       } else if (samplerate == SR_MHZ(100)) {
+               ret = upload_firmware(1, devc);
+               devc->num_channels = 8;
+       } else if (samplerate == SR_MHZ(200)) {
+               ret = upload_firmware(2, devc);
+               devc->num_channels = 4;
+       }
+
+       if (ret == SR_OK) {
+               devc->cur_samplerate = samplerate;
+               devc->period_ps = 1000000000000ULL / samplerate;
+               devc->samples_per_event = 16 / devc->num_channels;
+               devc->state.state = SIGMA_IDLE;
+       }
+
+       return ret;
+}
+
+/*
+ * In 100 and 200 MHz mode, only a single pin rising/falling can be
+ * set as trigger. In other modes, two rising/falling triggers can be set,
+ * in addition to value/mask trigger for any number of channels.
+ *
+ * The Sigma supports complex triggers using boolean expressions, but this
+ * has not been implemented yet.
+ */
+static int convert_trigger(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_trigger *trigger;
+       struct sr_trigger_stage *stage;
+       struct sr_trigger_match *match;
+       const GSList *l, *m;
+       int channelbit, trigger_set;
+
+       devc = sdi->priv;
+       memset(&devc->trigger, 0, sizeof(struct sigma_trigger));
+       if (!(trigger = sr_session_trigger_get(sdi->session)))
+               return SR_OK;
+
+       trigger_set = 0;
+       for (l = trigger->stages; l; l = l->next) {
+               stage = l->data;
+               for (m = stage->matches; m; m = m->next) {
+                       match = m->data;
+                       if (!match->channel->enabled)
+                               /* Ignore disabled channels with a trigger. */
+                               continue;
+                       channelbit = 1 << (match->channel->index);
+                       if (devc->cur_samplerate >= SR_MHZ(100)) {
+                               /* Fast trigger support. */
+                               if (trigger_set) {
+                                       sr_err("Only a single pin trigger is "
+                                                       "supported in 100 and 200MHz mode.");
+                                       return SR_ERR;
+                               }
+                               if (match->match == SR_TRIGGER_FALLING)
+                                       devc->trigger.fallingmask |= channelbit;
+                               else if (match->match == SR_TRIGGER_RISING)
+                                       devc->trigger.risingmask |= channelbit;
+                               else {
+                                       sr_err("Only rising/falling trigger is "
+                                                       "supported in 100 and 200MHz mode.");
+                                       return SR_ERR;
+                               }
+
+                               ++trigger_set;
+                       } else {
+                               /* Simple trigger support (event). */
+                               if (match->match == SR_TRIGGER_ONE) {
+                                       devc->trigger.simplevalue |= channelbit;
+                                       devc->trigger.simplemask |= channelbit;
+                               }
+                               else if (match->match == SR_TRIGGER_ZERO) {
+                                       devc->trigger.simplevalue &= ~channelbit;
+                                       devc->trigger.simplemask |= channelbit;
+                               }
+                               else if (match->match == SR_TRIGGER_FALLING) {
+                                       devc->trigger.fallingmask |= channelbit;
+                                       ++trigger_set;
+                               }
+                               else if (match->match == SR_TRIGGER_RISING) {
+                                       devc->trigger.risingmask |= channelbit;
+                                       ++trigger_set;
+                               }
+
+                               /*
+                                * Actually, Sigma supports 2 rising/falling triggers,
+                                * but they are ORed and the current trigger syntax
+                                * does not permit ORed triggers.
+                                */
+                               if (trigger_set > 1) {
+                                       sr_err("Only 1 rising/falling trigger "
+                                                  "is supported.");
+                                       return SR_ERR;
+                               }
+                       }
+               }
+       }
+
+
+       return SR_OK;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+
+       devc = sdi->priv;
+
+       /* TODO */
+       if (sdi->status == SR_ST_ACTIVE)
+               ftdi_usb_close(&devc->ftdic);
+
+       sdi->status = SR_ST_INACTIVE;
+
+       return SR_OK;
+}
+
+static int cleanup(void)
+{
+       return dev_clear();
+}
+
+static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+
+       (void)cg;
+
+       if (!sdi)
+               return SR_ERR;
+       devc = sdi->priv;
+
+       switch (id) {
+       case SR_CONF_SAMPLERATE:
+               *data = g_variant_new_uint64(devc->cur_samplerate);
+               break;
+       case SR_CONF_LIMIT_MSEC:
+               *data = g_variant_new_uint64(devc->limit_msec);
+               break;
+       case SR_CONF_CAPTURE_RATIO:
+               *data = g_variant_new_uint64(devc->capture_ratio);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       uint64_t tmp;
+       int ret;
+
+       (void)cg;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       devc = sdi->priv;
+
+       ret = SR_OK;
+       switch (id) {
+       case SR_CONF_SAMPLERATE:
+               ret = set_samplerate(sdi, g_variant_get_uint64(data));
+               break;
+       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:
+               tmp = g_variant_get_uint64(data);
+               devc->limit_msec = tmp * 1000 / devc->cur_samplerate;
+               break;
+       case SR_CONF_CAPTURE_RATIO:
+               tmp = g_variant_get_uint64(data);
+               if (tmp <= 100)
+                       devc->capture_ratio = tmp;
+               else
+                       ret = SR_ERR;
+               break;
+       default:
+               ret = SR_ERR_NA;
+       }
+
+       return ret;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       GVariant *gvar;
+       GVariantBuilder gvb;
+
+       (void)sdi;
+       (void)cg;
+
+       switch (key) {
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+               break;
+       case SR_CONF_SAMPLERATE:
+               g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
+               gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), samplerates,
+                               ARRAY_SIZE(samplerates), sizeof(uint64_t));
+               g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar);
+               *data = g_variant_builder_end(&gvb);
+               break;
+       case SR_CONF_TRIGGER_MATCH:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               trigger_matches, ARRAY_SIZE(trigger_matches),
+                               sizeof(int32_t));
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+/* Software trigger to determine exact trigger position. */
+static int get_trigger_offset(uint8_t *samples, uint16_t last_sample,
+                             struct sigma_trigger *t)
+{
+       int i;
+       uint16_t sample = 0;
+
+       for (i = 0; i < 8; ++i) {
+               if (i > 0)
+                       last_sample = sample;
+               sample = samples[2 * i] | (samples[2 * i + 1] << 8);
+
+               /* Simple triggers. */
+               if ((sample & t->simplemask) != t->simplevalue)
+                       continue;
+
+               /* Rising edge. */
+               if (((last_sample & t->risingmask) != 0) ||
+                   ((sample & t->risingmask) != t->risingmask))
+                       continue;
+
+               /* Falling edge. */
+               if ((last_sample & t->fallingmask) != t->fallingmask ||
+                   (sample & t->fallingmask) != 0)
+                       continue;
+
+               break;
+       }
+
+       /* If we did not match, return original trigger pos. */
+       return i & 0x7;
+}
+
+
+/*
+ * Return the timestamp of "DRAM cluster".
+ */
+static uint16_t sigma_dram_cluster_ts(struct sigma_dram_cluster *cluster)
+{
+       return (cluster->timestamp_hi << 8) | cluster->timestamp_lo;
+}
+
+static void sigma_decode_dram_cluster(struct sigma_dram_cluster *dram_cluster,
+                                     unsigned int events_in_cluster,
+                                     unsigned int triggered,
+                                     struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc = sdi->priv;
+       struct sigma_state *ss = &devc->state;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_logic logic;
+       uint16_t tsdiff, ts;
+       uint8_t samples[2048];
+       unsigned int i;
+
+       ts = sigma_dram_cluster_ts(dram_cluster);
+       tsdiff = ts - ss->lastts;
+       ss->lastts = ts;
+
+       packet.type = SR_DF_LOGIC;
+       packet.payload = &logic;
+       logic.unitsize = 2;
+       logic.data = samples;
+
+       /*
+        * First of all, send Sigrok a copy of the last sample from
+        * previous cluster as many times as needed to make up for
+        * the differential characteristics of data we get from the
+        * Sigma. Sigrok needs one sample of data per period.
+        *
+        * One DRAM cluster contains a timestamp and seven samples,
+        * the units of timestamp are "devc->period_ps" , the first
+        * sample in the cluster happens at the time of the timestamp
+        * and the remaining samples happen at timestamp +1...+6 .
+        */
+       for (ts = 0; ts < tsdiff - (EVENTS_PER_CLUSTER - 1); ts++) {
+               i = ts % 1024;
+               samples[2 * i + 0] = ss->lastsample & 0xff;
+               samples[2 * i + 1] = ss->lastsample >> 8;
+
+               /*
+                * If we have 1024 samples ready or we're at the
+                * end of submitting the padding samples, submit
+                * the packet to Sigrok.
+                */
+               if ((i == 1023) || (ts == (tsdiff - EVENTS_PER_CLUSTER))) {
+                       logic.length = (i + 1) * logic.unitsize;
+                       sr_session_send(sdi, &packet);
+               }
+       }
+
+       /*
+        * Parse the samples in current cluster and prepare them
+        * to be submitted to Sigrok.
+        */
+       for (i = 0; i < events_in_cluster; i++) {
+               samples[2 * i + 1] = dram_cluster->samples[i].sample_lo;
+               samples[2 * i + 0] = dram_cluster->samples[i].sample_hi;
+       }
+
+       /* Send data up to trigger point (if triggered). */
+       int trigger_offset = 0;
+       if (triggered) {
+               /*
+                * Trigger is not always accurate to sample because of
+                * pipeline delay. However, it always triggers before
+                * the actual event. We therefore look at the next
+                * samples to pinpoint the exact position of the trigger.
+                */
+               trigger_offset = get_trigger_offset(samples,
+                                       ss->lastsample, &devc->trigger);
+
+               if (trigger_offset > 0) {
+                       packet.type = SR_DF_LOGIC;
+                       logic.length = trigger_offset * logic.unitsize;
+                       sr_session_send(sdi, &packet);
+                       events_in_cluster -= trigger_offset;
+               }
+
+               /* Only send trigger if explicitly enabled. */
+               if (devc->use_triggers) {
+                       packet.type = SR_DF_TRIGGER;
+                       sr_session_send(sdi, &packet);
+               }
+       }
+
+       if (events_in_cluster > 0) {
+               packet.type = SR_DF_LOGIC;
+               logic.length = events_in_cluster * logic.unitsize;
+               logic.data = samples + (trigger_offset * logic.unitsize);
+               sr_session_send(sdi, &packet);
+       }
+
+       ss->lastsample =
+               samples[2 * (events_in_cluster - 1) + 0] |
+               (samples[2 * (events_in_cluster - 1) + 1] << 8);
+
+}
+
+/*
+ * Decode chunk of 1024 bytes, 64 clusters, 7 events per cluster.
+ * Each event is 20ns apart, and can contain multiple samples.
+ *
+ * For 200 MHz, events contain 4 samples for each channel, spread 5 ns apart.
+ * For 100 MHz, events contain 2 samples for each channel, spread 10 ns apart.
+ * For 50 MHz and below, events contain one sample for each channel,
+ * spread 20 ns apart.
+ */
+static int decode_chunk_ts(struct sigma_dram_line *dram_line,
+                          uint16_t events_in_line,
+                          uint32_t trigger_event,
+                          struct sr_dev_inst *sdi)
+{
+       struct sigma_dram_cluster *dram_cluster;
+       struct dev_context *devc = sdi->priv;
+       unsigned int clusters_in_line =
+               (events_in_line + (EVENTS_PER_CLUSTER - 1)) / EVENTS_PER_CLUSTER;
+       unsigned int events_in_cluster;
+       unsigned int i;
+       uint32_t trigger_cluster = ~0, triggered = 0;
+
+       /* Check if trigger is in this chunk. */
+       if (trigger_event < (64 * 7)) {
+               if (devc->cur_samplerate <= SR_MHZ(50)) {
+                       trigger_event -= MIN(EVENTS_PER_CLUSTER - 1,
+                                            trigger_event);
+               }
+
+               /* Find in which cluster the trigger occured. */
+               trigger_cluster = trigger_event / EVENTS_PER_CLUSTER;
+       }
+
+       /* For each full DRAM cluster. */
+       for (i = 0; i < clusters_in_line; i++) {
+               dram_cluster = &dram_line->cluster[i];
+
+               /* The last cluster might not be full. */
+               if ((i == clusters_in_line - 1) &&
+                   (events_in_line % EVENTS_PER_CLUSTER)) {
+                       events_in_cluster = events_in_line % EVENTS_PER_CLUSTER;
+               } else {
+                       events_in_cluster = EVENTS_PER_CLUSTER;
+               }
+
+               triggered = (i == trigger_cluster);
+               sigma_decode_dram_cluster(dram_cluster, events_in_cluster,
+                                         triggered, sdi);
+       }
+
+       return SR_OK;
+}
+
+static int download_capture(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc = sdi->priv;
+       const uint32_t chunks_per_read = 32;
+       struct sigma_dram_line *dram_line;
+       int bufsz;
+       uint32_t stoppos, triggerpos;
+       struct sr_datafeed_packet packet;
+       uint8_t modestatus;
+
+       uint32_t i;
+       uint32_t dl_lines_total, dl_lines_curr, dl_lines_done;
+       uint32_t dl_events_in_line = 64 * 7;
+       uint32_t trg_line = ~0, trg_event = ~0;
+
+       dram_line = g_try_malloc0(chunks_per_read * sizeof(*dram_line));
+       if (!dram_line)
+               return FALSE;
+
+       sr_info("Downloading sample data.");
+
+       /* Stop acquisition. */
+       sigma_set_register(WRITE_MODE, 0x11, devc);
+
+       /* Set SDRAM Read Enable. */
+       sigma_set_register(WRITE_MODE, 0x02, devc);
+
+       /* Get the current position. */
+       sigma_read_pos(&stoppos, &triggerpos, devc);
+
+       /* Check if trigger has fired. */
+       modestatus = sigma_get_register(READ_MODE, devc);
+       if (modestatus & 0x20) {
+               trg_line = triggerpos >> 9;
+               trg_event = triggerpos & 0x1ff;
+       }
+
+       /*
+        * Determine how many 1024b "DRAM lines" do we need to read from the
+        * Sigma so we have a complete set of samples. Note that the last
+        * line can be only partial, containing less than 64 clusters.
+        */
+       dl_lines_total = (stoppos >> 9) + 1;
+
+       dl_lines_done = 0;
+
+       while (dl_lines_total > dl_lines_done) {
+               /* We can download only up-to 32 DRAM lines in one go! */
+               dl_lines_curr = MIN(chunks_per_read, dl_lines_total);
+
+               bufsz = sigma_read_dram(dl_lines_done, dl_lines_curr,
+                                       (uint8_t *)dram_line, devc);
+               /* TODO: Check bufsz. For now, just avoid compiler warnings. */
+               (void)bufsz;
+
+               /* This is the first DRAM line, so find the initial timestamp. */
+               if (dl_lines_done == 0) {
+                       devc->state.lastts =
+                               sigma_dram_cluster_ts(&dram_line[0].cluster[0]);
+                       devc->state.lastsample = 0;
+               }
+
+               for (i = 0; i < dl_lines_curr; i++) {
+                       uint32_t trigger_event = ~0;
+                       /* The last "DRAM line" can be only partially full. */
+                       if (dl_lines_done + i == dl_lines_total - 1)
+                               dl_events_in_line = stoppos & 0x1ff;
+
+                       /* Test if the trigger happened on this line. */
+                       if (dl_lines_done + i == trg_line)
+                               trigger_event = trg_event;
+
+                       decode_chunk_ts(dram_line + i, dl_events_in_line,
+                                       trigger_event, sdi);
+               }
+
+               dl_lines_done += dl_lines_curr;
+       }
+
+       /* All done. */
+       packet.type = SR_DF_END;
+       sr_session_send(sdi, &packet);
+
+       dev_acquisition_stop(sdi, sdi);
+
+       g_free(dram_line);
+
+       return TRUE;
+}
+
+/*
+ * Handle the Sigma when in CAPTURE mode. This function checks:
+ * - Sampling time ended
+ * - DRAM capacity overflow
+ * This function triggers download of the samples from Sigma
+ * in case either of the above conditions is true.
+ */
+static int sigma_capture_mode(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc = sdi->priv;
+
+       uint64_t running_msec;
+       struct timeval tv;
+
+       uint32_t stoppos, triggerpos;
+
+       /* Check if the selected sampling duration passed. */
+       gettimeofday(&tv, 0);
+       running_msec = (tv.tv_sec - devc->start_tv.tv_sec) * 1000 +
+                      (tv.tv_usec - devc->start_tv.tv_usec) / 1000;
+       if (running_msec >= devc->limit_msec)
+               return download_capture(sdi);
+
+       /* Get the position in DRAM to which the FPGA is writing now. */
+       sigma_read_pos(&stoppos, &triggerpos, devc);
+       /* Test if DRAM is full and if so, download the data. */
+       if ((stoppos >> 9) == 32767)
+               return download_capture(sdi);
+
+       return TRUE;
+}
+
+static int receive_data(int fd, int revents, void *cb_data)
+{
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+
+       (void)fd;
+       (void)revents;
+
+       sdi = cb_data;
+       devc = sdi->priv;
+
+       if (devc->state.state == SIGMA_IDLE)
+               return TRUE;
+
+       if (devc->state.state == SIGMA_CAPTURE)
+               return sigma_capture_mode(sdi);
+
+       return TRUE;
+}
+
+/* Build a LUT entry used by the trigger functions. */
+static void build_lut_entry(uint16_t value, uint16_t mask, uint16_t *entry)
+{
+       int i, j, k, bit;
+
+       /* For each quad channel. */
+       for (i = 0; i < 4; ++i) {
+               entry[i] = 0xffff;
+
+               /* For each bit in LUT. */
+               for (j = 0; j < 16; ++j)
+
+                       /* For each channel in quad. */
+                       for (k = 0; k < 4; ++k) {
+                               bit = 1 << (i * 4 + k);
+
+                               /* Set bit in entry */
+                               if ((mask & bit) &&
+                                   ((!(value & bit)) !=
+                                   (!(j & (1 << k)))))
+                                       entry[i] &= ~(1 << j);
+                       }
+       }
+}
+
+/* Add a logical function to LUT mask. */
+static void add_trigger_function(enum triggerop oper, enum triggerfunc func,
+                                int index, int neg, uint16_t *mask)
+{
+       int i, j;
+       int x[2][2], tmp, a, b, aset, bset, rset;
+
+       memset(x, 0, 4 * sizeof(int));
+
+       /* Trigger detect condition. */
+       switch (oper) {
+       case OP_LEVEL:
+               x[0][1] = 1;
+               x[1][1] = 1;
+               break;
+       case OP_NOT:
+               x[0][0] = 1;
+               x[1][0] = 1;
+               break;
+       case OP_RISE:
+               x[0][1] = 1;
+               break;
+       case OP_FALL:
+               x[1][0] = 1;
+               break;
+       case OP_RISEFALL:
+               x[0][1] = 1;
+               x[1][0] = 1;
+               break;
+       case OP_NOTRISE:
+               x[1][1] = 1;
+               x[0][0] = 1;
+               x[1][0] = 1;
+               break;
+       case OP_NOTFALL:
+               x[1][1] = 1;
+               x[0][0] = 1;
+               x[0][1] = 1;
+               break;
+       case OP_NOTRISEFALL:
+               x[1][1] = 1;
+               x[0][0] = 1;
+               break;
+       }
+
+       /* Transpose if neg is set. */
+       if (neg) {
+               for (i = 0; i < 2; ++i) {
+                       for (j = 0; j < 2; ++j) {
+                               tmp = x[i][j];
+                               x[i][j] = x[1-i][1-j];
+                               x[1-i][1-j] = tmp;
+                       }
+               }
+       }
+
+       /* Update mask with function. */
+       for (i = 0; i < 16; ++i) {
+               a = (i >> (2 * index + 0)) & 1;
+               b = (i >> (2 * index + 1)) & 1;
+
+               aset = (*mask >> i) & 1;
+               bset = x[b][a];
+
+               if (func == FUNC_AND || func == FUNC_NAND)
+                       rset = aset & bset;
+               else if (func == FUNC_OR || func == FUNC_NOR)
+                       rset = aset | bset;
+               else if (func == FUNC_XOR || func == FUNC_NXOR)
+                       rset = aset ^ bset;
+
+               if (func == FUNC_NAND || func == FUNC_NOR || func == FUNC_NXOR)
+                       rset = !rset;
+
+               *mask &= ~(1 << i);
+
+               if (rset)
+                       *mask |= 1 << i;
+       }
+}
+
+/*
+ * Build trigger LUTs used by 50 MHz and lower sample rates for supporting
+ * simple pin change and state triggers. Only two transitions (rise/fall) can be
+ * set at any time, but a full mask and value can be set (0/1).
+ */
+static int build_basic_trigger(struct triggerlut *lut, struct dev_context *devc)
+{
+       int i,j;
+       uint16_t masks[2] = { 0, 0 };
+
+       memset(lut, 0, sizeof(struct triggerlut));
+
+       /* Contant for simple triggers. */
+       lut->m4 = 0xa000;
+
+       /* Value/mask trigger support. */
+       build_lut_entry(devc->trigger.simplevalue, devc->trigger.simplemask,
+                       lut->m2d);
+
+       /* Rise/fall trigger support. */
+       for (i = 0, j = 0; i < 16; ++i) {
+               if (devc->trigger.risingmask & (1 << i) ||
+                   devc->trigger.fallingmask & (1 << i))
+                       masks[j++] = 1 << i;
+       }
+
+       build_lut_entry(masks[0], masks[0], lut->m0d);
+       build_lut_entry(masks[1], masks[1], lut->m1d);
+
+       /* Add glue logic */
+       if (masks[0] || masks[1]) {
+               /* Transition trigger. */
+               if (masks[0] & devc->trigger.risingmask)
+                       add_trigger_function(OP_RISE, FUNC_OR, 0, 0, &lut->m3);
+               if (masks[0] & devc->trigger.fallingmask)
+                       add_trigger_function(OP_FALL, FUNC_OR, 0, 0, &lut->m3);
+               if (masks[1] & devc->trigger.risingmask)
+                       add_trigger_function(OP_RISE, FUNC_OR, 1, 0, &lut->m3);
+               if (masks[1] & devc->trigger.fallingmask)
+                       add_trigger_function(OP_FALL, FUNC_OR, 1, 0, &lut->m3);
+       } else {
+               /* Only value/mask trigger. */
+               lut->m3 = 0xffff;
+       }
+
+       /* Triggertype: event. */
+       lut->params.selres = 3;
+
+       return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct dev_context *devc;
+       struct clockselect_50 clockselect;
+       int frac, triggerpin, ret;
+       uint8_t triggerselect = 0;
+       struct triggerinout triggerinout_conf;
+       struct triggerlut lut;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       devc = sdi->priv;
+
+       if (convert_trigger(sdi) != SR_OK) {
+               sr_err("Failed to configure triggers.");
+               return SR_ERR;
+       }
+
+       /* If the samplerate has not been set, default to 200 kHz. */
+       if (devc->cur_firmware == -1) {
+               if ((ret = set_samplerate(sdi, SR_KHZ(200))) != SR_OK)
+                       return ret;
+       }
+
+       /* Enter trigger programming mode. */
+       sigma_set_register(WRITE_TRIGGER_SELECT1, 0x20, devc);
+
+       /* 100 and 200 MHz mode. */
+       if (devc->cur_samplerate >= SR_MHZ(100)) {
+               sigma_set_register(WRITE_TRIGGER_SELECT1, 0x81, devc);
+
+               /* Find which pin to trigger on from mask. */
+               for (triggerpin = 0; triggerpin < 8; ++triggerpin)
+                       if ((devc->trigger.risingmask | devc->trigger.fallingmask) &
+                           (1 << triggerpin))
+                               break;
+
+               /* Set trigger pin and light LED on trigger. */
+               triggerselect = (1 << LEDSEL1) | (triggerpin & 0x7);
+
+               /* Default rising edge. */
+               if (devc->trigger.fallingmask)
+                       triggerselect |= 1 << 3;
+
+       /* All other modes. */
+       } else if (devc->cur_samplerate <= SR_MHZ(50)) {
+               build_basic_trigger(&lut, devc);
+
+               sigma_write_trigger_lut(&lut, devc);
+
+               triggerselect = (1 << LEDSEL1) | (1 << LEDSEL0);
+       }
+
+       /* Setup trigger in and out pins to default values. */
+       memset(&triggerinout_conf, 0, sizeof(struct triggerinout));
+       triggerinout_conf.trgout_bytrigger = 1;
+       triggerinout_conf.trgout_enable = 1;
+
+       sigma_write_register(WRITE_TRIGGER_OPTION,
+                            (uint8_t *) &triggerinout_conf,
+                            sizeof(struct triggerinout), devc);
+
+       /* Go back to normal mode. */
+       sigma_set_register(WRITE_TRIGGER_SELECT1, triggerselect, devc);
+
+       /* Set clock select register. */
+       if (devc->cur_samplerate == SR_MHZ(200))
+               /* Enable 4 channels. */
+               sigma_set_register(WRITE_CLOCK_SELECT, 0xf0, devc);
+       else if (devc->cur_samplerate == SR_MHZ(100))
+               /* Enable 8 channels. */
+               sigma_set_register(WRITE_CLOCK_SELECT, 0x00, devc);
+       else {
+               /*
+                * 50 MHz mode (or fraction thereof). Any fraction down to
+                * 50 MHz / 256 can be used, but is not supported by sigrok API.
+                */
+               frac = SR_MHZ(50) / devc->cur_samplerate - 1;
+
+               clockselect.async = 0;
+               clockselect.fraction = frac;
+               clockselect.disabled_channels = 0;
+
+               sigma_write_register(WRITE_CLOCK_SELECT,
+                                    (uint8_t *) &clockselect,
+                                    sizeof(clockselect), devc);
+       }
+
+       /* Setup maximum post trigger time. */
+       sigma_set_register(WRITE_POST_TRIGGER,
+                          (devc->capture_ratio * 255) / 100, devc);
+
+       /* Start acqusition. */
+       gettimeofday(&devc->start_tv, 0);
+       sigma_set_register(WRITE_MODE, 0x0d, devc);
+
+       devc->cb_data = cb_data;
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(sdi, LOG_PREFIX);
+
+       /* Add capture source. */
+       sr_session_source_add(sdi->session, 0, G_IO_IN, 10, receive_data, (void *)sdi);
+
+       devc->state.state = SIGMA_CAPTURE;
+
+       return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct dev_context *devc;
+
+       (void)cb_data;
+
+       devc = sdi->priv;
+       devc->state.state = SIGMA_IDLE;
+
+       sr_session_source_remove(sdi->session, 0);
+
+       return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver asix_sigma_driver_info = {
+       .name = "asix-sigma",
+       .longname = "ASIX SIGMA/SIGMA2",
+       .api_version = 1,
+       .init = init,
+       .cleanup = cleanup,
+       .scan = scan,
+       .dev_list = dev_list,
+       .dev_clear = dev_clear,
+       .config_get = config_get,
+       .config_set = config_set,
+       .config_list = config_list,
+       .dev_open = dev_open,
+       .dev_close = dev_close,
+       .dev_acquisition_start = dev_acquisition_start,
+       .dev_acquisition_stop = dev_acquisition_stop,
+       .priv = NULL,
+};
diff --git a/src/hardware/asix-sigma/asix-sigma.h b/src/hardware/asix-sigma/asix-sigma.h
new file mode 100644 (file)
index 0000000..4c9deff
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010 HÃ¥vard Espeland <gus@ping.uio.no>,
+ * Copyright (C) 2010 Martin StensgÃ¥rd <mastensg@ping.uio.no>
+ * Copyright (C) 2010 Carl Henrik Lunde <chlunde@ping.uio.no>
+ *
+ * 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_ASIX_SIGMA_ASIX_SIGMA_H
+#define LIBSIGROK_HARDWARE_ASIX_SIGMA_ASIX_SIGMA_H
+
+#define LOG_PREFIX "asix-sigma"
+
+enum sigma_write_register {
+       WRITE_CLOCK_SELECT      = 0,
+       WRITE_TRIGGER_SELECT0   = 1,
+       WRITE_TRIGGER_SELECT1   = 2,
+       WRITE_MODE              = 3,
+       WRITE_MEMROW            = 4,
+       WRITE_POST_TRIGGER      = 5,
+       WRITE_TRIGGER_OPTION    = 6,
+       WRITE_PIN_VIEW          = 7,
+
+       WRITE_TEST              = 15,
+};
+
+enum sigma_read_register {
+       READ_ID                 = 0,
+       READ_TRIGGER_POS_LOW    = 1,
+       READ_TRIGGER_POS_HIGH   = 2,
+       READ_TRIGGER_POS_UP     = 3,
+       READ_STOP_POS_LOW       = 4,
+       READ_STOP_POS_HIGH      = 5,
+       READ_STOP_POS_UP        = 6,
+       READ_MODE               = 7,
+       READ_PIN_CHANGE_LOW     = 8,
+       READ_PIN_CHANGE_HIGH    = 9,
+       READ_BLOCK_LAST_TS_LOW  = 10,
+       READ_BLOCK_LAST_TS_HIGH = 11,
+       READ_PIN_VIEW           = 12,
+
+       READ_TEST               = 15,
+};
+
+#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_DRAM_WAIT_ACK      (0x5 << 4)
+
+/* Bit (1 << 4) can be low or high (double buffer / cache) */
+#define REG_DRAM_BLOCK         (0x6 << 4)
+#define REG_DRAM_BLOCK_BEGIN   (0x8 << 4)
+#define REG_DRAM_BLOCK_DATA    (0xa << 4)
+
+#define LEDSEL0                        6
+#define LEDSEL1                        7
+
+#define NEXT_REG               1
+
+#define EVENTS_PER_CLUSTER     7
+
+#define CHUNK_SIZE             1024
+
+/*
+ * The entire ASIX Sigma DRAM is an array of struct sigma_dram_line[1024];
+ */
+
+/* One "DRAM cluster" contains a timestamp and 7 samples, 16b total. */
+struct sigma_dram_cluster {
+       uint8_t         timestamp_lo;
+       uint8_t         timestamp_hi;
+       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. */
+struct triggerinout {
+       uint8_t trgout_resistor_enable : 1;
+       uint8_t trgout_resistor_pullup : 1;
+       uint8_t reserved1 : 1;
+       uint8_t trgout_bytrigger : 1;
+       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 {
+       /* The actual LUTs. */
+       uint16_t m0d[4], m1d[4], m2d[4];
+       uint16_t m3, m3s, m4;
+
+       /* Paramters should be sent as a single register write. */
+       struct {
+               uint8_t selc : 2;
+               uint8_t selpresc : 6;
+
+               uint8_t selinc : 2;
+               uint8_t selres : 2;
+               uint8_t sela : 2;
+               uint8_t selb : 2;
+
+               uint16_t cmpb;
+               uint16_t cmpa;
+       } params;
+};
+
+/* Trigger configuration */
+struct sigma_trigger {
+       /* Only two channels can be used in mask. */
+       uint16_t risingmask;
+       uint16_t fallingmask;
+
+       /* Simple trigger support (<= 50 MHz). */
+       uint16_t simplemask;
+       uint16_t simplevalue;
+
+       /* TODO: Advanced trigger support (boolean expressions). */
+};
+
+/* Events for trigger operation. */
+enum triggerop {
+       OP_LEVEL = 1,
+       OP_NOT,
+       OP_RISE,
+       OP_FALL,
+       OP_RISEFALL,
+       OP_NOTRISE,
+       OP_NOTFALL,
+       OP_NOTRISEFALL,
+};
+
+/* Logical functions for trigger operation. */
+enum triggerfunc {
+       FUNC_AND = 1,
+       FUNC_NAND,
+       FUNC_OR,
+       FUNC_NOR,
+       FUNC_XOR,
+       FUNC_NXOR,
+};
+
+struct sigma_state {
+       enum {
+               SIGMA_UNINITIALIZED = 0,
+               SIGMA_IDLE,
+               SIGMA_CAPTURE,
+               SIGMA_DOWNLOAD,
+       } state;
+
+       uint16_t lastts;
+       uint16_t lastsample;
+};
+
+/* Private, per-device-instance driver context. */
+struct dev_context {
+       struct ftdi_context ftdic;
+       uint64_t cur_samplerate;
+       uint64_t period_ps;
+       uint64_t limit_msec;
+       struct timeval start_tv;
+       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;
+       void *cb_data;
+};
+
+#endif
diff --git a/src/hardware/atten-pps3xxx/api.c b/src/hardware/atten-pps3xxx/api.c
new file mode 100644 (file)
index 0000000..5ca3dbe
--- /dev/null
@@ -0,0 +1,518 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Bert Vermeulen <bert@biot.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 <string.h>
+#include <errno.h>
+#include "protocol.h"
+
+/*
+ * The default serial communication settings on the device are 9600
+ * baud, 9 data bits. The 9th bit isn't actually used, and the vendor
+ * software uses Mark parity to absorb the extra bit.
+ *
+ * Since 9 data bits is not a standard available in POSIX, we use two
+ * stop bits to skip over the extra bit instead.
+ */
+#define SERIALCOMM "9600/8n2"
+
+static const int32_t scanopts[] = {
+       SR_CONF_CONN,
+       SR_CONF_SERIALCOMM,
+};
+
+static const int32_t devopts[] = {
+       SR_CONF_POWER_SUPPLY,
+       SR_CONF_CONTINUOUS,
+       SR_CONF_OUTPUT_CHANNEL,
+       SR_CONF_OVER_CURRENT_PROTECTION,
+};
+
+static const int32_t devopts_cg[] = {
+       SR_CONF_OUTPUT_VOLTAGE,
+       SR_CONF_OUTPUT_VOLTAGE_MAX,
+       SR_CONF_OUTPUT_CURRENT,
+       SR_CONF_OUTPUT_CURRENT_MAX,
+       SR_CONF_OUTPUT_ENABLED,
+};
+
+static const char *channel_modes[] = {
+       "Independent",
+       "Series",
+       "Parallel",
+};
+
+static struct pps_model models[] = {
+       { PPS_3203T_3S, "PPS3203T-3S",
+               CHANMODE_INDEPENDENT | CHANMODE_SERIES | CHANMODE_PARALLEL,
+               3,
+               {
+                       /* Channel 1 */
+                       { { 0, 32, 0.01 }, { 0, 3, 0.001 } },
+                       /* Channel 2 */
+                       { { 0, 32, 0.01 }, { 0, 3, 0.001 } },
+                       /* Channel 3 */
+                       { { 0, 6, 0.01 }, { 0, 3, 0.001 } },
+               },
+       },
+};
+
+
+SR_PRIV struct sr_dev_driver atten_pps3203_driver_info;
+static struct sr_dev_driver *di = &atten_pps3203_driver_info;
+
+static int init(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options, int modelid)
+{
+       struct sr_dev_inst *sdi;
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       struct sr_config *src;
+       struct sr_channel *ch;
+       struct sr_channel_group *cg;
+       struct sr_serial_dev_inst *serial;
+       GSList *l, *devices;
+       struct pps_model *model;
+       uint8_t packet[PACKET_SIZE];
+       unsigned int i;
+       int ret;
+       const char *conn, *serialcomm;
+       char channel[10];
+
+       devices = NULL;
+       drvc = di->priv;
+       drvc->instances = NULL;
+
+       conn = serialcomm = NULL;
+       for (l = options; l; l = l->next) {
+               src = l->data;
+               switch (src->key) {
+               case SR_CONF_CONN:
+                       conn = g_variant_get_string(src->data, NULL);
+                       break;
+               case SR_CONF_SERIALCOMM:
+                       serialcomm = g_variant_get_string(src->data, NULL);
+                       break;
+               }
+       }
+       if (!conn)
+               return NULL;
+       if (!serialcomm)
+               serialcomm = SERIALCOMM;
+
+       if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
+               return NULL;
+
+       if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
+               return NULL;
+       serial_flush(serial);
+
+       /* This is how the vendor software channels for hardware. */
+       memset(packet, 0, PACKET_SIZE);
+       packet[0] = 0xaa;
+       packet[1] = 0xaa;
+       if (serial_write(serial, packet, PACKET_SIZE) == -1) {
+               sr_err("Unable to write while probing for hardware: %s",
+                               strerror(errno));
+               return NULL;
+       }
+       /* The device responds with a 24-byte packet when it receives a packet.
+        * At 9600 baud, 300ms is long enough for it to have arrived. */
+       g_usleep(300 * 1000);
+       memset(packet, 0, PACKET_SIZE);
+       if ((ret = serial_read_nonblocking(serial, packet, PACKET_SIZE)) < 0) {
+               sr_err("Unable to read while probing for hardware: %s",
+                               strerror(errno));
+               return NULL;
+       }
+       if (ret != PACKET_SIZE || packet[0] != 0xaa || packet[1] != 0xaa) {
+               /* Doesn't look like an Atten PPS. */
+               return NULL;
+       }
+
+       model = NULL;
+       for (i = 0; i < ARRAY_SIZE(models); i++) {
+               if (models[i].modelid == modelid) {
+                       model = &models[i];
+                       break;
+               }
+       }
+       if (!model) {
+               sr_err("Unknown modelid %d", modelid);
+               return NULL;
+       }
+
+       sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "Atten", model->name, NULL);
+       sdi->driver = di;
+       sdi->inst_type = SR_INST_SERIAL;
+       sdi->conn = serial;
+       for (i = 0; i < MAX_CHANNELS; i++) {
+               snprintf(channel, 10, "CH%d", i + 1);
+               ch = sr_channel_new(i, SR_CHANNEL_ANALOG, TRUE, channel);
+               sdi->channels = g_slist_append(sdi->channels, ch);
+               cg = g_malloc(sizeof(struct sr_channel_group));
+               cg->name = g_strdup(channel);
+               cg->channels = g_slist_append(NULL, ch);
+               cg->priv = NULL;
+               sdi->channel_groups = g_slist_append(sdi->channel_groups, cg);
+       }
+
+       devc = g_malloc0(sizeof(struct dev_context));
+       devc->model = model;
+       devc->config = g_malloc0(sizeof(struct per_channel_config) * model->num_channels);
+       sdi->priv = devc;
+       drvc->instances = g_slist_append(drvc->instances, sdi);
+       devices = g_slist_append(devices, sdi);
+
+       serial_close(serial);
+       if (!devices)
+               sr_serial_dev_inst_free(serial);
+
+       return devices;
+}
+
+static GSList *scan_3203(GSList *options)
+{
+       return scan(options, PPS_3203T_3S);
+}
+
+static GSList *dev_list(void)
+{
+       return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int cleanup(void)
+{
+       return std_dev_clear(di, NULL);
+}
+
+static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       struct sr_channel *ch;
+       int channel, ret;
+
+       if (!sdi)
+               return SR_ERR_ARG;
+
+       devc = sdi->priv;
+
+       ret = SR_OK;
+       if (!cg) {
+               /* No channel group: global options. */
+               switch (key) {
+               case SR_CONF_OUTPUT_CHANNEL:
+                       *data = g_variant_new_string(channel_modes[devc->channel_mode]);
+                       break;
+               case SR_CONF_OVER_CURRENT_PROTECTION:
+                       *data = g_variant_new_boolean(devc->over_current_protection);
+                       break;
+               default:
+                       return SR_ERR_NA;
+               }
+       } else {
+               /* We only ever have one channel per channel group in this driver. */
+               ch = cg->channels->data;
+               channel = ch->index;
+
+               switch (key) {
+               case SR_CONF_OUTPUT_VOLTAGE:
+                       *data = g_variant_new_double(devc->config[channel].output_voltage_last);
+                       break;
+               case SR_CONF_OUTPUT_VOLTAGE_MAX:
+                       *data = g_variant_new_double(devc->config[channel].output_voltage_max);
+                       break;
+               case SR_CONF_OUTPUT_CURRENT:
+                       *data = g_variant_new_double(devc->config[channel].output_current_last);
+                       break;
+               case SR_CONF_OUTPUT_CURRENT_MAX:
+                       *data = g_variant_new_double(devc->config[channel].output_current_max);
+                       break;
+               case SR_CONF_OUTPUT_ENABLED:
+                       *data = g_variant_new_boolean(devc->config[channel].output_enabled);
+                       break;
+               default:
+                       return SR_ERR_NA;
+               }
+       }
+
+       return ret;
+}
+
+static int find_str(const char *str, const char **strings, int array_size)
+{
+       int idx, i;
+
+       idx = -1;
+       for (i = 0; i < array_size; i++) {
+               if (!strcmp(str, strings[i])) {
+                       idx = i;
+                       break;
+               }
+       }
+
+       return idx;
+}
+
+static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       struct sr_channel *ch;
+       gdouble dval;
+       int channel, ret, ival;
+       const char *sval;
+       gboolean bval;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       ret = SR_OK;
+       devc = sdi->priv;
+       if (!cg) {
+               /* No channel group: global options. */
+               switch (key) {
+               case SR_CONF_OUTPUT_CHANNEL:
+                       sval = g_variant_get_string(data, NULL);
+                       if ((ival = find_str(sval, channel_modes,
+                                                       ARRAY_SIZE(channel_modes))) == -1) {
+                               ret = SR_ERR_ARG;
+                               break;
+                       }
+                       if (devc->model->channel_modes && (1 << ival) == 0) {
+                               /* Not supported on this model. */
+                               ret = SR_ERR_ARG;
+                       }
+                       if (ival == devc->channel_mode_set)
+                               /* Nothing to do. */
+                               break;
+                       devc->channel_mode_set = ival;
+                       devc->config_dirty = TRUE;
+                       break;
+               case SR_CONF_OVER_CURRENT_PROTECTION:
+                       bval = g_variant_get_boolean(data);
+                       if (bval == devc->over_current_protection_set)
+                               /* Nothing to do. */
+                               break;
+                       devc->over_current_protection_set = bval;
+                       devc->config_dirty = TRUE;
+                       break;
+               default:
+                       return SR_ERR_NA;
+               }
+       } else {
+               /* Channel group specified: per-channel options. */
+               /* We only ever have one channel per channel group in this driver. */
+               ch = cg->channels->data;
+               channel = ch->index;
+
+               switch (key) {
+               case SR_CONF_OUTPUT_VOLTAGE_MAX:
+                       dval = g_variant_get_double(data);
+                       if (dval < 0 || dval > devc->model->channels[channel].voltage[1])
+                               ret = SR_ERR_ARG;
+                       devc->config[channel].output_voltage_max = dval;
+                       devc->config_dirty = TRUE;
+                       break;
+               case SR_CONF_OUTPUT_CURRENT_MAX:
+                       dval = g_variant_get_double(data);
+                       if (dval < 0 || dval > devc->model->channels[channel].current[1])
+                               ret = SR_ERR_ARG;
+                       devc->config[channel].output_current_max = dval;
+                       devc->config_dirty = TRUE;
+                       break;
+               case SR_CONF_OUTPUT_ENABLED:
+                       bval = g_variant_get_boolean(data);
+                       if (bval == devc->config[channel].output_enabled_set)
+                               /* Nothing to do. */
+                               break;
+                       devc->config[channel].output_enabled_set = bval;
+                       devc->config_dirty = TRUE;
+                       break;
+               default:
+                       ret = SR_ERR_NA;
+               }
+       }
+
+
+       return ret;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       struct sr_channel *ch;
+       GVariant *gvar;
+       GVariantBuilder gvb;
+       int channel, ret, i;
+
+       /* Always available, even without sdi. */
+       if (key == SR_CONF_SCAN_OPTIONS) {
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               scanopts, ARRAY_SIZE(scanopts), sizeof(int32_t));
+               return SR_OK;
+       }
+
+       if (!sdi)
+               return SR_ERR_ARG;
+       devc = sdi->priv;
+
+       ret = SR_OK;
+       if (!cg) {
+               /* No channel group: global options. */
+               switch (key) {
+               case SR_CONF_DEVICE_OPTIONS:
+                       *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                                       devopts, ARRAY_SIZE(devopts), sizeof(int32_t));
+                       break;
+               case SR_CONF_OUTPUT_CHANNEL:
+                       if (devc->model->channel_modes == CHANMODE_INDEPENDENT) {
+                               /* The 1-channel models. */
+                               *data = g_variant_new_strv(channel_modes, 1);
+                       } else {
+                               /* The other models support all modes. */
+                               *data = g_variant_new_strv(channel_modes, ARRAY_SIZE(channel_modes));
+                       }
+                       break;
+               default:
+                       return SR_ERR_NA;
+               }
+       } else {
+               /* Channel group specified: per-channel options. */
+               if (!sdi)
+                       return SR_ERR_ARG;
+               /* We only ever have one channel per channel group in this driver. */
+               ch = cg->channels->data;
+               channel = ch->index;
+
+               switch (key) {
+               case SR_CONF_DEVICE_OPTIONS:
+                       *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                                       devopts_cg, ARRAY_SIZE(devopts_cg), sizeof(int32_t));
+                       break;
+               case SR_CONF_OUTPUT_VOLTAGE_MAX:
+                       g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
+                       /* Min, max, step. */
+                       for (i = 0; i < 3; i++) {
+                               gvar = g_variant_new_double(devc->model->channels[channel].voltage[i]);
+                               g_variant_builder_add_value(&gvb, gvar);
+                       }
+                       *data = g_variant_builder_end(&gvb);
+                       break;
+               case SR_CONF_OUTPUT_CURRENT_MAX:
+                       g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
+                       /* Min, max, step. */
+                       for (i = 0; i < 3; i++) {
+                               gvar = g_variant_new_double(devc->model->channels[channel].current[i]);
+                               g_variant_builder_add_value(&gvb, gvar);
+                       }
+                       *data = g_variant_builder_end(&gvb);
+                       break;
+               default:
+                       return SR_ERR_NA;
+               }
+       }
+
+       return ret;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+
+       devc = sdi->priv;
+       if (devc->config_dirty)
+               /* Some configuration changes were queued up but didn't
+                * get sent to the device, likely because we were never
+                * in acquisition mode. Send them out now. */
+               send_config(sdi);
+
+       return std_serial_dev_close(sdi);
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi,
+               void *cb_data)
+{
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+       uint8_t packet[PACKET_SIZE];
+
+       (void)cb_data;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       devc = sdi->priv;
+       memset(devc->packet, 0x44, PACKET_SIZE);
+       devc->packet_size = 0;
+
+       devc->acquisition_running = TRUE;
+
+       serial = sdi->conn;
+       serial_source_add(sdi->session, serial, G_IO_IN, 50,
+                       atten_pps3xxx_receive_data, (void *)sdi);
+       std_session_send_df_header(cb_data, LOG_PREFIX);
+
+       /* Send a "channel" configuration packet now. */
+       memset(packet, 0, PACKET_SIZE);
+       packet[0] = 0xaa;
+       packet[1] = 0xaa;
+       send_packet(sdi, packet);
+
+       return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct dev_context *devc;
+
+       (void)cb_data;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       devc = sdi->priv;
+       devc->acquisition_running = FALSE;
+
+       return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver atten_pps3203_driver_info = {
+       .name = "atten-pps3203",
+       .longname = "Atten PPS3203T-3S",
+       .api_version = 1,
+       .init = init,
+       .cleanup = cleanup,
+       .scan = scan_3203,
+       .dev_list = dev_list,
+       .dev_clear = NULL,
+       .config_get = config_get,
+       .config_set = config_set,
+       .config_list = config_list,
+       .dev_open = std_serial_dev_open,
+       .dev_close = dev_close,
+       .dev_acquisition_start = dev_acquisition_start,
+       .dev_acquisition_stop = dev_acquisition_stop,
+       .priv = NULL,
+};
diff --git a/src/hardware/atten-pps3xxx/protocol.c b/src/hardware/atten-pps3xxx/protocol.c
new file mode 100644 (file)
index 0000000..ed4d550
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Bert Vermeulen <bert@biot.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 <string.h>
+#include <errno.h>
+#include "protocol.h"
+
+static void dump_packet(char *msg, uint8_t *packet)
+{
+       int i;
+       char str[128];
+
+       str[0] = 0;
+       for (i = 0; i < PACKET_SIZE; i++)
+               sprintf(str + strlen(str), "%.2x ", packet[i]);
+       sr_dbg("%s: %s", msg, str);
+
+}
+
+static void handle_packet(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_analog analog;
+       float value, data[MAX_CHANNELS];
+       int offset, i;
+
+       devc = sdi->priv;
+       dump_packet("received", devc->packet);
+       packet.type = SR_DF_ANALOG;
+       packet.payload = &analog;
+       analog.channels = sdi->channels;
+       analog.num_samples = 1;
+
+       analog.mq = SR_MQ_VOLTAGE;
+       analog.unit = SR_UNIT_VOLT;
+       analog.mqflags = SR_MQFLAG_DC;
+       analog.data = data;
+       for (i = 0; i < devc->model->num_channels; i++) {
+               offset = 2 + i * 4;
+               value = ((devc->packet[offset] << 8) + devc->packet[offset + 1]) / 100.0;
+               analog.data[i] = value;
+               devc->config[i].output_voltage_last = value;
+       }
+       sr_session_send(sdi, &packet);
+
+       analog.mq = SR_MQ_CURRENT;
+       analog.unit = SR_UNIT_AMPERE;
+       analog.mqflags = 0;
+       analog.data = data;
+       for (i = 0; i < devc->model->num_channels; i++) {
+               offset = 4 + i * 4;
+               value = ((devc->packet[offset] << 8) + devc->packet[offset + 1]) / 1000.0;
+               analog.data[i] = value;
+               devc->config[i].output_current_last = value;
+       }
+       sr_session_send(sdi, &packet);
+
+       for (i = 0; i < devc->model->num_channels; i++)
+               devc->config[i].output_enabled = (devc->packet[15] & (1 << i)) ? TRUE : FALSE;
+
+       devc->over_current_protection = devc->packet[18] ? TRUE : FALSE;
+       if (devc->packet[19] < 3)
+               devc->channel_mode = devc->packet[19];
+
+}
+
+SR_PRIV void send_packet(const struct sr_dev_inst *sdi, uint8_t *packet)
+{
+       struct sr_serial_dev_inst *serial;
+
+       serial = sdi->conn;
+       if (serial_write(serial, packet, PACKET_SIZE) == -1)
+               sr_dbg("Failed to send packet: %s", strerror(errno));
+       dump_packet("sent", packet);
+}
+
+SR_PRIV void send_config(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       uint8_t packet[PACKET_SIZE];
+       int value, offset, i;
+
+       devc = sdi->priv;
+       memset(packet, 0, PACKET_SIZE);
+       packet[0] = 0xaa;
+       packet[1] = 0x20;
+       packet[14] = 0x01;
+       packet[16] = 0x01;
+       for (i = 0; i < devc->model->num_channels; i++) {
+               offset = 2 + i * 4;
+               value = devc->config[i].output_voltage_max * 100;
+               packet[offset] = (value >> 8) & 0xff;
+               packet[offset + 1] = value & 0xff;
+               value = devc->config[i].output_current_max * 1000;
+               packet[offset + 2] = (value >> 8) & 0xff;
+               packet[offset + 3] = value & 0xff;
+               if (devc->config[i].output_enabled_set)
+                       packet[15] |= 1 << i;
+       }
+       packet[18] = devc->over_current_protection_set ? 1 : 0;
+       packet[19] = devc->channel_mode_set;
+       /* Checksum. */
+       value = 0;
+       for (i = 0; i < PACKET_SIZE - 1; i++)
+               value += packet[i];
+       packet[i] = value & 0xff;
+       send_packet(sdi, packet);
+       devc->config_dirty = FALSE;
+
+}
+
+SR_PRIV int atten_pps3xxx_receive_data(int fd, int revents, void *cb_data)
+{
+       struct dev_context *devc;
+       const struct sr_dev_inst *sdi;
+       struct sr_serial_dev_inst *serial;
+       struct sr_datafeed_packet packet;
+       unsigned char c;
+
+       (void)fd;
+
+       if (!(sdi = cb_data))
+               return TRUE;
+
+       if (!(devc = sdi->priv))
+               return TRUE;
+
+       serial = sdi->conn;
+       if (revents == G_IO_IN) {
+               if (serial_read_nonblocking(serial, &c, 1) < 0)
+                       return TRUE;
+               devc->packet[devc->packet_size++] = c;
+               if (devc->packet_size == PACKET_SIZE) {
+                       handle_packet(sdi);
+                       devc->packet_size = 0;
+                       if (devc->acquisition_running)
+                               send_config(sdi);
+                       else {
+                               serial_source_remove(sdi->session, serial);
+                               packet.type = SR_DF_END;
+                               sr_session_send(sdi, &packet);
+                       }
+               }
+       }
+
+       return TRUE;
+}
+
diff --git a/src/hardware/atten-pps3xxx/protocol.h b/src/hardware/atten-pps3xxx/protocol.h
new file mode 100644 (file)
index 0000000..1441305
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Bert Vermeulen <bert@biot.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_ATTEN_PPS3XXX_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_ATTEN_PPS3XXX_PROTOCOL_H
+
+#include <stdint.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "atten-pps3xxx"
+
+/* Packets to/from the device. */
+#define PACKET_SIZE 24
+
+enum {
+       PPS_3203T_3S,
+       PPS_3203T_2S,
+       PPS_3205T_3S,
+       PPS_3205T_2S,
+       PPS_3003S,
+       PPS_3005S,
+};
+
+/* Maximum number of output channels handled by this driver. */
+#define MAX_CHANNELS 3
+
+#define CHANMODE_INDEPENDENT 1 << 0
+#define CHANMODE_SERIES      1 << 1
+#define CHANMODE_PARALLEL    1 << 2
+
+struct channel_spec {
+       /* Min, max, step. */
+       gdouble voltage[3];
+       gdouble current[3];
+};
+
+struct pps_model {
+       int modelid;
+       char *name;
+       int channel_modes;
+       int num_channels;
+       struct channel_spec channels[MAX_CHANNELS];
+};
+
+struct per_channel_config {
+       /* Received from device. */
+       gdouble output_voltage_last;
+       gdouble output_current_last;
+       gboolean output_enabled;
+       /* Set by frontend. */
+       gdouble output_voltage_max;
+       gdouble output_current_max;
+       gboolean output_enabled_set;
+};
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+       /* Model-specific information */
+       struct pps_model *model;
+
+       /* Acquisition state */
+       gboolean acquisition_running;
+
+       /* Operational state */
+       gboolean config_dirty;
+       struct per_channel_config *config;
+       /* Received from device. */
+       int channel_mode;
+       gboolean over_current_protection;
+       /* Set by frontend. */
+       int channel_mode_set;
+       gboolean over_current_protection_set;
+
+       /* Temporary state across callbacks */
+       uint8_t packet[PACKET_SIZE];
+       int packet_size;
+
+};
+
+SR_PRIV int atten_pps3xxx_receive_data(int fd, int revents, void *cb_data);
+SR_PRIV void send_packet(const struct sr_dev_inst *sdi, uint8_t *packet);
+SR_PRIV void send_config(const struct sr_dev_inst *sdi);
+
+#endif
diff --git a/src/hardware/beaglelogic/api.c b/src/hardware/beaglelogic/api.c
new file mode 100644 (file)
index 0000000..c86925b
--- /dev/null
@@ -0,0 +1,413 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 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"
+
+SR_PRIV struct sr_dev_driver beaglelogic_driver_info;
+static struct sr_dev_driver *di = &beaglelogic_driver_info;
+
+/* Hardware capabiities */
+static const int32_t hwcaps[] = {
+       SR_CONF_LOGIC_ANALYZER,
+       SR_CONF_SAMPLERATE,
+       SR_CONF_TRIGGER_MATCH,
+
+       SR_CONF_LIMIT_SAMPLES,
+       SR_CONF_CONTINUOUS,
+
+       SR_CONF_NUM_LOGIC_CHANNELS,
+};
+
+/* Trigger matching capabilities */
+static const int32_t soft_trigger_matches[] = {
+       SR_TRIGGER_ZERO,
+       SR_TRIGGER_ONE,
+       SR_TRIGGER_RISING,
+       SR_TRIGGER_FALLING,
+       SR_TRIGGER_EDGE,
+};
+
+/* Channels are numbered 0-13 */
+SR_PRIV const char *beaglelogic_channel_names[NUM_CHANNELS + 1] = {
+       "P8_45", "P8_46", "P8_43", "P8_44", "P8_41", "P8_42", "P8_39", "P8_40",
+       "P8_27", "P8_29", "P8_28", "P8_30", "P8_21", "P8_20", NULL,
+};
+
+/* Possible sample rates : 10 Hz to 100 MHz = (100 / x) MHz */
+static const uint64_t samplerates[] = {
+               SR_HZ(10),
+               SR_MHZ(100),
+               SR_HZ(1),
+};
+
+static int init(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static struct dev_context * beaglelogic_devc_alloc(void)
+{
+       struct dev_context *devc;
+
+       /* Allocate zeroed structure */
+       devc = g_try_malloc0(sizeof(*devc));
+
+       /* Default non-zero values (if any) */
+       devc->fd = -1;
+       devc->limit_samples = (uint64_t)-1;
+
+       return devc;
+}
+
+static GSList *scan(GSList *options)
+{
+       struct drv_context *drvc;
+       GSList *devices, *l;
+       struct sr_config *src;
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       struct sr_channel *ch;
+       int i, maxch;
+
+       devices = NULL;
+       drvc = di->priv;
+       drvc->instances = NULL;
+
+       /* Probe for /dev/beaglelogic */
+       if (!g_file_test(BEAGLELOGIC_DEV_NODE, G_FILE_TEST_EXISTS))
+               return NULL;
+
+       sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, NULL, "BeagleLogic", "1.0");
+       sdi->driver = di;
+
+       /* Unless explicitly specified, keep max channels to 8 only */
+       maxch = 8;
+       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);
+       }
+
+       /* 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 */
+       for (i = 0; i < maxch; i++) {
+               if (!(ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE,
+                               beaglelogic_channel_names[i])))
+                       return NULL;
+               sdi->channels = g_slist_append(sdi->channels, ch);
+       }
+
+       sdi->priv = devc;
+       drvc->instances = g_slist_append(drvc->instances, sdi);
+       devices = g_slist_append(devices, sdi);
+
+       return devices;
+}
+
+static GSList *dev_list(void)
+{
+       return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int dev_clear(void)
+{
+       return std_dev_clear(di, NULL);
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc = sdi->priv;
+
+       /* Open BeagleLogic */
+       if (beaglelogic_open_nonblock(devc))
+               return SR_ERR;
+
+       /* Set fd and local attributes */
+       devc->pollfd.fd = devc->fd;
+       devc->pollfd.events = G_IO_IN;
+
+       /* Get the default attributes */
+       beaglelogic_get_samplerate(devc);
+       beaglelogic_get_sampleunit(devc);
+       beaglelogic_get_triggerflags(devc);
+       beaglelogic_get_buffersize(devc);
+       beaglelogic_get_bufunitsize(devc);
+
+       /* Map the kernel capture FIFO for reads, saves 1 level of memcpy */
+       if (beaglelogic_mmap(devc) != SR_OK) {
+               sr_err("Unable to map capture buffer");
+               beaglelogic_close(devc);
+               return SR_ERR;
+       }
+
+       /* We're good to go now */
+       sdi->status = SR_ST_ACTIVE;
+       return SR_OK;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc = sdi->priv;
+
+       if (sdi->status == SR_ST_ACTIVE) {
+               /* Close the memory mapping and the file */
+               beaglelogic_munmap(devc);
+               beaglelogic_close(devc);
+       }
+       sdi->status = SR_ST_INACTIVE;
+       return SR_OK;
+}
+
+static int cleanup(void)
+{
+       struct drv_context *drvc;
+       struct sr_dev_inst *sdi;
+       GSList *l;
+
+       /* unused driver */
+       if (!(drvc = di->priv))
+               return SR_OK;
+
+       /* Clean up the instances */
+       for (l = drvc->instances; l; l = l->next) {
+               sdi = l->data;
+               di->dev_close(sdi);
+               g_free(sdi->priv);
+               sr_dev_inst_free(sdi);
+       }
+       g_slist_free(drvc->instances);
+       drvc->instances = NULL;
+
+       di->priv = NULL;
+
+       return SR_OK;
+}
+
+static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc = sdi->priv;
+       (void)cg;
+
+       switch (key) {
+       case SR_CONF_LIMIT_SAMPLES:
+               *data = g_variant_new_uint64(devc->limit_samples);
+               break;
+
+       case SR_CONF_SAMPLERATE:
+               *data = g_variant_new_uint64(devc->cur_samplerate);
+               break;
+
+       case SR_CONF_NUM_LOGIC_CHANNELS:
+               *data = g_variant_new_uint32(g_slist_length(sdi->channels));
+               break;
+
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc = sdi->priv;
+       uint64_t tmp_u64;
+       (void)cg;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       switch (key) {
+       case SR_CONF_SAMPLERATE:
+               devc->cur_samplerate = g_variant_get_uint64(data);
+               return beaglelogic_set_samplerate(devc);
+
+       case SR_CONF_LIMIT_SAMPLES:
+               tmp_u64 = g_variant_get_uint64(data);
+               devc->limit_samples = tmp_u64;
+               devc->triggerflags = BL_TRIGGERFLAGS_ONESHOT;
+
+               /* Check if we have sufficient buffer size */
+               tmp_u64 *= SAMPLEUNIT_TO_BYTES(devc->sampleunit);
+               if (tmp_u64 > devc->buffersize) {
+                       sr_warn("Insufficient buffer space has been allocated.");
+                       sr_warn("Please use \'echo <size in bytes> > "\
+                               BEAGLELOGIC_SYSFS_ATTR(memalloc) \
+                               "\' as root to increase the buffer size, this"\
+                               " capture is now truncated to %d Msamples",
+                               devc->buffersize /
+                               (SAMPLEUNIT_TO_BYTES(devc->sampleunit) * 1000000));
+               }
+               return beaglelogic_set_triggerflags(devc);
+
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       int ret;
+       GVariant *gvar;
+       GVariantBuilder gvb;
+
+       (void)sdi;
+       (void)data;
+       (void)cg;
+
+       ret = SR_OK;
+       switch (key) {
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+               break;
+       case SR_CONF_SAMPLERATE:
+               g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
+               gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"),
+                       samplerates, ARRAY_SIZE(samplerates), sizeof(uint64_t));
+               g_variant_builder_add(&gvb, "{sv}", "samplerate-steps", gvar);
+               *data = g_variant_builder_end(&gvb);
+               break;
+       case SR_CONF_TRIGGER_MATCH:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               soft_trigger_matches, ARRAY_SIZE(soft_trigger_matches),
+                               sizeof(int32_t));
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return ret;
+}
+
+/* get a sane timeout for poll() */
+#define BUFUNIT_TIMEOUT_MS(devc)       (100 + ((devc->bufunitsize * 1000) / \
+                               (uint32_t)(devc->cur_samplerate)))
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi,
+                                   void *cb_data)
+{
+       (void)cb_data;
+       struct dev_context *devc = sdi->priv;
+       struct sr_trigger *trigger;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       /* Save user pointer */
+       devc->cb_data = cb_data;
+
+       /* Clear capture state */
+       devc->bytes_read = 0;
+       devc->offset = 0;
+
+       /* Configure channels */
+       devc->sampleunit = g_slist_length(sdi->channels) > 8 ?
+                       BL_SAMPLEUNIT_16_BITS : BL_SAMPLEUNIT_8_BITS;
+       beaglelogic_set_sampleunit(devc);
+
+       /* Configure triggers & send header packet */
+       if ((trigger = sr_session_trigger_get(sdi->session))) {
+               devc->stl = soft_trigger_logic_new(sdi, trigger);
+               devc->trigger_fired = FALSE;
+       } else
+               devc->trigger_fired = TRUE;
+       std_session_send_df_header(cb_data, LOG_PREFIX);
+
+       /* Trigger and add poll on file */
+       beaglelogic_start(devc);
+       sr_session_source_add_pollfd(sdi->session, &devc->pollfd,
+                       BUFUNIT_TIMEOUT_MS(devc), beaglelogic_receive_data,
+                       (void *)sdi);
+
+       return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct dev_context *devc = sdi->priv;
+       struct sr_datafeed_packet pkt;
+
+       (void)cb_data;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       /* Execute a stop on BeagleLogic */
+       beaglelogic_stop(devc);
+
+       /* lseek to offset 0, flushes the cache */
+       lseek(devc->fd, 0, SEEK_SET);
+
+       /* Remove session source and send EOT packet */
+       sr_session_source_remove_pollfd(sdi->session, &devc->pollfd);
+       pkt.type = SR_DF_END;
+       pkt.payload = NULL;
+       sr_session_send(sdi, &pkt);
+
+       return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver beaglelogic_driver_info = {
+       .name = "beaglelogic",
+       .longname = "BeagleLogic",
+       .api_version = 1,
+       .init = init,
+       .cleanup = cleanup,
+       .scan = scan,
+       .dev_list = dev_list,
+       .dev_clear = dev_clear,
+       .config_get = config_get,
+       .config_set = config_set,
+       .config_list = config_list,
+       .dev_open = dev_open,
+       .dev_close = dev_close,
+       .dev_acquisition_start = dev_acquisition_start,
+       .dev_acquisition_stop = dev_acquisition_stop,
+       .priv = NULL,
+};
diff --git a/src/hardware/beaglelogic/beaglelogic.h b/src/hardware/beaglelogic/beaglelogic.h
new file mode 100644 (file)
index 0000000..12e2f48
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 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/>.
+ */
+
+#ifndef BEAGLELOGIC_H_
+#define BEAGLELOGIC_H_
+
+#include <fcntl.h>
+
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+
+#include <stdlib.h>
+
+#include <unistd.h>
+
+/* BeagleLogic device node name */
+#define BEAGLELOGIC_DEV_NODE        "/dev/beaglelogic"
+#define BEAGLELOGIC_SYSFS_ATTR(a)   "/sys/devices/virtual/misc/beaglelogic/"\
+                                       __STRING(a)
+
+/* Reproduced verbatim from beaglelogic.h in the kernel tree until the kernel
+ * module hits the mainline. Contains the ABI, so DO NOT TOUCH this section */
+
+/* ioctl calls that can be issued on /dev/beaglelogic */
+#define IOCTL_BL_GET_VERSION        _IOR('k', 0x20, uint32_t)
+
+#define IOCTL_BL_GET_SAMPLE_RATE    _IOR('k', 0x21, uint32_t)
+#define IOCTL_BL_SET_SAMPLE_RATE    _IOW('k', 0x21, uint32_t)
+
+#define IOCTL_BL_GET_SAMPLE_UNIT    _IOR('k', 0x22, uint32_t)
+#define IOCTL_BL_SET_SAMPLE_UNIT    _IOW('k', 0x22, 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_CACHE_INVALIDATE    _IO('k', 0x25)
+
+#define IOCTL_BL_GET_BUFFER_SIZE    _IOR('k', 0x26, uint32_t)
+#define IOCTL_BL_SET_BUFFER_SIZE    _IOW('k', 0x26, uint32_t)
+
+#define IOCTL_BL_GET_BUFUNIT_SIZE   _IOR('k', 0x27, uint32_t)
+
+#define IOCTL_BL_FILL_TEST_PATTERN   _IO('k', 0x28)
+
+#define IOCTL_BL_START               _IO('k', 0x29)
+#define IOCTL_BL_STOP                _IO('k', 0x2A)
+
+/* Possible States of BeagleLogic */
+enum beaglelogic_states {
+       STATE_BL_DISABLED,      /* Powered off (at module start) */
+       STATE_BL_INITIALIZED,   /* Powered on */
+       STATE_BL_MEMALLOCD,     /* Buffers allocated */
+       STATE_BL_ARMED,         /* All Buffers DMA-mapped and configuration done */
+       STATE_BL_RUNNING,       /* Data being captured */
+       STATE_BL_REQUEST_STOP,  /* Stop requested */
+       STATE_BL_ERROR          /* Buffer overrun */
+};
+
+/* Setting attributes */
+enum beaglelogic_triggerflags {
+       BL_TRIGGERFLAGS_ONESHOT = 0,
+       BL_TRIGGERFLAGS_CONTINUOUS
+};
+
+/* Possible sample unit / formats */
+enum beaglelogic_sampleunit {
+       BL_SAMPLEUNIT_16_BITS = 0,
+       BL_SAMPLEUNIT_8_BITS
+};
+/* END beaglelogic.h */
+
+/* For all the functions below:
+ * Parameters:
+ *     devc : Device context structure to operate on
+ * Returns:
+ *     SR_OK or SR_ERR
+ */
+
+SR_PRIV int beaglelogic_open_nonblock(struct dev_context *devc);
+SR_PRIV int beaglelogic_close(struct dev_context *devc);
+
+SR_PRIV int beaglelogic_get_buffersize(struct dev_context *devc);
+SR_PRIV int beaglelogic_set_buffersize(struct dev_context *devc);
+
+SR_PRIV int beaglelogic_get_samplerate(struct dev_context *devc);
+SR_PRIV int beaglelogic_set_samplerate(struct dev_context *devc);
+
+SR_PRIV int beaglelogic_get_sampleunit(struct dev_context *devc);
+SR_PRIV int beaglelogic_set_sampleunit(struct dev_context *devc);
+
+SR_PRIV int beaglelogic_get_triggerflags(struct dev_context *devc);
+SR_PRIV int beaglelogic_set_triggerflags(struct dev_context *devc);
+
+/* Start and stop the capture operation */
+SR_PRIV int beaglelogic_start(struct dev_context *devc);
+SR_PRIV int beaglelogic_stop(struct dev_context *devc);
+
+/* Get the last error size */
+SR_PRIV int beaglelogic_getlasterror(struct dev_context *devc);
+
+/* Gets the unit size of the capture buffer (usually 4 or 8 MB) */
+SR_PRIV int beaglelogic_get_bufunitsize(struct dev_context *devc);
+
+SR_PRIV int beaglelogic_mmap(struct dev_context *devc);
+SR_PRIV int beaglelogic_munmap(struct dev_context *devc);
+
+/* Sources */
+SR_PRIV inline int beaglelogic_open_nonblock(struct dev_context *devc) {
+       devc->fd = open(BEAGLELOGIC_DEV_NODE, O_RDONLY | O_NONBLOCK);
+       return (devc->fd == -1 ? SR_ERR : SR_OK);
+}
+
+SR_PRIV inline int beaglelogic_close(struct dev_context *devc) {
+       return close(devc->fd);
+}
+
+SR_PRIV inline int beaglelogic_get_buffersize(struct dev_context *devc) {
+       return ioctl(devc->fd, IOCTL_BL_GET_BUFFER_SIZE, &devc->buffersize);
+}
+
+SR_PRIV inline int beaglelogic_set_buffersize(struct dev_context *devc) {
+       return ioctl(devc->fd, IOCTL_BL_SET_BUFFER_SIZE, devc->buffersize);
+}
+
+/* This is treated differently as it gets a uint64_t while a uint32_t is read */
+SR_PRIV inline int beaglelogic_get_samplerate(struct dev_context *devc) {
+       uint32_t arg, err;
+       err = ioctl(devc->fd, IOCTL_BL_GET_SAMPLE_RATE, &arg);
+       devc->cur_samplerate = arg;
+       return err;
+}
+
+SR_PRIV inline int beaglelogic_set_samplerate(struct dev_context *devc) {
+       return ioctl(devc->fd, IOCTL_BL_SET_SAMPLE_RATE,
+                       (uint32_t)devc->cur_samplerate);
+}
+
+SR_PRIV inline int beaglelogic_get_sampleunit(struct dev_context *devc) {
+       return ioctl(devc->fd, IOCTL_BL_GET_SAMPLE_UNIT, &devc->sampleunit);
+}
+
+SR_PRIV inline int beaglelogic_set_sampleunit(struct dev_context *devc) {
+       return ioctl(devc->fd, IOCTL_BL_SET_SAMPLE_UNIT, devc->sampleunit);
+}
+
+SR_PRIV inline int beaglelogic_get_triggerflags(struct dev_context *devc) {
+       return ioctl(devc->fd, IOCTL_BL_GET_TRIGGER_FLAGS, &devc->triggerflags);
+}
+
+SR_PRIV inline int beaglelogic_set_triggerflags(struct dev_context *devc) {
+       return ioctl(devc->fd, IOCTL_BL_SET_TRIGGER_FLAGS, devc->triggerflags);
+}
+
+SR_PRIV int beaglelogic_getlasterror(struct dev_context *devc) {
+       int fd;
+       char buf[16];
+       int ret;
+
+       if ((fd = open(BEAGLELOGIC_SYSFS_ATTR(lasterror), O_RDONLY)) == -1)
+               return SR_ERR;
+
+       if ((ret = read(fd, buf, 16)) < 0)
+               return SR_ERR;
+
+       close(fd);
+       devc->last_error = strtoul(buf, NULL, 10);
+
+       return SR_OK;
+}
+
+SR_PRIV inline int beaglelogic_start(struct dev_context *devc) {
+       return ioctl(devc->fd, IOCTL_BL_START);
+}
+
+SR_PRIV inline int beaglelogic_stop(struct dev_context *devc) {
+       return ioctl(devc->fd, IOCTL_BL_STOP);
+}
+
+SR_PRIV int beaglelogic_get_bufunitsize(struct dev_context *devc) {
+       return ioctl(devc->fd, IOCTL_BL_GET_BUFUNIT_SIZE, &devc->bufunitsize);
+}
+
+SR_PRIV int beaglelogic_mmap(struct dev_context *devc) {
+       if (!devc->buffersize)
+               beaglelogic_get_buffersize(devc);
+       devc->sample_buf = mmap(NULL, devc->buffersize,
+                       PROT_READ, MAP_SHARED, devc->fd, 0);
+       return (devc->sample_buf == MAP_FAILED ? -1 : SR_OK);
+}
+
+SR_PRIV int beaglelogic_munmap(struct dev_context *devc) {
+       return munmap(devc->sample_buf, devc->buffersize);
+}
+
+#endif /* BEAGLELOGIC_H_ */
diff --git a/src/hardware/beaglelogic/protocol.c b/src/hardware/beaglelogic/protocol.c
new file mode 100644 (file)
index 0000000..1c01b64
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 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 <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/* Define data packet size independent of packet (bufunitsize bytes) size
+ * from the BeagleLogic kernel module */
+#define PACKET_SIZE    (512 * 1024)
+
+/* This implementation is zero copy from the libsigrok side.
+ * It does not copy any data, just passes a pointer from the mmap'ed
+ * kernel buffers appropriately. It is up to the application which is
+ * using libsigrok to decide how to deal with the data.
+ */
+SR_PRIV int beaglelogic_receive_data(int fd, int revents, void *cb_data)
+{
+       const struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_logic logic;
+
+       int trigger_offset;
+       uint32_t packetsize;
+       uint64_t bytes_remaining;
+
+       if (!(sdi = cb_data) || !(devc = sdi->priv))
+               return TRUE;
+
+       packetsize = PACKET_SIZE;
+       logic.unitsize = SAMPLEUNIT_TO_BYTES(devc->sampleunit);
+
+       if (revents == G_IO_IN) {
+               sr_info("In callback G_IO_IN, offset=%d", devc->offset);
+
+               bytes_remaining = (devc->limit_samples * logic.unitsize) -
+                               devc->bytes_read;
+
+               /* Configure data packet */
+               packet.type = SR_DF_LOGIC;
+               packet.payload = &logic;
+               logic.data = devc->sample_buf + devc->offset;
+               logic.length = MIN(packetsize, bytes_remaining);
+
+               if (devc->trigger_fired) {
+                       /* Send the incoming transfer to the session bus. */
+                       sr_session_send(devc->cb_data, &packet);
+               } else {
+                       /* Check for trigger */
+                       trigger_offset = soft_trigger_logic_check(devc->stl,
+                                               logic.data,
+                                               packetsize);
+
+                       if (trigger_offset > -1) {
+                               trigger_offset *= logic.unitsize;
+                               logic.length = MIN(packetsize - trigger_offset,
+                                               bytes_remaining);
+                               logic.data += trigger_offset;
+
+                               sr_session_send(devc->cb_data, &packet);
+
+                               devc->trigger_fired = TRUE;
+                       }
+               }
+
+               /* Move the read pointer forward */
+               lseek(fd, packetsize, SEEK_CUR);
+
+               /* 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)
+                               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 */
+               packet.type = SR_DF_END;
+               packet.payload = NULL;
+               sr_session_send(devc->cb_data, &packet);
+
+               sr_session_source_remove_pollfd(sdi->session, &devc->pollfd);
+       }
+
+       return TRUE;
+}
diff --git a/src/hardware/beaglelogic/protocol.h b/src/hardware/beaglelogic/protocol.h
new file mode 100644 (file)
index 0000000..f2acfeb
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 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/>.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_BEAGLELOGIC_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_BEAGLELOGIC_PROTOCOL_H
+
+#include <stdint.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "beaglelogic"
+
+/* Maximum possible input channels */
+#define NUM_CHANNELS            14
+
+#define SAMPLEUNIT_TO_BYTES(x) ((x) == 1 ? 1 : 2)
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+       /* Model-specific information */
+       int max_channels;
+       uint32_t fw_ver;
+
+       /* Acquisition settings: see beaglelogic.h */
+       uint64_t cur_samplerate;
+       uint64_t limit_samples;
+       uint32_t sampleunit;
+       uint32_t triggerflags;
+
+       /* Buffers: size of each buffer block and the total buffer area */
+       uint32_t bufunitsize;
+       uint32_t buffersize;
+
+       /* Operational state */
+       int fd;
+       GPollFD pollfd;
+       int last_error;
+
+       uint64_t bytes_read;
+       uint64_t sent_samples;
+       uint32_t offset;
+       uint8_t *sample_buf;    /* mmap'd kernel buffer here */
+
+       void *cb_data;
+
+       /* Trigger logic */
+       struct soft_trigger_logic *stl;
+       gboolean trigger_fired;
+};
+
+SR_PRIV int beaglelogic_receive_data(int fd, int revents, void *cb_data);
+
+#endif
diff --git a/src/hardware/brymen-bm86x/api.c b/src/hardware/brymen-bm86x/api.c
new file mode 100644 (file)
index 0000000..be21583
--- /dev/null
@@ -0,0 +1,316 @@
+/*
+ * 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 "protocol.h"
+
+#define BRYMEN_BC86X "0820.0001"
+
+static const int32_t hwopts[] = {
+       SR_CONF_CONN,
+};
+
+static const int32_t hwcaps[] = {
+       SR_CONF_MULTIMETER,
+       SR_CONF_LIMIT_SAMPLES,
+       SR_CONF_LIMIT_MSEC,
+       SR_CONF_CONTINUOUS,
+};
+
+SR_PRIV struct sr_dev_driver brymen_bm86x_driver_info;
+static struct sr_dev_driver *di = &brymen_bm86x_driver_info;
+
+static int init(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(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;
+       struct sr_channel *ch;
+       const char *conn;
+
+       drvc = di->priv;
+       drvc->instances = NULL;
+
+       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;
+
+               if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE,
+                                           "Brymen", "BM869", NULL))) {
+                       sr_err("sr_dev_inst_new returned NULL.");
+                       return NULL;
+               }
+
+               if (!(devc = g_try_malloc0(sizeof(*devc)))) {
+                       sr_err("Device context malloc failed.");
+                       return NULL;
+               }
+
+               sdi->priv = devc;
+               sdi->driver = di;
+               if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1")))
+                       return NULL;
+               sdi->channels = g_slist_append(sdi->channels, ch);
+               if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P2")))
+                       return NULL;
+               sdi->channels = g_slist_append(sdi->channels, ch);
+
+               sdi->inst_type = SR_INST_USB;
+               sdi->conn = usb;
+
+               drvc->instances = g_slist_append(drvc->instances, sdi);
+               devices = g_slist_append(devices, sdi);
+       }
+
+       return devices;
+}
+
+static GSList *dev_list(void)
+{
+       return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+       struct drv_context *drvc = di->priv;
+       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;
+
+       /* 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;
+
+       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 cleanup(void)
+{
+       return std_dev_clear(di, NULL);
+}
+
+static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc = sdi->priv;
+
+       (void)cg;
+
+       switch (key) {
+       case SR_CONF_LIMIT_SAMPLES:
+               *data = g_variant_new_uint64(devc->limit_samples);
+               break;
+       case SR_CONF_LIMIT_MSEC:
+               *data = g_variant_new_uint64(devc->limit_msec);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_set(int 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;
+
+       if (!(devc = sdi->priv)) {
+               sr_err("sdi->priv was NULL.");
+               return SR_ERR_BUG;
+       }
+
+       switch (key) {
+       case SR_CONF_LIMIT_SAMPLES:
+               devc->limit_samples = g_variant_get_uint64(data);
+               sr_dbg("Setting sample limit to %" PRIu64 ".", devc->limit_samples);
+               break;
+       case SR_CONF_LIMIT_MSEC:
+               devc->limit_msec = g_variant_get_uint64(data);
+               sr_dbg("Setting time limit to %" PRIu64 "ms.", devc->limit_msec);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_list(int 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_INT32,
+                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+               break;
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi,
+                                   void *cb_data)
+{
+       struct dev_context *devc;
+
+       (void)cb_data;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       devc = sdi->priv;
+       devc->start_time = g_get_monotonic_time();
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(sdi, LOG_PREFIX);
+
+       sr_session_source_add(sdi->session, 0, 0, 10,
+                       brymen_bm86x_receive_data, (void *)sdi);
+
+       return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct sr_datafeed_packet packet;
+
+       (void)cb_data;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       /* Send end packet to the session bus. */
+       packet.type = SR_DF_END;
+       sr_session_send(sdi, &packet);
+
+       sr_session_source_remove(sdi->session, 0);
+
+       return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver brymen_bm86x_driver_info = {
+       .name = "brymen-bm86x",
+       .longname = "Brymen BM86X",
+       .api_version = 1,
+       .init = init,
+       .cleanup = cleanup,
+       .scan = scan,
+       .dev_list = 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,
+       .priv = NULL,
+};
diff --git a/src/hardware/brymen-bm86x/protocol.c b/src/hardware/brymen-bm86x/protocol.c
new file mode 100644 (file)
index 0000000..b8e16a3
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * 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 <string.h>
+#include <math.h>
+#include "protocol.h"
+
+#define USB_TIMEOUT 500
+
+static 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 flag)
+{
+       char c, *p = str;
+       int i, ret;
+
+       if (buf[0] & flag)
+               *p++ = '-';
+       for (i = 0; i < length; i++) {
+               if (i && i < 5 && buf[i+1] & 0x01)
+                       *p++ = '.';
+               c = char_map[buf[i+1] >> 1];
+               if (i == 5 && (c == 'C' || c == 'F'))
+                       *temp_unit = c;
+               else if (c)
+                       *p++ = c;
+       }
+       *p = 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, over_limit;
+
+       ret1 = brymen_bm86x_parse_digits(buf+2, 6, str, &floatval[0],
+                                        &temp_unit, 0x80);
+       over_limit = strstr(str, "0L") || strstr(str, "0.L");
+       ret2 = brymen_bm86x_parse_digits(buf+9, 4, str, &floatval[1],
+                                        &temp_unit, 0x10);
+
+       /* main display */
+       if (ret1 == SR_OK || over_limit) {
+               /* SI unit */
+               if (buf[8] & 0x01) {
+                       analog[0].mq = SR_MQ_VOLTAGE;
+                       analog[0].unit = SR_UNIT_VOLT;
+                       if (!strcmp(str, "diod"))
+                               analog[0].mqflags |= SR_MQFLAG_DIODE;
+               } else if (buf[14] & 0x80) {
+                       analog[0].mq = SR_MQ_CURRENT;
+                       analog[0].unit = SR_UNIT_AMPERE;
+               } else if (buf[14] & 0x20) {
+                       analog[0].mq = SR_MQ_CAPACITANCE;
+                       analog[0].unit = SR_UNIT_FARAD;
+               } else if (buf[14] & 0x10) {
+                       analog[0].mq = SR_MQ_CONDUCTANCE;
+                       analog[0].unit = SR_UNIT_SIEMENS;
+               } else if (buf[15] & 0x01) {
+                       analog[0].mq = SR_MQ_FREQUENCY;
+                       analog[0].unit = SR_UNIT_HERTZ;
+               } else if (buf[10] & 0x01) {
+                       analog[0].mq = SR_MQ_CONTINUITY;
+                       analog[0].unit = SR_UNIT_OHM;
+               } else if (buf[15] & 0x10) {
+                       analog[0].mq = SR_MQ_RESISTANCE;
+                       analog[0].unit = SR_UNIT_OHM;
+               } else if (buf[15] & 0x02) {
+                       analog[0].mq = SR_MQ_POWER;
+                       analog[0].unit = SR_UNIT_DECIBEL_MW;
+               } else if (buf[15] & 0x80) {
+                       analog[0].mq = SR_MQ_DUTY_CYCLE;
+                       analog[0].unit = SR_UNIT_PERCENTAGE;
+               } else if (buf[ 2] & 0x0A) {
+                       analog[0].mq = SR_MQ_TEMPERATURE;
+                       if (temp_unit == 'F')
+                               analog[0].unit = SR_UNIT_FAHRENHEIT;
+                       else
+                               analog[0].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].mqflags |= SR_MQFLAG_DC;
+               if (buf[2] & 0x01)  analog[0].mqflags |= SR_MQFLAG_AC;
+               if (buf[1] & 0x01)  analog[0].mqflags |= SR_MQFLAG_AUTORANGE;
+               if (buf[1] & 0x08)  analog[0].mqflags |= SR_MQFLAG_HOLD;
+               if (buf[1] & 0x20)  analog[0].mqflags |= SR_MQFLAG_MAX;
+               if (buf[1] & 0x40)  analog[0].mqflags |= SR_MQFLAG_MIN;
+               if (buf[1] & 0x80)  analog[0].mqflags |= SR_MQFLAG_AVG;
+               if (buf[3] & 0x01)  analog[0].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;  /* n */
+               if (buf[15] & 0x08)  floatval[0] *= 1e-6;  /* Âµ */
+               if (buf[15] & 0x04)  floatval[0] *= 1e-3;  /* m */
+               if (buf[15] & 0x40)  floatval[0] *= 1e3;   /* k */
+               if (buf[15] & 0x20)  floatval[0] *= 1e6;   /* M */
+
+               if (over_limit)      floatval[0] = INFINITY;
+       }
+
+       /* secondary display */
+       if (ret2 == SR_OK) {
+               /* SI unit */
+               if (buf[14] & 0x08) {
+                       analog[1].mq = SR_MQ_VOLTAGE;
+                       analog[1].unit = SR_UNIT_VOLT;
+               } else if (buf[9] & 0x04) {
+                       analog[1].mq = SR_MQ_CURRENT;
+                       analog[1].unit = SR_UNIT_AMPERE;
+               } else if (buf[14] & 0x04) {
+                       analog[1].mq = SR_MQ_FREQUENCY;
+                       analog[1].unit = SR_UNIT_HERTZ;
+               } else if (buf[9] & 0x40) {
+                       analog[1].mq = SR_MQ_TEMPERATURE;
+                       if (temp_unit == 'F')
+                               analog[1].unit = SR_UNIT_FAHRENHEIT;
+                       else
+                               analog[1].unit = SR_UNIT_CELSIUS;
+               }
+
+               /* AC flag */
+               if (buf[9] & 0x20)  analog[1].mqflags |= SR_MQFLAG_AC;
+
+               /* SI prefix */
+               if (buf[ 9] & 0x01)  floatval[1] *= 1e-6;  /* Âµ */
+               if (buf[ 9] & 0x02)  floatval[1] *= 1e-3;  /* m */
+               if (buf[14] & 0x02)  floatval[1] *= 1e3;   /* k */
+               if (buf[14] & 0x01)  floatval[1] *= 1e6;   /* M */
+       }
+
+       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];
+       float floatval[2];
+
+       devc = sdi->priv;
+
+       analog[0].mq = -1;
+       analog[0].mqflags = 0;
+
+       analog[1].mq = -1;
+       analog[1].mqflags = 0;
+
+       brymen_bm86x_parse(buf, floatval, analog);
+
+       if (analog[0].mq != -1) {
+               /* Got a measurement. */
+               analog[0].num_samples = 1;
+               analog[0].data = &floatval[0];
+               analog[0].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].channels);
+       }
+
+       if (analog[1].mq != -1) {
+               /* Got a measurement. */
+               analog[1].num_samples = 1;
+               analog[1].data = &floatval[1];
+               analog[1].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].channels);
+       }
+
+       if (analog[0].mq != -1 || analog[1].mq != -1)
+               devc->num_samples++;
+}
+
+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/%ld 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/%d 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;
+       int64_t time;
+
+       (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 (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
+               sr_info("Requested number of samples reached, stopping.");
+               sdi->driver->dev_acquisition_stop(sdi, cb_data);
+               return TRUE;
+       }
+
+       if (devc->limit_msec) {
+               time = (g_get_monotonic_time() - devc->start_time) / 1000;
+               if (time > (int64_t)devc->limit_msec) {
+                       sr_info("Requested time limit reached, stopping.");
+                       sdi->driver->dev_acquisition_stop(sdi, cb_data);
+                       return TRUE;
+               }
+       }
+
+       return TRUE;
+}
diff --git a/src/hardware/brymen-bm86x/protocol.h b/src/hardware/brymen-bm86x/protocol.h
new file mode 100644 (file)
index 0000000..57af155
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_BRYMEN_BM86X_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_BRYMEN_BM86X_PROTOCOL_H
+
+#include <stdint.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "brymen-bm86x"
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+       /* Acquisition settings */
+       uint64_t limit_samples;    /**< The sampling limit (in number of samples).*/
+       uint64_t limit_msec;       /**< The time limit (in milliseconds). */
+
+       /* Operational state */
+       int detached_kernel_driver;/**< Whether kernel driver was detached or not */
+       uint64_t num_samples;      /**< The number of already received samples. */
+       int64_t start_time;        /**< The time at which sampling started. */
+
+       /* Temporary state across callbacks */
+       int interrupt_pending;
+};
+
+SR_PRIV int brymen_bm86x_receive_data(int fd, int revents, void *cb_data);
+
+#endif
diff --git a/src/hardware/brymen-dmm/api.c b/src/hardware/brymen-dmm/api.c
new file mode 100644 (file)
index 0000000..1ccd18a
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * 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 "protocol.h"
+
+static const int32_t hwopts[] = {
+       SR_CONF_CONN,
+       SR_CONF_SERIALCOMM,
+};
+
+static const int32_t hwcaps[] = {
+       SR_CONF_MULTIMETER,
+       SR_CONF_LIMIT_SAMPLES,
+       SR_CONF_CONTINUOUS,
+       SR_CONF_LIMIT_MSEC,
+};
+
+SR_PRIV struct sr_dev_driver brymen_bm857_driver_info;
+static struct sr_dev_driver *di = &brymen_bm857_driver_info;
+
+static int init(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *brymen_scan(const char *conn, const char *serialcomm)
+{
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       struct drv_context *drvc;
+       struct sr_channel *ch;
+       struct sr_serial_dev_inst *serial;
+       GSList *devices;
+       int ret;
+       uint8_t buf[128];
+       size_t len;
+
+       if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
+               return NULL;
+
+       if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != 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);
+
+       if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "Brymen", "BM85x", NULL)))
+               goto scan_cleanup;
+
+       if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+               sr_err("Device context malloc failed.");
+               goto scan_cleanup;
+       }
+
+       sdi->inst_type = SR_INST_SERIAL;
+       sdi->conn = serial;
+       drvc = di->priv;
+       sdi->priv = devc;
+       sdi->driver = di;
+
+       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1")))
+               goto scan_cleanup;
+
+       sdi->channels = g_slist_append(sdi->channels, ch);
+       drvc->instances = g_slist_append(drvc->instances, sdi);
+       devices = g_slist_append(devices, sdi);
+
+scan_cleanup:
+       serial_close(serial);
+
+       return devices;
+}
+
+static GSList *scan(GSList *options)
+{
+       struct drv_context *drvc;
+       struct sr_config *src;
+       GSList *devices, *l;
+       const char *conn, *serialcomm;
+
+       devices = NULL;
+       drvc = di->priv;
+       drvc->instances = 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(conn, serialcomm);
+       } else {
+               /* But 9600/8n1 should work all of the time. */
+               devices = brymen_scan(conn, "9600/8n1/dtr=1/rts=1");
+       }
+
+       return devices;
+}
+
+static GSList *dev_list(void)
+{
+       return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int cleanup(void)
+{
+       return std_dev_clear(di, NULL);
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       int ret;
+
+       (void)cg;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       if (!(devc = sdi->priv)) {
+               sr_err("sdi->priv was NULL.");
+               return SR_ERR_BUG;
+       }
+
+       ret = SR_OK;
+       switch (id) {
+       case SR_CONF_LIMIT_SAMPLES:
+               devc->limit_samples = g_variant_get_uint64(data);
+               break;
+       case SR_CONF_LIMIT_MSEC:
+               devc->limit_msec = g_variant_get_uint64(data);
+               break;
+       default:
+               ret = SR_ERR_NA;
+       }
+
+       return ret;
+}
+
+static int config_list(int 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_INT32,
+                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+               break;
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       if (!(devc = sdi->priv)) {
+               sr_err("sdi->priv was NULL.");
+               return SR_ERR_BUG;
+       }
+
+       devc->cb_data = cb_data;
+
+       /*
+        * Reset the number of samples to take. If we've already collected our
+        * quota, but we start a new session, and don't reset this, we'll just
+        * quit without acquiring any new samples.
+        */
+       devc->num_samples = 0;
+       devc->starttime = g_get_monotonic_time();
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(cb_data, LOG_PREFIX);
+
+       /* 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 int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       return std_serial_dev_acquisition_stop(sdi, cb_data, std_serial_dev_close,
+                       sdi->conn, LOG_PREFIX);
+}
+
+SR_PRIV struct sr_dev_driver brymen_bm857_driver_info = {
+       .name = "brymen-bm857",
+       .longname = "Brymen BM857",
+       .api_version = 1,
+       .init = init,
+       .cleanup = cleanup,
+       .scan = scan,
+       .dev_list = 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 = dev_acquisition_stop,
+       .priv = NULL,
+};
diff --git a/src/hardware/brymen-dmm/parser.c b/src/hardware/brymen-dmm/parser.c
new file mode 100644 (file)
index 0000000..e4b1227
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+ * 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 "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(serial, &cmdout, 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->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->mq = SR_MQ_VOLTAGE;
+               analog->unit = SR_UNIT_VOLT;
+       }
+       if (flags.is_amp) {
+               analog->mq = SR_MQ_CURRENT;
+               analog->unit = SR_UNIT_AMPERE;
+       }
+       if (flags.is_ohm) {
+               if (flags.is_beep)
+                       analog->mq = SR_MQ_CONTINUITY;
+               else
+                       analog->mq = SR_MQ_RESISTANCE;
+               analog->unit = SR_UNIT_OHM;
+       }
+       if (flags.is_hertz) {
+               analog->mq = SR_MQ_FREQUENCY;
+               analog->unit = SR_UNIT_HERTZ;
+       }
+       if (flags.is_duty_cycle) {
+               analog->mq = SR_MQ_DUTY_CYCLE;
+               analog->unit = SR_UNIT_PERCENTAGE;
+       }
+       if (flags.is_capacitance) {
+               analog->mq = SR_MQ_CAPACITANCE;
+               analog->unit = SR_UNIT_FARAD;
+       }
+       if (flags.is_fahrenheit) {
+               analog->mq = SR_MQ_TEMPERATURE;
+               analog->unit = SR_UNIT_FAHRENHEIT;
+       }
+       if (flags.is_celsius) {
+               analog->mq = SR_MQ_TEMPERATURE;
+               analog->unit = SR_UNIT_CELSIUS;
+       }
+       if (flags.is_capacitance) {
+               analog->mq = SR_MQ_CAPACITANCE;
+               analog->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->mq = SR_MQ_POWER;
+               analog->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->mqflags |= SR_MQFLAG_DIODE;
+       /* We can have both AC+DC in a single measurement. */
+       if (flags.is_ac)
+               analog->mqflags |= SR_MQFLAG_AC;
+       if (flags.is_dc)
+               analog->mqflags |= SR_MQFLAG_DC;
+
+       if (flags.is_low_batt)
+               sr_info("Low battery!");
+
+       return SR_OK;
+}
diff --git a/src/hardware/brymen-dmm/protocol.c b/src/hardware/brymen-dmm/protocol.c
new file mode 100644 (file)
index 0000000..dff7b98
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * 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 "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;
+
+       devc = sdi->priv;
+
+       analog.num_samples = 1;
+       analog.mq = -1;
+
+       if (brymen_parse(buf, &floatval, &analog, NULL) != SR_OK)
+               return;
+       analog.data = &floatval;
+
+       analog.channels = sdi->channels;
+
+       if (analog.mq != -1) {
+               /* Got a measurement. */
+               packet.type = SR_DF_ANALOG;
+               packet.payload = &analog;
+               sr_session_send(devc->cb_data, &packet);
+               devc->num_samples++;
+       }
+}
+
+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(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;
+       int64_t time;
+
+       (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 (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
+               sr_info("Requested number of samples reached, stopping.");
+               sdi->driver->dev_acquisition_stop(sdi, cb_data);
+               return TRUE;
+       }
+
+       if (devc->limit_msec) {
+               time = (g_get_monotonic_time() - devc->starttime) / 1000;
+               if (time > (int64_t)devc->limit_msec) {
+                       sr_info("Requested time limit reached, stopping.");
+                       sdi->driver->dev_acquisition_stop(sdi, cb_data);
+                       return TRUE;
+               }
+       }
+
+       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;
+       int status, len, packet_len, stream_len;
+
+       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 * (1000000 / baudrate);
+       start = g_get_monotonic_time();
+
+       packet_len = i = ibuf = len = 0;
+       while (ibuf < maxlen) {
+               len = serial_read(serial, &buf[ibuf], maxlen - ibuf);
+               if (len > 0) {
+                       ibuf += len;
+                       sr_spew("Read %d 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 %dms.", time);
+                       break;
+               }
+               g_usleep(byte_delay_us);
+       }
+
+       *buflen = ibuf;
+       sr_err("Didn't find a valid packet (read %d bytes).", ibuf);
+
+       return SR_ERR;
+}
diff --git a/src/hardware/brymen-dmm/protocol.h b/src/hardware/brymen-dmm/protocol.h
new file mode 100644 (file)
index 0000000..7c9aaae
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * 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.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 {
+       /** The current sampling limit (in number of samples). */
+       uint64_t limit_samples;
+
+       /** The current sampling limit (in ms). */
+       uint64_t limit_msec;
+
+       /** Opaque pointer passed in by the frontend. */
+       void *cb_data;
+
+       /** The current number of already received samples. */
+       uint64_t num_samples;
+
+       /** Start time of acquisition session */
+       int64_t starttime;
+
+       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
diff --git a/src/hardware/cem-dt-885x/api.c b/src/hardware/cem-dt-885x/api.c
new file mode 100644 (file)
index 0000000..9aed547
--- /dev/null
@@ -0,0 +1,432 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert@biot.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 <string.h>
+#include "protocol.h"
+
+#define SERIALCOMM "9600/8n1"
+/* 23ms is the longest interval between tokens. */
+#define MAX_SCAN_TIME 25 * 1000
+
+static const int32_t hwopts[] = {
+       SR_CONF_CONN,
+};
+
+static const int32_t hwcaps[] = {
+       SR_CONF_SOUNDLEVELMETER,
+       SR_CONF_LIMIT_SAMPLES,
+       SR_CONF_CONTINUOUS,
+       SR_CONF_SPL_WEIGHT_FREQ,
+       SR_CONF_SPL_WEIGHT_TIME,
+       SR_CONF_SPL_MEASUREMENT_RANGE,
+       SR_CONF_DATALOG,
+       SR_CONF_HOLD_MAX,
+       SR_CONF_HOLD_MIN,
+       SR_CONF_POWER_OFF,
+       SR_CONF_DATA_SOURCE,
+};
+
+static const char *weight_freq[] = {
+       "A",
+       "C",
+};
+
+static const char *weight_time[] = {
+       "F",
+       "S",
+};
+
+static const uint64_t meas_ranges[][2] = {
+       { 30, 130 },
+       { 30, 80 },
+       { 50, 100 },
+       { 80, 130 },
+};
+
+static const char *data_sources[] = {
+       "Live",
+       "Memory",
+};
+SR_PRIV struct sr_dev_driver cem_dt_885x_driver_info;
+static struct sr_dev_driver *di = &cem_dt_885x_driver_info;
+
+
+static int init(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       struct sr_config *src;
+       struct sr_serial_dev_inst *serial;
+       struct sr_dev_inst *sdi;
+       struct sr_channel *ch;
+       GSList *l, *devices;
+       gint64 start;
+       const char *conn;
+       unsigned char c;
+
+       conn = NULL;
+       for (l = options; l; l = l->next) {
+               src = l->data;
+               if (src->key == SR_CONF_CONN)
+                       conn = g_variant_get_string(src->data, NULL);
+       }
+       if (!conn)
+               return NULL;
+
+       if (!(serial = sr_serial_dev_inst_new(conn, SERIALCOMM)))
+               return NULL;
+
+       if (serial_open(serial, SERIAL_RDONLY | SERIAL_NONBLOCK) != SR_OK)
+               return NULL;
+
+       devices = NULL;
+       drvc = di->priv;
+       start = g_get_monotonic_time();
+       while (g_get_monotonic_time() - start < MAX_SCAN_TIME) {
+               if (serial_read(serial, &c, 1) == 1 && c == 0xa5) {
+                       /* Found one. */
+                       if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "CEM",
+                                       "DT-885x", NULL)))
+                               return NULL;
+
+                       if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+                               sr_dbg("Device context malloc failed.");
+                               return NULL;
+                       }
+                       devc->cur_mqflags = 0;
+                       devc->recording = -1;
+                       devc->cur_meas_range = 0;
+                       devc->cur_data_source = DATA_SOURCE_LIVE;
+                       devc->enable_data_source_memory = FALSE;
+
+                       if (!(sdi->conn = sr_serial_dev_inst_new(conn, SERIALCOMM)))
+                               return NULL;
+
+                       sdi->inst_type = SR_INST_SERIAL;
+                       sdi->priv = devc;
+                       sdi->driver = di;
+                       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "SPL")))
+                               return NULL;
+                       sdi->channels = g_slist_append(sdi->channels, ch);
+                       drvc->instances = g_slist_append(drvc->instances, sdi);
+                       devices = g_slist_append(devices, sdi);
+                       break;
+               }
+               /* It takes about 1ms for a byte to come in. */
+               g_usleep(1000);
+       }
+
+       serial_close(serial);
+
+       return devices;
+}
+
+static GSList *dev_list(void)
+{
+       return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+       struct sr_serial_dev_inst *serial;
+
+       serial = sdi->conn;
+       if (serial_open(serial, SERIAL_RDWR) != SR_OK)
+               return SR_ERR;
+
+       sdi->status = SR_ST_ACTIVE;
+
+       return SR_OK;
+}
+
+static int cleanup(void)
+{
+       return std_dev_clear(di, NULL);
+}
+
+static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       GVariant *range[2];
+       uint64_t low, high;
+       int tmp, ret;
+
+       (void)cg;
+
+       if (!sdi)
+               return SR_ERR_ARG;
+
+       devc = sdi->priv;
+       ret = SR_OK;
+       switch (key) {
+       case SR_CONF_LIMIT_SAMPLES:
+               *data = g_variant_new_uint64(devc->limit_samples);
+               break;
+       case SR_CONF_DATALOG:
+               if ((ret = cem_dt_885x_recording_get(sdi, &tmp)) == SR_OK)
+                       *data = g_variant_new_boolean(tmp);
+               break;
+       case SR_CONF_SPL_WEIGHT_FREQ:
+               tmp = cem_dt_885x_weight_freq_get(sdi);
+               if (tmp == SR_MQFLAG_SPL_FREQ_WEIGHT_A)
+                       *data = g_variant_new_string("A");
+               else if (tmp == SR_MQFLAG_SPL_FREQ_WEIGHT_C)
+                       *data = g_variant_new_string("C");
+               else
+                       return SR_ERR;
+               break;
+       case SR_CONF_SPL_WEIGHT_TIME:
+               tmp = cem_dt_885x_weight_time_get(sdi);
+               if (tmp == SR_MQFLAG_SPL_TIME_WEIGHT_F)
+                       *data = g_variant_new_string("F");
+               else if (tmp == SR_MQFLAG_SPL_TIME_WEIGHT_S)
+                       *data = g_variant_new_string("S");
+               else
+                       return SR_ERR;
+               break;
+       case SR_CONF_HOLD_MAX:
+               if ((ret = cem_dt_885x_holdmode_get(sdi, &tmp)) == SR_OK)
+                       *data = g_variant_new_boolean(tmp == SR_MQFLAG_MAX);
+               break;
+       case SR_CONF_HOLD_MIN:
+               if ((ret = cem_dt_885x_holdmode_get(sdi, &tmp)) == SR_OK)
+                       *data = g_variant_new_boolean(tmp == SR_MQFLAG_MIN);
+               break;
+       case SR_CONF_SPL_MEASUREMENT_RANGE:
+               if ((ret = cem_dt_885x_meas_range_get(sdi, &low, &high)) == SR_OK) {
+                       range[0] = g_variant_new_uint64(low);
+                       range[1] = g_variant_new_uint64(high);
+                       *data = g_variant_new_tuple(range, 2);
+               }
+               break;
+       case SR_CONF_POWER_OFF:
+               *data = g_variant_new_boolean(FALSE);
+               break;
+       case SR_CONF_DATA_SOURCE:
+               if (devc->cur_data_source == DATA_SOURCE_LIVE)
+                       *data = g_variant_new_string("Live");
+               else
+                       *data = g_variant_new_string("Memory");
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return ret;
+}
+
+static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       uint64_t tmp_u64, low, high;
+       unsigned int i;
+       int tmp, ret;
+       const char *tmp_str;
+
+       (void)cg;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       if (!(devc = sdi->priv)) {
+               sr_err("sdi->priv was NULL.");
+               return SR_ERR_BUG;
+       }
+
+       ret = SR_OK;
+       switch (key) {
+       case SR_CONF_LIMIT_SAMPLES:
+               tmp_u64 = g_variant_get_uint64(data);
+               devc->limit_samples = tmp_u64;
+               ret = SR_OK;
+               break;
+       case SR_CONF_DATALOG:
+               ret = cem_dt_885x_recording_set(sdi, g_variant_get_boolean(data));
+               break;
+       case SR_CONF_SPL_WEIGHT_FREQ:
+               tmp_str = g_variant_get_string(data, NULL);
+               if (!strcmp(tmp_str, "A"))
+                       ret = cem_dt_885x_weight_freq_set(sdi,
+                                       SR_MQFLAG_SPL_FREQ_WEIGHT_A);
+               else if (!strcmp(tmp_str, "C"))
+                       ret = cem_dt_885x_weight_freq_set(sdi,
+                                       SR_MQFLAG_SPL_FREQ_WEIGHT_C);
+               else
+                       return SR_ERR_ARG;
+               break;
+       case SR_CONF_SPL_WEIGHT_TIME:
+               tmp_str = g_variant_get_string(data, NULL);
+               if (!strcmp(tmp_str, "F"))
+                       ret = cem_dt_885x_weight_time_set(sdi,
+                                       SR_MQFLAG_SPL_TIME_WEIGHT_F);
+               else if (!strcmp(tmp_str, "S"))
+                       ret = cem_dt_885x_weight_time_set(sdi,
+                                       SR_MQFLAG_SPL_TIME_WEIGHT_S);
+               else
+                       return SR_ERR_ARG;
+               break;
+       case SR_CONF_HOLD_MAX:
+               tmp = g_variant_get_boolean(data) ? SR_MQFLAG_MAX : 0;
+               ret = cem_dt_885x_holdmode_set(sdi, tmp);
+               break;
+       case SR_CONF_HOLD_MIN:
+               tmp = g_variant_get_boolean(data) ? SR_MQFLAG_MIN : 0;
+               ret = cem_dt_885x_holdmode_set(sdi, tmp);
+               break;
+       case SR_CONF_SPL_MEASUREMENT_RANGE:
+               g_variant_get(data, "(tt)", &low, &high);
+               ret = SR_ERR_ARG;
+               for (i = 0; i < ARRAY_SIZE(meas_ranges); i++) {
+                       if (meas_ranges[i][0] == low && meas_ranges[i][1] == high) {
+                               ret = cem_dt_885x_meas_range_set(sdi, low, high);
+                               break;
+                       }
+               }
+               break;
+       case SR_CONF_POWER_OFF:
+               if (g_variant_get_boolean(data))
+                       ret = cem_dt_885x_power_off(sdi);
+               break;
+       case SR_CONF_DATA_SOURCE:
+               tmp_str = g_variant_get_string(data, NULL);
+               if (!strcmp(tmp_str, "Live"))
+                       devc->cur_data_source = DATA_SOURCE_LIVE;
+               else if (!strcmp(tmp_str, "Memory"))
+                       devc->cur_data_source = DATA_SOURCE_MEMORY;
+               else
+                       return SR_ERR;
+               devc->enable_data_source_memory = devc->cur_data_source == DATA_SOURCE_MEMORY;
+               break;
+       default:
+               ret = SR_ERR_NA;
+       }
+
+       return ret;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       GVariant *tuple, *range[2];
+       GVariantBuilder gvb;
+       unsigned int i;
+       int ret;
+
+       (void)sdi;
+       (void)cg;
+
+       ret = SR_OK;
+       switch (key) {
+       case SR_CONF_SCAN_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+               break;
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_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 ret;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       if (!(devc = sdi->priv)) {
+               sr_err("sdi->priv was NULL.");
+               return SR_ERR_BUG;
+       }
+
+       devc->cb_data = cb_data;
+       devc->state = ST_INIT;
+       devc->num_samples = 0;
+       devc->buf_len = 0;
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(cb_data, LOG_PREFIX);
+
+       /* Poll every 100ms, or whenever some data comes in. */
+       serial = sdi->conn;
+       serial_source_add(sdi->session, serial, G_IO_IN, 150,
+                       cem_dt_885x_receive_data, (void *)sdi);
+
+       return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       return std_serial_dev_acquisition_stop(sdi, cb_data, std_serial_dev_close,
+                       sdi->conn, LOG_PREFIX);
+}
+
+SR_PRIV struct sr_dev_driver cem_dt_885x_driver_info = {
+       .name = "cem-dt-885x",
+       .longname = "CEM DT-885x",
+       .api_version = 1,
+       .init = init,
+       .cleanup = cleanup,
+       .scan = scan,
+       .dev_list = dev_list,
+       .dev_clear = NULL,
+       .config_get = config_get,
+       .config_set = config_set,
+       .config_list = config_list,
+       .dev_open = dev_open,
+       .dev_close = std_serial_dev_close,
+       .dev_acquisition_start = dev_acquisition_start,
+       .dev_acquisition_stop = dev_acquisition_stop,
+       .priv = NULL,
+};
diff --git a/src/hardware/cem-dt-885x/protocol.c b/src/hardware/cem-dt-885x/protocol.c
new file mode 100644 (file)
index 0000000..19e0830
--- /dev/null
@@ -0,0 +1,838 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert@biot.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 <string.h>
+#include "protocol.h"
+
+/* Length of expected payload for each token. */
+static int token_payloads[][2] = {
+       { TOKEN_WEIGHT_TIME_FAST, 0 },
+       { TOKEN_WEIGHT_TIME_SLOW, 0 },
+       { TOKEN_HOLD_MAX, 0 },
+       { TOKEN_HOLD_MIN, 0 },
+       { TOKEN_TIME, 3 },
+       { TOKEN_MEAS_RANGE_OVER, 0 },
+       { TOKEN_MEAS_RANGE_UNDER, 0 },
+       { TOKEN_STORE_FULL, 0 },
+       { TOKEN_RECORDING_ON, 0 },
+       { TOKEN_MEAS_WAS_READOUT, 1 },
+       { TOKEN_MEAS_WAS_BARGRAPH, 0 },
+       { TOKEN_MEASUREMENT, 2 },
+       { TOKEN_HOLD_NONE, 0 },
+       { TOKEN_BATTERY_LOW, 0 },
+       { TOKEN_MEAS_RANGE_OK, 0 },
+       { TOKEN_STORE_OK, 0 },
+       { TOKEN_RECORDING_OFF, 0 },
+       { TOKEN_WEIGHT_FREQ_A, 1 },
+       { TOKEN_WEIGHT_FREQ_C, 1 },
+       { TOKEN_BATTERY_OK, 0 },
+       { TOKEN_MEAS_RANGE_30_80, 0 },
+       { TOKEN_MEAS_RANGE_30_130, 0 },
+       { TOKEN_MEAS_RANGE_50_100, 0 },
+       { TOKEN_MEAS_RANGE_80_130, 0 },
+};
+
+static int find_token_payload_len(unsigned char c)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(token_payloads); i++) {
+               if (token_payloads[i][0] == c)
+                       return token_payloads[i][1];
+       }
+
+       return -1;
+}
+
+/* Process measurement or setting (0xa5 command). */
+static void process_mset(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_analog analog;
+       GString *dbg;
+       float fvalue;
+       int i;
+
+       devc = sdi->priv;
+       if (sr_log_loglevel_get() >= SR_LOG_SPEW) {
+               dbg = g_string_sized_new(128);
+               g_string_printf(dbg, "got command 0x%.2x token 0x%.2x",
+                               devc->cmd, devc->token);
+               if (devc->buf_len) {
+                       g_string_append_printf(dbg, " payload");
+                       for (i = 0; i < devc->buf_len; i++)
+                               g_string_append_printf(dbg, " %.2x", devc->buf[i]);
+               }
+               sr_spew("%s", dbg->str);
+               g_string_free(dbg, TRUE);
+       }
+
+       switch(devc->token) {
+       case TOKEN_WEIGHT_TIME_FAST:
+               devc->cur_mqflags |= SR_MQFLAG_SPL_TIME_WEIGHT_F;
+               devc->cur_mqflags &= ~SR_MQFLAG_SPL_TIME_WEIGHT_S;
+               break;
+       case TOKEN_WEIGHT_TIME_SLOW:
+               devc->cur_mqflags |= SR_MQFLAG_SPL_TIME_WEIGHT_S;
+               devc->cur_mqflags &= ~SR_MQFLAG_SPL_TIME_WEIGHT_F;
+               break;
+       case TOKEN_WEIGHT_FREQ_A:
+               devc->cur_mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_A;
+               devc->cur_mqflags &= ~SR_MQFLAG_SPL_FREQ_WEIGHT_C;
+               break;
+       case TOKEN_WEIGHT_FREQ_C:
+               devc->cur_mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_C;
+               devc->cur_mqflags &= ~SR_MQFLAG_SPL_FREQ_WEIGHT_A;
+               break;
+       case TOKEN_HOLD_MAX:
+               devc->cur_mqflags |= SR_MQFLAG_HOLD | SR_MQFLAG_MAX;
+               devc->cur_mqflags &= ~SR_MQFLAG_MIN;
+               break;
+       case TOKEN_HOLD_MIN:
+               devc->cur_mqflags |= SR_MQFLAG_HOLD | SR_MQFLAG_MIN;
+               devc->cur_mqflags &= ~SR_MQFLAG_MAX;
+               break;
+       case TOKEN_HOLD_NONE:
+               devc->cur_mqflags &= ~(SR_MQFLAG_MAX | SR_MQFLAG_MIN | SR_MQFLAG_HOLD);
+               break;
+       case TOKEN_MEASUREMENT:
+               fvalue = ((devc->buf[0] & 0xf0) >> 4) * 100;
+               fvalue += (devc->buf[0] & 0x0f) * 10;
+               fvalue += ((devc->buf[1] & 0xf0) >> 4);
+               fvalue += (devc->buf[1] & 0x0f) / 10.0;
+               devc->last_spl = fvalue;
+               break;
+       case TOKEN_MEAS_WAS_READOUT:
+       case TOKEN_MEAS_WAS_BARGRAPH:
+               if (devc->cur_mqflags & (SR_MQFLAG_MAX | SR_MQFLAG_MIN)) {
+                       if (devc->token == TOKEN_MEAS_WAS_BARGRAPH) {
+                               /* The device still sends bargraph measurements even
+                                * when in max/min hold mode. Suppress them here, unless
+                                * they're readout values. This duplicates the behavior
+                                * of the device display exactly. */
+                               break;
+                       }
+               }
+               memset(&analog, 0, sizeof(struct sr_datafeed_analog));
+               analog.mq = SR_MQ_SOUND_PRESSURE_LEVEL;
+               analog.mqflags = devc->cur_mqflags;
+               analog.unit = SR_UNIT_DECIBEL_SPL;
+               analog.channels = sdi->channels;
+               analog.num_samples = 1;
+               analog.data = &devc->last_spl;
+               packet.type = SR_DF_ANALOG;
+               packet.payload = &analog;
+               sr_session_send(devc->cb_data, &packet);
+
+               devc->num_samples++;
+               if (devc->limit_samples && devc->num_samples >= devc->limit_samples)
+                       sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi,
+                                       devc->cb_data);
+               break;
+       case TOKEN_RECORDING_ON:
+               devc->recording = TRUE;
+               break;
+       case TOKEN_RECORDING_OFF:
+               devc->recording = FALSE;
+               break;
+       case TOKEN_MEAS_RANGE_30_80:
+       case TOKEN_MEAS_RANGE_30_130:
+       case TOKEN_MEAS_RANGE_50_100:
+       case TOKEN_MEAS_RANGE_80_130:
+               devc->cur_meas_range = devc->token;
+               break;
+       case TOKEN_TIME:
+       case TOKEN_STORE_OK:
+       case TOKEN_STORE_FULL:
+       case TOKEN_BATTERY_OK:
+       case TOKEN_BATTERY_LOW:
+       case TOKEN_MEAS_RANGE_OK:
+       case TOKEN_MEAS_RANGE_OVER:
+       case TOKEN_MEAS_RANGE_UNDER:
+               /* Not useful, or not expressable in sigrok. */
+               break;
+       }
+
+}
+
+static void send_data(const struct sr_dev_inst *sdi, unsigned char *data,
+               uint64_t num_samples)
+{
+       struct dev_context *devc;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_analog analog;
+       float fbuf[SAMPLES_PER_PACKET];
+       unsigned int i;
+
+       devc = sdi->priv;
+
+       for (i = 0; i < num_samples; i ++) {
+               fbuf[i] = ((data[i * 2] & 0xf0) >> 4) * 100;
+               fbuf[i] += (data[i * 2] & 0x0f) * 10;
+               fbuf[i] += ((data[i * 2 + 1] & 0xf0) >> 4);
+               fbuf[i] += (data[i * 2 + 1] & 0x0f) / 10.0;
+       }
+       memset(&analog, 0, sizeof(struct sr_datafeed_analog));
+       analog.mq = SR_MQ_SOUND_PRESSURE_LEVEL;
+       analog.mqflags = devc->cur_mqflags;
+       analog.unit = SR_UNIT_DECIBEL_SPL;
+       analog.channels = sdi->channels;
+       analog.num_samples = num_samples;
+       analog.data = fbuf;
+       packet.type = SR_DF_ANALOG;
+       packet.payload = &analog;
+       sr_session_send(devc->cb_data, &packet);
+
+       devc->num_samples += analog.num_samples;
+       if (devc->limit_samples && devc->num_samples >= devc->limit_samples)
+               sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi,
+                               devc->cb_data);
+
+       return;
+}
+
+static void process_byte(const struct sr_dev_inst *sdi, const unsigned char c,
+               int handle_packets)
+{
+       struct dev_context *devc;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_meta meta;
+       struct sr_config *src;
+       gint64 cur_time;
+       int len;
+
+       if (!(devc = sdi->priv))
+               return;
+
+       if (c == 0xff) {
+               /* Device is in hold mode */
+               devc->cur_mqflags |= SR_MQFLAG_HOLD;
+
+               if (devc->hold_last_sent == 0) {
+                       /* First hold notification. */
+                       devc->hold_last_sent = g_get_monotonic_time();
+                       /* When the device leaves hold mode, it starts from scratch. */
+                       devc->state = ST_INIT;
+               } else {
+                       cur_time = g_get_monotonic_time();
+                       if (cur_time - devc->hold_last_sent > HOLD_REPEAT_INTERVAL) {
+                               /* Force the last measurement out again. */
+                               devc->cmd = 0xa5;
+                               devc->token = TOKEN_MEAS_WAS_READOUT;
+                               if (handle_packets)
+                                       process_mset(sdi);
+                               devc->hold_last_sent = cur_time;
+                       }
+               }
+
+               return;
+       }
+       devc->cur_mqflags &= ~SR_MQFLAG_HOLD;
+       devc->hold_last_sent = 0;
+
+       if (devc->state == ST_INIT) {
+               if (c == 0xa5) {
+                       devc->cmd = c;
+                       devc->token = 0x00;
+                       devc->state = ST_GET_TOKEN;
+               } else if (c == 0xbb) {
+                       devc->cmd = c;
+                       devc->buf_len = 0;
+                       devc->state = ST_GET_LOG_HEADER;
+                       sr_dbg("got command 0xbb");
+               }
+       } else if (devc->state == ST_GET_TOKEN) {
+               devc->token = c;
+               devc->buf_len = 0;
+               len = find_token_payload_len(devc->token);
+               if (len == -1 || len > 0) {
+                       devc->buf_len = 0;
+                       devc->state = ST_GET_DATA;
+               } else {
+                       if (handle_packets)
+                               process_mset(sdi);
+                       devc->state = ST_INIT;
+               }
+       } else if (devc->state == ST_GET_DATA) {
+               len = find_token_payload_len(devc->token);
+               if (len == -1) {
+                       /* We don't know this token. */
+                       sr_dbg("Unknown 0xa5 token 0x%.2x", devc->token);
+                       if (c == 0xa5 || c == 0xbb) {
+                               /* Looks like a new command however. */
+                               if (handle_packets)
+                                       process_mset(sdi);
+                               devc->state = ST_INIT;
+                       } else {
+                               devc->buf[devc->buf_len++] = c;
+                               if (devc->buf_len > BUF_SIZE) {
+                                       /* Shouldn't happen, ignore. */
+                                       devc->state = ST_INIT;
+                               }
+                       }
+               } else {
+                       devc->buf[devc->buf_len++] = c;
+                       if (devc->buf_len == len) {
+                               if (handle_packets)
+                                       process_mset(sdi);
+                               devc->state = ST_INIT;
+                       } else if (devc->buf_len > BUF_SIZE) {
+                               /* Shouldn't happen, ignore. */
+                               devc->state = ST_INIT;
+                       }
+               }
+       } else if (devc->state == ST_GET_LOG_HEADER) {
+               sr_dbg("log header: 0x%.2x", c);
+               if (devc->buf_len < 2)
+                       devc->buf[devc->buf_len++] = c;
+               if (devc->buf_len == 2) {
+                       sr_dbg("Device says it has %d bytes stored.",
+                                       ((devc->buf[0] << 8) + devc->buf[1]) - 100);
+                       devc->buf_len = 0;
+                       devc->state = ST_GET_LOG_RECORD_META;
+               }
+       } else if (devc->state == ST_GET_LOG_RECORD_META) {
+               sr_dbg("log meta: 0x%.2x", c);
+               if (c == RECORD_END) {
+                       devc->state = ST_INIT;
+                       /* Stop acquisition after transferring all stored
+                        * records. Otherwise the frontend would have no
+                        * way to tell where stored data ends and live
+                        * measurements begin. */
+                       sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi,
+                                       devc->cb_data);
+               } else if (c == RECORD_DATA) {
+                       devc->buf_len = 0;
+                       devc->state = ST_GET_LOG_RECORD_DATA;
+               } else {
+                       /* RECORD_DBA/RECORD_DBC + 7 bytes of metadata */
+                       devc->buf[devc->buf_len++] = c;
+                       if (devc->buf_len < 8)
+                               /* Keep filling up the record header. */
+                               return;
+                       if (devc->buf[0] == RECORD_DBA)
+                               devc->cur_mqflags = SR_MQFLAG_SPL_FREQ_WEIGHT_A;
+                       else if (devc->buf[0] == RECORD_DBC)
+                               devc->cur_mqflags = SR_MQFLAG_SPL_FREQ_WEIGHT_C;
+                       else {
+                               /* Shouldn't happen. */
+                               sr_dbg("Unknown record token 0x%.2x", c);
+                               return;
+                       }
+                       packet.type = SR_DF_META;
+                       packet.payload = &meta;
+                       src = sr_config_new(SR_CONF_SAMPLE_INTERVAL,
+                                       g_variant_new_uint64(devc->buf[7] * 1000));
+                       meta.config = g_slist_append(NULL, src);
+                       sr_session_send(devc->cb_data, &packet);
+                       g_free(src);
+                       devc->buf_len = 0;
+               }
+       } else if (devc->state == ST_GET_LOG_RECORD_DATA) {
+               sr_dbg("log data: 0x%.2x", c);
+               if (c == RECORD_DBA || c == RECORD_DBC || c == RECORD_DATA || c == RECORD_END) {
+                       /* Work around off-by-one bug in device firmware. This
+                        * happens only on the last record, i.e. before RECORD_END */
+                       if (devc->buf_len & 1)
+                               devc->buf_len--;
+                       /* Done with this set of samples */
+                       send_data(sdi, devc->buf, devc->buf_len / 2);
+                       devc->buf_len = 0;
+
+                       /* Process this meta marker in the right state. */
+                       devc->state = ST_GET_LOG_RECORD_META;
+                       process_byte(sdi, c, handle_packets);
+               } else {
+                       devc->buf[devc->buf_len++] = c;
+                       if (devc->buf_len == SAMPLES_PER_PACKET * 2) {
+                               send_data(sdi, devc->buf, devc->buf_len / 2);
+                               devc->buf_len = 0;
+                       }
+               }
+       }
+
+}
+
+SR_PRIV int cem_dt_885x_receive_data(int fd, int revents, void *cb_data)
+{
+       const struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+       unsigned char c, cmd;
+
+       (void)fd;
+
+       if (!(sdi = cb_data))
+               return TRUE;
+
+       devc = sdi->priv;
+       serial = sdi->conn;
+       if (revents == G_IO_IN) {
+               if (serial_read(serial, &c, 1) != 1)
+                       return TRUE;
+               process_byte(sdi, c, TRUE);
+
+               if (devc->enable_data_source_memory) {
+                       if (devc->state == ST_GET_LOG_HEADER) {
+                               /* Memory transfer started. */
+                               devc->enable_data_source_memory = FALSE;
+                       } else {
+                               /* Tell device to start transferring from memory. */
+                               cmd = CMD_TRANSFER_MEMORY;
+                               serial_write(serial, &cmd, 1);
+                       }
+               }
+       }
+
+       return TRUE;
+}
+
+
+static int wait_for_token(const struct sr_dev_inst *sdi, int8_t *tokens, int timeout)
+{
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+       gint64 start_time;
+       int i;
+       unsigned char c;
+
+       serial = sdi->conn;
+       devc = sdi->priv;
+       devc->state = ST_INIT;
+       start_time = g_get_monotonic_time() / 1000;
+       while (TRUE) {
+               if (serial_read(serial, &c, 1) != 1)
+                       /* Device might have gone away. */
+                       return SR_ERR;
+               process_byte(sdi, c, FALSE);
+               if (devc->state != ST_INIT)
+                       /* Wait for a whole packet to get processed. */
+                       continue;
+               for (i = 0; tokens[i] != -1; i++) {
+                       if (devc->token == tokens[i]) {
+                               sr_spew("wait_for_token: got token 0x%.2x", devc->token);
+                               return SR_OK;
+                       }
+               }
+               if (timeout && g_get_monotonic_time() / 1000 - start_time > timeout)
+                       return SR_ERR_TIMEOUT;
+       }
+
+       return SR_OK;
+}
+
+/* cmd is the command to send, tokens are the tokens that denote the state
+ * which the command affects. The first token is the desired state. */
+static int cem_dt_885x_toggle(const struct sr_dev_inst *sdi, uint8_t cmd,
+               int8_t *tokens, int timeout)
+{
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+
+       serial = sdi->conn;
+       devc = sdi->priv;
+
+       /* The device doesn't respond to commands very well. The
+        * only thing to do is wait for the token that will confirm
+        * whether the command worked or not, and resend if needed. */
+       while (TRUE) {
+               if (serial_write(serial, (const void *)&cmd, 1) != 1)
+                       return SR_ERR;
+               if (wait_for_token(sdi, tokens, timeout) == SR_ERR)
+                       return SR_ERR;
+               if (devc->token == tokens[0])
+                       /* It worked. */
+                       break;
+       }
+
+       return SR_OK;
+}
+
+SR_PRIV gboolean cem_dt_885x_recording_get(const struct sr_dev_inst *sdi,
+               int *state)
+{
+       struct dev_context *devc;
+       int8_t tokens[5];
+
+       devc = sdi->priv;
+       if (devc->recording == -1) {
+               /* Didn't pick up device state yet. */
+               tokens[0] = TOKEN_RECORDING_ON;
+               tokens[1] = TOKEN_RECORDING_OFF;
+               tokens[2] = -1;
+               if (wait_for_token(sdi, tokens, 510) != SR_OK)
+                       return SR_ERR;
+       }
+       *state = devc->token == TOKEN_RECORDING_ON;
+
+       return SR_OK;
+}
+
+SR_PRIV int cem_dt_885x_recording_set(const struct sr_dev_inst *sdi,
+               gboolean state)
+{
+       struct dev_context *devc;
+       int ret;
+       int8_t tokens[5];
+
+       devc = sdi->priv;
+
+       /* The toggle below needs the desired state in first position. */
+       if (state) {
+               tokens[0] = TOKEN_RECORDING_ON;
+               tokens[1] = TOKEN_RECORDING_OFF;
+       } else {
+               tokens[0] = TOKEN_RECORDING_OFF;
+               tokens[1] = TOKEN_RECORDING_ON;
+       }
+       tokens[2] = -1;
+
+       if (devc->recording == -1) {
+               /* Didn't pick up device state yet. */
+               if (wait_for_token(sdi, tokens, 0) != SR_OK)
+                       return SR_ERR;
+               if (devc->token == tokens[0])
+                       /* Nothing to do. */
+                       return SR_OK;
+       } else if (devc->recording == state)
+               /* Nothing to do. */
+               return SR_OK;
+
+       /* Recording state notifications are sent at 2Hz, so allow just over
+        * that, 510ms, for the state to come in. */
+       ret = cem_dt_885x_toggle(sdi, CMD_TOGGLE_RECORDING, tokens, 510);
+
+       return ret;
+}
+
+SR_PRIV int cem_dt_885x_weight_freq_get(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       int cur_setting;
+       int8_t tokens[5];
+
+       devc = sdi->priv;
+
+       cur_setting = devc->cur_mqflags & (SR_MQFLAG_SPL_FREQ_WEIGHT_A | SR_MQFLAG_SPL_FREQ_WEIGHT_C);
+       if (cur_setting == 0) {
+               /* Didn't pick up device state yet. */
+               tokens[0] = TOKEN_WEIGHT_FREQ_A;
+               tokens[1] = TOKEN_WEIGHT_FREQ_C;
+               tokens[2] = -1;
+               if (wait_for_token(sdi, tokens, 0) != SR_OK)
+                       return SR_ERR;
+               if (devc->token == TOKEN_WEIGHT_FREQ_A)
+                       return SR_MQFLAG_SPL_FREQ_WEIGHT_A;
+               else
+                       return SR_MQFLAG_SPL_FREQ_WEIGHT_C;
+       } else
+               return cur_setting;
+}
+
+SR_PRIV int cem_dt_885x_weight_freq_set(const struct sr_dev_inst *sdi, int freqw)
+{
+       struct dev_context *devc;
+       int cur_setting, ret;
+       int8_t tokens[5];
+
+       devc = sdi->priv;
+
+       cur_setting = devc->cur_mqflags & (SR_MQFLAG_SPL_FREQ_WEIGHT_A | SR_MQFLAG_SPL_FREQ_WEIGHT_C);
+       if (cur_setting == freqw)
+               /* Already set to this frequency weighting. */
+               return SR_OK;
+
+       /* The toggle below needs the desired state in first position. */
+       if (freqw == SR_MQFLAG_SPL_FREQ_WEIGHT_A) {
+               tokens[0] = TOKEN_WEIGHT_FREQ_A;
+               tokens[1] = TOKEN_WEIGHT_FREQ_C;
+       } else {
+               tokens[0] = TOKEN_WEIGHT_FREQ_C;
+               tokens[1] = TOKEN_WEIGHT_FREQ_A;
+       }
+       tokens[2] = -1;
+
+       if (cur_setting == 0) {
+               /* Didn't pick up device state yet. */
+               if (wait_for_token(sdi, tokens, 0) != SR_OK)
+                       return SR_ERR;
+               if (devc->token == tokens[0])
+                       /* Nothing to do. */
+                       return SR_OK;
+       }
+
+       /* 10ms timeout seems to work best for this. */
+       ret = cem_dt_885x_toggle(sdi, CMD_TOGGLE_WEIGHT_FREQ, tokens, 10);
+
+       return ret;
+}
+
+SR_PRIV int cem_dt_885x_weight_time_get(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       int cur_setting;
+       int8_t tokens[5];
+
+       devc = sdi->priv;
+
+       cur_setting = devc->cur_mqflags & (SR_MQFLAG_SPL_TIME_WEIGHT_F | SR_MQFLAG_SPL_TIME_WEIGHT_S);
+       if (cur_setting == 0) {
+               /* Didn't pick up device state yet. */
+               tokens[0] = TOKEN_WEIGHT_TIME_FAST;
+               tokens[1] = TOKEN_WEIGHT_TIME_SLOW;
+               tokens[2] = -1;
+               if (wait_for_token(sdi, tokens, 0) != SR_OK)
+                       return SR_ERR;
+               if (devc->token == TOKEN_WEIGHT_TIME_FAST)
+                       return SR_MQFLAG_SPL_TIME_WEIGHT_F;
+               else
+                       return SR_MQFLAG_SPL_TIME_WEIGHT_S;
+       } else
+               return cur_setting;
+}
+
+SR_PRIV int cem_dt_885x_weight_time_set(const struct sr_dev_inst *sdi, int timew)
+{
+       struct dev_context *devc;
+       int cur_setting, ret;
+       int8_t tokens[5];
+
+       devc = sdi->priv;
+
+       cur_setting = devc->cur_mqflags & (SR_MQFLAG_SPL_TIME_WEIGHT_F | SR_MQFLAG_SPL_TIME_WEIGHT_S);
+       if (cur_setting == timew)
+               /* Already set to this time weighting. */
+               return SR_OK;
+
+       /* The toggle below needs the desired state in first position. */
+       if (timew == SR_MQFLAG_SPL_TIME_WEIGHT_F) {
+               tokens[0] = TOKEN_WEIGHT_TIME_FAST;
+               tokens[1] = TOKEN_WEIGHT_TIME_SLOW;
+       } else {
+               tokens[0] = TOKEN_WEIGHT_TIME_SLOW;
+               tokens[1] = TOKEN_WEIGHT_TIME_FAST;
+       }
+       tokens[2] = -1;
+
+       if (cur_setting == 0) {
+               /* Didn't pick up device state yet. */
+               if (wait_for_token(sdi, tokens, 0) != SR_OK)
+                       return SR_ERR;
+               if (devc->token == tokens[0])
+                       /* Nothing to do. */
+                       return SR_OK;
+       }
+
+       /* 51ms timeout seems to work best for this. */
+       ret = cem_dt_885x_toggle(sdi, CMD_TOGGLE_WEIGHT_TIME, tokens, 51);
+
+       return ret;
+}
+
+SR_PRIV int cem_dt_885x_holdmode_get(const struct sr_dev_inst *sdi,
+               gboolean *holdmode)
+{
+       struct dev_context *devc;
+       int8_t tokens[5];
+
+       devc = sdi->priv;
+
+       if (devc->cur_mqflags == 0) {
+               tokens[0] = TOKEN_HOLD_MAX;
+               tokens[1] = TOKEN_HOLD_MIN;
+               tokens[2] = TOKEN_HOLD_NONE;
+               tokens[3] = -1;
+               if (wait_for_token(sdi, tokens, 0) != SR_OK)
+                       return SR_ERR;
+               if (devc->token == TOKEN_HOLD_MAX)
+                       devc->cur_mqflags = SR_MQFLAG_MAX;
+               else if (devc->token == TOKEN_HOLD_MIN)
+                       devc->cur_mqflags = SR_MQFLAG_MIN;
+       }
+       *holdmode = devc->cur_mqflags & (SR_MQFLAG_MAX | SR_MQFLAG_MIN);
+
+       return SR_OK;
+}
+
+SR_PRIV int cem_dt_885x_holdmode_set(const struct sr_dev_inst *sdi, int holdmode)
+{
+       struct dev_context *devc;
+       int cur_setting, ret;
+       int8_t tokens[5];
+
+       devc = sdi->priv;
+
+       /* The toggle below needs the desired state in first position. */
+       if (holdmode == SR_MQFLAG_MAX) {
+               tokens[0] = TOKEN_HOLD_MAX;
+               tokens[1] = TOKEN_HOLD_MIN;
+               tokens[2] = TOKEN_HOLD_NONE;
+       } else if (holdmode == SR_MQFLAG_MIN) {
+               tokens[0] = TOKEN_HOLD_MIN;
+               tokens[1] = TOKEN_HOLD_MAX;
+               tokens[2] = TOKEN_HOLD_NONE;
+       } else {
+               tokens[0] = TOKEN_HOLD_NONE;
+               tokens[1] = TOKEN_HOLD_MAX;
+               tokens[2] = TOKEN_HOLD_MIN;
+       }
+       tokens[3] = -1;
+
+       if (devc->cur_mqflags == 0) {
+               /* Didn't pick up device state yet. */
+               if (wait_for_token(sdi, tokens, 0) != SR_OK)
+                       return SR_ERR;
+               if (devc->token == tokens[0])
+                       /* Nothing to do. */
+                       return SR_OK;
+       } else {
+               cur_setting = devc->cur_mqflags & (SR_MQFLAG_MAX | SR_MQFLAG_MIN);
+               if (cur_setting == holdmode)
+                       /* Already set correctly. */
+                       return SR_OK;
+       }
+
+       /* 51ms timeout seems to work best for this. */
+       ret = cem_dt_885x_toggle(sdi, CMD_TOGGLE_HOLD_MAX_MIN, tokens, 51);
+
+       return ret;
+}
+
+SR_PRIV int cem_dt_885x_meas_range_get(const struct sr_dev_inst *sdi,
+               uint64_t *low, uint64_t *high)
+{
+       struct dev_context *devc;
+       int8_t tokens[5];
+
+       devc = sdi->priv;
+       if (devc->cur_meas_range == 0) {
+               tokens[0] = TOKEN_MEAS_RANGE_30_130;
+               tokens[1] = TOKEN_MEAS_RANGE_30_80;
+               tokens[2] = TOKEN_MEAS_RANGE_50_100;
+               tokens[3] = TOKEN_MEAS_RANGE_80_130;
+               tokens[4] = -1;
+               if (wait_for_token(sdi, tokens, 0) != SR_OK)
+                       return SR_ERR;
+               devc->cur_meas_range = devc->token;
+       }
+
+       switch (devc->cur_meas_range) {
+       case TOKEN_MEAS_RANGE_30_130:
+               *low = 30;
+               *high = 130;
+               break;
+       case TOKEN_MEAS_RANGE_30_80:
+               *low = 30;
+               *high = 80;
+               break;
+       case TOKEN_MEAS_RANGE_50_100:
+               *low = 50;
+               *high = 100;
+               break;
+       case TOKEN_MEAS_RANGE_80_130:
+               *low = 80;
+               *high = 130;
+               break;
+       default:
+               return SR_ERR;
+       }
+
+       return SR_OK;
+}
+
+SR_PRIV int cem_dt_885x_meas_range_set(const struct sr_dev_inst *sdi,
+               uint64_t low, uint64_t high)
+{
+       struct dev_context *devc;
+       int ret;
+       int8_t token, tokens[6];
+
+       devc = sdi->priv;
+       if (low == 30 && high == 130)
+               token = TOKEN_MEAS_RANGE_30_130;
+       else if (low == 30 &&  high == 80)
+               token = TOKEN_MEAS_RANGE_30_80;
+       else if (low == 50 &&  high == 100)
+               token = TOKEN_MEAS_RANGE_50_100;
+       else if (low == 80 &&  high == 130)
+               token = TOKEN_MEAS_RANGE_80_130;
+       else
+               return SR_ERR;
+
+       sr_dbg("want 0x%.2x", token);
+       /* The toggle below needs the desired state in first position. */
+       tokens[0] = token;
+       tokens[1] = TOKEN_MEAS_RANGE_30_130;
+       tokens[2] = TOKEN_MEAS_RANGE_30_80;
+       tokens[3] = TOKEN_MEAS_RANGE_50_100;
+       tokens[4] = TOKEN_MEAS_RANGE_80_130;
+       tokens[5] = -1;
+
+       if (devc->cur_meas_range == 0) {
+               /* 110ms should be enough for two of these announcements */
+               if (wait_for_token(sdi, tokens, 110) != SR_OK)
+                       return SR_ERR;
+               devc->cur_meas_range = devc->token;
+       }
+
+       if (devc->cur_meas_range == token)
+               /* Already set to this range. */
+               return SR_OK;
+
+       /* For measurement range, it works best to ignore announcements of the
+        * current setting and keep resending the toggle quickly. */
+       tokens[1] = -1;
+       ret = cem_dt_885x_toggle(sdi, CMD_TOGGLE_MEAS_RANGE, tokens, 11);
+
+       return ret;
+}
+
+SR_PRIV int cem_dt_885x_power_off(const struct sr_dev_inst *sdi)
+{
+       struct sr_serial_dev_inst *serial;
+       char c, cmd;
+
+       serial = sdi->conn;
+
+       /* Reopen the port in non-blocking mode, so we can properly
+        * detect when the device stops communicating. */
+       serial_close(serial);
+       if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
+               return SR_ERR;
+
+       cmd = CMD_TOGGLE_POWER_OFF;
+       while (TRUE) {
+               serial_flush(serial);
+               if (serial_write(serial, (const void *)&cmd, 1) != 1)
+                       return SR_ERR;
+               /* It never takes more than 23ms for the next token to arrive. */
+               g_usleep(25 * 1000);
+               if (serial_read(serial, &c, 1) != 1)
+                       /* Device is no longer responding. Good! */
+                       break;
+       }
+
+       /* In case the user manually turns on the device again, reset
+        * the port back to blocking. */
+       serial_close(serial);
+       serial_open(serial, SERIAL_RDWR);
+
+       return SR_OK;
+}
diff --git a/src/hardware/cem-dt-885x/protocol.h b/src/hardware/cem-dt-885x/protocol.h
new file mode 100644 (file)
index 0000000..233ef86
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert@biot.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_CEM_DT_885X_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_CEM_DT_885X_PROTOCOL_H
+
+#include <stdint.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "cem-dt-885x"
+
+/* When retrieving samples from device memory, group this many
+ * together into a sigrok packet. */
+#define SAMPLES_PER_PACKET 50
+
+/* Various temporary storage, at least 8 bytes. */
+#define BUF_SIZE SAMPLES_PER_PACKET * 2
+
+/* When in hold mode, force the last measurement out at this interval.
+ * We're using 50ms, which duplicates the non-hold 20Hz update rate. */
+#define HOLD_REPEAT_INTERVAL 50 * 1000
+
+enum {
+       TOKEN_WEIGHT_TIME_FAST = 0x02,
+       TOKEN_WEIGHT_TIME_SLOW = 0x03,
+       TOKEN_HOLD_MAX = 0x04,
+       TOKEN_HOLD_MIN = 0x05,
+       TOKEN_TIME = 0x06,
+       TOKEN_MEAS_RANGE_OVER = 0x07,
+       TOKEN_MEAS_RANGE_UNDER = 0x08,
+       TOKEN_STORE_FULL = 0x09,
+       TOKEN_RECORDING_ON = 0x0a,
+       TOKEN_MEAS_WAS_READOUT = 0x0b,
+       TOKEN_MEAS_WAS_BARGRAPH = 0x0c,
+       TOKEN_MEASUREMENT = 0xd,
+       TOKEN_HOLD_NONE = 0x0e,
+       TOKEN_BATTERY_LOW = 0x0f,
+       TOKEN_MEAS_RANGE_OK = 0x11,
+       TOKEN_STORE_OK = 0x19,
+       TOKEN_RECORDING_OFF = 0x1a,
+       TOKEN_WEIGHT_FREQ_A = 0x1b,
+       TOKEN_WEIGHT_FREQ_C = 0x1c,
+       TOKEN_BATTERY_OK = 0x1f,
+       TOKEN_MEAS_RANGE_30_80 = 0x30,
+       TOKEN_MEAS_RANGE_30_130 = 0x40,
+       TOKEN_MEAS_RANGE_50_100 = 0x4b,
+       TOKEN_MEAS_RANGE_80_130 = 0x4c,
+};
+
+enum {
+       CMD_TOGGLE_RECORDING = 0x55,
+       CMD_TOGGLE_WEIGHT_FREQ = 0x99,
+       CMD_TOGGLE_WEIGHT_TIME = 0x77,
+       CMD_TOGGLE_HOLD_MAX_MIN = 0x11,
+       CMD_TOGGLE_MEAS_RANGE = 0x88,
+       CMD_TOGGLE_POWER_OFF = 0x33,
+       CMD_TRANSFER_MEMORY = 0xac,
+};
+
+enum {
+       RECORD_DBA = 0xaa,
+       RECORD_DBC = 0xcc,
+       RECORD_DATA = 0xac,
+       RECORD_END = 0xdd,
+};
+
+enum {
+       DATA_SOURCE_LIVE,
+       DATA_SOURCE_MEMORY,
+};
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+       /* Device state */
+       uint64_t cur_mqflags;
+       int recording;
+       int cur_meas_range;
+       int cur_data_source;
+
+       /* Acquisition settings */
+       uint64_t limit_samples;
+
+       /* Operational state */
+       int state;
+       uint64_t num_samples;
+       gboolean enable_data_source_memory;
+
+       /* Temporary state across callbacks */
+       void *cb_data;
+       unsigned char cmd;
+       unsigned char token;
+       int buf_len;
+       unsigned char buf[BUF_SIZE];
+       float last_spl;
+       gint64 hold_last_sent;
+};
+
+/* Parser state machine. */
+enum {
+       ST_INIT,
+       ST_GET_TOKEN,
+       ST_GET_DATA,
+       ST_GET_LOG_HEADER,
+       ST_GET_LOG_RECORD_META,
+       ST_GET_LOG_RECORD_DATA,
+};
+
+SR_PRIV int cem_dt_885x_receive_data(int fd, int revents, void *cb_data);
+SR_PRIV int cem_dt_885x_recording_set(const struct sr_dev_inst *sdi, gboolean start);
+SR_PRIV gboolean cem_dt_885x_recording_get(const struct sr_dev_inst *sdi,
+               int *state);
+SR_PRIV int cem_dt_885x_weight_freq_get(const struct sr_dev_inst *sdi);
+SR_PRIV int cem_dt_885x_weight_freq_set(const struct sr_dev_inst *sdi, int freqw);
+SR_PRIV int cem_dt_885x_weight_time_get(const struct sr_dev_inst *sdi);
+SR_PRIV int cem_dt_885x_weight_time_set(const struct sr_dev_inst *sdi, int timew);
+SR_PRIV int cem_dt_885x_holdmode_get(const struct sr_dev_inst *sdi,
+               gboolean *holdmode);
+SR_PRIV int cem_dt_885x_holdmode_set(const struct sr_dev_inst *sdi, int holdmode);
+SR_PRIV int cem_dt_885x_meas_range_get(const struct sr_dev_inst *sdi,
+               uint64_t *low, uint64_t *high);
+SR_PRIV int cem_dt_885x_meas_range_set(const struct sr_dev_inst *sdi,
+               uint64_t low, uint64_t high);
+SR_PRIV int cem_dt_885x_power_off(const struct sr_dev_inst *sdi);
+
+#endif
diff --git a/src/hardware/center-3xx/api.c b/src/hardware/center-3xx/api.c
new file mode 100644 (file)
index 0000000..3f39b19
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "protocol.h"
+
+static const int32_t hwopts[] = {
+       SR_CONF_CONN,
+       SR_CONF_SERIALCOMM,
+};
+
+static const int32_t hwcaps[] = {
+       SR_CONF_THERMOMETER,
+       SR_CONF_LIMIT_SAMPLES,
+       SR_CONF_LIMIT_MSEC,
+       SR_CONF_CONTINUOUS,
+};
+
+static const char *channel_names[] = {
+       "T1", "T2", "T3", "T4",
+       NULL,
+};
+
+SR_PRIV struct sr_dev_driver center_309_driver_info;
+SR_PRIV struct sr_dev_driver voltcraft_k204_driver_info;
+
+SR_PRIV const struct center_dev_info center_devs[] = {
+       {
+               "Center", "309", "9600/8n1", 4, 32000, 45,
+               center_3xx_packet_valid,
+               &center_309_driver_info, receive_data_CENTER_309,
+       },
+       {
+               "Voltcraft", "K204", "9600/8n1", 4, 32000, 45,
+               center_3xx_packet_valid,
+               &voltcraft_k204_driver_info, receive_data_VOLTCRAFT_K204,
+       },
+};
+
+static int dev_clear(int idx)
+{
+       return std_dev_clear(center_devs[idx].di, NULL);
+}
+
+static int init(struct sr_context *sr_ctx, int idx)
+{
+       sr_dbg("Selected '%s' subdriver.", center_devs[idx].di->name);
+
+       return std_init(sr_ctx, center_devs[idx].di, LOG_PREFIX);
+}
+
+static GSList *center_scan(const char *conn, const char *serialcomm, int idx)
+{
+       int i;
+       struct sr_dev_inst *sdi;
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       struct sr_channel *ch;
+       struct sr_serial_dev_inst *serial;
+       GSList *devices;
+
+       if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
+               return NULL;
+
+       if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
+               return NULL;
+
+       drvc = center_devs[idx].di->priv;
+       devices = NULL;
+       serial_flush(serial);
+
+       sr_info("Found device on port %s.", conn);
+
+       if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, center_devs[idx].vendor,
+                                   center_devs[idx].device, NULL)))
+               goto scan_cleanup;
+
+       if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+               sr_err("Device context malloc failed.");
+               goto scan_cleanup;
+       }
+
+       sdi->inst_type = SR_INST_SERIAL;
+       sdi->conn = serial;
+
+       sdi->priv = devc;
+       sdi->driver = center_devs[idx].di;
+
+       for (i = 0; i <  center_devs[idx].num_channels; i++) {
+               if (!(ch = sr_channel_new(i, SR_CHANNEL_ANALOG,
+                                          TRUE, channel_names[i])))
+                       goto scan_cleanup;
+               sdi->channels = g_slist_append(sdi->channels, ch);
+       }
+
+       drvc->instances = g_slist_append(drvc->instances, sdi);
+       devices = g_slist_append(devices, sdi);
+
+scan_cleanup:
+       serial_close(serial);
+
+       return devices;
+}
+
+static GSList *scan(GSList *options, int idx)
+{
+       struct sr_config *src;
+       GSList *l, *devices;
+       const char *conn, *serialcomm;
+
+       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 = center_scan(conn, serialcomm, idx);
+       } else {
+               /* Try the default. */
+               devices = center_scan(conn, center_devs[idx].conn, idx);
+       }
+
+       return devices;
+}
+
+static GSList *dev_list(int idx)
+{
+       return ((struct drv_context *)(center_devs[idx].di->priv))->instances;
+}
+
+static int cleanup(int idx)
+{
+       return dev_clear(idx);
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+
+       (void)cg;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       devc = sdi->priv;
+
+       switch (id) {
+       case SR_CONF_LIMIT_SAMPLES:
+               if (g_variant_get_uint64(data) == 0)
+                       return SR_ERR_ARG;
+               devc->limit_samples = g_variant_get_uint64(data);
+               break;
+       case SR_CONF_LIMIT_MSEC:
+               if (g_variant_get_uint64(data) == 0)
+                       return SR_ERR_ARG;
+               devc->limit_msec = g_variant_get_uint64(data);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_list(int 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_INT32,
+                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+               break;
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi,
+                                   void *cb_data, int idx)
+{
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       devc = sdi->priv;
+       devc->cb_data = cb_data;
+       devc->num_samples = 0;
+       devc->starttime = g_get_monotonic_time();
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(cb_data, LOG_PREFIX);
+
+       /* Poll every 500ms, or whenever some data comes in. */
+       serial = sdi->conn;
+       serial_source_add(sdi->session, serial, G_IO_IN, 500,
+                     center_devs[idx].receive_data, (void *)sdi);
+
+       return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       return std_serial_dev_acquisition_stop(sdi, cb_data,
+                       std_serial_dev_close, sdi->conn, LOG_PREFIX);
+}
+
+/* Driver-specific API function wrappers */
+#define HW_INIT(X) \
+static int init_##X(struct sr_context *sr_ctx) { return init(sr_ctx, X); }
+#define HW_CLEANUP(X) \
+static int cleanup_##X(void) { return cleanup(X); }
+#define HW_SCAN(X) \
+static GSList *scan_##X(GSList *options) { return scan(options, X); }
+#define HW_DEV_LIST(X) \
+static GSList *dev_list_##X(void) { return dev_list(X); }
+#define HW_DEV_CLEAR(X) \
+static int dev_clear_##X(void) { return dev_clear(X); }
+#define HW_DEV_ACQUISITION_START(X) \
+static int dev_acquisition_start_##X(const struct sr_dev_inst *sdi, \
+void *cb_data) { return dev_acquisition_start(sdi, cb_data, X); }
+
+/* Driver structs and API function wrappers */
+#define DRV(ID, ID_UPPER, NAME, LONGNAME) \
+HW_INIT(ID_UPPER) \
+HW_CLEANUP(ID_UPPER) \
+HW_SCAN(ID_UPPER) \
+HW_DEV_LIST(ID_UPPER) \
+HW_DEV_CLEAR(ID_UPPER) \
+HW_DEV_ACQUISITION_START(ID_UPPER) \
+SR_PRIV struct sr_dev_driver ID##_driver_info = { \
+       .name = NAME, \
+       .longname = LONGNAME, \
+       .api_version = 1, \
+       .init = init_##ID_UPPER, \
+       .cleanup = cleanup_##ID_UPPER, \
+       .scan = scan_##ID_UPPER, \
+       .dev_list = dev_list_##ID_UPPER, \
+       .dev_clear = dev_clear_##ID_UPPER, \
+       .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_##ID_UPPER, \
+       .dev_acquisition_stop = dev_acquisition_stop, \
+       .priv = NULL, \
+};
+
+DRV(center_309, CENTER_309, "center-309", "Center 309")
+DRV(voltcraft_k204, VOLTCRAFT_K204, "voltcraft-k204", "Voltcraft K204")
diff --git a/src/hardware/center-3xx/protocol.c b/src/hardware/center-3xx/protocol.c
new file mode 100644 (file)
index 0000000..ef8b9dc
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "protocol.h"
+
+struct center_info {
+       float temp[4];
+       gboolean rec, std, max, min, maxmin, t1t2, rel, hold, lowbat, celsius;
+       gboolean memfull, autooff;
+       gboolean mode_std, mode_rel, mode_max, mode_min, mode_maxmin;
+};
+
+static int center_send(struct sr_serial_dev_inst *serial, const char *cmd)
+{
+       int ret;
+
+       if ((ret = serial_write(serial, cmd, strlen(cmd))) < 0) {
+               sr_err("Error sending '%s' command: %d.", cmd, ret);
+               return SR_ERR;
+       }
+
+       return SR_OK;
+}
+
+SR_PRIV gboolean center_3xx_packet_valid(const uint8_t *buf)
+{
+       return (buf[0] == 0x02 && buf[44] == 0x03);
+}
+
+static void log_packet(const uint8_t *buf, int idx)
+{
+       int i;
+       GString *s;
+
+       s = g_string_sized_new(100);
+       g_string_printf(s, "Packet: ");
+       for (i = 0; i < center_devs[idx].packet_size; i++)
+               g_string_append_printf(s, "%02x ", buf[i]);
+       sr_spew("%s", s->str);
+       g_string_free(s, TRUE);
+}
+
+static int packet_parse(const uint8_t *buf, int idx, struct center_info *info)
+{
+       int i;
+       uint16_t temp_u16;
+
+       log_packet(buf, idx);
+
+       /* Byte 0: Always 0x02. */
+
+       /* Byte 1: Various status bits. */
+       info->rec         = (buf[1] & (1 << 0)) != 0;
+       info->mode_std    = (((buf[1] >> 1) & 0x3) == 0);
+       info->mode_max    = (((buf[1] >> 1) & 0x3) == 1);
+       info->mode_min    = (((buf[1] >> 1) & 0x3) == 2);
+       info->mode_maxmin = (((buf[1] >> 1) & 0x3) == 3);
+       /* TODO: Rel. Not available on all models. */
+       info->t1t2        = (buf[1] & (1 << 3)) != 0;
+       info->rel         = (buf[1] & (1 << 4)) != 0;
+       info->hold        = (buf[1] & (1 << 5)) != 0;
+       info->lowbat      = (buf[1] & (1 << 6)) != 0;
+       info->celsius     = (buf[1] & (1 << 7)) != 0;
+
+       /* Byte 2: Further status bits. */
+       info->memfull     = (buf[2] & (1 << 0)) != 0;
+       info->autooff     = (buf[2] & (1 << 7)) != 0;
+
+       /* Byte 7+8/9+10/11+12/13+14: channel T1/T2/T3/T4 temperature. */
+       for (i = 0; i < 4; i++) {
+               temp_u16 = buf[8 + (i * 2)];
+               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. */
+       for (i = 0; i < 4; i++) {
+               /* Bit = 0: Divide by 10. Bit = 1: Don't divide by 10. */
+               if ((buf[43] & (1 << i)) == 0)
+                       info->temp[i] /= 10;
+       }
+
+       /* Bytes 39-42: Overflow/overlimit bits, depending on mode. */
+       for (i = 0; i < 4; i++) {
+               if (info->mode_std && ((buf[39] & (1 << i)) != 0))
+                       info->temp[i] = INFINITY;
+               /* TODO: Rel. Not available on all models. */
+               // if (info->mode_rel && ((buf[40] & (1 << i)) != 0))
+               //      info->temp[i] = INFINITY;
+               if (info->mode_max && ((buf[41] & (1 << i)) != 0))
+                       info->temp[i] = INFINITY;
+               if (info->mode_min && ((buf[42] & (1 << i)) != 0))
+                       info->temp[i] = INFINITY;
+               /* TODO: Minmax? */
+       }
+
+       /* Byte 44: Always 0x03. */
+
+       return SR_OK;
+}
+
+static int handle_packet(const uint8_t *buf, struct sr_dev_inst *sdi, int idx)
+{
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_analog analog;
+       struct dev_context *devc;
+       struct center_info info;
+       GSList *l;
+       int i, ret;
+
+       devc = sdi->priv;
+
+       memset(&analog, 0, sizeof(struct sr_datafeed_analog));
+       memset(&info, 0, sizeof(struct center_info));
+
+       ret = packet_parse(buf, idx, &info);
+       if (ret < 0) {
+               sr_err("Failed to parse packet.");
+               return SR_ERR;
+       }
+
+       /* Common values for all 4 channels. */
+       packet.type = SR_DF_ANALOG;
+       packet.payload = &analog;
+       analog.mq = SR_MQ_TEMPERATURE;
+       analog.unit = (info.celsius) ? SR_UNIT_CELSIUS : SR_UNIT_FAHRENHEIT;
+       analog.num_samples = 1;
+
+       /* Send the values for T1 - T4. */
+       for (i = 0; i < 4; i++) {
+               l = NULL;
+               l = g_slist_append(l, g_slist_nth_data(sdi->channels, i));
+               analog.channels = l;
+               analog.data = &(info.temp[i]);
+               sr_session_send(devc->cb_data, &packet);
+               g_slist_free(l);
+       }
+
+       devc->num_samples++;
+
+       return SR_OK;
+}
+
+/* Return TRUE if a full packet was parsed, FALSE otherwise. */
+static gboolean handle_new_data(struct sr_dev_inst *sdi, int idx)
+{
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+       int len, i, offset = 0, ret = FALSE;
+
+       devc = sdi->priv;
+       serial = sdi->conn;
+
+       /* Try to get as much data as the buffer can hold. */
+       len = SERIAL_BUFSIZE - devc->buflen;
+       len = serial_read(serial, devc->buf + devc->buflen, len);
+       if (len < 1) {
+               sr_err("Serial port read error: %d.", len);
+               return FALSE;
+       }
+
+       devc->buflen += len;
+
+       /* Now look for packets in that data. */
+       while ((devc->buflen - offset) >= center_devs[idx].packet_size) {
+               if (center_devs[idx].packet_valid(devc->buf + offset)) {
+                       handle_packet(devc->buf + offset, sdi, idx);
+                       offset += center_devs[idx].packet_size;
+                       ret = TRUE;
+               } else {
+                       offset++;
+               }
+       }
+
+       /* If we have any data left, move it to the beginning of our buffer. */
+       for (i = 0; i < devc->buflen - offset; i++)
+               devc->buf[i] = devc->buf[offset + i];
+       devc->buflen -= offset;
+
+       return ret;
+}
+
+static int receive_data(int fd, int revents, int idx, void *cb_data)
+{
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       int64_t t;
+       static gboolean request_new_packet = TRUE;
+       struct sr_serial_dev_inst *serial;
+
+       (void)fd;
+
+       if (!(sdi = cb_data))
+               return TRUE;
+
+       if (!(devc = sdi->priv))
+               return TRUE;
+
+       serial = sdi->conn;
+
+       if (revents == G_IO_IN) {
+               /* New data arrived. */
+               request_new_packet = handle_new_data(sdi, idx);
+       } else {
+               /*
+                * Timeout. Send "A" to request a packet, but then don't send
+                * further "A" commands until we received a full packet first.
+                */
+               if (request_new_packet) {
+                       center_send(serial, "A");
+                       request_new_packet = FALSE;
+               }
+       }
+
+       if (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
+               sr_info("Requested number of samples reached.");
+               sdi->driver->dev_acquisition_stop(sdi, cb_data);
+               return TRUE;
+       }
+
+       if (devc->limit_msec) {
+               t = (g_get_monotonic_time() - devc->starttime) / 1000;
+               if (t > (int64_t)devc->limit_msec) {
+                       sr_info("Requested time limit reached.");
+                       sdi->driver->dev_acquisition_stop(sdi, cb_data);
+                       return TRUE;
+               }
+       }
+
+       return TRUE;
+}
+
+#define RECEIVE_DATA(ID_UPPER) \
+SR_PRIV int receive_data_##ID_UPPER(int fd, int revents, void *cb_data) { \
+       return receive_data(fd, revents, ID_UPPER, cb_data); }
+
+/* Driver-specific receive_data() wrappers */
+RECEIVE_DATA(CENTER_309)
+RECEIVE_DATA(VOLTCRAFT_K204)
diff --git a/src/hardware/center-3xx/protocol.h b/src/hardware/center-3xx/protocol.h
new file mode 100644 (file)
index 0000000..71e2630
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#ifndef LIBSIGROK_HARDWARE_CENTER_3XX_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_CENTER_3XX_PROTOCOL_H
+
+#include <stdint.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "center-3xx"
+
+/* Note: When adding entries here, don't forget to update CENTER_DEV_COUNT. */
+enum {
+       CENTER_309,
+       VOLTCRAFT_K204,
+};
+
+#define CENTER_DEV_COUNT 2
+
+struct center_dev_info {
+       char *vendor;
+       char *device;
+       char *conn;
+       int num_channels;
+       uint32_t max_sample_points;
+       uint8_t packet_size;
+       gboolean (*packet_valid)(const uint8_t *);
+       struct sr_dev_driver *di;
+       int (*receive_data)(int, int, void *);
+};
+
+extern SR_PRIV const struct center_dev_info center_devs[CENTER_DEV_COUNT];
+
+#define SERIAL_BUFSIZE 256
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+       /** The current sampling limit (in number of samples). */
+       uint64_t limit_samples;
+
+       /** The current sampling limit (in ms). */
+       uint64_t limit_msec;
+
+       /** Opaque pointer passed in by the frontend. */
+       void *cb_data;
+
+       /** The current number of already received samples. */
+       uint64_t num_samples;
+
+       int64_t starttime;
+
+       uint8_t buf[SERIAL_BUFSIZE];
+       int bufoffset;
+       int buflen;
+};
+
+SR_PRIV gboolean center_3xx_packet_valid(const uint8_t *buf);
+
+SR_PRIV int receive_data_CENTER_309(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_VOLTCRAFT_K204(int fd, int revents, void *cb_data);
+
+#endif
diff --git a/src/hardware/chronovu-la/api.c b/src/hardware/chronovu-la/api.c
new file mode 100644 (file)
index 0000000..5a8a3d3
--- /dev/null
@@ -0,0 +1,558 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2011-2014 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "protocol.h"
+
+SR_PRIV struct sr_dev_driver chronovu_la_driver_info;
+static struct sr_dev_driver *di = &chronovu_la_driver_info;
+
+static const int32_t hwcaps[] = {
+       SR_CONF_LOGIC_ANALYZER,
+       SR_CONF_SAMPLERATE,
+       SR_CONF_TRIGGER_MATCH,
+       SR_CONF_LIMIT_MSEC, /* TODO: Not yet implemented. */
+       SR_CONF_LIMIT_SAMPLES, /* TODO: Not yet implemented. */
+};
+
+static const int32_t trigger_matches[] = {
+       SR_TRIGGER_ZERO,
+       SR_TRIGGER_ONE,
+       SR_TRIGGER_RISING,
+       SR_TRIGGER_FALLING,
+};
+
+/* The ChronoVu LA8/LA16 can have multiple VID/PID pairs. */
+static struct {
+       uint16_t vid;
+       uint16_t pid;
+       int model;
+       const char *iproduct;
+} vid_pid[] = {
+       { 0x0403, 0x6001, CHRONOVU_LA8,  "ChronoVu LA8"  },
+       { 0x0403, 0x8867, CHRONOVU_LA8,  "ChronoVu LA8"  },
+       { 0x0403, 0x6001, CHRONOVU_LA16, "ChronoVu LA16" },
+       { 0x0403, 0x8867, CHRONOVU_LA16, "ChronoVu LA16" },
+};
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data);
+
+static void clear_helper(void *priv)
+{
+       struct dev_context *devc;
+
+       devc = priv;
+
+       ftdi_free(devc->ftdic);
+       g_free(devc->final_buf);
+}
+
+static int dev_clear(void)
+{
+       return std_dev_clear(di, clear_helper);
+}
+
+static int init(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static int add_device(int idx, int model, GSList **devices)
+{
+       int ret;
+       unsigned int i;
+       struct sr_dev_inst *sdi;
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       struct sr_channel *ch;
+
+       ret = SR_OK;
+
+       drvc = di->priv;
+
+       /* Allocate memory for our private device context. */
+       devc = g_try_malloc(sizeof(struct dev_context));
+
+       /* Set some sane defaults. */
+       devc->prof = &cv_profiles[model];
+       devc->ftdic = NULL; /* Will be set in the open() API call. */
+       devc->cur_samplerate = 0; /* Set later (different for LA8/LA16). */
+       devc->limit_msec = 0;
+       devc->limit_samples = 0;
+       devc->cb_data = NULL;
+       memset(devc->mangled_buf, 0, BS);
+       devc->final_buf = NULL;
+       devc->trigger_pattern = 0x0000; /* Irrelevant, see trigger_mask. */
+       devc->trigger_mask = 0x0000; /* All channels: "don't care". */
+       devc->trigger_edgemask = 0x0000; /* All channels: "state triggered". */
+       devc->trigger_found = 0;
+       devc->done = 0;
+       devc->block_counter = 0;
+       devc->divcount = 0;
+       devc->usb_vid = vid_pid[idx].vid;
+       devc->usb_pid = vid_pid[idx].pid;
+       memset(devc->samplerates, 0, sizeof(uint64_t) * 255);
+
+       /* Allocate memory where we'll store the de-mangled data. */
+       if (!(devc->final_buf = g_try_malloc(SDRAM_SIZE))) {
+               sr_err("Failed to allocate memory for sample buffer.");
+               ret = SR_ERR_MALLOC;
+               goto err_free_devc;
+       }
+
+       /* We now know the device, set its max. samplerate as default. */
+       devc->cur_samplerate = devc->prof->max_samplerate;
+
+       /* Register the device with libsigrok. */
+       sdi = sr_dev_inst_new(0, SR_ST_INITIALIZING,
+                             "ChronoVu", devc->prof->modelname, NULL);
+       if (!sdi) {
+               sr_err("Failed to create device instance.");
+               ret = SR_ERR;
+               goto err_free_final_buf;
+       }
+       sdi->driver = di;
+       sdi->priv = devc;
+
+       for (i = 0; i < devc->prof->num_channels; i++) {
+               if (!(ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE,
+                                         cv_channel_names[i]))) {
+                       ret = SR_ERR;
+                       goto err_free_dev_inst;
+               }
+               sdi->channels = g_slist_append(sdi->channels, ch);
+       }
+
+       *devices = g_slist_append(*devices, sdi);
+       drvc->instances = g_slist_append(drvc->instances, sdi);
+
+       return SR_OK;
+
+err_free_dev_inst:
+       sr_dev_inst_free(sdi);
+err_free_final_buf:
+       g_free(devc->final_buf);
+err_free_devc:
+       g_free(devc);
+
+       return ret;
+}
+
+static GSList *scan(GSList *options)
+{
+       int ret;
+       unsigned int i;
+       GSList *devices;
+       struct ftdi_context *ftdic;
+
+       (void)options;
+
+       devices = NULL;
+
+       /* Allocate memory for the FTDI context and initialize it. */
+       if (!(ftdic = ftdi_new())) {
+               sr_err("Failed to initialize libftdi.");
+               return NULL;
+       }
+
+       /* Check for LA8 and/or LA16 devices with various VID/PIDs. */
+       for (i = 0; i < ARRAY_SIZE(vid_pid); i++) {
+               ret = ftdi_usb_open_desc(ftdic, vid_pid[i].vid,
+                       vid_pid[i].pid, vid_pid[i].iproduct, NULL);
+               /* Show errors other than "device not found". */
+               if (ret < 0 && ret != -3)
+                       sr_dbg("Error finding/opening device (%d): %s.",
+                              ret, ftdi_get_error_string(ftdic));
+               if (ret < 0)
+                       continue; /* No device found, or not usable. */
+
+               sr_dbg("Found %s device (%04x:%04x).",
+                      vid_pid[i].iproduct, vid_pid[i].vid, vid_pid[i].pid);
+
+               if ((ret = add_device(i, vid_pid[i].model, &devices)) < 0)
+                       sr_dbg("Failed to add device: %d.", ret);
+
+               if ((ret = ftdi_usb_close(ftdic)) < 0)
+                       sr_dbg("Failed to close FTDI device (%d): %s.",
+                              ret, ftdi_get_error_string(ftdic));
+       }
+
+       /* Close USB device, deinitialize and free the FTDI context. */
+       ftdi_free(ftdic);
+       ftdic = NULL;
+
+       return devices;
+}
+
+static GSList *dev_list(void)
+{
+       return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       int ret;
+
+       ret = SR_ERR;
+
+       if (!(devc = sdi->priv))
+               return SR_ERR_BUG;
+
+       /* Allocate memory for the FTDI context and initialize it. */
+       if (!(devc->ftdic = ftdi_new())) {
+               sr_err("Failed to initialize libftdi.");
+               return SR_ERR;
+       }
+
+       sr_dbg("Opening %s device (%04x:%04x).", devc->prof->modelname,
+              devc->usb_vid, devc->usb_pid);
+
+       /* Open the device. */
+       if ((ret = ftdi_usb_open_desc(devc->ftdic, devc->usb_vid,
+                       devc->usb_pid, devc->prof->iproduct, NULL)) < 0) {
+               sr_err("Failed to open FTDI device (%d): %s.",
+                      ret, ftdi_get_error_string(devc->ftdic));
+               goto err_ftdi_free;
+       }
+       sr_dbg("Device opened successfully.");
+
+       /* Purge RX/TX buffers in the FTDI chip. */
+       if ((ret = ftdi_usb_purge_buffers(devc->ftdic)) < 0) {
+               sr_err("Failed to purge FTDI buffers (%d): %s.",
+                      ret, ftdi_get_error_string(devc->ftdic));
+               goto err_ftdi_free;
+       }
+       sr_dbg("FTDI buffers purged successfully.");
+
+       /* Enable flow control in the FTDI chip. */
+       if ((ret = ftdi_setflowctrl(devc->ftdic, SIO_RTS_CTS_HS)) < 0) {
+               sr_err("Failed to enable FTDI flow control (%d): %s.",
+                      ret, ftdi_get_error_string(devc->ftdic));
+               goto err_ftdi_free;
+       }
+       sr_dbg("FTDI flow control enabled successfully.");
+
+       /* Wait 100ms. */
+       g_usleep(100 * 1000);
+
+       sdi->status = SR_ST_ACTIVE;
+
+       return SR_OK;
+
+err_ftdi_free:
+       ftdi_free(devc->ftdic); /* Close device (if open), free FTDI context. */
+       devc->ftdic = NULL;
+       return ret;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+       int ret;
+       struct dev_context *devc;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_OK;
+
+       devc = sdi->priv;
+
+       if (devc->ftdic && (ret = ftdi_usb_close(devc->ftdic)) < 0)
+               sr_err("Failed to close FTDI device (%d): %s.",
+                      ret, ftdi_get_error_string(devc->ftdic));
+       sdi->status = SR_ST_INACTIVE;
+
+       return SR_OK;
+}
+
+static int cleanup(void)
+{
+       return dev_clear();
+}
+
+static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+
+       (void)cg;
+
+       switch (id) {
+       case SR_CONF_SAMPLERATE:
+               if (!sdi || !(devc = sdi->priv))
+                       return SR_ERR_BUG;
+               *data = g_variant_new_uint64(devc->cur_samplerate);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_set(int id, 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;
+
+       if (!(devc = sdi->priv))
+               return SR_ERR_BUG;
+
+       switch (id) {
+       case SR_CONF_SAMPLERATE:
+               if (cv_set_samplerate(sdi, g_variant_get_uint64(data)) < 0)
+                       return SR_ERR;
+               break;
+       case SR_CONF_LIMIT_MSEC:
+               if (g_variant_get_uint64(data) == 0)
+                       return SR_ERR_ARG;
+               devc->limit_msec = g_variant_get_uint64(data);
+               break;
+       case SR_CONF_LIMIT_SAMPLES:
+               if (g_variant_get_uint64(data) == 0)
+                       return SR_ERR_ARG;
+               devc->limit_samples = g_variant_get_uint64(data);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       GVariant *gvar, *grange[2];
+       GVariantBuilder gvb;
+       struct dev_context *devc;
+
+       (void)cg;
+
+       switch (key) {
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+               break;
+       case SR_CONF_SAMPLERATE:
+               if (!sdi || !sdi->priv || !(devc = sdi->priv))
+                       return SR_ERR_BUG;
+               cv_fill_samplerates_if_needed(sdi);
+               g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
+               gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"),
+                               devc->samplerates,
+                               ARRAY_SIZE(devc->samplerates),
+                               sizeof(uint64_t));
+               g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar);
+               *data = g_variant_builder_end(&gvb);
+               break;
+       case SR_CONF_LIMIT_SAMPLES:
+               if (!sdi || !sdi->priv || !(devc = sdi->priv) || !devc->prof)
+                       return SR_ERR_BUG;
+               grange[0] = g_variant_new_uint64(0);
+               if (devc->prof->model == CHRONOVU_LA8)
+                       grange[1] = g_variant_new_uint64(MAX_NUM_SAMPLES);
+               else
+                       grange[1] = g_variant_new_uint64(MAX_NUM_SAMPLES / 2);
+               *data = g_variant_new_tuple(grange, 2);
+               break;
+       case SR_CONF_TRIGGER_MATCH:
+               if (!sdi || !sdi->priv || !(devc = sdi->priv) || !devc->prof)
+                       return SR_ERR_BUG;
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               trigger_matches, devc->prof->num_trigger_matches,
+                               sizeof(int32_t));
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int receive_data(int fd, int revents, void *cb_data)
+{
+       int i, ret;
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+
+       (void)fd;
+       (void)revents;
+
+       if (!(sdi = cb_data)) {
+               sr_err("cb_data was NULL.");
+               return FALSE;
+       }
+
+       if (!(devc = sdi->priv)) {
+               sr_err("sdi->priv was NULL.");
+               return FALSE;
+       }
+
+       if (!devc->ftdic) {
+               sr_err("devc->ftdic was NULL.");
+               return FALSE;
+       }
+
+       /* Get one block of data. */
+       if ((ret = cv_read_block(devc)) < 0) {
+               sr_err("Failed to read data block: %d.", ret);
+               dev_acquisition_stop(sdi, sdi);
+               return FALSE;
+       }
+
+       /* We need to get exactly NUM_BLOCKS blocks (i.e. 8MB) of data. */
+       if (devc->block_counter != (NUM_BLOCKS - 1)) {
+               devc->block_counter++;
+               return TRUE;
+       }
+
+       sr_dbg("Sampling finished, sending data to session bus now.");
+
+       /*
+        * All data was received and demangled, send it to the session bus.
+        *
+        * Note: Due to the method how data is spread across the 8MByte of
+        * SDRAM, we can _not_ send it to the session bus in a streaming
+        * manner while we receive it. We have to receive and de-mangle the
+        * full 8MByte first, only then the whole buffer contains valid data.
+        */
+       for (i = 0; i < NUM_BLOCKS; i++)
+               cv_send_block_to_session_bus(devc, i);
+
+       dev_acquisition_stop(sdi, sdi);
+
+       return TRUE;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct dev_context *devc;
+       uint8_t buf[8];
+       int bytes_to_write, bytes_written;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       if (!(devc = sdi->priv)) {
+               sr_err("sdi->priv was NULL.");
+               return SR_ERR_BUG;
+       }
+
+       if (!devc->ftdic) {
+               sr_err("devc->ftdic was NULL.");
+               return SR_ERR_BUG;
+       }
+
+       devc->divcount = cv_samplerate_to_divcount(sdi, devc->cur_samplerate);
+       if (devc->divcount == 0xff) {
+               sr_err("Invalid divcount/samplerate.");
+               return SR_ERR;
+       }
+
+       if (cv_convert_trigger(sdi) != SR_OK) {
+               sr_err("Failed to configure trigger.");
+               return SR_ERR;
+       }
+
+       /* Fill acquisition parameters into buf[]. */
+       if (devc->prof->model == CHRONOVU_LA8) {
+               buf[0] = devc->divcount;
+               buf[1] = 0xff; /* This byte must always be 0xff. */
+               buf[2] = devc->trigger_pattern & 0xff;
+               buf[3] = devc->trigger_mask & 0xff;
+               bytes_to_write = 4;
+       } else {
+               buf[0] = devc->divcount;
+               buf[1] = 0xff; /* This byte must always be 0xff. */
+               buf[2] = (devc->trigger_pattern & 0xff00) >> 8;  /* LSB */
+               buf[3] = (devc->trigger_pattern & 0x00ff) >> 0;  /* MSB */
+               buf[4] = (devc->trigger_mask & 0xff00) >> 8;     /* LSB */
+               buf[5] = (devc->trigger_mask & 0x00ff) >> 0;     /* MSB */
+               buf[6] = (devc->trigger_edgemask & 0xff00) >> 8; /* LSB */
+               buf[7] = (devc->trigger_edgemask & 0x00ff) >> 0; /* MSB */
+               bytes_to_write = 8;
+       }
+
+       /* Start acquisition. */
+       bytes_written = cv_write(devc, buf, bytes_to_write);
+
+       if (bytes_written < 0 || bytes_written != bytes_to_write) {
+               sr_err("Acquisition failed to start.");
+               return SR_ERR;
+       }
+
+       sr_dbg("Hardware acquisition started successfully.");
+
+       devc->cb_data = cb_data;
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(sdi, LOG_PREFIX);
+
+       /* Time when we should be done (for detecting trigger timeouts). */
+       devc->done = (devc->divcount + 1) * devc->prof->trigger_constant +
+                       g_get_monotonic_time() + (10 * G_TIME_SPAN_SECOND);
+       devc->block_counter = 0;
+       devc->trigger_found = 0;
+
+       /* Hook up a dummy handler to receive data from the device. */
+       sr_session_source_add(sdi->session, -1, G_IO_IN, 0, receive_data, (void *)sdi);
+
+       return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct sr_datafeed_packet packet;
+
+       (void)cb_data;
+
+       sr_dbg("Stopping acquisition.");
+       sr_session_source_remove(sdi->session, -1);
+
+       /* Send end packet to the session bus. */
+       sr_dbg("Sending SR_DF_END.");
+       packet.type = SR_DF_END;
+       sr_session_send(sdi, &packet);
+
+       return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver chronovu_la_driver_info = {
+       .name = "chronovu-la",
+       .longname = "ChronoVu LA8/LA16",
+       .api_version = 1,
+       .init = init,
+       .cleanup = cleanup,
+       .scan = scan,
+       .dev_list = dev_list,
+       .dev_clear = dev_clear,
+       .config_get = config_get,
+       .config_set = config_set,
+       .config_list = config_list,
+       .dev_open = dev_open,
+       .dev_close = dev_close,
+       .dev_acquisition_start = dev_acquisition_start,
+       .dev_acquisition_stop = dev_acquisition_stop,
+       .priv = NULL,
+};
diff --git a/src/hardware/chronovu-la/protocol.c b/src/hardware/chronovu-la/protocol.c
new file mode 100644 (file)
index 0000000..c2f31a2
--- /dev/null
@@ -0,0 +1,506 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2011-2014 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "protocol.h"
+
+SR_PRIV const struct cv_profile cv_profiles[] = {
+       { CHRONOVU_LA8,  "LA8",  "ChronoVu LA8",  8,  SR_MHZ(100), 2, 0.8388608 },
+       { CHRONOVU_LA16, "LA16", "ChronoVu LA16", 16, SR_MHZ(200), 4, 0.042 },
+       { 0, NULL, NULL, 0, 0, 0, 0.0 },
+};
+
+/* LA8: channels are numbered 0-7. LA16: channels are numbered 0-15. */
+SR_PRIV const char *cv_channel_names[] = {
+       "0", "1", "2", "3", "4", "5", "6", "7",
+       "8", "9", "10", "11", "12", "13", "14", "15",
+};
+
+static int close_usb_reset_sequencer(struct dev_context *devc);
+
+SR_PRIV void cv_fill_samplerates_if_needed(const struct sr_dev_inst *sdi)
+{
+       int i;
+       struct dev_context *devc;
+
+       devc = sdi->priv;
+
+       if (devc->samplerates[0] != 0)
+               return;
+
+       for (i = 0; i < 255; i++)
+               devc->samplerates[254 - i] = devc->prof->max_samplerate / (i + 1);
+}
+
+/**
+ * Check if the given samplerate is supported by the hardware.
+ *
+ * @param sdi Device instance.
+ * @param samplerate The samplerate (in Hz) to check.
+ *
+ * @return 1 if the samplerate is supported/valid, 0 otherwise.
+ */
+static int is_valid_samplerate(const struct sr_dev_inst *sdi,
+                              uint64_t samplerate)
+{
+       int i;
+       struct dev_context *devc;
+
+       devc = sdi->priv;
+
+       cv_fill_samplerates_if_needed(sdi);
+
+       for (i = 0; i < 255; i++) {
+               if (devc->samplerates[i] == samplerate)
+                       return 1;
+       }
+
+       sr_err("Invalid samplerate (%" PRIu64 "Hz).", samplerate);
+
+       return 0;
+}
+
+/**
+ * Convert a samplerate (in Hz) to the 'divcount' value the device wants.
+ *
+ * The divcount value can be 0x00 - 0xfe (0xff is not valid).
+ *
+ * LA8:
+ * sample period = (divcount + 1) * 10ns.
+ * divcount = 0x00: 10ns period, 100MHz samplerate.
+ * divcount = 0xfe: 2550ns period, 392.15kHz samplerate.
+ *
+ * LA16:
+ * sample period = (divcount + 1) * 5ns.
+ * divcount = 0x00: 5ns period, 200MHz samplerate.
+ * divcount = 0xfe: 1275ns period, ~784.31kHz samplerate.
+ *
+ * @param sdi Device instance.
+ * @param samplerate The samplerate in Hz.
+ *
+ * @return The divcount value as needed by the hardware, or 0xff upon errors.
+ */
+SR_PRIV uint8_t cv_samplerate_to_divcount(const struct sr_dev_inst *sdi,
+                                         uint64_t samplerate)
+{
+       struct dev_context *devc;
+
+       devc = sdi->priv;
+
+       if (samplerate == 0) {
+               sr_err("Can't convert invalid samplerate of 0 Hz.");
+               return 0xff;
+       }
+
+       if (!is_valid_samplerate(sdi, samplerate)) {
+               sr_err("Can't get divcount, samplerate invalid.");
+               return 0xff;
+       }
+
+       return (devc->prof->max_samplerate / samplerate) - 1;
+}
+
+/**
+ * Write data of a certain length to the FTDI device.
+ *
+ * @param devc The struct containing private per-device-instance data. Must not
+ *             be NULL. devc->ftdic must not be NULL either.
+ * @param buf The buffer containing the data to write. Must not be NULL.
+ * @param size The number of bytes to write. Must be > 0.
+ *
+ * @return The number of bytes written, or a negative value upon errors.
+ */
+SR_PRIV int cv_write(struct dev_context *devc, uint8_t *buf, int size)
+{
+       int bytes_written;
+
+       /* Note: Caller ensures devc/devc->ftdic/buf != NULL and size > 0. */
+
+       bytes_written = ftdi_write_data(devc->ftdic, buf, size);
+
+       if (bytes_written < 0) {
+               sr_err("Failed to write data (%d): %s.",
+                      bytes_written, ftdi_get_error_string(devc->ftdic));
+               (void) close_usb_reset_sequencer(devc); /* Ignore errors. */
+       } else if (bytes_written != size) {
+               sr_err("Failed to write data, only %d/%d bytes written.",
+                      size, bytes_written);
+               (void) close_usb_reset_sequencer(devc); /* Ignore errors. */
+       }
+
+       return bytes_written;
+}
+
+/**
+ * Read a certain amount of bytes from the FTDI device.
+ *
+ * @param devc The struct containing private per-device-instance data. Must not
+ *             be NULL. devc->ftdic must not be NULL either.
+ * @param buf The buffer where the received data will be stored. Must not
+ *            be NULL.
+ * @param size The number of bytes to read. Must be >= 1.
+ *
+ * @return The number of bytes read, or a negative value upon errors.
+ */
+static int cv_read(struct dev_context *devc, uint8_t *buf, int size)
+{
+       int bytes_read;
+
+       /* Note: Caller ensures devc/devc->ftdic/buf != NULL and size > 0. */
+
+       bytes_read = ftdi_read_data(devc->ftdic, buf, size);
+
+       if (bytes_read < 0) {
+               sr_err("Failed to read data (%d): %s.",
+                      bytes_read, ftdi_get_error_string(devc->ftdic));
+       } else if (bytes_read != size) {
+               // sr_err("Failed to read data, only %d/%d bytes read.",
+               //        bytes_read, size);
+       }
+
+       return bytes_read;
+}
+
+/**
+ * Close the USB port and reset the sequencer logic.
+ *
+ * @param devc The struct containing private per-device-instance data.
+ *
+ * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments.
+ */
+static int close_usb_reset_sequencer(struct dev_context *devc)
+{
+       /* Magic sequence of bytes for resetting the sequencer logic. */
+       uint8_t buf[8] = {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01};
+       int ret;
+
+       /* Note: Caller checked that devc and devc->ftdic != NULL. */
+
+       if (devc->ftdic->usb_dev) {
+               /* Reset the sequencer logic, then wait 100ms. */
+               sr_dbg("Resetting sequencer logic.");
+               (void) cv_write(devc, buf, 8); /* Ignore errors. */
+               g_usleep(100 * 1000);
+
+               /* Purge FTDI buffers, then reset and close the FTDI device. */
+               sr_dbg("Purging buffers, resetting+closing FTDI device.");
+
+               /* Log errors, but ignore them (i.e., don't abort). */
+               if ((ret = ftdi_usb_purge_buffers(devc->ftdic)) < 0)
+                       sr_err("Failed to purge FTDI buffers (%d): %s.",
+                              ret, ftdi_get_error_string(devc->ftdic));
+               if ((ret = ftdi_usb_reset(devc->ftdic)) < 0)
+                       sr_err("Failed to reset FTDI device (%d): %s.",
+                              ret, ftdi_get_error_string(devc->ftdic));
+               if ((ret = ftdi_usb_close(devc->ftdic)) < 0)
+                       sr_err("Failed to close FTDI device (%d): %s.",
+                              ret, ftdi_get_error_string(devc->ftdic));
+       }
+
+       /* Close USB device, deinitialize and free the FTDI context. */
+       ftdi_free(devc->ftdic);
+       devc->ftdic = NULL;
+
+       return SR_OK;
+}
+
+/**
+ * Reset the ChronoVu device.
+ *
+ * A reset is required after a failed read/write operation or upon timeouts.
+ *
+ * @param devc The struct containing private per-device-instance data.
+ *
+ * @return SR_OK upon success, SR_ERR upon failure.
+ */
+static int reset_device(struct dev_context *devc)
+{
+       uint8_t buf[BS];
+       gint64 done, now;
+       int bytes_read;
+
+       /* Note: Caller checked that devc and devc->ftdic != NULL. */
+
+       sr_dbg("Resetting the device.");
+
+       /*
+        * Purge pending read data from the FTDI hardware FIFO until
+        * no more data is left, or a timeout occurs (after 20s).
+        */
+       done = (20 * G_TIME_SPAN_SECOND) + g_get_monotonic_time();
+       do {
+               /* Try to read bytes until none are left (or errors occur). */
+               bytes_read = cv_read(devc, (uint8_t *)&buf, BS);
+               now = g_get_monotonic_time();
+       } while ((done > now) && (bytes_read > 0));
+
+       /* Reset the sequencer logic and close the USB port. */
+       (void) close_usb_reset_sequencer(devc); /* Ignore errors. */
+
+       sr_dbg("Device reset finished.");
+
+       return SR_OK;
+}
+
+SR_PRIV int cv_convert_trigger(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_trigger *trigger;
+       struct sr_trigger_stage *stage;
+       struct sr_trigger_match *match;
+       const GSList *l, *m;
+       uint16_t channel_bit;
+
+       devc = sdi->priv;
+       devc->trigger_pattern = 0x0000; /* Default to "low" trigger. */
+       devc->trigger_mask = 0x0000; /* Default to "don't care". */
+       devc->trigger_edgemask = 0x0000; /* Default to "state triggered". */
+
+       if (!(trigger = sr_session_trigger_get(sdi->session)))
+               return SR_OK;
+
+       if (g_slist_length(trigger->stages) > 1) {
+               sr_err("This device only supports 1 trigger stage.");
+               return SR_ERR;
+       }
+
+       for (l = trigger->stages; l; l = l->next) {
+               stage = l->data;
+               for (m = stage->matches; m; m = m->next) {
+                       match = m->data;
+                       if (!match->channel->enabled)
+                               /* Ignore disabled channels with a trigger. */
+                               continue;
+                       if (devc->prof->model == CHRONOVU_LA8 &&
+                                       (match->match == SR_TRIGGER_RISING
+                                       || match->match == SR_TRIGGER_FALLING)) {
+                               sr_err("This model supports only simple triggers.");
+                               return SR_ERR;
+                       }
+                       channel_bit = (1 << (match->channel->index));
+
+                       /* state: 1 == high, edge: 1 == rising edge. */
+                       if (match->match == SR_TRIGGER_ONE
+                                       || match->match == SR_TRIGGER_RISING)
+                               devc->trigger_pattern |= channel_bit;
+
+                       /* LA16 (but not LA8) supports edge triggering. */
+                       if ((devc->prof->model == CHRONOVU_LA16)) {
+                               if (match->match == SR_TRIGGER_RISING
+                                               || match->match == SR_TRIGGER_FALLING)
+                                               devc->trigger_edgemask |= channel_bit;
+                       }
+               }
+       }
+
+       sr_dbg("Trigger pattern/mask/edgemask = 0x%04x / 0x%04x / 0x%04x.",
+                       devc->trigger_pattern, devc->trigger_mask,
+                       devc->trigger_edgemask);
+
+       return SR_OK;
+}
+
+SR_PRIV int cv_set_samplerate(const struct sr_dev_inst *sdi, uint64_t samplerate)
+{
+       struct dev_context *devc;
+
+       /* Note: Caller checked that sdi and sdi->priv != NULL. */
+
+       devc = sdi->priv;
+
+       sr_spew("Trying to set samplerate to %" PRIu64 "Hz.", samplerate);
+
+       cv_fill_samplerates_if_needed(sdi);
+
+       /* Check if this is a samplerate supported by the hardware. */
+       if (!is_valid_samplerate(sdi, samplerate)) {
+               sr_dbg("Failed to set invalid samplerate (%" PRIu64 "Hz).",
+                      samplerate);
+               return SR_ERR;
+       }
+
+       devc->cur_samplerate = samplerate;
+
+       sr_dbg("Samplerate set to %" PRIu64 "Hz.", devc->cur_samplerate);
+
+       return SR_OK;
+}
+
+/**
+ * Get a block of data from the device.
+ *
+ * @param devc The struct containing private per-device-instance data. Must not
+ *             be NULL. devc->ftdic must not be NULL either.
+ *
+ * @return SR_OK upon success, or SR_ERR upon errors.
+ */
+SR_PRIV int cv_read_block(struct dev_context *devc)
+{
+       int i, byte_offset, m, mi, p, q, index, bytes_read;
+       gint64 now;
+
+       /* Note: Caller checked that devc and devc->ftdic != NULL. */
+
+       sr_spew("Reading block %d.", devc->block_counter);
+
+       bytes_read = cv_read(devc, devc->mangled_buf, BS);
+
+       /* If first block read got 0 bytes, retry until success or timeout. */
+       if ((bytes_read == 0) && (devc->block_counter == 0)) {
+               do {
+                       sr_spew("Reading block 0 (again).");
+                       /* Note: If bytes_read < 0 cv_read() will log errors. */
+                       bytes_read = cv_read(devc, devc->mangled_buf, BS);
+                       now = g_get_monotonic_time();
+               } while ((devc->done > now) && (bytes_read == 0));
+       }
+
+       /* Check if block read was successful or a timeout occured. */
+       if (bytes_read != BS) {
+               sr_err("Trigger timed out. Bytes read: %d.", bytes_read);
+               (void) reset_device(devc); /* Ignore errors. */
+               return SR_ERR;
+       }
+
+       /* De-mangle the data. */
+       sr_spew("Demangling block %d.", devc->block_counter);
+       byte_offset = devc->block_counter * BS;
+       m = byte_offset / (1024 * 1024);
+       mi = m * (1024 * 1024);
+       for (i = 0; i < BS; i++) {
+               if (devc->prof->model == CHRONOVU_LA8) {
+                       p = i & (1 << 0);
+                       index = m * 2 + (((byte_offset + i) - mi) / 2) * 16;
+                       index += (devc->divcount == 0) ? p : (1 - p);
+               } else {
+                       p = i & (1 << 0);
+                       q = i & (1 << 1);
+                       index = m * 4 + (((byte_offset + i) - mi) / 4) * 32;
+                       index += q + (1 - p);
+               }
+               devc->final_buf[index] = devc->mangled_buf[i];
+       }
+
+       return SR_OK;
+}
+
+SR_PRIV void cv_send_block_to_session_bus(struct dev_context *devc, int block)
+{
+       int i, idx;
+       uint8_t sample, expected_sample, tmp8;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_logic logic;
+       int trigger_point; /* Relative trigger point (in this block). */
+
+       /* Note: Caller ensures devc/devc->ftdic != NULL and block > 0. */
+
+       /* TODO: Implement/test proper trigger support for the LA16. */
+
+       /* Check if we can find the trigger condition in this block. */
+       trigger_point = -1;
+       expected_sample = devc->trigger_pattern & devc->trigger_mask;
+       for (i = 0; i < BS; i++) {
+               /* Don't continue if the trigger was found previously. */
+               if (devc->trigger_found)
+                       break;
+
+               /*
+                * Also, don't continue if triggers are "don't care", i.e. if
+                * no trigger conditions were specified by the user. In that
+                * case we don't want to send an SR_DF_TRIGGER packet at all.
+                */
+               if (devc->trigger_mask == 0x0000)
+                       break;
+
+               sample = *(devc->final_buf + (block * BS) + i);
+
+               if ((sample & devc->trigger_mask) == expected_sample) {
+                       trigger_point = i;
+                       devc->trigger_found = 1;
+                       break;
+               }
+       }
+
+       /* Swap low and high bytes of the 16-bit LA16 samples. */
+       if (devc->prof->model == CHRONOVU_LA16) {
+               for (i = 0; i < BS; i += 2) {
+                       idx = (block * BS) + i;
+                       tmp8 = devc->final_buf[idx];
+                       devc->final_buf[idx] = devc->final_buf[idx + 1];
+                       devc->final_buf[idx + 1] = tmp8;
+               }
+       }
+
+       /* If no trigger was found, send one SR_DF_LOGIC packet. */
+       if (trigger_point == -1) {
+               /* Send an SR_DF_LOGIC packet to the session bus. */
+               sr_spew("Sending SR_DF_LOGIC packet (%d bytes) for "
+                       "block %d.", BS, block);
+               packet.type = SR_DF_LOGIC;
+               packet.payload = &logic;
+               logic.length = BS;
+               logic.unitsize = devc->prof->num_channels / 8;
+               logic.data = devc->final_buf + (block * BS);
+               sr_session_send(devc->cb_data, &packet);
+               return;
+       }
+
+       /*
+        * We found the trigger, so some special handling is needed. We have
+        * to send an SR_DF_LOGIC packet with the samples before the trigger
+        * (if any), then the SD_DF_TRIGGER packet itself, then another
+        * SR_DF_LOGIC packet with the samples after the trigger (if any).
+        */
+
+       /* TODO: Send SR_DF_TRIGGER packet before or after the actual sample? */
+
+       /* If at least one sample is located before the trigger... */
+       if (trigger_point > 0) {
+               /* Send pre-trigger SR_DF_LOGIC packet to the session bus. */
+               sr_spew("Sending pre-trigger SR_DF_LOGIC packet, "
+                       "start = %d, length = %d.", block * BS, trigger_point);
+               packet.type = SR_DF_LOGIC;
+               packet.payload = &logic;
+               logic.length = trigger_point;
+               logic.unitsize = devc->prof->num_channels / 8;
+               logic.data = devc->final_buf + (block * BS);
+               sr_session_send(devc->cb_data, &packet);
+       }
+
+       /* Send the SR_DF_TRIGGER packet to the session bus. */
+       sr_spew("Sending SR_DF_TRIGGER packet, sample = %d.",
+               (block * BS) + trigger_point);
+       packet.type = SR_DF_TRIGGER;
+       packet.payload = NULL;
+       sr_session_send(devc->cb_data, &packet);
+
+       /* If at least one sample is located after the trigger... */
+       if (trigger_point < (BS - 1)) {
+               /* Send post-trigger SR_DF_LOGIC packet to the session bus. */
+               sr_spew("Sending post-trigger SR_DF_LOGIC packet, "
+                       "start = %d, length = %d.",
+                       (block * BS) + trigger_point, BS - trigger_point);
+               packet.type = SR_DF_LOGIC;
+               packet.payload = &logic;
+               logic.length = BS - trigger_point;
+               logic.unitsize = devc->prof->num_channels / 8;
+               logic.data = devc->final_buf + (block * BS) + trigger_point;
+               sr_session_send(devc->cb_data, &packet);
+       }
+}
diff --git a/src/hardware/chronovu-la/protocol.h b/src/hardware/chronovu-la/protocol.h
new file mode 100644 (file)
index 0000000..c74feaa
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2011-2014 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#ifndef LIBSIGROK_HARDWARE_CHRONOVU_LA_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_CHRONOVU_LA_PROTOCOL_H
+
+#include <glib.h>
+#include <ftdi.h>
+#include <stdint.h>
+#include <string.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "la8/la16"
+
+#define SDRAM_SIZE                     (8 * 1024 * 1024)
+#define MAX_NUM_SAMPLES                        SDRAM_SIZE
+
+#define BS                             4096 /* Block size */
+#define NUM_BLOCKS                     2048 /* Number of blocks */
+
+enum {
+       CHRONOVU_LA8,
+       CHRONOVU_LA16,
+};
+
+struct cv_profile {
+       int model;
+       const char *modelname;
+       const char *iproduct; /* USB iProduct string */
+       unsigned int num_channels;
+       uint64_t max_samplerate;
+       const int num_trigger_matches;
+       float trigger_constant;
+};
+
+/* Private, per-device-instance driver context. */
+struct dev_context {
+       /** Device profile struct for this device. */
+       const struct cv_profile *prof;
+
+       /** FTDI device context (used by libftdi). */
+       struct ftdi_context *ftdic;
+
+       /** The currently configured samplerate of the device. */
+       uint64_t cur_samplerate;
+
+       /** The current sampling limit (in ms). */
+       uint64_t limit_msec;
+
+       /** The current sampling limit (in number of samples). */
+       uint64_t limit_samples;
+
+       void *cb_data;
+
+       /**
+        * A buffer containing some (mangled) samples from the device.
+        * Format: Pretty mangled-up (due to hardware reasons), see code.
+        */
+       uint8_t mangled_buf[BS];
+
+       /**
+        * An 8MB buffer where we'll store the de-mangled samples.
+        * LA8: Each sample is 1 byte, MSB is channel 7, LSB is channel 0.
+        * LA16: Each sample is 2 bytes, MSB is channel 15, LSB is channel 0.
+        */
+       uint8_t *final_buf;
+
+       /**
+        * Trigger pattern.
+        * A 1 bit matches a high signal, 0 matches a low signal on a channel.
+        *
+        * If the resp. 'trigger_edgemask' bit is set, 1 means "rising edge",
+        * and 0 means "falling edge".
+        */
+       uint16_t trigger_pattern;
+
+       /**
+        * Trigger mask.
+        * A 1 bit means "must match trigger_pattern", 0 means "don't care".
+        */
+       uint16_t trigger_mask;
+
+       /**
+        * Trigger edge mask.
+        * A 1 bit means "edge triggered", 0 means "state triggered".
+        *
+        * Edge triggering is only supported on LA16 (but not LA8).
+        */
+       uint16_t trigger_edgemask;
+
+       /** Tells us whether an SR_DF_TRIGGER packet was already sent. */
+       int trigger_found;
+
+       /** Used for keeping track how much time has passed. */
+       gint64 done;
+
+       /** Counter/index for the data block to be read. */
+       int block_counter;
+
+       /** The divcount value (determines the sample period). */
+       uint8_t divcount;
+
+       /** This ChronoVu device's USB VID/PID. */
+       uint16_t usb_vid;
+       uint16_t usb_pid;
+
+       /** Samplerates supported by this device. */
+       uint64_t samplerates[255];
+};
+
+/* protocol.c */
+extern SR_PRIV const char *cv_channel_names[];
+extern const struct cv_profile cv_profiles[];
+SR_PRIV void cv_fill_samplerates_if_needed(const struct sr_dev_inst *sdi);
+SR_PRIV uint8_t cv_samplerate_to_divcount(const struct sr_dev_inst *sdi,
+                                         uint64_t samplerate);
+SR_PRIV int cv_write(struct dev_context *devc, uint8_t *buf, int size);
+SR_PRIV int cv_convert_trigger(const struct sr_dev_inst *sdi);
+SR_PRIV int cv_set_samplerate(const struct sr_dev_inst *sdi, uint64_t samplerate);
+SR_PRIV int cv_read_block(struct dev_context *devc);
+SR_PRIV void cv_send_block_to_session_bus(struct dev_context *devc, int block);
+
+#endif
diff --git a/src/hardware/colead-slm/api.c b/src/hardware/colead-slm/api.c
new file mode 100644 (file)
index 0000000..d5fc9ac
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert@biot.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 <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "protocol.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+
+/* The Colead SL-5868P uses this. */
+#define SERIALCOMM "2400/8n1"
+
+static const int32_t hwopts[] = {
+       SR_CONF_CONN,
+       SR_CONF_SERIALCOMM,
+};
+
+static const int32_t hwcaps[] = {
+       SR_CONF_SOUNDLEVELMETER,
+       SR_CONF_LIMIT_SAMPLES,
+       SR_CONF_LIMIT_MSEC,
+       SR_CONF_CONTINUOUS,
+};
+
+SR_PRIV struct sr_dev_driver colead_slm_driver_info;
+static struct sr_dev_driver *di = &colead_slm_driver_info;
+
+static int init(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       struct sr_dev_inst *sdi;
+       struct sr_config *src;
+       struct sr_channel *ch;
+       GSList *devices, *l;
+       const char *conn, *serialcomm;
+
+       drvc = di->priv;
+       drvc->instances = NULL;
+
+       devices = NULL;
+
+       conn = serialcomm = NULL;
+       for (l = options; l; l = l->next) {
+               src = l->data;
+               switch (src->key) {
+               case SR_CONF_CONN:
+                       conn = g_variant_get_string(src->data, NULL);
+                       break;
+               case SR_CONF_SERIALCOMM:
+                       serialcomm = g_variant_get_string(src->data, NULL);
+                       break;
+               }
+       }
+       if (!conn)
+               return NULL;
+       if (!serialcomm)
+               serialcomm = SERIALCOMM;
+
+       if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "Colead",
+                       "SL-5868P", NULL)))
+               return NULL;
+
+       if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+               sr_dbg("Device context malloc failed.");
+               return NULL;
+       }
+
+       if (!(sdi->conn = sr_serial_dev_inst_new(conn, serialcomm)))
+               return NULL;
+
+       sdi->inst_type = SR_INST_SERIAL;
+       sdi->priv = devc;
+       sdi->driver = di;
+       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1")))
+               return NULL;
+       sdi->channels = g_slist_append(sdi->channels, ch);
+       drvc->instances = g_slist_append(drvc->instances, sdi);
+       devices = g_slist_append(devices, sdi);
+
+       return devices;
+}
+
+static GSList *dev_list(void)
+{
+       return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+       struct sr_serial_dev_inst *serial;
+
+       serial = sdi->conn;
+       if (serial_open(serial, SERIAL_RDWR) != SR_OK)
+               return SR_ERR;
+
+       sdi->status = SR_ST_ACTIVE;
+
+       return SR_OK;
+}
+
+static int cleanup(void)
+{
+       return std_dev_clear(di, NULL);
+}
+
+static int config_set(int id, 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;
+
+       if (!(devc = sdi->priv)) {
+               sr_err("sdi->priv was NULL.");
+               return SR_ERR_BUG;
+       }
+
+       switch (id) {
+       case SR_CONF_LIMIT_MSEC:
+               /* TODO: not yet implemented */
+               if (g_variant_get_uint64(data) == 0) {
+                       sr_err("LIMIT_MSEC can't be 0.");
+                       return SR_ERR;
+               }
+               devc->limit_msec = g_variant_get_uint64(data);;
+               sr_dbg("Setting time limit to %" PRIu64 "ms.",
+                      devc->limit_msec);
+               break;
+       case SR_CONF_LIMIT_SAMPLES:
+               devc->limit_samples = g_variant_get_uint64(data);
+               sr_dbg("Setting sample limit to %" PRIu64 ".",
+                      devc->limit_samples);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_list(int 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_INT32,
+                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+               break;
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       if (!(devc = sdi->priv)) {
+               sr_err("sdi->priv was NULL.");
+               return SR_ERR_BUG;
+       }
+
+       devc->cb_data = cb_data;
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(cb_data, LOG_PREFIX);
+
+       /* Poll every 150ms, or whenever some data comes in. */
+       serial = sdi->conn;
+       serial_source_add(sdi->session, serial, G_IO_IN, 150,
+                       colead_slm_receive_data, (void *)sdi);
+
+       return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       return std_serial_dev_acquisition_stop(sdi, cb_data, std_serial_dev_close,
+                       sdi->conn, LOG_PREFIX);
+}
+
+SR_PRIV struct sr_dev_driver colead_slm_driver_info = {
+       .name = "colead-slm",
+       .longname = "Colead SLM",
+       .api_version = 1,
+       .init = init,
+       .cleanup = cleanup,
+       .scan = scan,
+       .dev_list = dev_list,
+       .dev_clear = NULL,
+       .config_get = NULL,
+       .config_set = config_set,
+       .config_list = config_list,
+       .dev_open = dev_open,
+       .dev_close = std_serial_dev_close,
+       .dev_acquisition_start = dev_acquisition_start,
+       .dev_acquisition_stop = dev_acquisition_stop,
+       .priv = NULL,
+};
diff --git a/src/hardware/colead-slm/protocol.c b/src/hardware/colead-slm/protocol.c
new file mode 100644 (file)
index 0000000..4abcdd5
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert@biot.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 <stdlib.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "protocol.h"
+#include <errno.h>
+#include <string.h>
+
+static void process_packet(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_analog analog;
+       GString *dbg;
+       float fvalue;
+       int checksum, mode, i;
+
+       devc = sdi->priv;
+       if (sr_log_loglevel_get() >= SR_LOG_SPEW) {
+               dbg = g_string_sized_new(128);
+               g_string_printf(dbg, "received packet:");
+               for (i = 0; i < 10; i++)
+                       g_string_append_printf(dbg, " %.2x", (devc->buf)[i]);
+               sr_spew("%s", dbg->str);
+               g_string_free(dbg, TRUE);
+       }
+
+       if (devc->buf[0] != 0x08 || devc->buf[1] != 0x04) {
+               sr_dbg("invalid packet header.");
+               return;
+       }
+
+       if (devc->buf[8] != 0x01) {
+               sr_dbg("invalid measurement.");
+               return;
+       }
+
+       checksum = 0;
+       for (i = 0; i < 9; i++)
+               checksum += devc->buf[i];
+       if ((checksum & 0xff) != devc->buf[9]) {
+               sr_dbg("invalid packet checksum.");
+               return;
+       }
+
+       fvalue = 0.0;
+       for (i = 3; i < 8; i++) {
+               if (devc->buf[i] > 0x09)
+                       continue;
+               fvalue *= 10;
+               fvalue += devc->buf[i];
+       }
+       fvalue /= 10;
+
+       memset(&analog, 0, sizeof(struct sr_datafeed_analog));
+       analog.mq = SR_MQ_SOUND_PRESSURE_LEVEL;
+       analog.unit = SR_UNIT_DECIBEL_SPL;
+       analog.channels = sdi->channels;
+       analog.num_samples = 1;
+       analog.data = &fvalue;
+
+       /* High nibble should only have 0x01 or 0x02. */
+       mode = (devc->buf[2] >> 4) & 0x0f;
+       if (mode == 0x02)
+               analog.mqflags |= SR_MQFLAG_HOLD;
+       else if (mode != 0x01) {
+               sr_dbg("unknown measurement mode 0x%.2x", mode);
+               return;
+       }
+
+       /* Low nibble has 14 combinations of direct/long-term average,
+        * time scale of that average, frequency weighting, and time
+        * weighting. */
+       mode = devc->buf[2] & 0x0f;
+       switch (mode) {
+               case 0x0:
+                       analog.mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_A \
+                                       | SR_MQFLAG_SPL_TIME_WEIGHT_F;
+                       break;
+               case 0x1:
+                       analog.mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_A \
+                                       | SR_MQFLAG_SPL_TIME_WEIGHT_S;
+                       break;
+               case 0x2:
+                       analog.mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_C \
+                                       | SR_MQFLAG_SPL_TIME_WEIGHT_F;
+                       break;
+               case 0x3:
+                       analog.mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_C \
+                                       | SR_MQFLAG_SPL_TIME_WEIGHT_S;
+                       break;
+               case 0x4:
+                       analog.mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_FLAT \
+                                       | SR_MQFLAG_SPL_TIME_WEIGHT_F;
+                       break;
+               case 0x5:
+                       analog.mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_FLAT \
+                                       | SR_MQFLAG_SPL_TIME_WEIGHT_S;
+                       break;
+               case 0x6:
+                       analog.mqflags |= SR_MQFLAG_SPL_PCT_OVER_ALARM \
+                                       | SR_MQFLAG_SPL_FREQ_WEIGHT_A \
+                                       | SR_MQFLAG_SPL_TIME_WEIGHT_F;
+                       break;
+               case 0x7:
+                       analog.mqflags |= SR_MQFLAG_SPL_PCT_OVER_ALARM \
+                                       | SR_MQFLAG_SPL_FREQ_WEIGHT_A \
+                                       | SR_MQFLAG_SPL_TIME_WEIGHT_S;
+                       break;
+               case 0x8:
+                       /* 10-second mean, but we don't have MQ flags to express it. */
+                       analog.mqflags |= SR_MQFLAG_SPL_LAT \
+                                       | SR_MQFLAG_SPL_FREQ_WEIGHT_A \
+                                       | SR_MQFLAG_SPL_TIME_WEIGHT_F;
+                       break;
+               case 0x9:
+                       /* Mean over a time period between 11 seconds and 24 hours.
+                        * Which is so silly that there's no point in expressing
+                        * either this or the previous case.  */
+                       analog.mqflags |= SR_MQFLAG_SPL_LAT \
+                                       | SR_MQFLAG_SPL_FREQ_WEIGHT_A \
+                                       | SR_MQFLAG_SPL_TIME_WEIGHT_F;
+                       break;
+               case 0xa:
+                       /* 10-second mean. */
+                       analog.mqflags |= SR_MQFLAG_SPL_LAT \
+                                       | SR_MQFLAG_SPL_FREQ_WEIGHT_A \
+                                       | SR_MQFLAG_SPL_TIME_WEIGHT_S;
+                       break;
+               case 0xb:
+                       /* Mean over a time period between 11 seconds and 24 hours. */
+                       analog.mqflags |= SR_MQFLAG_SPL_LAT \
+                                       | SR_MQFLAG_SPL_FREQ_WEIGHT_A \
+                                       | SR_MQFLAG_SPL_TIME_WEIGHT_S;
+                       break;
+               case 0xc:
+                       /* Internal calibration on 1kHz sine at 94dB, not useful
+                        * to anything but the device. */
+                       analog.mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_FLAT;
+                       break;
+               case 0xd:
+                       /* Internal calibration on 1kHz sine at 94dB, not useful
+                        * to anything but the device. */
+                       analog.mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_FLAT;
+                       break;
+               default:
+                       sr_dbg("unknown configuration 0x%.2x", mode);
+                       return;
+                       break;
+       }
+
+       packet.type = SR_DF_ANALOG;
+       packet.payload = &analog;
+       sr_session_send(devc->cb_data, &packet);
+
+       devc->num_samples++;
+
+}
+
+SR_PRIV int colead_slm_receive_data(int fd, int revents, void *cb_data)
+{
+       const struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+       int len;
+       char buf[128];
+
+       (void)fd;
+
+       if (!(sdi = cb_data))
+               return TRUE;
+
+       if (!(devc = sdi->priv))
+               return TRUE;
+
+       if (revents != G_IO_IN)
+               /* Timeout event. */
+               return TRUE;
+
+       serial = sdi->conn;
+       if (devc->state == IDLE) {
+               if (serial_read(serial, buf, 128) != 1 || buf[0] != 0x10)
+                       /* Nothing there, or caught the tail end of a previous packet,
+                        * or some garbage. Unless it's a single "data ready" byte,
+                        * we don't want it. */
+                       return TRUE;
+               /* Got 0x10, "measurement ready". */
+               if (serial_write(serial, "\x20", 1) == -1)
+                       sr_err("unable to send command: %s", strerror(errno));
+               else {
+                       devc->state = COMMAND_SENT;
+                       devc->buflen = 0;
+               }
+       } else {
+               len = serial_read(serial, devc->buf + devc->buflen,
+                               10 - devc->buflen);
+               if (len < 1)
+                       return TRUE;
+               devc->buflen += len;
+               if (devc->buflen > 10) {
+                       sr_dbg("buffer overrun");
+                       devc->state = IDLE;
+                       return TRUE;
+               }
+               if (devc->buflen == 10) {
+                       /* If we got here, we're sure the device sent a "data ready"
+                        * notification, we asked for data, and got it. */
+                       process_packet(sdi);
+                       devc->state = IDLE;
+               }
+       }
+
+       return TRUE;
+}
diff --git a/src/hardware/colead-slm/protocol.h b/src/hardware/colead-slm/protocol.h
new file mode 100644 (file)
index 0000000..8942ac8
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert@biot.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_COLEAD_SLM_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_COLEAD_SLM_PROTOCOL_H
+
+#include <stdint.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "colead-slm"
+
+enum {
+       IDLE,
+       COMMAND_SENT,
+};
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+       /** The current sampling limit (in number of samples). */
+       uint64_t limit_samples;
+
+       /** The current sampling limit (in ms). */
+       uint64_t limit_msec;
+
+       /** Opaque pointer passed in by the frontend. */
+       void *cb_data;
+
+       /** The current number of already received samples. */
+       uint64_t num_samples;
+       int state;
+       char buf[10];
+       int buflen;
+};
+
+SR_PRIV int colead_slm_receive_data(int fd, int revents, void *cb_data);
+
+#endif
diff --git a/src/hardware/conrad-digi-35-cpu/api.c b/src/hardware/conrad-digi-35-cpu/api.c
new file mode 100644 (file)
index 0000000..01adcef
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Matthias Heidbrink <m-sigrok@heidbrink.biz>
+ *
+ * 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
+ *  <em>Conrad DIGI 35 CPU</em> power supply driver
+ *  @internal
+ */
+
+#include "protocol.h"
+
+#define SERIALCOMM "9600/8n1"
+
+static const int32_t hwopts[] = {
+       SR_CONF_CONN,
+       SR_CONF_SERIALCOMM,
+};
+
+static const int32_t hwcaps[] = {
+       SR_CONF_POWER_SUPPLY,
+       SR_CONF_OUTPUT_VOLTAGE,
+       SR_CONF_OUTPUT_CURRENT,
+       /* There's no SR_CONF_OUTPUT_ENABLED; can't know/set status remotely. */
+       SR_CONF_OVER_CURRENT_PROTECTION,
+};
+
+SR_PRIV struct sr_dev_driver conrad_digi_35_cpu_driver_info;
+static struct sr_dev_driver *di = &conrad_digi_35_cpu_driver_info;
+
+static int init(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+       struct sr_dev_inst *sdi;
+       struct drv_context *drvc;
+       struct sr_config *src;
+       struct sr_channel *ch;
+       struct sr_serial_dev_inst *serial;
+       GSList *l, *devices;
+       const char *conn, *serialcomm;
+
+       devices = NULL;
+       drvc = di->priv;
+       drvc->instances = NULL;
+       conn = serialcomm = NULL;
+
+       for (l = options; l; l = l->next) {
+               src = l->data;
+               switch (src->key) {
+               case SR_CONF_CONN:
+                       conn = g_variant_get_string(src->data, NULL);
+                       break;
+               case SR_CONF_SERIALCOMM:
+                       serialcomm = g_variant_get_string(src->data, NULL);
+                       break;
+               }
+       }
+       if (!conn)
+               return NULL;
+       if (!serialcomm)
+               serialcomm = SERIALCOMM;
+
+       /*
+        * We cannot scan for this device because it is write-only.
+        * So just check that the port parameters are valid and assume that
+        * the device is there.
+        */
+
+       if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
+               return NULL;
+
+       if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
+               return NULL;
+
+       serial_flush(serial);
+       serial_close(serial);
+
+       sr_spew("Conrad DIGI 35 CPU assumed at %s.", conn);
+
+       if (!(sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, "Conrad", "DIGI 35 CPU", NULL)))
+               return NULL;
+
+       sdi->conn = serial;
+       sdi->priv = NULL;
+       sdi->driver = di;
+       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "CH1")))
+               return NULL;
+       sdi->channels = g_slist_append(sdi->channels, ch);
+
+       drvc->instances = g_slist_append(drvc->instances, sdi);
+       devices = g_slist_append(devices, sdi);
+
+       return devices;
+}
+
+static GSList *dev_list(void)
+{
+       return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int cleanup(void)
+{
+       return std_dev_clear(di, NULL);
+}
+
+static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       int ret;
+       double dblval;
+
+       (void)cg;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       ret = SR_OK;
+       switch (key) {
+       case SR_CONF_OUTPUT_VOLTAGE:
+               dblval = g_variant_get_double(data);
+               if ((dblval < 0.0) || (dblval > 35.0)) {
+                       sr_err("Voltage out of range (0 - 35.0)!");
+                       return SR_ERR_ARG;
+               }
+               ret = send_msg1(sdi, 'V', (int) (dblval * 10 + 0.5));
+               break;
+       case SR_CONF_OUTPUT_CURRENT:
+               dblval = g_variant_get_double(data);
+               if ((dblval < 0.01) || (dblval > 2.55)) {
+                       sr_err("Current out of range (0 - 2.55)!");
+                       return SR_ERR_ARG;
+               }
+               ret = send_msg1(sdi, 'C', (int) (dblval * 100 + 0.5));
+               break;
+       /* No SR_CONF_OUTPUT_ENABLED :-( . */
+       case SR_CONF_OVER_CURRENT_PROTECTION:
+               if (g_variant_get_boolean(data))
+                       ret = send_msg1(sdi, 'V', 900);
+               else /* Constant current mode */
+                       ret = send_msg1(sdi, 'V', 901);
+               break;
+       default:
+               ret = SR_ERR_NA;
+       }
+
+       return ret;
+}
+
+static int config_list(int 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_INT32,
+                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+               break;
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return ret;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+       (void)cb_data;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       (void)cb_data;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver conrad_digi_35_cpu_driver_info = {
+       .name = "conrad-digi-35-cpu",
+       .longname = "Conrad DIGI 35 CPU",
+       .api_version = 1,
+       .init = init,
+       .cleanup = cleanup,
+       .scan = scan,
+       .dev_list = 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 = dev_acquisition_stop,
+       .priv = NULL,
+};
diff --git a/src/hardware/conrad-digi-35-cpu/protocol.c b/src/hardware/conrad-digi-35-cpu/protocol.c
new file mode 100644 (file)
index 0000000..7657b31
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Matthias Heidbrink <m-sigrok@heidbrink.biz>
+ *
+ * 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
+ * <em>Conrad DIGI 35 CPU</em> power supply driver
+ * @internal
+ */
+
+#include "protocol.h"
+
+/**
+ * Send command with parameter.
+ *
+ * @param[in] cmd Command
+ * @param[in] param Parameter (0..999, depending on command).
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_ARG Invalid argument.
+ * @retval SR_ERR Error.
+ */
+SR_PRIV int send_msg1(const struct sr_dev_inst *sdi, char cmd, int param)
+{
+       struct sr_serial_dev_inst *serial;
+       char buf[5];
+
+       if (!sdi || !(serial = sdi->conn))
+               return SR_ERR_ARG;
+
+       snprintf(buf, sizeof(buf), "%c%03d", cmd, param);
+       buf[4] = '\r';
+
+       sr_spew("send_msg1(): %c%c%c%c\\r", buf[0], buf[1], buf[2], buf[3]);
+
+       if (serial_write(serial, buf, sizeof(buf)) == -1) {
+               sr_err("Write error for cmd=%c: %d %s", cmd, errno, strerror(errno));
+               return SR_ERR;
+       }
+
+       /*
+        * Wait 50ms to ensure that the device does not swallow any of the
+        * following commands.
+        */
+       g_usleep(50000);
+
+       return SR_OK;
+}
diff --git a/src/hardware/conrad-digi-35-cpu/protocol.h b/src/hardware/conrad-digi-35-cpu/protocol.h
new file mode 100644 (file)
index 0000000..fcde852
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Matthias Heidbrink <m-sigrok@heidbrink.biz>
+ *
+ * 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
+ * <em>Conrad DIGI 35 CPU</em> power supply driver
+ * @internal
+ */
+
+#ifndef LIBSIGROK_HARDWARE_CONRAD_DIGI_35_CPU_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_CONRAD_DIGI_35_CPU_PROTOCOL_H
+
+#include <stdint.h>
+#include <errno.h>
+#include <string.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "conrad-digi-35-cpu"
+
+SR_PRIV int send_msg1(const struct sr_dev_inst *sdi, char cmd, int param);
+
+#endif
diff --git a/src/hardware/demo/demo.c b/src/hardware/demo/demo.c
new file mode 100644 (file)
index 0000000..b2f3a50
--- /dev/null
@@ -0,0 +1,782 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
+ * Copyright (C) 2011 Olivier Fauchon <olivier@aixmarseille.com>
+ * 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 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <math.h>
+#ifdef _WIN32
+#include <io.h>
+#include <fcntl.h>
+#define pipe(fds) _pipe(fds, 4096, _O_BINARY)
+#endif
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "demo"
+
+#define DEFAULT_NUM_LOGIC_CHANNELS     8
+#define DEFAULT_NUM_ANALOG_CHANNELS    4
+
+/* The size in bytes of chunks to send through the session bus. */
+#define LOGIC_BUFSIZE        4096
+/* Size of the analog pattern space per channel. */
+#define ANALOG_BUFSIZE       4096
+
+#define ANALOG_AMPLITUDE 25
+#define ANALOG_SAMPLES_PER_PERIOD 20
+
+/* Logic patterns we can generate. */
+enum {
+       /**
+        * Spells "sigrok" across 8 channels using '0's (with '1's as
+        * "background") when displayed using the 'bits' output format.
+        * The pattern is repeated every 8 channels, shifted to the right
+        * in time by one bit.
+        */
+       PATTERN_SIGROK,
+
+       /** Pseudo-random values on all channels. */
+       PATTERN_RANDOM,
+
+       /**
+        * Incrementing number across 8 channels. The pattern is repeated
+        * every 8 channels, shifted to the right in time by one bit.
+        */
+       PATTERN_INC,
+
+       /** All channels have a low logic state. */
+       PATTERN_ALL_LOW,
+
+       /** All channels have a high logic state. */
+       PATTERN_ALL_HIGH,
+};
+
+/* Analog patterns we can generate. */
+enum {
+       /**
+        * Square wave.
+        */
+       PATTERN_SQUARE,
+       PATTERN_SINE,
+       PATTERN_TRIANGLE,
+       PATTERN_SAWTOOTH,
+};
+
+static const char *logic_pattern_str[] = {
+       "sigrok",
+       "random",
+       "incremental",
+       "all-low",
+       "all-high",
+};
+
+static const char *analog_pattern_str[] = {
+       "square",
+       "sine",
+       "triangle",
+       "sawtooth",
+};
+
+struct analog_gen {
+       int pattern;
+       float pattern_data[ANALOG_BUFSIZE];
+       unsigned int num_samples;
+       struct sr_datafeed_analog packet;
+};
+
+/* Private, per-device-instance driver context. */
+struct dev_context {
+       int pipe_fds[2];
+       GIOChannel *channel;
+       uint64_t cur_samplerate;
+       uint64_t limit_samples;
+       uint64_t limit_msec;
+       uint64_t logic_counter;
+       uint64_t analog_counter;
+       int64_t starttime;
+       uint64_t step;
+       /* Logic */
+       int32_t num_logic_channels;
+       unsigned int logic_unitsize;
+       /* There is only ever one logic channel group, so its pattern goes here. */
+       uint8_t logic_pattern;
+       unsigned char logic_data[LOGIC_BUFSIZE];
+       /* Analog */
+       int32_t num_analog_channels;
+       GSList *analog_channel_groups;
+};
+
+static const int32_t scanopts[] = {
+       SR_CONF_NUM_LOGIC_CHANNELS,
+       SR_CONF_NUM_ANALOG_CHANNELS,
+};
+
+static const int devopts[] = {
+       SR_CONF_LOGIC_ANALYZER,
+       SR_CONF_DEMO_DEV,
+       SR_CONF_SAMPLERATE,
+       SR_CONF_LIMIT_SAMPLES,
+       SR_CONF_LIMIT_MSEC,
+};
+
+static const int devopts_cg[] = {
+       SR_CONF_PATTERN_MODE,
+};
+
+static const uint64_t samplerates[] = {
+       SR_HZ(1),
+       SR_GHZ(1),
+       SR_HZ(1),
+};
+
+static uint8_t pattern_sigrok[] = {
+       0x4c, 0x92, 0x92, 0x92, 0x64, 0x00, 0x00, 0x00,
+       0x82, 0xfe, 0xfe, 0x82, 0x00, 0x00, 0x00, 0x00,
+       0x7c, 0x82, 0x82, 0x92, 0x74, 0x00, 0x00, 0x00,
+       0xfe, 0x12, 0x12, 0x32, 0xcc, 0x00, 0x00, 0x00,
+       0x7c, 0x82, 0x82, 0x82, 0x7c, 0x00, 0x00, 0x00,
+       0xfe, 0x10, 0x28, 0x44, 0x82, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0xbe, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+SR_PRIV struct sr_dev_driver demo_driver_info;
+static struct sr_dev_driver *di = &demo_driver_info;
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data);
+
+
+static int init(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static void generate_analog_pattern(const struct sr_channel_group *cg, uint64_t sample_rate)
+{
+       struct analog_gen *ag;
+       double t, frequency;
+       float value;
+       unsigned int num_samples, i;
+       int last_end;
+
+       ag = cg->priv;
+       num_samples = ANALOG_BUFSIZE / sizeof(float);
+
+       sr_dbg("Generating %s pattern for channel group %s",
+              analog_pattern_str[ag->pattern], cg->name);
+
+       switch (ag->pattern) {
+       case PATTERN_SQUARE:
+               value = ANALOG_AMPLITUDE;
+               last_end = 0;
+               for (i = 0; i < num_samples; i++) {
+                       if (i % 5 == 0)
+                               value = -value;
+                       if (i % 10 == 0)
+                               last_end = i - 1;
+                       ag->pattern_data[i] = value;
+               }
+               ag->num_samples = last_end;
+               break;
+
+       case PATTERN_SINE:
+               frequency = (double) sample_rate / ANALOG_SAMPLES_PER_PERIOD;
+
+               /* Make sure the number of samples we put out is an integer
+                * multiple of our period size */
+               /* FIXME we actually need only one period. A ringbuffer would be
+                * usefull here.*/
+               while (num_samples % ANALOG_SAMPLES_PER_PERIOD != 0)
+                       num_samples--;
+
+               for (i = 0; i < num_samples; i++) {
+                       t = (double) i / (double) sample_rate;
+                       ag->pattern_data[i] = ANALOG_AMPLITUDE *
+                                               sin(2 * M_PI * frequency * t);
+               }
+
+               ag->num_samples = num_samples;
+               break;
+
+       case PATTERN_TRIANGLE:
+               frequency = (double) sample_rate / ANALOG_SAMPLES_PER_PERIOD;
+
+               while (num_samples % ANALOG_SAMPLES_PER_PERIOD != 0)
+                       num_samples--;
+
+               for (i = 0; i < num_samples; i++) {
+                       t = (double) i / (double) sample_rate;
+                       ag->pattern_data[i] = (2 * ANALOG_AMPLITUDE / M_PI) *
+                                               asin(sin(2 * M_PI * frequency * t));
+               }
+
+               ag->num_samples = num_samples;
+               break;
+
+       case PATTERN_SAWTOOTH:
+               frequency = (double) sample_rate / ANALOG_SAMPLES_PER_PERIOD;
+
+               while (num_samples % ANALOG_SAMPLES_PER_PERIOD != 0)
+                       num_samples--;
+
+               for (i = 0; i < num_samples; i++) {
+                       t = (double) i / (double) sample_rate;
+                       ag->pattern_data[i] = 2 * ANALOG_AMPLITUDE *
+                                               ((t * frequency) - floor(0.5f + t * frequency));
+               }
+
+               ag->num_samples = num_samples;
+               break;
+       }
+}
+
+static GSList *scan(GSList *options)
+{
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       struct sr_dev_inst *sdi;
+       struct sr_channel *ch;
+       struct sr_channel_group *cg;
+       struct sr_config *src;
+       struct analog_gen *ag;
+       GSList *devices, *l;
+       int num_logic_channels, num_analog_channels, pattern, i;
+       char channel_name[16];
+
+       drvc = di->priv;
+
+       num_logic_channels = DEFAULT_NUM_LOGIC_CHANNELS;
+       num_analog_channels = DEFAULT_NUM_ANALOG_CHANNELS;
+       for (l = options; l; l = l->next) {
+               src = l->data;
+               switch (src->key) {
+               case SR_CONF_NUM_LOGIC_CHANNELS:
+                       num_logic_channels = g_variant_get_int32(src->data);
+                       break;
+               case SR_CONF_NUM_ANALOG_CHANNELS:
+                       num_analog_channels = g_variant_get_int32(src->data);
+                       break;
+               }
+       }
+
+       devices = NULL;
+       sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, "Demo device", NULL, NULL);
+       if (!sdi) {
+               sr_err("Device instance creation failed.");
+               return NULL;
+       }
+       sdi->driver = di;
+
+       if (!(devc = g_try_malloc(sizeof(struct dev_context)))) {
+               sr_err("Device context malloc failed.");
+               return NULL;
+       }
+       devc->cur_samplerate = SR_KHZ(200);
+       devc->limit_samples = 0;
+       devc->limit_msec = 0;
+       devc->step = 0;
+       devc->num_logic_channels = num_logic_channels;
+       devc->logic_unitsize = (devc->num_logic_channels + 7) / 8;
+       devc->logic_pattern = PATTERN_SIGROK;
+       devc->num_analog_channels = num_analog_channels;
+       devc->analog_channel_groups = NULL;
+
+       /* Logic channels, all in one channel group. */
+       if (!(cg = g_try_malloc(sizeof(struct sr_channel_group))))
+               return NULL;
+       cg->name = g_strdup("Logic");
+       cg->channels = NULL;
+       cg->priv = NULL;
+       for (i = 0; i < num_logic_channels; i++) {
+               sprintf(channel_name, "D%d", i);
+               if (!(ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE, channel_name)))
+                       return NULL;
+               sdi->channels = g_slist_append(sdi->channels, ch);
+               cg->channels = g_slist_append(cg->channels, ch);
+       }
+       sdi->channel_groups = g_slist_append(NULL, cg);
+
+       /* Analog channels, channel groups and pattern generators. */
+
+       pattern = 0;
+       for (i = 0; i < num_analog_channels; i++) {
+               sprintf(channel_name, "A%d", i);
+               if (!(ch = sr_channel_new(i + num_logic_channels,
+                               SR_CHANNEL_ANALOG, TRUE, channel_name)))
+                       return NULL;
+               sdi->channels = g_slist_append(sdi->channels, ch);
+
+               /* Every analog channel gets its own channel group. */
+               if (!(cg = g_try_malloc(sizeof(struct sr_channel_group))))
+                       return NULL;
+               cg->name = g_strdup(channel_name);
+               cg->channels = g_slist_append(NULL, ch);
+
+               /* Every channel group gets a generator struct. */
+               if (!(ag = g_try_malloc(sizeof(struct analog_gen))))
+                       return NULL;
+               ag->packet.channels = cg->channels;
+               ag->packet.mq = 0;
+               ag->packet.mqflags = 0;
+               ag->packet.unit = SR_UNIT_VOLT;
+               ag->packet.data = ag->pattern_data;
+               ag->pattern = pattern;
+               cg->priv = ag;
+
+               sdi->channel_groups = g_slist_append(sdi->channel_groups, cg);
+               devc->analog_channel_groups = g_slist_append(devc->analog_channel_groups, cg);
+
+               if (++pattern == ARRAY_SIZE(analog_pattern_str))
+                       pattern = 0;
+       }
+
+       sdi->priv = devc;
+       devices = g_slist_append(devices, sdi);
+       drvc->instances = g_slist_append(drvc->instances, sdi);
+
+       return devices;
+}
+
+static GSList *dev_list(void)
+{
+       return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+       sdi->status = SR_ST_ACTIVE;
+
+       return SR_OK;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+       sdi->status = SR_ST_INACTIVE;
+
+       return SR_OK;
+}
+
+static int cleanup(void)
+{
+       return std_dev_clear(di, NULL);
+}
+
+static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       struct sr_channel *ch;
+       struct analog_gen *ag;
+       int pattern;
+
+       if (!sdi)
+               return SR_ERR_ARG;
+
+       devc = sdi->priv;
+       switch (id) {
+       case SR_CONF_SAMPLERATE:
+               *data = g_variant_new_uint64(devc->cur_samplerate);
+               break;
+       case SR_CONF_LIMIT_SAMPLES:
+               *data = g_variant_new_uint64(devc->limit_samples);
+               break;
+       case SR_CONF_LIMIT_MSEC:
+               *data = g_variant_new_uint64(devc->limit_msec);
+               break;
+       case SR_CONF_PATTERN_MODE:
+               if (!cg)
+                       return SR_ERR_CHANNEL_GROUP;
+               ch = cg->channels->data;
+               if (ch->type == SR_CHANNEL_LOGIC) {
+                       pattern = devc->logic_pattern;
+                       *data = g_variant_new_string(logic_pattern_str[pattern]);
+               } else if (ch->type == SR_CHANNEL_ANALOG) {
+                       ag = cg->priv;
+                       pattern = ag->pattern;
+                       *data = g_variant_new_string(analog_pattern_str[pattern]);
+               } else
+                       return SR_ERR_BUG;
+               break;
+       case SR_CONF_NUM_LOGIC_CHANNELS:
+               *data = g_variant_new_int32(devc->num_logic_channels);
+               break;
+       case SR_CONF_NUM_ANALOG_CHANNELS:
+               *data = g_variant_new_int32(devc->num_analog_channels);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       struct analog_gen *ag;
+       struct sr_channel *ch;
+       int pattern, ret;
+       unsigned int i;
+       const char *stropt;
+
+       devc = sdi->priv;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       ret = SR_OK;
+       switch (id) {
+       case SR_CONF_SAMPLERATE:
+               devc->cur_samplerate = g_variant_get_uint64(data);
+               sr_dbg("Setting samplerate to %" PRIu64, devc->cur_samplerate);
+               break;
+       case SR_CONF_LIMIT_SAMPLES:
+               devc->limit_msec = 0;
+               devc->limit_samples = g_variant_get_uint64(data);
+               sr_dbg("Setting sample limit to %" PRIu64, devc->limit_samples);
+               break;
+       case SR_CONF_LIMIT_MSEC:
+               devc->limit_msec = g_variant_get_uint64(data);
+               devc->limit_samples = 0;
+               sr_dbg("Setting time limit to %" PRIu64"ms", devc->limit_msec);
+               break;
+       case SR_CONF_PATTERN_MODE:
+               if (!cg)
+                       return SR_ERR_CHANNEL_GROUP;
+               stropt = g_variant_get_string(data, NULL);
+               ch = cg->channels->data;
+               pattern = -1;
+               if (ch->type == SR_CHANNEL_LOGIC) {
+                       for (i = 0; i < ARRAY_SIZE(logic_pattern_str); i++) {
+                               if (!strcmp(stropt, logic_pattern_str[i])) {
+                                       pattern = i;
+                                       break;
+                               }
+                       }
+                       if (pattern == -1)
+                               return SR_ERR_ARG;
+                       devc->logic_pattern = pattern;
+
+                       /* Might as well do this now, these are static. */
+                       if (pattern == PATTERN_ALL_LOW)
+                               memset(devc->logic_data, 0x00, LOGIC_BUFSIZE);
+                       else if (pattern == PATTERN_ALL_HIGH)
+                               memset(devc->logic_data, 0xff, LOGIC_BUFSIZE);
+                       sr_dbg("Setting logic pattern to %s",
+                                       logic_pattern_str[pattern]);
+               } else if (ch->type == SR_CHANNEL_ANALOG) {
+                       for (i = 0; i < ARRAY_SIZE(analog_pattern_str); i++) {
+                               if (!strcmp(stropt, analog_pattern_str[i])) {
+                                       pattern = i;
+                                       break;
+                               }
+                       }
+                       if (pattern == -1)
+                               return SR_ERR_ARG;
+                       sr_dbg("Setting analog pattern for channel group %s to %s",
+                                       cg->name, analog_pattern_str[pattern]);
+                       ag = cg->priv;
+                       ag->pattern = pattern;
+               } else
+                       return SR_ERR_BUG;
+               break;
+       default:
+               ret = SR_ERR_NA;
+       }
+
+       return ret;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct sr_channel *ch;
+       GVariant *gvar;
+       GVariantBuilder gvb;
+
+       (void)sdi;
+
+       if (key == SR_CONF_SCAN_OPTIONS) {
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               scanopts, ARRAY_SIZE(scanopts), sizeof(int32_t));
+               return SR_OK;
+       }
+
+       if (!sdi)
+               return SR_ERR_ARG;
+
+       if (!cg) {
+               switch (key) {
+               case SR_CONF_DEVICE_OPTIONS:
+                       *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                                       devopts, ARRAY_SIZE(devopts), sizeof(int32_t));
+                       break;
+               case SR_CONF_SAMPLERATE:
+                       g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
+                       gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), samplerates,
+                                       ARRAY_SIZE(samplerates), sizeof(uint64_t));
+                       g_variant_builder_add(&gvb, "{sv}", "samplerate-steps", gvar);
+                       *data = g_variant_builder_end(&gvb);
+                       break;
+               default:
+                       return SR_ERR_NA;
+               }
+       } else {
+               ch = cg->channels->data;
+               switch (key) {
+               case SR_CONF_DEVICE_OPTIONS:
+                       *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                                       devopts_cg, ARRAY_SIZE(devopts_cg), sizeof(int32_t));
+                       break;
+               case SR_CONF_PATTERN_MODE:
+                       if (ch->type == SR_CHANNEL_LOGIC)
+                               *data = g_variant_new_strv(logic_pattern_str,
+                                               ARRAY_SIZE(logic_pattern_str));
+                       else if (ch->type == SR_CHANNEL_ANALOG)
+                               *data = g_variant_new_strv(analog_pattern_str,
+                                               ARRAY_SIZE(analog_pattern_str));
+                       else
+                               return SR_ERR_BUG;
+                       break;
+               default:
+                       return SR_ERR_NA;
+               }
+       }
+
+       return SR_OK;
+}
+
+static void logic_generator(struct sr_dev_inst *sdi, uint64_t size)
+{
+       struct dev_context *devc;
+       uint64_t i, j;
+       uint8_t pat;
+
+       devc = sdi->priv;
+
+       switch (devc->logic_pattern) {
+       case PATTERN_SIGROK:
+               memset(devc->logic_data, 0x00, size);
+               for (i = 0; i < size; i += devc->logic_unitsize) {
+                       for (j = 0; j < devc->logic_unitsize; j++) {
+                               pat = pattern_sigrok[(devc->step + j) % sizeof(pattern_sigrok)] >> 1;
+                               devc->logic_data[i + j] = ~pat;
+                       }
+                       devc->step++;
+               }
+               break;
+       case PATTERN_RANDOM:
+               for (i = 0; i < size; i++)
+                       devc->logic_data[i] = (uint8_t)(rand() & 0xff);
+               break;
+       case PATTERN_INC:
+               for (i = 0; i < size; i++) {
+                       for (j = 0; j < devc->logic_unitsize; j++) {
+                               devc->logic_data[i + j] = devc->step;
+                       }
+                       devc->step++;
+               }
+               break;
+       case PATTERN_ALL_LOW:
+       case PATTERN_ALL_HIGH:
+               /* These were set when the pattern mode was selected. */
+               break;
+       default:
+               sr_err("Unknown pattern: %d.", devc->logic_pattern);
+               break;
+       }
+}
+
+/* Callback handling data */
+static int prepare_data(int fd, int revents, void *cb_data)
+{
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_logic logic;
+       struct sr_channel_group *cg;
+       struct analog_gen *ag;
+       GSList *l;
+       uint64_t logic_todo, analog_todo, expected_samplenum, analog_samples, sending_now;
+       int64_t time, elapsed;
+
+       (void)fd;
+       (void)revents;
+
+       sdi = cb_data;
+       devc = sdi->priv;
+
+       /* How many "virtual" samples should we have collected by now? */
+       time = g_get_monotonic_time();
+       elapsed = time - devc->starttime;
+       expected_samplenum = elapsed * devc->cur_samplerate / 1000000;
+
+       /* Of those, how many do we still have to send? */
+       logic_todo = MIN(expected_samplenum, devc->limit_samples) - devc->logic_counter;
+       analog_todo = MIN(expected_samplenum, devc->limit_samples) - devc->analog_counter;
+
+       while (logic_todo || analog_todo) {
+               /* Logic */
+               if (devc->num_logic_channels > 0 && logic_todo > 0) {
+                       sending_now = MIN(logic_todo,
+                                       LOGIC_BUFSIZE / devc->logic_unitsize);
+                       logic_generator(sdi, sending_now * devc->logic_unitsize);
+                       packet.type = SR_DF_LOGIC;
+                       packet.payload = &logic;
+                       logic.length = sending_now * devc->logic_unitsize;
+                       logic.unitsize = devc->logic_unitsize;
+                       logic.data = devc->logic_data;
+                       sr_session_send(sdi, &packet);
+                       logic_todo -= sending_now;
+                       devc->logic_counter += sending_now;
+               }
+
+               /* Analog, one channel at a time */
+               if (devc->num_analog_channels > 0 && analog_todo > 0) {
+                       sending_now = 0;
+                       for (l = devc->analog_channel_groups; l; l = l->next) {
+                               cg = l->data;
+                               ag = cg->priv;
+                               packet.type = SR_DF_ANALOG;
+                               packet.payload = &ag->packet;
+
+                               /* FIXME we should make sure we output a whole
+                                * period of data before we send out again the
+                                * beginning of our buffer. A ring buffer would
+                                * help here as well */
+
+                               analog_samples = MIN(analog_todo, ag->num_samples);
+                               /* Whichever channel group gets there first. */
+                               sending_now = MAX(sending_now, analog_samples);
+                               ag->packet.num_samples = analog_samples;
+                               sr_session_send(sdi, &packet);
+                       }
+                       analog_todo -= sending_now;
+                       devc->analog_counter += sending_now;
+               }
+       }
+
+       if (devc->logic_counter >= devc->limit_samples &&
+                       devc->analog_counter >= devc->limit_samples) {
+               sr_dbg("Requested number of samples reached.");
+               dev_acquisition_stop(sdi, cb_data);
+               return TRUE;
+       }
+
+       return TRUE;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+       GSList *l;
+       struct dev_context *devc;
+
+       (void)cb_data;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       devc = sdi->priv;
+       if (devc->limit_samples == 0)
+               return SR_ERR;
+       devc->logic_counter = devc->analog_counter = 0;
+
+       /*
+        * Setting two channels connected by a pipe is a remnant from when the
+        * demo driver generated data in a thread, and collected and sent the
+        * data in the main program loop.
+        * They are kept here because it provides a convenient way of setting
+        * up a timeout-based polling mechanism.
+        */
+       if (pipe(devc->pipe_fds)) {
+               sr_err("%s: pipe() failed", __func__);
+               return SR_ERR;
+       }
+
+       for (l = devc->analog_channel_groups; l; l = l->next) {
+               generate_analog_pattern(l->data, devc->cur_samplerate);
+       }
+
+       devc->channel = g_io_channel_unix_new(devc->pipe_fds[0]);
+
+       g_io_channel_set_flags(devc->channel, G_IO_FLAG_NONBLOCK, NULL);
+
+       /* Set channel encoding to binary (default is UTF-8). */
+       g_io_channel_set_encoding(devc->channel, NULL, NULL);
+
+       /* Make channels to unbuffered. */
+       g_io_channel_set_buffered(devc->channel, FALSE);
+
+       sr_session_source_add_channel(sdi->session, devc->channel, G_IO_IN | G_IO_ERR,
+                       40, prepare_data, (void *)sdi);
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(sdi, LOG_PREFIX);
+
+       /* We use this timestamp to decide how many more samples to send. */
+       devc->starttime = g_get_monotonic_time();
+
+       return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct dev_context *devc;
+       struct sr_datafeed_packet packet;
+
+       (void)cb_data;
+
+       devc = sdi->priv;
+       sr_dbg("Stopping acquisition.");
+
+       sr_session_source_remove_channel(sdi->session, devc->channel);
+       g_io_channel_shutdown(devc->channel, FALSE, NULL);
+       g_io_channel_unref(devc->channel);
+       devc->channel = NULL;
+
+       /* Send last packet. */
+       packet.type = SR_DF_END;
+       sr_session_send(sdi, &packet);
+
+       return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver demo_driver_info = {
+       .name = "demo",
+       .longname = "Demo driver and pattern generator",
+       .api_version = 1,
+       .init = init,
+       .cleanup = cleanup,
+       .scan = scan,
+       .dev_list = 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,
+       .priv = NULL,
+};
diff --git a/src/hardware/fluke-dmm/api.c b/src/hardware/fluke-dmm/api.c
new file mode 100644 (file)
index 0000000..3d739a1
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert@biot.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 <glib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "fluke-dmm.h"
+
+static const int32_t hwopts[] = {
+       SR_CONF_CONN,
+       SR_CONF_SERIALCOMM,
+};
+
+static const int32_t hwcaps[] = {
+       SR_CONF_MULTIMETER,
+       SR_CONF_LIMIT_SAMPLES,
+       SR_CONF_LIMIT_MSEC,
+       SR_CONF_CONTINUOUS,
+};
+
+SR_PRIV struct sr_dev_driver flukedmm_driver_info;
+static struct sr_dev_driver *di = &flukedmm_driver_info;
+
+static char *scan_conn[] = {
+       /* 287/289 */
+       "115200/8n1",
+       /* 187/189 */
+       "9600/8n1",
+       /* Scopemeter 190 series */
+       "1200/8n1",
+       NULL
+};
+
+static const struct flukedmm_profile supported_flukedmm[] = {
+       { FLUKE_187, "187", 100, 1000 },
+       { FLUKE_189, "189", 100, 1000 },
+       { FLUKE_287, "287", 100, 1000 },
+       { FLUKE_190, "199B", 1000, 3500 },
+};
+
+static int init(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *fluke_scan(const char *conn, const char *serialcomm)
+{
+       struct sr_dev_inst *sdi;
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       struct sr_channel *ch;
+       struct sr_serial_dev_inst *serial;
+       GSList *devices;
+       int retry, len, i, s;
+       char buf[128], *b, **tokens;
+
+       if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
+               return NULL;
+
+       if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
+               return NULL;
+
+       drvc = di->priv;
+       b = buf;
+       retry = 0;
+       devices = NULL;
+       /* We'll try the discovery sequence three times in case the device
+        * is not in an idle state when we send ID. */
+       while (!devices && retry < 3) {
+               retry++;
+               serial_flush(serial);
+               if (serial_write(serial, "ID\r", 3) == -1) {
+                       sr_err("Unable to send ID string: %s.",
+                              strerror(errno));
+                       continue;
+               }
+
+               /* Response is first a CMD_ACK byte (ASCII '0' for OK,
+                * or '1' to signify an error. */
+               len = 128;
+               serial_readline(serial, &b, &len, 150);
+               if (len != 1)
+                       continue;
+               if (buf[0] != '0')
+                       continue;
+
+               /* If CMD_ACK was OK, ID string follows. */
+               len = 128;
+               serial_readline(serial, &b, &len, 850);
+               if (len < 10)
+                       continue;
+               if (strcspn(buf, ",") < 15)
+                       /* Looks like it's comma-separated. */
+                       tokens = g_strsplit(buf, ",", 3);
+               else
+                       /* Fluke 199B, at least, uses semicolon. */
+                       tokens = g_strsplit(buf, ";", 3);
+               if (!strncmp("FLUKE", tokens[0], 5)
+                               && tokens[1] && tokens[2]) {
+                       for (i = 0; supported_flukedmm[i].model; i++) {
+                               if (strcmp(supported_flukedmm[i].modelname, tokens[0] + 6))
+                                       continue;
+                               /* Skip leading spaces in version number. */
+                               for (s = 0; tokens[1][s] == ' '; s++);
+                               if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "Fluke",
+                                               tokens[0] + 6, tokens[1] + s)))
+                                       return NULL;
+                               if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+                                       sr_err("Device context malloc failed.");
+                                       return NULL;
+                               }
+                               devc->profile = &supported_flukedmm[i];
+                               sdi->inst_type = SR_INST_SERIAL;
+                               sdi->conn = serial;
+                               sdi->priv = devc;
+                               sdi->driver = di;
+                               if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1")))
+                                       return NULL;
+                               sdi->channels = g_slist_append(sdi->channels, ch);
+                               drvc->instances = g_slist_append(drvc->instances, sdi);
+                               devices = g_slist_append(devices, sdi);
+                               break;
+                       }
+               }
+               g_strfreev(tokens);
+               if (devices)
+                       /* Found one. */
+                       break;
+       }
+       serial_close(serial);
+       if (!devices)
+               sr_serial_dev_inst_free(serial);
+
+       return devices;
+}
+
+static GSList *scan(GSList *options)
+{
+       struct sr_config *src;
+       GSList *l, *devices;
+       int i;
+       const char *conn, *serialcomm;
+
+       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 = fluke_scan(conn, serialcomm);
+       } else {
+               for (i = 0; scan_conn[i]; i++) {
+                       if ((devices = fluke_scan(conn, scan_conn[i])))
+                               break;
+                       /* The Scopemeter 199B, at least, requires this
+                        * after all the 115k/9.6k confusion. */
+                       g_usleep(5000);
+               }
+       }
+
+       return devices;
+}
+
+static GSList *dev_list(void)
+{
+       return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int cleanup(void)
+{
+       return std_dev_clear(di, NULL);
+}
+
+static int config_set(int id, 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;
+
+       if (!(devc = sdi->priv)) {
+               sr_err("sdi->priv was NULL.");
+               return SR_ERR_BUG;
+       }
+
+       switch (id) {
+       case SR_CONF_LIMIT_MSEC:
+               /* TODO: not yet implemented */
+               if (g_variant_get_uint64(data) == 0) {
+                       sr_err("LIMIT_MSEC can't be 0.");
+                       return SR_ERR;
+               }
+               devc->limit_msec = g_variant_get_uint64(data);
+               sr_dbg("Setting time limit to %" PRIu64 "ms.",
+                      devc->limit_msec);
+               break;
+       case SR_CONF_LIMIT_SAMPLES:
+               devc->limit_samples = g_variant_get_uint64(data);
+               sr_dbg("Setting sample limit to %" PRIu64 ".",
+                      devc->limit_samples);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_list(int 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_INT32,
+                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+               break;
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       if (!(devc = sdi->priv)) {
+               sr_err("sdi->priv was NULL.");
+               return SR_ERR_BUG;
+       }
+
+       devc->cb_data = cb_data;
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(cb_data, LOG_PREFIX);
+
+       /* Poll every 100ms, or whenever some data comes in. */
+       serial = sdi->conn;
+       serial_source_add(sdi->session, serial, G_IO_IN, 50,
+                       fluke_receive_data, (void *)sdi);
+
+       if (serial_write(serial, "QM\r", 3) == -1) {
+               sr_err("Unable to send QM: %s.", strerror(errno));
+               return SR_ERR;
+       }
+       devc->cmd_sent_at = g_get_monotonic_time() / 1000;
+       devc->expect_response = TRUE;
+
+       return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       return std_serial_dev_acquisition_stop(sdi, cb_data, std_serial_dev_close,
+                       sdi->conn, LOG_PREFIX);
+}
+
+SR_PRIV struct sr_dev_driver flukedmm_driver_info = {
+       .name = "fluke-dmm",
+       .longname = "Fluke 18x/28x series DMMs",
+       .api_version = 1,
+       .init = init,
+       .cleanup = cleanup,
+       .scan = scan,
+       .dev_list = 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 = dev_acquisition_stop,
+       .priv = NULL,
+};
diff --git a/src/hardware/fluke-dmm/fluke-dmm.h b/src/hardware/fluke-dmm/fluke-dmm.h
new file mode 100644 (file)
index 0000000..d162bdd
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert@biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_FLUKE_DMM_FLUKE_DMM_H
+#define LIBSIGROK_HARDWARE_FLUKE_DMM_FLUKE_DMM_H
+
+#define LOG_PREFIX "fluke-dmm"
+
+#define FLUKEDMM_BUFSIZE  256
+
+/* Supported models */
+enum {
+       FLUKE_187 = 1,
+       FLUKE_189,
+       FLUKE_287,
+       FLUKE_190,
+};
+
+/* Supported device profiles */
+struct flukedmm_profile {
+       int model;
+       const char *modelname;
+       /* How often to poll, in ms. */
+       int poll_period;
+       /* If no response received, how long to wait before retrying. */
+       int timeout;
+};
+
+/* Private, per-device-instance driver context. */
+struct dev_context {
+       const struct flukedmm_profile *profile;
+       uint64_t limit_samples;
+       uint64_t limit_msec;
+
+       /* Opaque pointer passed in by the frontend. */
+       void *cb_data;
+
+       /* Runtime. */
+       uint64_t num_samples;
+       char buf[FLUKEDMM_BUFSIZE];
+       int buflen;
+       int64_t cmd_sent_at;
+       int expect_response;
+       int meas_type;
+       int is_relative;
+       int mq;
+       int unit;
+       int mqflags;
+};
+
+SR_PRIV int fluke_receive_data(int fd, int revents, void *cb_data);
+
+#endif
diff --git a/src/hardware/fluke-dmm/fluke.c b/src/hardware/fluke-dmm/fluke.c
new file mode 100644 (file)
index 0000000..edb6734
--- /dev/null
@@ -0,0 +1,536 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert@biot.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 <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <errno.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "fluke-dmm.h"
+
+static struct sr_datafeed_analog *handle_qm_18x(const struct sr_dev_inst *sdi,
+               char **tokens)
+{
+       struct sr_datafeed_analog *analog;
+       float fvalue;
+       char *e, *u;
+       gboolean is_oor;
+
+       if (strcmp(tokens[0], "QM") || !tokens[1])
+               return NULL;
+
+       if ((e = strstr(tokens[1], "Out of range"))) {
+               is_oor = TRUE;
+               fvalue = -1;
+               while(*e && *e != '.')
+                       e++;
+       } else {
+               is_oor = FALSE;
+               /* Delimit the float, since sr_atof_ascii() wants only
+                * a valid float here. */
+               e = tokens[1];
+               while(*e && *e != ' ')
+                       e++;
+               *e++ = '\0';
+               if (sr_atof_ascii(tokens[1], &fvalue) != SR_OK || fvalue == 0.0) {
+                       /* Happens all the time, when switching modes. */
+                       sr_dbg("Invalid float.");
+                       return NULL;
+               }
+       }
+       while(*e && *e == ' ')
+               e++;
+
+       if (!(analog = g_try_malloc0(sizeof(struct sr_datafeed_analog))))
+               return NULL;
+       if (!(analog->data = g_try_malloc(sizeof(float))))
+               return NULL;
+       analog->channels = sdi->channels;
+       analog->num_samples = 1;
+       if (is_oor)
+               *analog->data = NAN;
+       else
+               *analog->data = fvalue;
+       analog->mq = -1;
+
+       if ((u = strstr(e, "V DC")) || (u = strstr(e, "V AC"))) {
+               analog->mq = SR_MQ_VOLTAGE;
+               analog->unit = SR_UNIT_VOLT;
+               if (!is_oor && e[0] == 'm')
+                       *analog->data /= 1000;
+               /* This catches "V AC", "V DC" and "V AC+DC". */
+               if (strstr(u, "AC"))
+                       analog->mqflags |= SR_MQFLAG_AC | SR_MQFLAG_RMS;
+               if (strstr(u, "DC"))
+                       analog->mqflags |= SR_MQFLAG_DC;
+       } else if ((u = strstr(e, "dBV")) || (u = strstr(e, "dBm"))) {
+               analog->mq = SR_MQ_VOLTAGE;
+               if (u[2] == 'm')
+                       analog->unit = SR_UNIT_DECIBEL_MW;
+               else
+                       analog->unit = SR_UNIT_DECIBEL_VOLT;
+               analog->mqflags |= SR_MQFLAG_AC | SR_MQFLAG_RMS;
+       } else if ((u = strstr(e, "Ohms"))) {
+               analog->mq = SR_MQ_RESISTANCE;
+               analog->unit = SR_UNIT_OHM;
+               if (is_oor)
+                       *analog->data = INFINITY;
+               else if (e[0] == 'k')
+                       *analog->data *= 1000;
+               else if (e[0] == 'M')
+                       *analog->data *= 1000000;
+       } else if (!strcmp(e, "nS")) {
+               analog->mq = SR_MQ_CONDUCTANCE;
+               analog->unit = SR_UNIT_SIEMENS;
+               *analog->data /= 1e+9;
+       } else if ((u = strstr(e, "Farads"))) {
+               analog->mq = SR_MQ_CAPACITANCE;
+               analog->unit = SR_UNIT_FARAD;
+               if (!is_oor) {
+                       if (e[0] == 'm')
+                               *analog->data /= 1e+3;
+                       else if (e[0] == 'u')
+                               *analog->data /= 1e+6;
+                       else if (e[0] == 'n')
+                               *analog->data /= 1e+9;
+               }
+       } else if ((u = strstr(e, "Deg C")) || (u = strstr(e, "Deg F"))) {
+               analog->mq = SR_MQ_TEMPERATURE;
+               if (u[4] == 'C')
+                       analog->unit = SR_UNIT_CELSIUS;
+               else
+                       analog->unit = SR_UNIT_FAHRENHEIT;
+       } else if ((u = strstr(e, "A AC")) || (u = strstr(e, "A DC"))) {
+               analog->mq = SR_MQ_CURRENT;
+               analog->unit = SR_UNIT_AMPERE;
+               /* This catches "A AC", "A DC" and "A AC+DC". */
+               if (strstr(u, "AC"))
+                       analog->mqflags |= SR_MQFLAG_AC | SR_MQFLAG_RMS;
+               if (strstr(u, "DC"))
+                       analog->mqflags |= SR_MQFLAG_DC;
+               if (!is_oor) {
+                       if (e[0] == 'm')
+                               *analog->data /= 1e+3;
+                       else if (e[0] == 'u')
+                               *analog->data /= 1e+6;
+               }
+       } else if ((u = strstr(e, "Hz"))) {
+               analog->mq = SR_MQ_FREQUENCY;
+               analog->unit = SR_UNIT_HERTZ;
+               if (e[0] == 'k')
+                       *analog->data *= 1e+3;
+       } else if (!strcmp(e, "%")) {
+               analog->mq = SR_MQ_DUTY_CYCLE;
+               analog->unit = SR_UNIT_PERCENTAGE;
+       } else if ((u = strstr(e, "ms"))) {
+               analog->mq = SR_MQ_PULSE_WIDTH;
+               analog->unit = SR_UNIT_SECOND;
+               *analog->data /= 1e+3;
+       }
+
+       if (analog->mq == -1) {
+               /* Not a valid measurement. */
+               g_free(analog->data);
+               g_free(analog);
+               analog = NULL;
+       }
+
+       return analog;
+}
+
+static struct sr_datafeed_analog *handle_qm_28x(const struct sr_dev_inst *sdi,
+               char **tokens)
+{
+       struct sr_datafeed_analog *analog;
+       float fvalue;
+
+       if (!tokens[1])
+               return NULL;
+
+       if (sr_atof_ascii(tokens[0], &fvalue) != SR_OK || fvalue == 0.0) {
+               sr_err("Invalid float '%s'.", tokens[0]);
+               return NULL;
+       }
+
+       if (!(analog = g_try_malloc0(sizeof(struct sr_datafeed_analog))))
+               return NULL;
+       if (!(analog->data = g_try_malloc(sizeof(float))))
+               return NULL;
+       analog->channels = sdi->channels;
+       analog->num_samples = 1;
+       *analog->data = fvalue;
+       analog->mq = -1;
+
+       if (!strcmp(tokens[1], "VAC") || !strcmp(tokens[1], "VDC")) {
+               analog->mq = SR_MQ_VOLTAGE;
+               analog->unit = SR_UNIT_VOLT;
+               if (!strcmp(tokens[2], "NORMAL")) {
+                       if (tokens[1][1] == 'A') {
+                               analog->mqflags |= SR_MQFLAG_AC;
+                               analog->mqflags |= SR_MQFLAG_RMS;
+                       } else
+                               analog->mqflags |= SR_MQFLAG_DC;
+               } else if (!strcmp(tokens[2], "OL") || !strcmp(tokens[2], "OL_MINUS")) {
+                       *analog->data = NAN;
+               } else
+                       analog->mq = -1;
+       } else if (!strcmp(tokens[1], "dBV") || !strcmp(tokens[1], "dBm")) {
+               analog->mq = SR_MQ_VOLTAGE;
+               if (tokens[1][2] == 'm')
+                       analog->unit = SR_UNIT_DECIBEL_MW;
+               else
+                       analog->unit = SR_UNIT_DECIBEL_VOLT;
+               analog->mqflags |= SR_MQFLAG_AC | SR_MQFLAG_RMS;
+       } else if (!strcmp(tokens[1], "CEL") || !strcmp(tokens[1], "FAR")) {
+               if (!strcmp(tokens[2], "NORMAL")) {
+                       analog->mq = SR_MQ_TEMPERATURE;
+                       if (tokens[1][0] == 'C')
+                               analog->unit = SR_UNIT_CELSIUS;
+                       else
+                               analog->unit = SR_UNIT_FAHRENHEIT;
+               }
+       } else if (!strcmp(tokens[1], "OHM")) {
+               if (!strcmp(tokens[3], "NONE")) {
+                       analog->mq = SR_MQ_RESISTANCE;
+                       analog->unit = SR_UNIT_OHM;
+                       if (!strcmp(tokens[2], "OL") || !strcmp(tokens[2], "OL_MINUS")) {
+                               *analog->data = INFINITY;
+                       } else if (strcmp(tokens[2], "NORMAL"))
+                               analog->mq = -1;
+               } else if (!strcmp(tokens[3], "OPEN_CIRCUIT")) {
+                       analog->mq = SR_MQ_CONTINUITY;
+                       analog->unit = SR_UNIT_BOOLEAN;
+                       *analog->data = 0.0;
+               } else if (!strcmp(tokens[3], "SHORT_CIRCUIT")) {
+                       analog->mq = SR_MQ_CONTINUITY;
+                       analog->unit = SR_UNIT_BOOLEAN;
+                       *analog->data = 1.0;
+               }
+       } else if (!strcmp(tokens[1], "F")
+                       && !strcmp(tokens[2], "NORMAL")
+                       && !strcmp(tokens[3], "NONE")) {
+               analog->mq = SR_MQ_CAPACITANCE;
+               analog->unit = SR_UNIT_FARAD;
+       } else if (!strcmp(tokens[1], "AAC") || !strcmp(tokens[1], "ADC")) {
+               analog->mq = SR_MQ_CURRENT;
+               analog->unit = SR_UNIT_AMPERE;
+               if (!strcmp(tokens[2], "NORMAL")) {
+                       if (tokens[1][1] == 'A') {
+                               analog->mqflags |= SR_MQFLAG_AC;
+                               analog->mqflags |= SR_MQFLAG_RMS;
+                       } else
+                               analog->mqflags |= SR_MQFLAG_DC;
+               } else if (!strcmp(tokens[2], "OL") || !strcmp(tokens[2], "OL_MINUS")) {
+                       *analog->data = NAN;
+               } else
+                       analog->mq = -1;
+       } if (!strcmp(tokens[1], "Hz") && !strcmp(tokens[2], "NORMAL")) {
+               analog->mq = SR_MQ_FREQUENCY;
+               analog->unit = SR_UNIT_HERTZ;
+       } else if (!strcmp(tokens[1], "PCT") && !strcmp(tokens[2], "NORMAL")) {
+               analog->mq = SR_MQ_DUTY_CYCLE;
+               analog->unit = SR_UNIT_PERCENTAGE;
+       } else if (!strcmp(tokens[1], "S") && !strcmp(tokens[2], "NORMAL")) {
+               analog->mq = SR_MQ_PULSE_WIDTH;
+               analog->unit = SR_UNIT_SECOND;
+       } else if (!strcmp(tokens[1], "SIE") && !strcmp(tokens[2], "NORMAL")) {
+               analog->mq = SR_MQ_CONDUCTANCE;
+               analog->unit = SR_UNIT_SIEMENS;
+       }
+
+       if (analog->mq == -1) {
+               /* Not a valid measurement. */
+               g_free(analog->data);
+               g_free(analog);
+               analog = NULL;
+       }
+
+       return analog;
+}
+
+static void handle_qm_19x_meta(const struct sr_dev_inst *sdi, char **tokens)
+{
+       struct dev_context *devc;
+       int meas_type, meas_unit, meas_char, i;
+
+       /* Make sure we have 7 valid tokens. */
+       for (i = 0; tokens[i] && i < 7; i++);
+       if (i != 7)
+               return;
+
+       if (strcmp(tokens[1], "1"))
+               /* Invalid measurement. */
+               return;
+
+       if (strcmp(tokens[2], "3"))
+               /* Only interested in input from the meter mode source. */
+               return;
+
+       devc = sdi->priv;
+
+       /* Measurement type 11 == absolute, 19 = relative */
+       meas_type = strtol(tokens[0], NULL, 10);
+       if (meas_type != 11 && meas_type != 19)
+               /* Device is in some mode we don't support. */
+               return;
+
+       /* We might get metadata for absolute and relative mode (if the device
+        * is in relative mode). In that case, relative takes precedence. */
+       if (meas_type == 11 && devc->meas_type == 19)
+               return;
+
+       meas_unit = strtol(tokens[3], NULL, 10);
+       if (meas_unit == 0)
+               /* Device is turned off. Really. */
+               return;
+       meas_char = strtol(tokens[4], NULL, 10);
+
+       devc->mq = devc->unit = -1;
+       devc->mqflags = 0;
+       switch (meas_unit) {
+       case 1:
+               devc->mq = SR_MQ_VOLTAGE;
+               devc->unit = SR_UNIT_VOLT;
+               if (meas_char == 1)
+                       devc->mqflags |= SR_MQFLAG_DC;
+               else if (meas_char == 2)
+                       devc->mqflags |= SR_MQFLAG_AC;
+               else if (meas_char == 3)
+                       devc->mqflags |= SR_MQFLAG_DC | SR_MQFLAG_AC;
+               else if (meas_char == 15)
+                       devc->mqflags |= SR_MQFLAG_DIODE;
+               break;
+       case 2:
+               devc->mq = SR_MQ_CURRENT;
+               devc->unit = SR_UNIT_AMPERE;
+               if (meas_char == 1)
+                       devc->mqflags |= SR_MQFLAG_DC;
+               else if (meas_char == 2)
+                       devc->mqflags |= SR_MQFLAG_AC;
+               else if (meas_char == 3)
+                       devc->mqflags |= SR_MQFLAG_DC | SR_MQFLAG_AC;
+               break;
+       case 3:
+               if (meas_char == 1) {
+                       devc->mq = SR_MQ_RESISTANCE;
+                       devc->unit = SR_UNIT_OHM;
+               } else if (meas_char == 16) {
+                       devc->mq = SR_MQ_CONTINUITY;
+                       devc->unit = SR_UNIT_BOOLEAN;
+               }
+               break;
+       case 12:
+               devc->mq = SR_MQ_TEMPERATURE;
+               devc->unit = SR_UNIT_CELSIUS;
+               break;
+       case 13:
+               devc->mq = SR_MQ_TEMPERATURE;
+               devc->unit = SR_UNIT_FAHRENHEIT;
+               break;
+       default:
+               sr_dbg("unknown unit: %d", meas_unit);
+       }
+       if (devc->mq == -1 && devc->unit == -1)
+               return;
+
+       /* If we got here, we know how to interpret the measurement. */
+       devc->meas_type = meas_type;
+       if (meas_type == 11)
+               /* Absolute meter reading. */
+               devc->is_relative = FALSE;
+       else if (!strcmp(tokens[0], "19"))
+               /* Relative meter reading. */
+               devc->is_relative = TRUE;
+
+}
+
+static void handle_qm_19x_data(const struct sr_dev_inst *sdi, char **tokens)
+{
+       struct dev_context *devc;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_analog analog;
+       float fvalue;
+
+       if (!strcmp(tokens[0], "9.9E+37")) {
+               /* An invalid measurement shows up on the display as "OL", but
+                * comes through like this. Since comparing 38-digit floats
+                * is rather problematic, we'll cut through this here. */
+               fvalue = NAN;
+       } else {
+               if (sr_atof_ascii(tokens[0], &fvalue) != SR_OK || fvalue == 0.0) {
+                       sr_err("Invalid float '%s'.", tokens[0]);
+                       return;
+               }
+       }
+
+       devc = sdi->priv;
+       if (devc->mq == -1 || devc->unit == -1)
+               /* Don't have valid metadata yet. */
+               return;
+
+
+       if (devc->mq == SR_MQ_RESISTANCE && isnan(fvalue))
+               fvalue = INFINITY;
+       else if (devc->mq == SR_MQ_CONTINUITY) {
+               if (isnan(fvalue))
+                       fvalue = 0.0;
+               else
+                       fvalue = 1.0;
+       }
+
+       analog.channels = sdi->channels;
+       analog.num_samples = 1;
+       analog.data = &fvalue;
+       analog.mq = devc->mq;
+       analog.unit = devc->unit;
+       analog.mqflags = 0;
+       packet.type = SR_DF_ANALOG;
+       packet.payload = &analog;
+       sr_session_send(devc->cb_data, &packet);
+       devc->num_samples++;
+
+}
+
+static void handle_line(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_analog *analog;
+       int num_tokens, n, i;
+       char cmd[16], **tokens;
+
+       devc = sdi->priv;
+       serial = sdi->conn;
+       sr_spew("Received line '%s' (%d).", devc->buf, devc->buflen);
+
+       if (devc->buflen == 1) {
+               if (devc->buf[0] != '0') {
+                       /* Not just a CMD_ACK from the query command. */
+                       sr_dbg("Got CMD_ACK '%c'.", devc->buf[0]);
+                       devc->expect_response = FALSE;
+               }
+               devc->buflen = 0;
+               return;
+       }
+
+       analog = NULL;
+       tokens = g_strsplit(devc->buf, ",", 0);
+       if (tokens[0]) {
+               if (devc->profile->model == FLUKE_187 || devc->profile->model == FLUKE_189) {
+                       devc->expect_response = FALSE;
+                       analog = handle_qm_18x(sdi, tokens);
+               } else if (devc->profile->model == FLUKE_287) {
+                       devc->expect_response = FALSE;
+                       analog = handle_qm_28x(sdi, tokens);
+               } else if (devc->profile->model == FLUKE_190) {
+                       devc->expect_response = FALSE;
+                       for (num_tokens = 0; tokens[num_tokens]; num_tokens++);
+                       if (num_tokens >= 7) {
+                               /* Response to QM: this is a comma-separated list of
+                                * fields with metadata about the measurement. This
+                                * format can return multiple sets of metadata,
+                                * split into sets of 7 tokens each. */
+                               devc->meas_type = 0;
+                               for (i = 0; i < num_tokens; i += 7)
+                                       handle_qm_19x_meta(sdi, tokens + i);
+                               if (devc->meas_type) {
+                                       /* Slip the request in now, before the main
+                                        * timer loop asks for metadata again. */
+                                       n = sprintf(cmd, "QM %d\r", devc->meas_type);
+                                       if (serial_write(serial, cmd, n) == -1)
+                                               sr_err("Unable to send QM (measurement): %s.",
+                                                               strerror(errno));
+                               }
+                       } else {
+                               /* Response to QM <n> measurement request. */
+                               handle_qm_19x_data(sdi, tokens);
+                       }
+               }
+       }
+       g_strfreev(tokens);
+       devc->buflen = 0;
+
+       if (analog) {
+               /* Got a measurement. */
+               packet.type = SR_DF_ANALOG;
+               packet.payload = analog;
+               sr_session_send(devc->cb_data, &packet);
+               devc->num_samples++;
+               g_free(analog->data);
+               g_free(analog);
+       }
+
+}
+
+SR_PRIV int fluke_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 len;
+       int64_t now, elapsed;
+
+       (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. */
+               while(FLUKEDMM_BUFSIZE - devc->buflen - 1 > 0) {
+                       len = serial_read(serial, devc->buf + devc->buflen, 1);
+                       if (len < 1)
+                               break;
+                       devc->buflen++;
+                       *(devc->buf + devc->buflen) = '\0';
+                       if (*(devc->buf + devc->buflen - 1) == '\r') {
+                               *(devc->buf + --devc->buflen) = '\0';
+                               handle_line(sdi);
+                               break;
+                       }
+               }
+       }
+
+       if (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
+               sdi->driver->dev_acquisition_stop(sdi, cb_data);
+               return TRUE;
+       }
+
+       now = g_get_monotonic_time() / 1000;
+       elapsed = now - devc->cmd_sent_at;
+       /* Send query command at poll_period interval, or after 1 second
+        * has elapsed. This will make it easier to recover from any
+        * out-of-sync or temporary disconnect issues. */
+       if ((devc->expect_response == FALSE && elapsed > devc->profile->poll_period)
+                       || elapsed > devc->profile->timeout) {
+               if (serial_write(serial, "QM\r", 3) == -1)
+                       sr_err("Unable to send QM: %s.", strerror(errno));
+               devc->cmd_sent_at = now;
+               devc->expect_response = TRUE;
+       }
+
+       return TRUE;
+}
diff --git a/src/hardware/fx2lafw/api.c b/src/hardware/fx2lafw/api.c
new file mode 100644 (file)
index 0000000..3242afc
--- /dev/null
@@ -0,0 +1,618 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
+ * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "protocol.h"
+
+static const struct fx2lafw_profile supported_fx2[] = {
+       /*
+        * CWAV USBee AX
+        * EE Electronics ESLA201A
+        * ARMFLY AX-Pro
+        */
+       { 0x08a9, 0x0014, "CWAV", "USBee AX", NULL,
+               FIRMWARE_DIR "/fx2lafw-cwav-usbeeax.fw",
+               0, NULL, NULL},
+       /*
+        * CWAV USBee DX
+        * XZL-Studio DX
+        */
+       { 0x08a9, 0x0015, "CWAV", "USBee DX", NULL,
+               FIRMWARE_DIR "/fx2lafw-cwav-usbeedx.fw",
+               DEV_CAPS_16BIT, NULL, NULL },
+
+       /*
+        * CWAV USBee SX
+        */
+       { 0x08a9, 0x0009, "CWAV", "USBee SX", NULL,
+               FIRMWARE_DIR "/fx2lafw-cwav-usbeesx.fw",
+               0, NULL, NULL},
+
+       /*
+        * Saleae Logic
+        * EE Electronics ESLA100
+        * Robomotic MiniLogic
+        * Robomotic BugLogic 3
+        */
+       { 0x0925, 0x3881, "Saleae", "Logic", NULL,
+               FIRMWARE_DIR "/fx2lafw-saleae-logic.fw",
+               0, NULL, NULL},
+
+       /*
+        * Default Cypress FX2 without EEPROM, e.g.:
+        * Lcsoft Mini Board
+        * Braintechnology USB Interface V2.x
+        */
+       { 0x04B4, 0x8613, "Cypress", "FX2", NULL,
+               FIRMWARE_DIR "/fx2lafw-cypress-fx2.fw",
+               DEV_CAPS_16BIT, NULL, NULL },
+
+       /*
+        * Braintechnology USB-LPS
+        */
+       { 0x16d0, 0x0498, "Braintechnology", "USB-LPS", NULL,
+               FIRMWARE_DIR "/fx2lafw-braintechnology-usb-lps.fw",
+               DEV_CAPS_16BIT, NULL, NULL },
+
+       { 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+};
+
+static const int32_t hwopts[] = {
+       SR_CONF_CONN,
+};
+
+static const int32_t hwcaps[] = {
+       SR_CONF_LOGIC_ANALYZER,
+       SR_CONF_TRIGGER_MATCH,
+       SR_CONF_SAMPLERATE,
+
+       /* These are really implemented in the driver, not the hardware. */
+       SR_CONF_LIMIT_SAMPLES,
+       SR_CONF_CONTINUOUS,
+};
+
+static const char *channel_names[] = {
+       "0",  "1",  "2",  "3",  "4",  "5",  "6",  "7",
+       "8",  "9", "10", "11", "12", "13", "14", "15",
+       NULL,
+};
+
+static const int32_t soft_trigger_matches[] = {
+       SR_TRIGGER_ZERO,
+       SR_TRIGGER_ONE,
+       SR_TRIGGER_RISING,
+       SR_TRIGGER_FALLING,
+       SR_TRIGGER_EDGE,
+};
+
+static const uint64_t samplerates[] = {
+       SR_KHZ(20),
+       SR_KHZ(25),
+       SR_KHZ(50),
+       SR_KHZ(100),
+       SR_KHZ(200),
+       SR_KHZ(250),
+       SR_KHZ(500),
+       SR_MHZ(1),
+       SR_MHZ(2),
+       SR_MHZ(3),
+       SR_MHZ(4),
+       SR_MHZ(6),
+       SR_MHZ(8),
+       SR_MHZ(12),
+       SR_MHZ(16),
+       SR_MHZ(24),
+};
+
+SR_PRIV struct sr_dev_driver fx2lafw_driver_info;
+static struct sr_dev_driver *di = &fx2lafw_driver_info;
+
+static int init(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       struct sr_dev_inst *sdi;
+       struct sr_usb_dev_inst *usb;
+       struct sr_channel *ch;
+       struct sr_config *src;
+       const struct fx2lafw_profile *prof;
+       GSList *l, *devices, *conn_devices;
+       struct libusb_device_descriptor des;
+       libusb_device **devlist;
+       struct libusb_device_handle *hdl;
+       int devcnt, num_logic_channels, ret, i, j;
+       const char *conn;
+       char manufacturer[64], product[64];
+
+       drvc = di->priv;
+
+       conn = NULL;
+       for (l = options; l; l = l->next) {
+               src = l->data;
+               switch (src->key) {
+               case SR_CONF_CONN:
+                       conn = g_variant_get_string(src->data, NULL);
+                       break;
+               }
+       }
+       if (conn)
+               conn_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn);
+       else
+               conn_devices = NULL;
+
+       /* Find all fx2lafw compatible devices and upload firmware to them. */
+       devices = NULL;
+       libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
+       for (i = 0; devlist[i]; i++) {
+               if (conn) {
+                       usb = NULL;
+                       for (l = conn_devices; l; l = l->next) {
+                               usb = l->data;
+                               if (usb->bus == libusb_get_bus_number(devlist[i])
+                                       && usb->address == libusb_get_device_address(devlist[i]))
+                                       break;
+                       }
+                       if (!l)
+                               /* This device matched none of the ones that
+                                * matched the conn specification. */
+                               continue;
+               }
+
+               if ((ret = libusb_get_device_descriptor( devlist[i], &des)) != 0) {
+                       sr_warn("Failed to get device descriptor: %s.",
+                               libusb_error_name(ret));
+                       continue;
+               }
+
+               if ((ret = libusb_open(devlist[i], &hdl)) < 0)
+                       continue;
+
+               if (des.iManufacturer == 0) {
+                       manufacturer[0] = '\0';
+               } else if ((ret = libusb_get_string_descriptor_ascii(hdl,
+                               des.iManufacturer, (unsigned char *) manufacturer,
+                               sizeof(manufacturer))) < 0) {
+                       sr_warn("Failed to get manufacturer string descriptor: %s.",
+                               libusb_error_name(ret));
+                       continue;
+               }
+
+               if (des.iProduct == 0) {
+                       product[0] = '\0';
+               } else if ((ret = libusb_get_string_descriptor_ascii(hdl,
+                               des.iProduct, (unsigned char *) product,
+                               sizeof(product))) < 0) {
+                       sr_warn("Failed to get product string descriptor: %s.",
+                               libusb_error_name(ret));
+                       continue;
+               }
+
+               libusb_close(hdl);
+
+               prof = NULL;
+               for (j = 0; supported_fx2[j].vid; j++) {
+                       if (des.idVendor == supported_fx2[j].vid &&
+                                       des.idProduct == supported_fx2[j].pid &&
+                                       (!supported_fx2[j].usb_manufacturer ||
+                                        !strcmp(manufacturer, supported_fx2[j].usb_manufacturer)) &&
+                                       (!supported_fx2[j].usb_manufacturer ||
+                                        !strcmp(product, supported_fx2[j].usb_product))) {
+                               prof = &supported_fx2[j];
+                               break;
+                       }
+               }
+
+               /* Skip if the device was not found. */
+               if (!prof)
+                       continue;
+
+               devcnt = g_slist_length(drvc->instances);
+               sdi = sr_dev_inst_new(devcnt, SR_ST_INITIALIZING,
+                       prof->vendor, prof->model, prof->model_version);
+               if (!sdi)
+                       return NULL;
+               sdi->driver = di;
+
+               /* Fill in channellist according to this device's profile. */
+               num_logic_channels = prof->dev_caps & DEV_CAPS_16BIT ? 16 : 8;
+               for (j = 0; j < num_logic_channels; j++) {
+                       if (!(ch = sr_channel_new(j, SR_CHANNEL_LOGIC, TRUE,
+                                       channel_names[j])))
+                               return NULL;
+                       sdi->channels = g_slist_append(sdi->channels, ch);
+               }
+
+               devc = fx2lafw_dev_new();
+               devc->profile = prof;
+               sdi->priv = devc;
+               drvc->instances = g_slist_append(drvc->instances, sdi);
+               devices = g_slist_append(devices, sdi);
+
+               if (fx2lafw_check_conf_profile(devlist[i])) {
+                       /* Already has the firmware, so fix the new address. */
+                       sr_dbg("Found an fx2lafw device.");
+                       sdi->status = SR_ST_INACTIVE;
+                       sdi->inst_type = SR_INST_USB;
+                       sdi->conn = sr_usb_dev_inst_new(libusb_get_bus_number(devlist[i]),
+                                       libusb_get_device_address(devlist[i]), NULL);
+               } else {
+                       if (ezusb_upload_firmware(devlist[i], USB_CONFIGURATION,
+                               prof->firmware) == SR_OK)
+                               /* Store when this device's FW was updated. */
+                               devc->fw_updated = g_get_monotonic_time();
+                       else
+                               sr_err("Firmware upload failed for "
+                                      "device %d.", devcnt);
+                       sdi->inst_type = SR_INST_USB;
+                       sdi->conn = sr_usb_dev_inst_new(libusb_get_bus_number(devlist[i]),
+                                       0xff, NULL);
+               }
+       }
+       libusb_free_device_list(devlist, 1);
+       g_slist_free_full(conn_devices, (GDestroyNotify)sr_usb_dev_inst_free);
+
+       return devices;
+}
+
+static GSList *dev_list(void)
+{
+       return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+       struct sr_usb_dev_inst *usb;
+       struct dev_context *devc;
+       int ret;
+       int64_t timediff_us, timediff_ms;
+
+       devc = sdi->priv;
+       usb = sdi->conn;
+
+       /*
+        * If the firmware was recently uploaded, wait up to MAX_RENUM_DELAY_MS
+        * milliseconds for the FX2 to renumerate.
+        */
+       ret = SR_ERR;
+       if (devc->fw_updated > 0) {
+               sr_info("Waiting for device to reset.");
+               /* Takes >= 300ms for the FX2 to be gone from the USB bus. */
+               g_usleep(300 * 1000);
+               timediff_ms = 0;
+               while (timediff_ms < MAX_RENUM_DELAY_MS) {
+                       if ((ret = fx2lafw_dev_open(sdi, di)) == SR_OK)
+                               break;
+                       g_usleep(100 * 1000);
+
+                       timediff_us = g_get_monotonic_time() - devc->fw_updated;
+                       timediff_ms = timediff_us / 1000;
+                       sr_spew("Waited %" PRIi64 "ms.", timediff_ms);
+               }
+               if (ret != SR_OK) {
+                       sr_err("Device failed to renumerate.");
+                       return SR_ERR;
+               }
+               sr_info("Device came back after %" PRIi64 "ms.", timediff_ms);
+       } else {
+               sr_info("Firmware upload was not needed.");
+               ret = fx2lafw_dev_open(sdi, di);
+       }
+
+       if (ret != SR_OK) {
+               sr_err("Unable to open device.");
+               return SR_ERR;
+       }
+
+       ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE);
+       if (ret != 0) {
+               switch (ret) {
+               case LIBUSB_ERROR_BUSY:
+                       sr_err("Unable to claim USB interface. Another "
+                              "program or driver has already claimed it.");
+                       break;
+               case LIBUSB_ERROR_NO_DEVICE:
+                       sr_err("Device has been disconnected.");
+                       break;
+               default:
+                       sr_err("Unable to claim interface: %s.",
+                              libusb_error_name(ret));
+                       break;
+               }
+
+               return SR_ERR;
+       }
+
+       if (devc->cur_samplerate == 0) {
+               /* Samplerate hasn't been set; default to the slowest one. */
+               devc->cur_samplerate = samplerates[0];
+       }
+
+       return SR_OK;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+       struct sr_usb_dev_inst *usb;
+
+       usb = sdi->conn;
+       if (usb->devhdl == NULL)
+               return SR_ERR;
+
+       sr_info("fx2lafw: Closing device %d on %d.%d interface %d.",
+               sdi->index, usb->bus, usb->address, USB_INTERFACE);
+       libusb_release_interface(usb->devhdl, USB_INTERFACE);
+       libusb_close(usb->devhdl);
+       usb->devhdl = NULL;
+       sdi->status = SR_ST_INACTIVE;
+
+       return SR_OK;
+}
+
+static int cleanup(void)
+{
+       int ret;
+       struct drv_context *drvc;
+
+       if (!(drvc = di->priv))
+               return SR_OK;
+
+       ret = std_dev_clear(di, NULL);
+
+       g_free(drvc);
+       di->priv = NULL;
+
+       return ret;
+}
+
+static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       struct sr_usb_dev_inst *usb;
+       char str[128];
+
+       (void)cg;
+
+       if (!sdi)
+               return SR_ERR_ARG;
+
+       devc = sdi->priv;
+
+       switch (id) {
+       case SR_CONF_CONN:
+               if (!sdi->conn)
+                       return SR_ERR_ARG;
+               usb = sdi->conn;
+               if (usb->address == 255)
+                       /* Device still needs to re-enumerate after firmware
+                        * upload, so we don't know its (future) address. */
+                       return SR_ERR;
+               snprintf(str, 128, "%d.%d", usb->bus, usb->address);
+               *data = g_variant_new_string(str);
+               break;
+       case SR_CONF_LIMIT_SAMPLES:
+               *data = g_variant_new_uint64(devc->limit_samples);
+               break;
+       case SR_CONF_SAMPLERATE:
+               *data = g_variant_new_uint64(devc->cur_samplerate);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       int ret;
+
+       (void)cg;
+
+       if (!sdi)
+               return SR_ERR_ARG;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR;
+
+       devc = sdi->priv;
+
+       ret = SR_OK;
+
+       switch (id)
+       {
+               case SR_CONF_SAMPLERATE:
+                       devc->cur_samplerate = g_variant_get_uint64(data);
+                       break;
+               case SR_CONF_LIMIT_SAMPLES:
+                       devc->limit_samples = g_variant_get_uint64(data);
+                       break;
+               default:
+                       ret = SR_ERR_NA;
+       }
+
+       return ret;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       GVariant *gvar;
+       GVariantBuilder gvb;
+
+       (void)sdi;
+       (void)cg;
+
+       switch (key) {
+       case SR_CONF_SCAN_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+               break;
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+               break;
+       case SR_CONF_SAMPLERATE:
+               g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
+               gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), samplerates,
+                               ARRAY_SIZE(samplerates), sizeof(uint64_t));
+               g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar);
+               *data = g_variant_builder_end(&gvb);
+               break;
+       case SR_CONF_TRIGGER_MATCH:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               soft_trigger_matches, ARRAY_SIZE(soft_trigger_matches),
+                               sizeof(int32_t));
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int receive_data(int fd, int revents, void *cb_data)
+{
+       struct timeval tv;
+       struct drv_context *drvc;
+
+       (void)fd;
+       (void)revents;
+       (void)cb_data;
+
+       drvc = di->priv;
+
+       tv.tv_sec = tv.tv_usec = 0;
+       libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
+
+       return TRUE;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct dev_context *devc;
+       struct drv_context *drvc;
+       struct sr_usb_dev_inst *usb;
+       struct sr_trigger *trigger;
+       struct libusb_transfer *transfer;
+       unsigned int i, timeout, num_transfers;
+       int ret;
+       unsigned char *buf;
+       size_t size;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       drvc = di->priv;
+       devc = sdi->priv;
+       usb = sdi->conn;
+
+       devc->cb_data = cb_data;
+       devc->sent_samples = 0;
+       devc->acq_aborted = FALSE;
+       devc->empty_transfer_count = 0;
+
+       if ((trigger = sr_session_trigger_get(sdi->session))) {
+               devc->stl = soft_trigger_logic_new(sdi, trigger);
+               devc->trigger_fired = FALSE;
+       } else
+               devc->trigger_fired = TRUE;
+
+       timeout = fx2lafw_get_timeout(devc);
+       num_transfers = fx2lafw_get_number_of_transfers(devc);
+       size = fx2lafw_get_buffer_size(devc);
+       devc->submitted_transfers = 0;
+
+       devc->transfers = g_try_malloc0(sizeof(*devc->transfers) * num_transfers);
+       if (!devc->transfers) {
+               sr_err("USB transfers malloc failed.");
+               return SR_ERR_MALLOC;
+       }
+
+       devc->num_transfers = num_transfers;
+       for (i = 0; i < num_transfers; i++) {
+               if (!(buf = g_try_malloc(size))) {
+                       sr_err("USB transfer buffer malloc failed.");
+                       return SR_ERR_MALLOC;
+               }
+               transfer = libusb_alloc_transfer(0);
+               libusb_fill_bulk_transfer(transfer, usb->devhdl,
+                               2 | LIBUSB_ENDPOINT_IN, buf, size,
+                               fx2lafw_receive_transfer, (void *)sdi, timeout);
+               if ((ret = libusb_submit_transfer(transfer)) != 0) {
+                       sr_err("Failed to submit transfer: %s.",
+                              libusb_error_name(ret));
+                       libusb_free_transfer(transfer);
+                       g_free(buf);
+                       fx2lafw_abort_acquisition(devc);
+                       return SR_ERR;
+               }
+               devc->transfers[i] = transfer;
+               devc->submitted_transfers++;
+       }
+
+       devc->ctx = drvc->sr_ctx;
+
+       usb_source_add(sdi->session, devc->ctx, timeout, receive_data, NULL);
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(cb_data, LOG_PREFIX);
+
+       if ((ret = fx2lafw_command_start_acquisition(sdi)) != SR_OK) {
+               fx2lafw_abort_acquisition(devc);
+               return ret;
+       }
+
+       return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       (void)cb_data;
+
+       fx2lafw_abort_acquisition(sdi->priv);
+
+       return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver fx2lafw_driver_info = {
+       .name = "fx2lafw",
+       .longname = "fx2lafw (generic driver for FX2 based LAs)",
+       .api_version = 1,
+       .init = init,
+       .cleanup = cleanup,
+       .scan = scan,
+       .dev_list = 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,
+       .priv = NULL,
+};
diff --git a/src/hardware/fx2lafw/protocol.c b/src/hardware/fx2lafw/protocol.c
new file mode 100644 (file)
index 0000000..433f907
--- /dev/null
@@ -0,0 +1,532 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
+ * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "protocol.h"
+
+/* Protocol commands */
+#define CMD_GET_FW_VERSION             0xb0
+#define CMD_START                      0xb1
+#define CMD_GET_REVID_VERSION          0xb2
+
+#define CMD_START_FLAGS_WIDE_POS       5
+#define CMD_START_FLAGS_CLK_SRC_POS    6
+
+#define CMD_START_FLAGS_SAMPLE_8BIT    (0 << CMD_START_FLAGS_WIDE_POS)
+#define CMD_START_FLAGS_SAMPLE_16BIT   (1 << CMD_START_FLAGS_WIDE_POS)
+
+#define CMD_START_FLAGS_CLK_30MHZ      (0 << CMD_START_FLAGS_CLK_SRC_POS)
+#define CMD_START_FLAGS_CLK_48MHZ      (1 << CMD_START_FLAGS_CLK_SRC_POS)
+
+#pragma pack(push, 1)
+
+struct version_info {
+       uint8_t major;
+       uint8_t minor;
+};
+
+struct cmd_start_acquisition {
+       uint8_t flags;
+       uint8_t sample_delay_h;
+       uint8_t sample_delay_l;
+};
+
+#pragma pack(pop)
+
+static int command_get_fw_version(libusb_device_handle *devhdl,
+                                 struct version_info *vi)
+{
+       int ret;
+
+       ret = libusb_control_transfer(devhdl, LIBUSB_REQUEST_TYPE_VENDOR |
+               LIBUSB_ENDPOINT_IN, CMD_GET_FW_VERSION, 0x0000, 0x0000,
+               (unsigned char *)vi, sizeof(struct version_info), 100);
+
+       if (ret < 0) {
+               sr_err("Unable to get version info: %s.",
+                      libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+       return SR_OK;
+}
+
+static int command_get_revid_version(struct sr_dev_inst *sdi, uint8_t *revid)
+{
+       struct sr_usb_dev_inst *usb = sdi->conn;
+       libusb_device_handle *devhdl = usb->devhdl;
+       int ret;
+
+       ret = libusb_control_transfer(devhdl, LIBUSB_REQUEST_TYPE_VENDOR |
+               LIBUSB_ENDPOINT_IN, CMD_GET_REVID_VERSION, 0x0000, 0x0000,
+               revid, 1, 100);
+
+       if (ret < 0) {
+               sr_err("Unable to get REVID: %s.", libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+       return SR_OK;
+}
+
+SR_PRIV int fx2lafw_command_start_acquisition(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc = sdi->priv;
+       struct sr_usb_dev_inst *usb = sdi->conn;
+       libusb_device_handle *devhdl = usb->devhdl;
+       uint64_t samplerate = devc->cur_samplerate;
+       gboolean samplewide = devc->sample_wide;
+       struct cmd_start_acquisition cmd = { 0 };
+       int delay = 0, ret;
+
+       /* Compute the sample rate. */
+       if (samplewide && samplerate > MAX_16BIT_SAMPLE_RATE) {
+               sr_err("Unable to sample at %" PRIu64 "Hz "
+                      "when collecting 16-bit samples.", samplerate);
+               return SR_ERR;
+       }
+
+       if ((SR_MHZ(48) % samplerate) == 0) {
+               cmd.flags = CMD_START_FLAGS_CLK_48MHZ;
+               delay = SR_MHZ(48) / samplerate - 1;
+               if (delay > MAX_SAMPLE_DELAY)
+                       delay = 0;
+       }
+
+       if (delay == 0 && (SR_MHZ(30) % samplerate) == 0) {
+               cmd.flags = CMD_START_FLAGS_CLK_30MHZ;
+               delay = SR_MHZ(30) / samplerate - 1;
+       }
+
+       sr_info("GPIF delay = %d, clocksource = %sMHz.", delay,
+               (cmd.flags & CMD_START_FLAGS_CLK_48MHZ) ? "48" : "30");
+
+       if (delay <= 0 || delay > MAX_SAMPLE_DELAY) {
+               sr_err("Unable to sample at %" PRIu64 "Hz.", samplerate);
+               return SR_ERR;
+       }
+
+       cmd.sample_delay_h = (delay >> 8) & 0xff;
+       cmd.sample_delay_l = delay & 0xff;
+
+       /* Select the sampling width. */
+       cmd.flags |= samplewide ? CMD_START_FLAGS_SAMPLE_16BIT :
+               CMD_START_FLAGS_SAMPLE_8BIT;
+
+       /* Send the control message. */
+       ret = libusb_control_transfer(devhdl, LIBUSB_REQUEST_TYPE_VENDOR |
+                       LIBUSB_ENDPOINT_OUT, CMD_START, 0x0000, 0x0000,
+                       (unsigned char *)&cmd, sizeof(cmd), 100);
+       if (ret < 0) {
+               sr_err("Unable to send start command: %s.",
+                      libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+       return SR_OK;
+}
+
+/**
+ * Check the USB configuration to determine if this is an fx2lafw device.
+ *
+ * @return TRUE if the device's configuration profile match fx2lafw
+ *         configuration, FALSE otherwise.
+ */
+SR_PRIV gboolean fx2lafw_check_conf_profile(libusb_device *dev)
+{
+       struct libusb_device_descriptor des;
+       struct libusb_device_handle *hdl;
+       gboolean ret;
+       unsigned char strdesc[64];
+
+       hdl = NULL;
+       ret = FALSE;
+       while (!ret) {
+               /* Assume the FW has not been loaded, unless proven wrong. */
+               if (libusb_get_device_descriptor(dev, &des) != 0)
+                       break;
+
+               if (libusb_open(dev, &hdl) != 0)
+                       break;
+
+               if (libusb_get_string_descriptor_ascii(hdl,
+                   des.iManufacturer, strdesc, sizeof(strdesc)) < 0)
+                       break;
+               if (strncmp((const char *)strdesc, "sigrok", 6))
+                       break;
+
+               if (libusb_get_string_descriptor_ascii(hdl,
+                               des.iProduct, strdesc, sizeof(strdesc)) < 0)
+                       break;
+               if (strncmp((const char *)strdesc, "fx2lafw", 7))
+                       break;
+
+               /* If we made it here, it must be an fx2lafw. */
+               ret = TRUE;
+       }
+       if (hdl)
+               libusb_close(hdl);
+
+       return ret;
+}
+
+SR_PRIV int fx2lafw_dev_open(struct sr_dev_inst *sdi, struct sr_dev_driver *di)
+{
+       libusb_device **devlist;
+       struct sr_usb_dev_inst *usb;
+       struct libusb_device_descriptor des;
+       struct dev_context *devc;
+       struct drv_context *drvc;
+       struct version_info vi;
+       int ret, skip, i, device_count;
+       uint8_t revid;
+
+       drvc = di->priv;
+       devc = sdi->priv;
+       usb = sdi->conn;
+
+       if (sdi->status == SR_ST_ACTIVE)
+               /* Device is already in use. */
+               return SR_ERR;
+
+       skip = 0;
+       device_count = libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
+       if (device_count < 0) {
+               sr_err("Failed to get device list: %s.",
+                      libusb_error_name(device_count));
+               return SR_ERR;
+       }
+
+       for (i = 0; i < device_count; i++) {
+               if ((ret = libusb_get_device_descriptor(devlist[i], &des))) {
+                       sr_err("Failed to get device descriptor: %s.",
+                              libusb_error_name(ret));
+                       continue;
+               }
+
+               if (des.idVendor != devc->profile->vid
+                   || des.idProduct != devc->profile->pid)
+                       continue;
+
+               if (sdi->status == SR_ST_INITIALIZING) {
+                       if (skip != sdi->index) {
+                               /* Skip devices of this type that aren't the one we want. */
+                               skip += 1;
+                               continue;
+                       }
+               } else if (sdi->status == SR_ST_INACTIVE) {
+                       /*
+                        * This device is fully enumerated, so we need to find
+                        * this device by vendor, product, bus and address.
+                        */
+                       if (libusb_get_bus_number(devlist[i]) != usb->bus
+                               || libusb_get_device_address(devlist[i]) != usb->address)
+                               /* This is not the one. */
+                               continue;
+               }
+
+               if (!(ret = libusb_open(devlist[i], &usb->devhdl))) {
+                       if (usb->address == 0xff)
+                               /*
+                                * First time we touch this device after FW
+                                * upload, so we don't know the address yet.
+                                */
+                               usb->address = libusb_get_device_address(devlist[i]);
+               } else {
+                       sr_err("Failed to open device: %s.",
+                              libusb_error_name(ret));
+                       break;
+               }
+
+               ret = command_get_fw_version(usb->devhdl, &vi);
+               if (ret != SR_OK) {
+                       sr_err("Failed to get firmware version.");
+                       break;
+               }
+
+               ret = command_get_revid_version(sdi, &revid);
+               if (ret != SR_OK) {
+                       sr_err("Failed to get REVID.");
+                       break;
+               }
+
+               /*
+                * Changes in major version mean incompatible/API changes, so
+                * bail out if we encounter an incompatible version.
+                * Different minor versions are OK, they should be compatible.
+                */
+               if (vi.major != FX2LAFW_REQUIRED_VERSION_MAJOR) {
+                       sr_err("Expected firmware version %d.x, "
+                              "got %d.%d.", FX2LAFW_REQUIRED_VERSION_MAJOR,
+                              vi.major, vi.minor);
+                       break;
+               }
+
+               sdi->status = SR_ST_ACTIVE;
+               sr_info("Opened device %d on %d.%d, "
+                       "interface %d, firmware %d.%d.",
+                       sdi->index, usb->bus, usb->address,
+                       USB_INTERFACE, vi.major, vi.minor);
+
+               sr_info("Detected REVID=%d, it's a Cypress CY7C68013%s.",
+                       revid, (revid != 1) ? " (FX2)" : "A (FX2LP)");
+
+               break;
+       }
+       libusb_free_device_list(devlist, 1);
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR;
+
+       return SR_OK;
+}
+
+SR_PRIV struct dev_context *fx2lafw_dev_new(void)
+{
+       struct dev_context *devc;
+
+       if (!(devc = g_try_malloc(sizeof(struct dev_context)))) {
+               sr_err("Device context malloc failed.");
+               return NULL;
+       }
+
+       devc->profile = NULL;
+       devc->fw_updated = 0;
+       devc->cur_samplerate = 0;
+       devc->limit_samples = 0;
+       devc->sample_wide = FALSE;
+       devc->stl = NULL;
+
+       return devc;
+}
+
+SR_PRIV void fx2lafw_abort_acquisition(struct dev_context *devc)
+{
+       int i;
+
+       devc->acq_aborted = TRUE;
+
+       for (i = devc->num_transfers - 1; i >= 0; i--) {
+               if (devc->transfers[i])
+                       libusb_cancel_transfer(devc->transfers[i]);
+       }
+}
+
+static void finish_acquisition(struct sr_dev_inst *sdi)
+{
+       struct sr_datafeed_packet packet;
+       struct dev_context *devc;
+
+       devc = sdi->priv;
+
+       /* Terminate session. */
+       packet.type = SR_DF_END;
+       sr_session_send(sdi, &packet);
+
+       /* Remove fds from polling. */
+       usb_source_remove(sdi->session, devc->ctx);
+
+       devc->num_transfers = 0;
+       g_free(devc->transfers);
+
+       if (devc->stl) {
+               soft_trigger_logic_free(devc->stl);
+               devc->stl = NULL;
+       }
+}
+
+static void free_transfer(struct libusb_transfer *transfer)
+{
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       unsigned int i;
+
+       sdi = transfer->user_data;
+       devc = sdi->priv;
+
+       g_free(transfer->buffer);
+       transfer->buffer = NULL;
+       libusb_free_transfer(transfer);
+
+       for (i = 0; i < devc->num_transfers; i++) {
+               if (devc->transfers[i] == transfer) {
+                       devc->transfers[i] = NULL;
+                       break;
+               }
+       }
+
+       devc->submitted_transfers--;
+       if (devc->submitted_transfers == 0)
+               finish_acquisition(sdi);
+}
+
+static void resubmit_transfer(struct libusb_transfer *transfer)
+{
+       int ret;
+
+       if ((ret = libusb_submit_transfer(transfer)) == LIBUSB_SUCCESS)
+               return;
+
+       sr_err("%s: %s", __func__, libusb_error_name(ret));
+       free_transfer(transfer);
+
+}
+
+SR_PRIV void fx2lafw_receive_transfer(struct libusb_transfer *transfer)
+{
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       gboolean packet_has_error = FALSE;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_logic logic;
+       unsigned int num_samples;
+       int trigger_offset, cur_sample_count, unitsize;
+
+       sdi = transfer->user_data;
+       devc = sdi->priv;
+
+       /*
+        * If acquisition has already ended, just free any queued up
+        * transfer that come in.
+        */
+       if (devc->acq_aborted) {
+               free_transfer(transfer);
+               return;
+       }
+
+       sr_info("receive_transfer(): status %d received %d bytes.",
+               transfer->status, transfer->actual_length);
+
+       /* Save incoming transfer before reusing the transfer struct. */
+       unitsize = devc->sample_wide ? 2 : 1;
+       cur_sample_count = transfer->actual_length / unitsize;
+
+       switch (transfer->status) {
+       case LIBUSB_TRANSFER_NO_DEVICE:
+               fx2lafw_abort_acquisition(devc);
+               free_transfer(transfer);
+               return;
+       case LIBUSB_TRANSFER_COMPLETED:
+       case LIBUSB_TRANSFER_TIMED_OUT: /* We may have received some data though. */
+               break;
+       default:
+               packet_has_error = TRUE;
+               break;
+       }
+
+       if (transfer->actual_length == 0 || packet_has_error) {
+               devc->empty_transfer_count++;
+               if (devc->empty_transfer_count > MAX_EMPTY_TRANSFERS) {
+                       /*
+                        * The FX2 gave up. End the acquisition, the frontend
+                        * will work out that the samplecount is short.
+                        */
+                       fx2lafw_abort_acquisition(devc);
+                       free_transfer(transfer);
+               } else {
+                       resubmit_transfer(transfer);
+               }
+               return;
+       } else {
+               devc->empty_transfer_count = 0;
+       }
+
+       if (devc->trigger_fired) {
+               if (devc->sent_samples < devc->limit_samples) {
+                       /* Send the incoming transfer to the session bus. */
+                       packet.type = SR_DF_LOGIC;
+                       packet.payload = &logic;
+                       if (devc->sent_samples + cur_sample_count > devc->limit_samples)
+                               num_samples = devc->limit_samples - devc->sent_samples;
+                       else
+                               num_samples = cur_sample_count;
+                       logic.length = num_samples * unitsize;
+                       logic.unitsize = unitsize;
+                       logic.data = transfer->buffer;
+                       sr_session_send(devc->cb_data, &packet);
+                       devc->sent_samples += num_samples;
+               }
+       } else {
+               trigger_offset = soft_trigger_logic_check(devc->stl,
+                               transfer->buffer, transfer->actual_length);
+               if (trigger_offset > -1) {
+                       packet.type = SR_DF_LOGIC;
+                       packet.payload = &logic;
+                       num_samples = cur_sample_count - trigger_offset;
+                       if (devc->limit_samples &&
+                                       num_samples > devc->limit_samples - devc->sent_samples)
+                               num_samples = devc->limit_samples - devc->sent_samples;
+                       logic.length = num_samples * unitsize;
+                       logic.unitsize = unitsize;
+                       logic.data = transfer->buffer + trigger_offset * unitsize;
+                       sr_session_send(devc->cb_data, &packet);
+                       devc->sent_samples += num_samples;
+
+                       devc->trigger_fired = TRUE;
+               }
+       }
+
+       if (devc->limit_samples && devc->sent_samples >= devc->limit_samples) {
+               fx2lafw_abort_acquisition(devc);
+               free_transfer(transfer);
+       } else
+               resubmit_transfer(transfer);
+}
+
+static unsigned int to_bytes_per_ms(unsigned int samplerate)
+{
+       return samplerate / 1000;
+}
+
+SR_PRIV size_t fx2lafw_get_buffer_size(struct dev_context *devc)
+{
+       size_t s;
+
+       /*
+        * The buffer should be large enough to hold 10ms of data and
+        * a multiple of 512.
+        */
+       s = 10 * to_bytes_per_ms(devc->cur_samplerate);
+       return (s + 511) & ~511;
+}
+
+SR_PRIV unsigned int fx2lafw_get_number_of_transfers(struct dev_context *devc)
+{
+       unsigned int n;
+
+       /* Total buffer size should be able to hold about 500ms of data. */
+       n = (500 * to_bytes_per_ms(devc->cur_samplerate) /
+               fx2lafw_get_buffer_size(devc));
+
+       if (n > NUM_SIMUL_TRANSFERS)
+               return NUM_SIMUL_TRANSFERS;
+
+       return n;
+}
+
+SR_PRIV unsigned int fx2lafw_get_timeout(struct dev_context *devc)
+{
+       size_t total_size;
+       unsigned int timeout;
+
+       total_size = fx2lafw_get_buffer_size(devc) *
+                       fx2lafw_get_number_of_transfers(devc);
+       timeout = total_size / to_bytes_per_ms(devc->cur_samplerate);
+       return timeout + timeout / 4; /* Leave a headroom of 25% percent. */
+}
diff --git a/src/hardware/fx2lafw/protocol.h b/src/hardware/fx2lafw/protocol.h
new file mode 100644 (file)
index 0000000..fef0dd7
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
+ * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_FX2LAFW_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_FX2LAFW_PROTOCOL_H
+
+#include <glib.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libusb.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "fx2lafw"
+
+#define USB_INTERFACE          0
+#define USB_CONFIGURATION      1
+#define NUM_TRIGGER_STAGES     4
+
+#define MAX_RENUM_DELAY_MS     3000
+#define NUM_SIMUL_TRANSFERS    32
+#define MAX_EMPTY_TRANSFERS    (NUM_SIMUL_TRANSFERS * 2)
+
+#define FX2LAFW_REQUIRED_VERSION_MAJOR 1
+
+#define MAX_8BIT_SAMPLE_RATE   SR_MHZ(24)
+#define MAX_16BIT_SAMPLE_RATE  SR_MHZ(12)
+
+/* 6 delay states of up to 256 clock ticks */
+#define MAX_SAMPLE_DELAY       (6 * 256)
+
+#define DEV_CAPS_16BIT_POS     0
+
+#define DEV_CAPS_16BIT         (1 << DEV_CAPS_16BIT_POS)
+
+struct fx2lafw_profile {
+       uint16_t vid;
+       uint16_t pid;
+
+       const char *vendor;
+       const char *model;
+       const char *model_version;
+
+       const char *firmware;
+
+       uint32_t dev_caps;
+
+       const char *usb_manufacturer;
+       const char *usb_product;
+};
+
+struct dev_context {
+       const struct fx2lafw_profile *profile;
+       /*
+        * Since we can't keep track of an fx2lafw device after upgrading
+        * the firmware (it renumerates into a different device address
+        * after the upgrade) this is like a global lock. No device will open
+        * until a proper delay after the last device was upgraded.
+        */
+       int64_t fw_updated;
+
+       /* Device/capture settings */
+       uint64_t cur_samplerate;
+       uint64_t limit_samples;
+
+       /* Operational settings */
+       gboolean trigger_fired;
+       gboolean acq_aborted;
+       gboolean sample_wide;
+       struct soft_trigger_logic *stl;
+
+       unsigned int sent_samples;
+       int submitted_transfers;
+       int empty_transfer_count;
+
+       void *cb_data;
+       unsigned int num_transfers;
+       struct libusb_transfer **transfers;
+       struct sr_context *ctx;
+};
+
+SR_PRIV int fx2lafw_command_start_acquisition(const struct sr_dev_inst *sdi);
+SR_PRIV gboolean fx2lafw_check_conf_profile(libusb_device *dev);
+SR_PRIV int fx2lafw_dev_open(struct sr_dev_inst *sdi, struct sr_dev_driver *di);
+SR_PRIV struct dev_context *fx2lafw_dev_new(void);
+SR_PRIV void fx2lafw_abort_acquisition(struct dev_context *devc);
+SR_PRIV void fx2lafw_receive_transfer(struct libusb_transfer *transfer);
+SR_PRIV size_t fx2lafw_get_buffer_size(struct dev_context *devc);
+SR_PRIV unsigned int fx2lafw_get_number_of_transfers(struct dev_context *devc);
+SR_PRIV unsigned int fx2lafw_get_timeout(struct dev_context *devc);
+
+#endif
diff --git a/src/hardware/gmc-mh-1x-2x/api.c b/src/hardware/gmc-mh-1x-2x/api.c
new file mode 100644 (file)
index 0000000..96621bb
--- /dev/null
@@ -0,0 +1,618 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013, 2014 Matthias Heidbrink <m-sigrok@heidbrink.biz>
+ *
+ * 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
+ *  Gossen Metrawatt Metrahit 1x/2x drivers
+ *  @internal
+ */
+
+#include <string.h>
+#include "protocol.h"
+
+/* Serial communication parameters for Metrahit 1x/2x with 'RS232' adaptor */
+#define SERIALCOMM_1X_RS232 "8228/6n1/dtr=1/rts=1/flow=0" /* =8192, closer with divider */
+#define SERIALCOMM_2X_RS232 "9600/6n1/dtr=1/rts=1/flow=0"
+#define SERIALCOMM_2X "9600/8n1/dtr=1/rts=1/flow=0"
+#define VENDOR_GMC "Gossen Metrawatt"
+
+SR_PRIV struct sr_dev_driver gmc_mh_1x_2x_rs232_driver_info;
+SR_PRIV struct sr_dev_driver gmc_mh_2x_bd232_driver_info;
+
+static const int32_t hwopts[] = {
+       SR_CONF_CONN,
+       SR_CONF_SERIALCOMM,
+};
+
+/** Hardware capabilities for Metrahit 1x/2x devices in send mode. */
+static const int32_t hwcaps_sm[] = {
+       SR_CONF_MULTIMETER,
+       SR_CONF_THERMOMETER,    /**< All GMC 1x/2x multimeters seem to support this */
+       SR_CONF_LIMIT_SAMPLES,
+       SR_CONF_LIMIT_MSEC,
+       SR_CONF_CONTINUOUS,
+};
+
+/** Hardware capabilities for Metrahit 2x devices in bidirectional Mode. */
+static const int32_t hwcaps_bd[] = {
+       SR_CONF_MULTIMETER,
+       SR_CONF_THERMOMETER,    /**< All GMC 1x/2x multimeters seem to support this */
+       SR_CONF_LIMIT_SAMPLES,
+       SR_CONF_LIMIT_MSEC,
+       SR_CONF_CONTINUOUS,
+       SR_CONF_POWER_OFF,
+};
+
+
+/* TODO:
+ * - For the 29S SR_CONF_ENERGYMETER, too.
+ * - SR_CONF_PATTERN_MODE for some 2x devices
+ * - SR_CONF_DATALOG for 22M, 26M, 29S and storage adaptors.
+ * Need to implement device-specific lists.
+ */
+
+/** Init driver gmc_mh_1x_2x_rs232. */
+static int init_1x_2x_rs232(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, &gmc_mh_1x_2x_rs232_driver_info, LOG_PREFIX);
+}
+
+/** Init driver gmc_mh_2x_bd232. */
+static int init_2x_bd232(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, &gmc_mh_2x_bd232_driver_info, LOG_PREFIX);
+}
+
+/**
+ * Read single byte from serial port.
+ *
+ * @retval -1 Timeout or error.
+ * @retval other Byte.
+ */
+static int read_byte(struct sr_serial_dev_inst *serial, gint64 timeout)
+{
+       uint8_t result = 0;
+       int rc = 0;
+
+       for (;;) {
+               rc = serial_read(serial, &result, 1);
+               if (rc == 1) {
+                       sr_spew("read: 0x%02x/%d", result, result);
+                       return result;
+               }
+               if (g_get_monotonic_time() > timeout)
+                       return -1;
+               g_usleep(2000);
+       }
+}
+
+/**
+ * Try to detect GMC 1x/2x multimeter model in send mode for max. 1 second.
+ *
+ * @param serial Configured, open serial port.
+ *
+ * @retval NULL Detection failed.
+ * @retval other Model code.
+ */
+static enum model scan_model_sm(struct sr_serial_dev_inst *serial)
+{
+       int byte, bytecnt, cnt;
+       enum model model;
+       gint64 timeout_us;
+
+       model = METRAHIT_NONE;
+       timeout_us = g_get_monotonic_time() + 1 * 1000 * 1000;
+
+       /*
+        * Try to find message consisting of device code and several
+        * (at least 4) data bytes.
+        */
+       for (bytecnt = 0; bytecnt < 100; bytecnt++) {
+               byte = read_byte(serial, timeout_us);
+               if ((byte == -1) || (timeout_us < g_get_monotonic_time()))
+                       break;
+               if ((byte & MSGID_MASK) == MSGID_INF) {
+                       if (!(model = gmc_decode_model_sm(byte & MSGC_MASK)))
+                               break;
+                       /* Now expect (at least) 4 data bytes. */
+                       for (cnt = 0; cnt < 4; cnt++) {
+                               byte = read_byte(serial, timeout_us);
+                               if ((byte == -1) ||
+                                               ((byte & MSGID_MASK) != MSGID_DATA))
+                               {
+                                       model = METRAHIT_NONE;
+                                       bytecnt = 100;
+                                       break;
+                               }
+                       }
+                       break;
+               }
+       }
+
+       return model;
+}
+
+/**
+ * Scan for Metrahit 1x and Metrahit 2x in send mode using Gossen Metrawatt
+ * 'RS232' interface.
+ *
+ * The older 1x models use 8192 baud and the newer 2x 9600 baud.
+ * The DMM usually sends up to about 20 messages per second. However, depending
+ * on configuration and measurement mode the intervals can be much larger and
+ * then the detection might not work.
+ */
+static GSList *scan_1x_2x_rs232(GSList *options)
+{
+       struct sr_dev_inst *sdi;
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       struct sr_config *src;
+       struct sr_channel *ch;
+       struct sr_serial_dev_inst *serial;
+       GSList *l, *devices;
+       const char *conn, *serialcomm;
+       enum model model;
+       gboolean serialcomm_given;
+
+       devices = NULL;
+       drvc = (&gmc_mh_1x_2x_rs232_driver_info)->priv;
+       drvc->instances = NULL;
+       conn = serialcomm = NULL;
+       model = METRAHIT_NONE;
+       serialcomm_given = FALSE;
+
+       sr_spew("scan_1x_2x_rs232() called!");
+
+       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);
+                       serialcomm_given = TRUE;
+                       break;
+               }
+       }
+       if (!conn)
+               return NULL;
+       if (!serialcomm)
+               serialcomm = SERIALCOMM_2X_RS232;
+
+       if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
+               return NULL;
+
+       if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK) {
+               sr_serial_dev_inst_free(serial);
+               return NULL;
+       }
+
+       serial_flush(serial);
+
+       model = scan_model_sm(serial);
+
+       /*
+        * If detection failed and no user-supplied parameters,
+        * try second baud rate.
+        */
+       if ((model == METRAHIT_NONE) && !serialcomm_given) {
+               serialcomm = SERIALCOMM_1X_RS232;
+               g_free(serial->serialcomm);
+               serial->serialcomm = g_strdup(serialcomm);
+               if (serial_set_paramstr(serial, serialcomm) == SR_OK) {
+                       serial_flush(serial);
+                       model = scan_model_sm(serial);
+               }
+       }
+
+       if (model != METRAHIT_NONE) {
+               sr_spew("%s %s detected!", VENDOR_GMC, gmc_model_str(model));
+               if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, VENDOR_GMC,
+                               gmc_model_str(model), NULL)))
+                       return NULL;
+               if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+                       sr_err("Device context malloc failed.");
+                       return NULL;
+               }
+               devc->model = model;
+               devc->limit_samples = 0;
+               devc->limit_msec = 0;
+               devc->num_samples = 0;
+               devc->elapsed_msec = g_timer_new();
+               devc->settings_ok = FALSE;
+
+               sdi->conn = serial;
+               sdi->priv = devc;
+               sdi->driver = &gmc_mh_1x_2x_rs232_driver_info;
+               if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1")))
+                       return NULL;
+               sdi->channels = g_slist_append(sdi->channels, ch);
+               drvc->instances = g_slist_append(drvc->instances, sdi);
+               devices = g_slist_append(devices, sdi);
+       }
+
+       return devices;
+}
+
+/** Scan for Metrahit 2x in a bidirectional mode using Gossen Metrawatt 'BD 232' interface.
+ *
+ */
+static GSList *scan_2x_bd232(GSList *options)
+{
+       struct sr_dev_inst *sdi;
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       struct sr_config *src;
+       struct sr_channel *ch;
+       struct sr_serial_dev_inst *serial;
+       GSList *l, *devices;
+       const char *conn, *serialcomm;
+       int cnt, byte;
+       gint64 timeout_us;
+
+       sdi = NULL;
+       devc = NULL;
+       conn = serialcomm = NULL;
+       devices = NULL;
+
+       drvc = (&gmc_mh_2x_bd232_driver_info)->priv;
+       drvc->instances = NULL;
+
+       sr_spew("scan_2x_bd232() called!");
+
+       for (l = options; l; l = l->next) {
+               src = l->data;
+               switch (src->key) {
+               case SR_CONF_CONN:
+                       conn = g_variant_get_string(src->data, NULL);
+                       break;
+               case SR_CONF_SERIALCOMM:
+                       serialcomm = g_variant_get_string(src->data, NULL);
+                       break;
+               }
+       }
+       if (!conn)
+               return NULL;
+       if (!serialcomm)
+               serialcomm = SERIALCOMM_2X;
+
+       if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
+               return NULL;
+
+       if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
+               goto exit_err;
+
+       if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+               sr_err("Device context malloc failed.");
+               goto exit_err;
+       }
+
+       if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, VENDOR_GMC, NULL, NULL)))
+               goto exit_err;
+
+       sdi->priv = devc;
+
+       /* Send message 03 "Query multimeter version and status" */
+       sdi->conn = serial;
+       sdi->priv = devc;
+       if (req_stat14(sdi, TRUE) != SR_OK)
+               goto exit_err;
+
+       /* Wait for reply from device(s) for up to 2s. */
+       timeout_us = g_get_monotonic_time() + 2*1000*1000;
+
+       while (timeout_us > g_get_monotonic_time()) {
+               /* Receive reply (14 bytes) */
+               devc->buflen = 0;
+               for (cnt = 0; cnt < 14; cnt++) {
+                       byte = read_byte(serial, timeout_us);
+                       if (byte != -1)
+                               devc->buf[devc->buflen++] = (byte & MASK_6BITS);
+               }
+
+               if (devc->buflen != 14)
+                       continue;
+
+               devc->addr = devc->buf[0];
+               process_msg14(sdi);
+               devc->buflen = 0;
+
+               if (devc->model != METRAHIT_NONE) {
+                       sr_spew("%s %s detected!", VENDOR_GMC, gmc_model_str(devc->model));
+
+                       devc->elapsed_msec = g_timer_new();
+
+                       sdi->model = g_strdup(gmc_model_str(devc->model));
+                       sdi->version = g_strdup_printf("Firmware %d.%d", devc->fw_ver_maj, devc->fw_ver_min);
+                       sdi->conn = serial;
+                       sdi->priv = devc;
+                       sdi->driver = &gmc_mh_2x_bd232_driver_info;
+                       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1")))
+                               goto exit_err;
+                       sdi->channels = g_slist_append(sdi->channels, ch);
+                       drvc->instances = g_slist_append(drvc->instances, sdi);
+                       devices = g_slist_append(devices, sdi);
+
+                       if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+                               sr_err("Device context malloc failed.");
+                               goto exit_err;
+                       }
+
+                       if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, VENDOR_GMC, NULL, NULL)))
+                               goto exit_err;
+               }
+       };
+
+       /* Free last alloc if no device found */
+       if (devc->model == METRAHIT_NONE) {
+               g_free(devc);
+               sr_dev_inst_free(sdi);
+       }
+
+       return devices;
+
+exit_err:
+       sr_info("scan_2x_bd232(): Error!");
+
+       if (serial)
+               sr_serial_dev_inst_free(serial);
+       if (devc)
+               g_free(devc);
+       if (sdi)
+               sr_dev_inst_free(sdi);
+
+       return NULL;
+}
+
+/** Driver device list function */
+static GSList *dev_list_1x_2x_rs232(void)
+{
+       return ((struct drv_context *)(gmc_mh_1x_2x_rs232_driver_info.priv))->instances;
+}
+
+/** Driver device list function */
+static GSList *dev_list_2x_bd232(void)
+{
+       return ((struct drv_context *)(gmc_mh_2x_bd232_driver_info.priv))
+                       ->instances;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+
+       std_serial_dev_close(sdi);
+
+       sdi->status = SR_ST_INACTIVE;
+
+       /* Free dynamically allocated resources. */
+       if ((devc = sdi->priv) && devc->elapsed_msec) {
+               g_timer_destroy(devc->elapsed_msec);
+               devc->elapsed_msec = NULL;
+               devc->model = METRAHIT_NONE;
+       }
+
+       return SR_OK;
+}
+
+static int cleanup_sm_rs232(void)
+{
+       return std_dev_clear(&gmc_mh_1x_2x_rs232_driver_info, NULL);
+}
+
+static int cleanup_2x_bd232(void)
+{
+       return std_dev_clear(&gmc_mh_2x_bd232_driver_info, NULL);
+}
+
+/** Get value of configuration item */
+static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
+                     const struct sr_channel_group *cg)
+{
+       int ret;
+       struct dev_context *devc;
+
+       (void)cg;
+
+       ret = SR_OK;
+
+       if (!sdi || !(devc = sdi->priv))
+               return SR_ERR_ARG;
+
+       ret = SR_OK;
+       switch (key) {
+       case SR_CONF_LIMIT_SAMPLES:
+               *data = g_variant_new_uint64(devc->limit_samples);
+               break;
+       case SR_CONF_LIMIT_MSEC:
+               *data = g_variant_new_uint64(devc->limit_msec);
+               break;
+       case SR_CONF_POWER_OFF:
+               *data = g_variant_new_boolean(FALSE);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return ret;
+}
+
+/** Implementation of config_list, auxiliary function for common parts, */
+static int config_list_common(int 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_INT32,
+                                                 hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+/** Implementation of config_list for Metrahit 1x/2x send mode */
+static int config_list_sm(int key, GVariant **data, const struct sr_dev_inst *sdi,
+                         const struct sr_channel_group *cg)
+{
+       switch (key) {
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                                                 hwcaps_sm, ARRAY_SIZE(hwcaps_sm), sizeof(int32_t));
+               break;
+       default:
+               return config_list_common(key, data, sdi, cg);
+       }
+
+       return SR_OK;
+}
+
+/** Implementation of config_list for Metrahit 2x bidirectional mode */
+static int config_list_bd(int key, GVariant **data, const struct sr_dev_inst *sdi,
+                         const struct sr_channel_group *cg)
+{
+       switch (key) {
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                                                 hwcaps_bd, ARRAY_SIZE(hwcaps_bd), sizeof(int32_t));
+               break;
+       default:
+               return config_list_common(key, data, sdi, cg);
+       }
+
+       return SR_OK;
+}
+
+static int dev_acquisition_start_1x_2x_rs232(const struct sr_dev_inst *sdi,
+                                            void *cb_data)
+{
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+
+       if (!sdi || !cb_data || !(devc = sdi->priv))
+               return SR_ERR_BUG;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       devc->cb_data = cb_data;
+       devc->settings_ok = FALSE;
+       devc->buflen = 0;
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(cb_data, LOG_PREFIX);
+
+       /* Start timer, if required. */
+       if (devc->limit_msec)
+               g_timer_start(devc->elapsed_msec);
+
+       /* Poll every 40ms, or whenever some data comes in. */
+       serial = sdi->conn;
+       serial_source_add(sdi->session, serial, G_IO_IN, 40,
+                       gmc_mh_1x_2x_receive_data, (void *)sdi);
+
+       return SR_OK;
+}
+
+static int dev_acquisition_start_2x_bd232(const struct sr_dev_inst *sdi,
+                                         void *cb_data)
+{
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+
+       if (!sdi || !cb_data || !(devc = sdi->priv))
+               return SR_ERR_BUG;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       devc->cb_data = cb_data;
+       devc->settings_ok = FALSE;
+       devc->buflen = 0;
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(cb_data, LOG_PREFIX);
+
+       /* Start timer, if required. */
+       if (devc->limit_msec)
+               g_timer_start(devc->elapsed_msec);
+
+       /* Poll every 40ms, or whenever some data comes in. */
+       serial = sdi->conn;
+       serial_source_add(sdi->session, serial, G_IO_IN, 40,
+                       gmc_mh_2x_receive_data, (void *)sdi);
+
+       /* Send start message */
+       return req_meas14(sdi);
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct dev_context *devc;
+
+       /* Stop timer, if required. */
+       if (sdi && (devc = sdi->priv) && devc->limit_msec)
+               g_timer_stop(devc->elapsed_msec);
+
+       return std_serial_dev_acquisition_stop(sdi, cb_data, dev_close,
+                       sdi->conn, LOG_PREFIX);
+}
+
+SR_PRIV struct sr_dev_driver gmc_mh_1x_2x_rs232_driver_info = {
+       .name = "gmc-mh-1x-2x-rs232",
+       .longname = "Gossen Metrawatt Metrahit 1x/2x, RS232 interface",
+       .api_version = 1,
+       .init = init_1x_2x_rs232,
+       .cleanup = cleanup_sm_rs232,
+       .scan = scan_1x_2x_rs232,
+       .dev_list = dev_list_1x_2x_rs232,
+       .dev_clear = NULL,
+       .config_get = config_get,
+       .config_set = config_set,
+       .config_list = config_list_sm,
+       .dev_open = std_serial_dev_open,
+       .dev_close = dev_close,
+       .dev_acquisition_start = dev_acquisition_start_1x_2x_rs232,
+       .dev_acquisition_stop = dev_acquisition_stop,
+       .priv = NULL,
+};
+
+SR_PRIV struct sr_dev_driver gmc_mh_2x_bd232_driver_info = {
+       .name = "gmc-mh-2x-bd232",
+       .longname = "Gossen Metrawatt Metrahit 2x, BD232/SI232-II interface",
+       .api_version = 1,
+       .init = init_2x_bd232,
+       .cleanup = cleanup_2x_bd232,
+       .scan = scan_2x_bd232,
+       .dev_list = dev_list_2x_bd232,
+       .dev_clear = NULL,
+       .config_get = config_get,
+       .config_set = config_set,
+       .config_list = config_list_bd,
+       .dev_open = std_serial_dev_open,
+       .dev_close = dev_close,
+       .dev_acquisition_start = dev_acquisition_start_2x_bd232,
+       .dev_acquisition_stop = dev_acquisition_stop,
+       .priv = NULL,
+};
diff --git a/src/hardware/gmc-mh-1x-2x/protocol.c b/src/hardware/gmc-mh-1x-2x/protocol.c
new file mode 100644 (file)
index 0000000..dc1a683
--- /dev/null
@@ -0,0 +1,1551 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013, 2014 Matthias Heidbrink <m-sigrok@heidbrink.biz>
+ *
+ * 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
+ *  Gossen Metrawatt Metrahit 1x/2x drivers
+ *  @internal
+ */
+
+#include <math.h>
+#include <string.h>
+#include "protocol.h"
+
+/* Internal Headers */
+static guchar calc_chksum_14(guchar* dta);
+static int chk_msg14(struct sr_dev_inst *sdi);
+
+/** Set or clear flags in devc->mqflags. */
+static void setmqf(struct dev_context *devc, uint64_t flags, gboolean set)
+{
+       if (set)
+               devc->mqflags |= flags;
+       else
+               devc->mqflags &= ~flags;
+}
+
+/** Decode current type and measured value, Metrahit 12-16. */
+static void decode_ctmv_16(uint8_t ctmv, struct dev_context *devc)
+{
+       devc->mq = 0;
+       devc->unit = 0;
+       devc->mqflags = 0;
+
+       switch (ctmv) {
+       case 0x00: /* 0000 - */
+               break;
+       case 0x01: /* 0001 mV DC */
+               devc->scale1000 = -1; /* Fall through */
+       case 0x02: /* 0010 V DC */
+       case 0x03: /* 0011 V AC+DC */
+       case 0x04: /* 0100 V AC */
+               devc->mq = SR_MQ_VOLTAGE;
+               devc->unit = SR_UNIT_VOLT;
+               if (ctmv <= 0x03)
+                       devc->mqflags |= SR_MQFLAG_DC;
+               if (ctmv >= 0x03) {
+                       devc->mqflags |= SR_MQFLAG_AC;
+                       if (devc->model >= METRAHIT_16S)
+                               devc->mqflags |= SR_MQFLAG_RMS;
+               }
+               break;
+       case 0x05: /* 0101 Hz (15S/16S only) */
+       case 0x06: /* 0110 kHz (15S/16S only) */
+               devc->mq = SR_MQ_FREQUENCY;
+               devc->unit = SR_UNIT_HERTZ;
+               if (ctmv == 0x06)
+                       devc->scale1000 = 1;
+               break;
+       case 0x07: /* 0111 % (15S/16S only) */
+               devc->mq = SR_MQ_DUTY_CYCLE;
+               devc->unit = SR_UNIT_PERCENTAGE;
+               break;
+       case 0x08: /* 1000 Diode */
+               devc->mq = SR_MQ_VOLTAGE;
+               devc->unit = SR_UNIT_VOLT;
+               devc->mqflags |= SR_MQFLAG_DIODE;
+               break;
+       case 0x09: /* 1001 Ohm, Â°C */
+       case 0x0a: /* 1010 kOhm */
+       case 0x0b: /* 1011 MOhm */
+               devc->mq = SR_MQ_RESISTANCE; /* Changed to temp. later if req.*/
+               devc->unit = SR_UNIT_OHM;
+               devc->scale1000 = ctmv - 0x09;
+               break;
+       case 0x0c: /* 1100 nF (15S/16S only) */
+       case 0x0d: /* 1101 ÂµF (15S/16S only) */
+               devc->mq = SR_MQ_CAPACITANCE;
+               devc->unit = SR_UNIT_FARAD;
+               if (ctmv == 0x0c)
+                       devc->scale1000 = -3;
+               else
+                       devc->scale1000 = -2;
+               break;
+       case 0x0e: /* mA, ÂµA */
+               devc->scale1000 = -1; /* Fall through. */
+       case 0x0f: /* A */
+               devc->mq = SR_MQ_CURRENT;
+               devc->unit = SR_UNIT_AMPERE;
+               if (devc->model == METRAHIT_16S)
+                       devc->mqflags |= SR_MQFLAG_RMS;
+               /* 16I A only with clamp, RMS questionable. */
+               break;
+       }
+}
+
+/**
+ * Decode range/sign/acdc byte special chars (Metrahit 12-16).
+ *
+ * @param[in] rs Range and sign byte.
+ */
+static void decode_rs_16(uint8_t rs, struct dev_context *devc)
+{
+       sr_spew("decode_rs_16(%d) scale = %f", rs, devc->scale);
+
+       if (rs & 0x04) /* Sign */
+               devc->scale *= -1.0;
+
+       if (devc->mq == SR_MQ_CURRENT) {
+               if (rs & 0x08) /* Current is AC */
+                       devc->mqflags |= SR_MQFLAG_AC;
+               else
+                       devc->mqflags |= SR_MQFLAG_DC;
+       }
+
+       switch (rs & 0x03) {
+       case 0:
+               if (devc->mq == SR_MQ_VOLTAGE) /* V */
+                       devc->scale *= 0.1;
+               else if (devc->mq == SR_MQ_CURRENT) /* 000.0 ÂµA */
+                       devc->scale *= 0.00001;
+               else if (devc->mq == SR_MQ_RESISTANCE) {
+                       if (devc->buflen >= 10) {
+                               /* Â°C with 10 byte msg type, otherwise GOhm. */
+                               devc->mq = SR_MQ_TEMPERATURE;
+                               devc->unit = SR_UNIT_CELSIUS;
+                               devc->scale *= 0.01;
+                       } else if (devc->scale1000 == 2) {
+                               /* 16I Iso 500/1000V 3 GOhm */
+                               devc->scale *= 0.1;
+                       }
+               }
+               break;
+       case 1:
+               devc->scale *= 0.0001;
+               break;
+       case 2:
+               devc->scale *= 0.001;
+               break;
+       case 3:
+               devc->scale *= 0.01;
+               break;
+       }
+}
+
+/**
+ * Decode special chars, Metrahit 12-16.
+ *
+ * @param[in] spc Special characters 1 and 2 (s1 | (s2 << 4)).
+ */
+static void decode_spc_16(uint8_t spc, struct dev_context *devc)
+{
+       /* xxxx1xxx ON */
+       /* TODO: What does that mean? Power on? The 16I sets this. */
+       /* xxxxx1xx BEEP */
+       /* xxxxxx1x Low battery */
+       /* xxxxxxx1 FUSE */
+       /* 1xxxxxxx MIN */
+       setmqf(devc, SR_MQFLAG_MIN, spc & 0x80);
+
+       /* x1xxxxxx MAN */
+       setmqf(devc, SR_MQFLAG_AUTORANGE, !(spc & 0x40));
+
+       /* xx1xxxxx DATA */
+       setmqf(devc, SR_MQFLAG_HOLD, spc & 0x20);
+
+       /* xxx1xxxx MAX */
+       setmqf(devc, SR_MQFLAG_MAX, spc & 0x10);
+}
+
+/** Decode current type and measured value, Metrahit 18. */
+static void decode_ctmv_18(uint8_t ctmv, struct dev_context *devc)
+{
+       devc->mq = 0;
+       devc->unit = 0;
+       devc->mqflags = 0;
+
+       switch (ctmv) {
+       case 0x00: /* 0000 - */
+               break;
+       case 0x01: /* 0001 V AC */
+       case 0x02: /* 0010 V AC+DC */
+       case 0x03: /* 0011 V DC */
+               devc->mq = SR_MQ_VOLTAGE;
+               devc->unit = SR_UNIT_VOLT;
+               if (ctmv <= 0x02)
+                       devc->mqflags |= (SR_MQFLAG_AC | SR_MQFLAG_RMS);
+               if (ctmv >= 0x02)
+                       devc->mqflags |= SR_MQFLAG_DC;
+               break;
+       case 0x04: /* 0100 Ohm/Ohm with buzzer */
+               devc->mq = SR_MQ_RESISTANCE;
+               devc->unit = SR_UNIT_OHM;
+               break;
+       case 0x05: /* 0101 Diode/Diode with buzzer */
+               devc->mq = SR_MQ_VOLTAGE;
+               devc->unit = SR_UNIT_VOLT;
+               devc->mqflags |= SR_MQFLAG_DIODE;
+               break;
+       case 0x06: /* 0110 Â°C */
+               devc->mq = SR_MQ_TEMPERATURE;
+               devc->unit = SR_UNIT_CELSIUS;
+               break;
+       case 0x07: /* 0111 F */
+               devc->mq = SR_MQ_CAPACITANCE;
+               devc->unit = SR_UNIT_FARAD;
+               break;
+       case 0x08: /* 1000 mA DC */
+       case 0x09: /* 1001 A DC */
+       case 0x0a: /* 1010 mA AC+DC */
+       case 0x0b: /* 1011 A AC+DC */
+               devc->mq = SR_MQ_CURRENT;
+               devc->unit = SR_UNIT_AMPERE;
+               devc->mqflags |= SR_MQFLAG_DC;
+               if (ctmv >= 0x0a)
+                       devc->mqflags |= (SR_MQFLAG_AC | SR_MQFLAG_RMS);
+               if ((ctmv == 0x08) || (ctmv == 0x0a))
+                       devc->scale1000 = -1;
+               break;
+       case 0x0c: /* 1100 Hz */
+               devc->mq = SR_MQ_FREQUENCY;
+               devc->unit = SR_UNIT_HERTZ;
+               break;
+       case 0x0d: /* 1101 dB */
+               devc->mq = SR_MQ_VOLTAGE;
+               devc->unit = SR_UNIT_DECIBEL_VOLT;
+               devc->mqflags |= SR_MQFLAG_AC; /* dB available for AC only */
+               break;
+       case 0x0e: /* 1110 Events AC, Events AC+DC. Actually delivers just
+               * current voltage via IR, nothing more. */
+               devc->mq = SR_MQ_VOLTAGE;
+               devc->unit = SR_UNIT_VOLT;
+               devc->mqflags |= SR_MQFLAG_AC | SR_MQFLAG_DC | SR_MQFLAG_RMS;
+               break;
+       case 0x0f: /* 1111 Clock */
+               devc->mq = SR_MQ_TIME;
+               devc->unit = SR_UNIT_SECOND;
+               devc->mqflags |= SR_MQFLAG_DURATION;
+               break;
+       }
+}
+
+/**
+ * Decode range/sign/acdc byte special chars, Metrahit 18.
+ *
+ * @param[in] rs Rance/sign byte.
+ */
+static void decode_rs_18(uint8_t rs, struct dev_context *devc)
+{
+       int range;
+
+       /* Sign */
+       if (((devc->scale > 0) && (rs & 0x08)) ||
+                       ((devc->scale < 0) && !(rs & 0x08)))
+               devc->scale *= -1.0;
+
+       /* Range */
+       range = rs & 0x07;
+       switch (devc->mq) {
+       case SR_MQ_VOLTAGE:
+               if (devc->unit == SR_UNIT_DECIBEL_VOLT) {
+                       devc->scale *= pow(10.0, -2);
+                       /*
+                        * When entering relative mode, the device switches
+                        * from 10 byte to 6 byte msg format. Unfortunately
+                        * it switches back to 10 byte when the second value
+                        * is measured, so that's not sufficient to
+                        * identify relative mode.
+                        */
+               }
+               else if (devc->vmains_29S)
+                       devc->scale *= pow(10.0, range - 2);
+               else
+                       devc->scale *= pow(10.0, range - 5);
+               break;
+       case SR_MQ_CURRENT:
+               if (devc->scale1000 == -1)
+                       devc->scale *= pow(10.0, range - 5);
+               else
+                       devc->scale *= pow(10.0, range - 4);
+               break;
+       case SR_MQ_RESISTANCE:
+               devc->scale *= pow(10.0, range - 2);
+               break;
+       case SR_MQ_FREQUENCY:
+               devc->scale *= pow(10.0, range - 2);
+               break;
+       case SR_MQ_TEMPERATURE:
+               devc->scale *= pow(10.0, range - 2);
+               break;
+       case SR_MQ_CAPACITANCE:
+               devc->scale *= pow(10.0, range - 13);
+               break;
+               /* TODO: 29S Mains measurements. */
+       }
+}
+
+/**
+ * Decode special chars, Metrahit 18.
+ *
+ * @param[in] spc Special characters 1 and 2 (s1 | (s2 << 4)).
+ */
+static void decode_spc_18(uint8_t spc, struct dev_context *devc)
+{
+       /* xxxx1xxx ZERO */
+       /* xxxxx1xx BEEP */
+       /* xxxxxx1x Low battery */
+       /* xxxxxxx1 Fuse */
+
+       if (devc->mq == SR_MQ_TIME) {
+               /* xxx1xxxx Clock running: 1; stop: 0 */
+               sr_spew("Clock running: %d", spc >> 4);
+       } else {
+               /* 1xxxxxxx MAN */
+               setmqf(devc, SR_MQFLAG_AUTORANGE, !(spc & 0x80));
+
+               /* x1xxxxxx MIN */
+               setmqf(devc, SR_MQFLAG_MIN, spc & 0x40);
+
+               /* xx1xxxxx MAX */
+               setmqf(devc, SR_MQFLAG_MAX, spc & 0x20);
+
+               /* xxx1xxxx DATA */
+               setmqf(devc, SR_MQFLAG_HOLD, spc & 0x10);
+       }
+}
+
+/**
+ * Decode current type and measured value, Metrahit 2x.
+ *
+ * @param[in] ctmv Current type and measured value (v1 | (v2 << 4)).
+ */
+static void decode_ctmv_2x(uint8_t ctmv, struct dev_context *devc)
+{
+       if ((ctmv > 0x1c) || (!devc)) {
+               sr_err("decode_ctmv_2x(%d): invalid param(s)!", ctmv);
+               return;
+       }
+
+       devc->mq = 0;
+       devc->unit = 0;
+       devc->mqflags = 0;
+
+       switch (ctmv) {
+       /* 00000 unused */
+       case 0x01: /* 00001 V DC */
+       case 0x02: /* 00010 V AC+DC */
+       case 0x03: /* 00011 V AC */
+               devc->mq = SR_MQ_VOLTAGE;
+               devc->unit = SR_UNIT_VOLT;
+               if (ctmv <= 0x02)
+                       devc->mqflags |= SR_MQFLAG_DC;
+               if (ctmv >= 0x02) {
+                       devc->mqflags |= SR_MQFLAG_AC;
+                       if (devc->model >= METRAHIT_24S)
+                               devc->mqflags |= SR_MQFLAG_RMS;
+               }
+               break;
+       case 0x04: /* 00100 mA DC */
+       case 0x05: /* 00101 mA AC+DC */
+               devc->scale1000 = -1;
+       case 0x06: /* 00110 A DC */
+       case 0x07: /* 00111 A AC+DC */
+               devc->mq = SR_MQ_CURRENT;
+               devc->unit = SR_UNIT_AMPERE;
+               devc->mqflags |= SR_MQFLAG_DC;
+               if ((ctmv == 0x05) || (ctmv == 0x07)) {
+                       devc->mqflags |= SR_MQFLAG_AC;
+                       if (devc->model >= METRAHIT_24S)
+                               devc->mqflags |= SR_MQFLAG_RMS;
+               }
+               break;
+       case 0x08: /* 01000 Ohm */
+               devc->mq = SR_MQ_RESISTANCE;
+               devc->unit = SR_UNIT_OHM;
+               break;
+       case 0x09: /* 01001 F */
+               devc->mq = SR_MQ_CAPACITANCE;
+               devc->unit = SR_UNIT_FARAD;
+               devc->scale *= 0.1;
+               break;
+       case 0x0a: /* 01010 V dB */
+               devc->mq = SR_MQ_VOLTAGE;
+               devc->unit = SR_UNIT_DECIBEL_VOLT;
+               devc->mqflags |= SR_MQFLAG_AC;
+               if (devc->model >= METRAHIT_24S)
+                       devc->mqflags |= SR_MQFLAG_RMS;
+               break;
+       case 0x0b: /* 01011 Hz U ACDC */
+       case 0x0c: /* 01100 Hz U AC */
+               devc->mq = SR_MQ_FREQUENCY;
+               devc->unit = SR_UNIT_HERTZ;
+               devc->mqflags |= SR_MQFLAG_AC;
+               if (ctmv <= 0x0b)
+                       devc->mqflags |= SR_MQFLAG_DC;
+               break;
+       case 0x0d: /* 01101 W on power, mA range (29S only) */
+               devc->scale *= 0.001;
+               /* Fall through! */
+       case 0x0e: /* 01110 W on power, A range (29S only) */
+               devc->mq = SR_MQ_POWER;
+               devc->unit = SR_UNIT_WATT;
+               break;
+       case 0x0f: /* 01111 Diode */
+       case 0x10: /* 10000 Diode with buzzer (actually cont. with voltage) */
+               devc->unit = SR_UNIT_VOLT;
+               if (ctmv == 0x0f) {
+                       devc->mq = SR_MQ_VOLTAGE;
+                       devc->mqflags |= SR_MQFLAG_DIODE;
+               } else {
+                       devc->mq = SR_MQ_CONTINUITY;
+                       devc->scale *= 0.00001;
+               }
+               devc->unit = SR_UNIT_VOLT;
+               break;
+       case 0x11: /* 10001 Ohm with buzzer */
+               devc->mq = SR_MQ_CONTINUITY;
+               devc->unit = SR_UNIT_OHM;
+               devc->scale1000 = -1;
+               break;
+       case 0x12: /* 10010 Temperature */
+               devc->mq = SR_MQ_TEMPERATURE;
+               devc->unit = SR_UNIT_CELSIUS;
+               /* This can be Fahrenheit. That is detected by range=4 later. */
+               break;
+       /* 0x13 10011, 0x14 10100 unsed */
+       case 0x15: /* 10101 Press (29S only) */
+               /* TODO: What does that mean? Possibly phase shift?
+                  Then we need a unit/flag for it. */
+               devc->mq = SR_MQ_GAIN;
+               devc->unit = SR_UNIT_PERCENTAGE;
+               break;
+       case 0x16: /* 10110 Pulse W (29S only) */
+               /* TODO: Own unit and flag for this! */
+               devc->mq = SR_MQ_POWER;
+               devc->unit = SR_UNIT_WATT;
+               break;
+       case 0x17: /* 10111 TRMS V on mains (29S only) */
+               devc->mq = SR_MQ_VOLTAGE;
+               devc->unit = SR_UNIT_VOLT;
+               devc->mqflags |= (SR_MQFLAG_AC | SR_MQFLAG_RMS);
+               devc->vmains_29S = TRUE;
+               break;
+       case 0x18: /* 11000 Counter (zero crossings of a signal) */
+               devc->mq = SR_MQ_VOLTAGE;
+               devc->unit = SR_UNIT_UNITLESS;
+               break;
+       case 0x19: /* 11001 Events U ACDC */
+       case 0x1a: /* 11010 Events U AC */
+               /* TODO: No unit or flags for this yet! */
+               devc->mq = SR_MQ_VOLTAGE;
+               devc->unit = SR_UNIT_UNITLESS;
+               devc->mqflags |= SR_MQFLAG_AC;
+               if (ctmv <= 0x19)
+                       devc->mqflags |= SR_MQFLAG_DC;
+               break;
+       case 0x1b: /* 11011 pulse on mains (29S only) */
+               /* TODO: No unit or flags for this yet! */
+               devc->mq = SR_MQ_VOLTAGE;
+               devc->unit = SR_UNIT_UNITLESS;
+               devc->mqflags |= SR_MQFLAG_AC;
+               break;
+       case 0x1c: /* 11100 dropout on mains (29S only) */
+               /* TODO: No unit or flags for this yet! */
+               devc->mq = SR_MQ_VOLTAGE;
+               devc->unit = SR_UNIT_UNITLESS;
+               devc->mqflags |= SR_MQFLAG_AC;
+               break;
+       case 0x1f: /* 11111 Undocumented: 25S in stopwatch mode.
+                       The value is voltage, not time, so treat it such. */
+               devc->mq = SR_MQ_VOLTAGE;
+               devc->unit = SR_UNIT_VOLT;
+               devc->mqflags |= SR_MQFLAG_DC;
+               break;
+       case 0x20: /* 100000 Undocumented: 25S in event count mode.
+               Value is 0 anyway. */
+               devc->mq = SR_MQ_VOLTAGE;
+               devc->unit = SR_UNIT_UNITLESS;
+               break;
+       default:
+               sr_err("decode_ctmv_2x(%d, ...): Unknown ctmv!", ctmv);
+               break;
+       }
+}
+
+/**
+ * Decode range/sign/acdc byte special chars, Metrahit 2x, table TR.
+ *
+ * @param[in] rs Range/sign byte.
+ */
+static void decode_rs_2x(uint8_t rs, struct dev_context *devc)
+{
+       int range;
+
+       /* Sign */
+       if (((devc->scale > 0) && (rs & 0x08)) ||
+                       ((devc->scale < 0) && !(rs & 0x08)))
+               devc->scale *= -1.0;
+
+       /* Range */
+       range = rs & 0x07;
+       switch (devc->mq) {
+       case SR_MQ_VOLTAGE:
+               if (devc->unit == SR_UNIT_DECIBEL_VOLT)
+                       devc->scale *= pow(10.0, -3);
+               else if (devc->vmains_29S)
+                       devc->scale *= pow(10.0, range - 2);
+               else
+                       devc->scale *= pow(10.0, range - 6);
+               break;
+       case SR_MQ_CURRENT:
+               if (devc->scale1000 != -1) /* uA, mA */
+                       range += 1;/* mA and A ranges differ by 10^4, not 10^3!*/
+               devc->scale *= pow(10.0, range - 6);
+               break;
+       case SR_MQ_RESISTANCE:
+               devc->scale *= pow(10.0, range - 3);
+               break;
+       case SR_MQ_FREQUENCY:
+               devc->scale *= pow(10.0, range - 3);
+               break;
+       case SR_MQ_TEMPERATURE:
+               if (range == 4) /* Indicator for Â°F */
+                       devc->unit = SR_UNIT_FAHRENHEIT;
+               devc->scale *= pow(10.0, - 2);
+               break;
+       case SR_MQ_CAPACITANCE:
+               if (range == 7)
+                       range -= 1; /* Same value as range 6 */
+               devc->scale *= pow(10.0, range - 13);
+               break;
+       /* TODO: 29S Mains measurements. */
+       }
+}
+
+/**
+ * Decode range/sign/acdc byte special chars, Metrahit 2x, table TR 2.
+ *
+ * @param[in] rs Range/sign byte.
+ */
+static void decode_rs_2x_TR2(uint8_t rs, struct dev_context *devc)
+{
+       int range;
+
+       /* Range */
+       range = rs & 0x07;
+       switch (devc->mq) {
+       case SR_MQ_CURRENT:
+               if (devc->scale1000 == -1) /* mA */
+                       switch(range) {
+                       case 0: case 1: /* 100, 300 ÂµA */
+                               devc->scale *= pow(10.0, -6);
+                               break;
+                       case 2: case 3: /* 1, 3 mA */
+                               devc->scale *= pow(10.0, -5);
+                               break;
+                       case 4: case 5: /* 10, 30 mA */
+                               devc->scale *= pow(10.0, -4);
+                               break;
+                       case 6: case 7: /* 100, 300 mA */
+                               devc->scale *= pow(10.0, -3);
+                               break;
+                       }
+               else /* A */
+                       switch(range) {
+                       case 0: case 1: /* 1, 3 A */
+                               devc->scale *= pow(10.0, -5);
+                               break;
+                       case 2: /* 10 A */
+                               devc->scale *= pow(10.0, -4);
+                               break;
+                       }
+               break;
+       default:
+               decode_rs_2x(rs, devc);
+               return;
+       }
+
+       /* Sign */
+       if (((devc->scale > 0) && (rs & 0x08)) ||
+                       ((devc->scale < 0) && !(rs & 0x08)))
+               devc->scale *= -1.0;
+}
+
+
+/**
+ * Decode special chars (Metrahit 2x).
+ *
+ * @param[in] spc Special characters 1 and 2 (s1 | (s2 << 4)).
+ */
+static void decode_spc_2x(uint8_t spc, struct dev_context *devc)
+{
+       /* xxxxxxx1 Fuse */
+
+       /* xxxxxx1x Low battery */
+
+       /* xxxxx1xx BEEP */
+
+       /* xxxx1xxx ZERO */
+
+       /* xxx1xxxx DATA */
+       setmqf(devc, SR_MQFLAG_HOLD, spc & 0x10);
+
+       /* x11xxxxx unused */
+       /* 1xxxxxxx MAN */
+       setmqf(devc, SR_MQFLAG_AUTORANGE, !(spc & 0x80));
+}
+
+/** Clean range and sign. */
+static void clean_rs_v(struct dev_context *devc)
+{
+       devc->value = 0.0;
+       devc->scale = 1.0;
+}
+
+/** Clean current type, measured variable, range and sign. */
+static void clean_ctmv_rs_v(struct dev_context *devc)
+{
+       devc->mq = 0;
+       devc->unit = 0;
+       devc->mqflags = 0;
+       devc->scale1000 = 0;
+       devc->vmains_29S = FALSE;
+       clean_rs_v(devc);
+}
+
+/** Send prepared value. */
+static void send_value(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_datafeed_analog analog;
+       struct sr_datafeed_packet packet;
+
+       devc = sdi->priv;
+
+       memset(&analog, 0, sizeof(analog));
+       analog.channels = sdi->channels;
+       analog.num_samples = 1;
+       analog.mq = devc->mq;
+       analog.unit = devc->unit;
+       analog.mqflags = devc->mqflags;
+       analog.data = &devc->value;
+
+       memset(&packet, 0, sizeof(packet));
+       packet.type = SR_DF_ANALOG;
+       packet.payload = &analog;
+       sr_session_send(devc->cb_data, &packet);
+
+       devc->num_samples++;
+}
+
+/** Process 6-byte data message, Metrahit 1x/2x send mode. */
+static void process_msg_dta_6(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       int cnt;
+       uint8_t dgt;
+
+       devc = sdi->priv;
+       clean_rs_v(devc);
+
+       /* Byte 0, range and sign */
+       if (devc->model <= METRAHIT_16X)
+               decode_rs_16(bc(devc->buf[0]), devc);
+       else if (devc->model < METRAHIT_2X)
+               decode_rs_18(bc(devc->buf[0]), devc);
+       else {
+               decode_rs_2x(bc(devc->buf[0]), devc);
+               devc->scale *= 10; /* Compensate for format having only 5 digits, decode_rs_2x() assumes 6. */
+       }
+
+       /* Bytes 1-5, digits (ls first). */
+       for (cnt = 0; cnt < 5; cnt++) {
+               dgt = bc(devc->buf[1 + cnt]);
+               if (dgt >= 10) {
+                       /* 10 Overload; on model <= 16X also 11 possible. */
+                       devc->value = NAN;
+                       devc->scale = 1.0;
+                       break;
+               }
+               devc->value += pow(10.0, cnt) * dgt;
+       }
+
+       sr_spew("process_msg_dta_6() value=%f scale=%f scale1000=%d",
+               devc->value, devc->scale, devc->scale1000);
+       if (devc->value != NAN)
+               devc->value *= devc->scale * pow(1000.0, devc->scale1000);
+
+       /* Create and send packet. */
+       send_value(sdi);
+}
+
+/** Process 5-byte info message, Metrahit 1x/2x. */
+static void process_msg_inf_5(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       enum model model;
+
+       devc = sdi->priv;
+
+       clean_ctmv_rs_v(devc);
+
+       /* Process byte 0 */
+       model = gmc_decode_model_sm(bc(devc->buf[0]));
+       if (model != devc->model) {
+               sr_warn("Model mismatch in data: Detected %s, now %s",
+                       gmc_model_str(devc->model), gmc_model_str(model));
+       }
+
+       /* Process bytes 1-4 */
+       if (devc->model <= METRAHIT_16X) {
+               decode_ctmv_16(bc(devc->buf[1]), devc);
+               decode_spc_16(bc(devc->buf[2]) | (bc(devc->buf[3]) << 4), devc);
+               decode_rs_16(bc(devc->buf[4]), devc);
+       } else if (devc->model <= METRAHIT_18S) {
+               decode_ctmv_18(bc(devc->buf[1]), devc);
+               decode_spc_18(bc(devc->buf[2]) | (bc(devc->buf[3]) << 4), devc);
+               decode_rs_18(bc(devc->buf[4]), devc);
+       } else { /* Must be Metrahit 2x */
+               decode_ctmv_2x(bc(devc->buf[1]), devc);
+               decode_spc_2x(bc(devc->buf[2]) | (bc(devc->buf[3]) << 4), devc);
+               decode_rs_2x(bc(devc->buf[4]), devc);
+       }
+}
+
+/** Process 10-byte info/data message, Metrahit 15+. */
+static void process_msg_inf_10(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       int cnt;
+       uint8_t dgt;
+
+       devc = sdi->priv;
+
+       process_msg_inf_5(sdi);
+
+       /* Now decode numbers */
+       for (cnt = 0; cnt < 5; cnt++) {
+               dgt = bc(devc->buf[5 + cnt]);
+               if (dgt == 11) { /* Empty digit */
+                       dgt = 0;
+               }
+               else if (dgt >= 12) { /* Overload */
+                       devc->value = NAN;
+                       devc->scale = 1.0;
+                       break;
+               }
+               devc->value += pow(10.0, cnt) * dgt;
+       }
+       sr_spew("process_msg_inf_10() value=%f scale=%f scalet=%d",
+               devc->value, devc->scale,  devc->scale1000);
+
+       if (devc->value != NAN)
+               devc->value *= devc->scale * pow(1000.0, devc->scale1000);
+
+       /* Create and send packet. */
+       send_value(sdi);
+}
+
+/** Decode send interval (Metrahit 2x only). */
+static const char *decode_send_interval(uint8_t si)
+{
+       switch (si) {
+       case 0x00:
+               return "0.05";
+       case 0x01:
+               return "0.1";
+       case 0x02:
+               return "0.2";
+       case 0x03:
+               return "0.5";
+       case 0x04:
+               return "00:01";
+       case 0x05:
+               return "00:02";
+       case 0x06:
+               return "00:05";
+       case 0x07:
+               return "00:10";
+       case 0x08:
+               return "00:20";
+       case 0x09:
+               return "00:30";
+       case 0x0a:
+               return "01:00";
+       case 0x0b:
+               return "02:00";
+       case 0x0c:
+               return "05:00";
+       case 0x0d:
+               return "10:00";
+       case 0x0e:
+               return "----";
+       case 0x0f:
+               return "data";
+       default:
+               return "Unknown value";
+       }
+}
+
+/** Process 13-byte info/data message, Metrahit 2x. */
+static void process_msg_inf_13(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       enum model model;
+       int cnt;
+       uint8_t dgt;
+
+       devc = sdi->priv;
+
+       clean_ctmv_rs_v(devc);
+
+       /* Byte 0, model. */
+       model = gmc_decode_model_sm(bc(devc->buf[0]));
+       if (model != devc->model) {
+               sr_warn("Model mismatch in data: Detected %s, now %s",
+                       gmc_model_str(devc->model), gmc_model_str(model));
+       }
+
+       /* Bytes 1-4, 11. */
+       decode_ctmv_2x(bc(devc->buf[1]) | (bc(devc->buf[11]) << 4), devc);
+       decode_spc_2x(bc(devc->buf[2]) | (bc(devc->buf[3]) << 4), devc);
+       decode_rs_2x(bc(devc->buf[4]), devc);
+
+       /* Bytes 5-10, digits (ls first). */
+       for (cnt = 0; cnt < 6; cnt++) {
+               dgt = bc(devc->buf[5 + cnt]);
+               if (dgt == 10) { /* Overload */
+                       devc->value = NAN;
+                       devc->scale = 1.0;
+                       break;
+               }
+               devc->value += pow(10.0, cnt) * dgt;
+       }
+       sr_spew("process_msg_inf_13() value=%f scale=%f scale1000=%d mq=%d "
+               "unit=%d mqflags=0x%02llx", devc->value, devc->scale,
+               devc->scale1000, devc->mq, devc->unit, devc->mqflags);
+       if (devc->value != NAN)
+               devc->value *= devc->scale * pow(1000.0, devc->scale1000);
+
+       /* Byte 12, Send Interval */
+       sr_spew("Send interval: %s", decode_send_interval(bc(devc->buf[12])));
+
+       /* Create and send packet. */
+       send_value(sdi);
+}
+
+/** Dump contents of 14-byte message.
+ *  @param buf Pointer to array of 14 data bytes.
+ *  @param[in] raw Write only data bytes, no interpretation.
+ */
+void dump_msg14(guchar* buf, gboolean raw)
+{
+       if (!buf)
+               return;
+
+       if (raw)
+               sr_spew("msg14: 0x %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]);
+       else
+               sr_spew("msg14: 0x a=%d c1=%02x c2=%02x cmd=%02x dta=%02x "
+                       "%02x %02x %02x %02x %02x %02x %02x %02x chs=%02x",
+                       buf[1] == 0x2b?buf[0] >> 2:buf[0] % 0x0f, 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]);
+}
+
+/** Calc checksum for 14 byte message type.
+ *
+ *  @param[in] dta Pointer to array of 13 data bytes.
+ *  @return Checksum.
+ */
+static guchar calc_chksum_14(guchar* dta)
+{
+       guchar cnt, chs;
+
+       for (chs = 0, cnt = 0; cnt < 13; cnt++)
+               chs += dta[cnt];
+
+       return (64 - chs) & MASK_6BITS;
+}
+
+/** Check 14-byte message, Metrahit 2x. */
+static int chk_msg14(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       int retc;
+       gboolean isreq; /* Message is request to multimeter (otherwise response) */
+       uint8_t addr;  /* Adaptor address */
+
+       retc = SR_OK;
+
+       /* Check parameters and message */
+       if (!sdi || !(devc = sdi->priv))
+               return SR_ERR_ARG;
+
+       if (devc->buflen != 14) {
+               sr_err("process_msg_14(): Msg len 14 expected!");
+               return SR_ERR_ARG;
+       }
+
+       isreq = devc->buf[1] == 0x2b;
+       if (isreq)
+               addr = devc->buf[0] >> 2;
+       else
+               addr = devc->buf[0] & 0x0f;
+
+       if ((devc->addr != addr) && !(isreq && (addr == 0))) {
+               sr_err("process_msg_14(): Address mismatch, msg for other device!");
+               retc = SR_ERR_ARG;
+       }
+
+       if (devc->buf[1] == 0) { /* Error msg from device! */
+               retc = SR_ERR_ARG;
+               switch (devc->buf[2]) {
+               case 1: /* Not used */
+                       sr_err("Device: Illegal error code!");
+                       break;
+               case 2: /* Incorrect check sum of received block */
+                       sr_err("Device: Incorrect checksum in cmd!");
+                       break;
+               case 3: /* Incorrect length of received block */
+                       sr_err("Device: Incorrect block length in cmd!");
+                       break;
+               case 4: /* Incorrect 2nd or 3rd byte */
+                       sr_err("Device: Incorrect byte 2 or 3 in cmd!");
+                       break;
+               case 5: /* Parameter out of range */
+                       sr_err("Device: Parameter out of range!");
+                       break;
+               default:
+                       sr_err("Device: Unknown error code!");
+               }
+               retc = SR_ERR_ARG;
+       }
+       else if (!isreq && ((devc->buf[1] != 0x27) || (devc->buf[2] != 0x3f))) {
+               sr_err("process_msg_14(): byte 1/2 unexpected!");
+               retc = SR_ERR_ARG;
+       }
+
+       if (calc_chksum_14(devc->buf) != devc->buf[13]) {
+               sr_err("process_msg_14(): Invalid checksum!");
+               retc = SR_ERR_ARG;
+       }
+
+       if (retc != SR_OK)
+               dump_msg14(devc->buf, TRUE);
+
+       return retc;
+}
+
+/** Check 14-byte message, Metrahit 2x. */
+SR_PRIV int process_msg14(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       int retc;
+       uint8_t addr;
+       uint8_t cnt, dgt;
+
+       if ((retc = chk_msg14(sdi)) != SR_OK)
+               return retc;
+
+       devc = sdi->priv;
+
+       clean_ctmv_rs_v(devc);
+       addr = devc->buf[0] & MASK_6BITS;
+       if (addr != devc->addr)
+               sr_info("Device address mismatch %d/%d!", addr, devc->addr);
+
+       switch (devc->buf[3]) { /* That's the command this reply is for */
+       /* 0 cannot occur, the respective message is not a 14-byte message */
+       case 1: /* Read first free and occupied address */
+               sr_spew("Cmd %d unimplemented!", devc->buf[3]);
+               break;
+       case 2: /* Clear all RAM in multimeter */
+               sr_spew("Cmd %d unimplemented!", devc->buf[3]);
+               break;
+       case 3: /* Read firmware version and status */
+               sr_spew("Cmd 3, Read firmware and status", devc->buf[3]);
+               switch (devc->cmd_idx) {
+               case 0:
+                       devc->fw_ver_maj = devc->buf[5];
+                       devc->fw_ver_min = devc->buf[4];
+                       sr_spew("Firmware version %d.%d", (int)devc->fw_ver_maj, (int)devc->fw_ver_min);
+                       sr_spew("Rotary Switch Position (1..10): %d", (int)devc->buf[6]);
+                       /** Docs say values 0..9, but that's not true */
+                       sr_spew("Measurement Function: %d ", (int)devc->buf[7]);
+                       decode_ctmv_2x(devc->buf[7], devc);
+                       sr_spew("Range: 0x%x", devc->buf[8]);
+                       decode_rs_2x_TR2(devc->buf[8] & 0x0f, devc);  /* Docs wrong, uses conversion table TR_2! */
+                       devc->autorng = (devc->buf[8] & 0x20) == 0;
+                       // TODO 9, 10: 29S special functions
+                       devc->ubatt = 0.1 * (float)devc->buf[11];
+                       devc->model = gmc_decode_model_bd(devc->buf[12]);
+                       sr_spew("Model=%s, battery voltage=%2.1f V", gmc_model_str(devc->model), (double)devc->ubatt);
+                       break;
+               case 1:
+                       sr_spew("Internal version %d.%d", (int)devc->buf[5], (int)devc->buf[4]);
+                       sr_spew("Comm mode: 0x%x", (int)devc->buf[6]);
+                       sr_spew("Block cnt%%64: %d", (int)devc->buf[7]);
+                       sr_spew("drpCi: %d  drpCh: %d", (int)devc->buf[8], (int)devc->buf[9]);
+                       // Semantics undocumented. Possibly Metrahit 29S dropouts stuff?
+                       break;
+               default:
+                       sr_spew("Cmd 3: Unknown cmd_idx=%d", devc->cmd_idx);
+                       break;
+               }
+               break;
+       case 4: /* Set real time, date, sample rate, trigger, ... */
+               sr_spew("Cmd %d unimplemented!", devc->buf[3]);
+               break;
+       case 5: /* Read real time, date, sample rate, trigger... */
+               sr_spew("Cmd %d unimplemented!", devc->buf[3]);
+               break;
+       case 6: /* Set modes or power off */
+               sr_spew("Cmd %d unimplemented!", devc->buf[3]);
+               break;
+       case 7: /* Set measurement function, range, autom/man. */
+               sr_spew("Cmd %d unimplemented!", devc->buf[3]);
+               break;
+       case 8: /* Get one measurement value */
+               sr_spew("Cmd 8, get one measurement value");
+               sr_spew("Measurement Function: %d ", (int)devc->buf[5]);
+               decode_ctmv_2x(devc->buf[5], devc);
+               if (!(devc->buf[6] & 0x10)) /* If bit4=0, old data. */
+                       return SR_OK;
+
+               decode_rs_2x_TR2(devc->buf[6] & 0x0f, devc); // The docs say conversion table TR_3, but that does not work
+               setmqf(devc, SR_MQFLAG_AUTORANGE, devc->autorng);
+               /* 6 digits */
+               for (cnt = 0; cnt < 6; cnt++) {
+                       dgt = bc(devc->buf[7 + cnt]);
+                       if (dgt == 10) { /* Overload */
+                               devc->value = NAN;
+                               devc->scale = 1.0;
+                               break;
+                       }
+                       else if (dgt == 13) { /* FUSE */
+                               sr_err("FUSE!");
+                       }
+                       else if (dgt == 14) { /* Function recognition mode, OPEN */
+                               sr_info("Function recognition mode, OPEN!");
+                               devc->value = NAN;
+                               devc->scale = 1.0;
+                               break;
+                       }
+                       devc->value += pow(10.0, cnt) * dgt;
+               }
+               sr_spew("process_msg14() value=%f scale=%f scale1000=%d mq=%d "
+                       "unit=%d mqflags=0x%02llx", devc->value, devc->scale,
+                       devc->scale1000, devc->mq, devc->unit, devc->mqflags);
+               if (devc->value != NAN)
+                       devc->value *= devc->scale * pow(1000.0, devc->scale1000);
+
+               send_value(sdi);
+
+               break;
+       default:
+               sr_spew("Unknown cmd %d!", devc->buf[3]);
+               break;
+       }
+
+       return SR_OK;
+}
+
+/** Data reception callback function. */
+SR_PRIV int gmc_mh_1x_2x_receive_data(int fd, int revents, void *cb_data)
+{
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+       uint8_t buf, msgt;
+       int len;
+       gdouble elapsed_s;
+
+       (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. */
+               while (GMC_BUFSIZE - devc->buflen - 1 > 0) {
+                       len = serial_read(serial, devc->buf + devc->buflen, 1);
+                       if (len < 1)
+                               break;
+                       buf = *(devc->buf + devc->buflen);
+                       sr_spew("read 0x%02x/%d/%d", buf, buf, buf & MSGC_MASK);
+                       devc->buflen += len;
+                       if (!devc->settings_ok) {
+                               /*
+                                * If no device type/settings record processed
+                                * yet, wait for one.
+                                */
+                               if ((devc->buf[0] & MSGID_MASK) != MSGID_INF) {
+                                       devc->buflen = 0;
+                                       continue;
+                               }
+                               devc->settings_ok = TRUE;
+                       }
+
+                       msgt = devc->buf[0] & MSGID_MASK;
+                       switch (msgt) {
+                       case MSGID_INF:
+                               if (devc->buflen == 13) {
+                                       process_msg_inf_13(sdi);
+                                       devc->buflen = 0;
+                                       continue;
+                               } else if ((devc->buflen == 10) &&
+                                          (devc->model <= METRAHIT_18S)) {
+                                       process_msg_inf_10(sdi);
+                                       devc->buflen = 0;
+                                       continue;
+                               }
+                               else if ((devc->buflen >= 5) &&
+                                        (devc->buf[devc->buflen - 1] &
+                                         MSGID_MASK) != MSGID_DATA) {
+                                       /*
+                                        * Char just received is beginning
+                                        * of next message.
+                                        */
+                                       process_msg_inf_5(sdi);
+                                       devc->buf[0] =
+                                                       devc->buf[devc->buflen - 1];
+                                       devc->buflen = 1;
+                                       continue;
+                               }
+                               break;
+                       case MSGID_DTA:
+                       case MSGID_D10:
+                               if (devc->buflen == 6) {
+                                       process_msg_dta_6(sdi);
+                                       devc->buflen = 0;
+                               }
+                               break;
+                       case MSGID_DATA:
+                               sr_err("Comm error, unexpected data byte!");
+                               devc->buflen = 0;
+                               break;
+                       }
+               }
+       }
+
+       /* If number of samples or time limit reached, stop acquisition. */
+       if (devc->limit_samples && (devc->num_samples >= devc->limit_samples))
+               sdi->driver->dev_acquisition_stop(sdi, cb_data);
+
+       if (devc->limit_msec) {
+               elapsed_s = g_timer_elapsed(devc->elapsed_msec, NULL);
+               if ((elapsed_s * 1000) >= devc->limit_msec)
+                       sdi->driver->dev_acquisition_stop(sdi, cb_data);
+       }
+
+       return TRUE;
+}
+
+SR_PRIV int gmc_mh_2x_receive_data(int fd, int revents, void *cb_data)
+{
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+       uint8_t buf;
+       int len;
+       gdouble elapsed_s;
+
+       (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. */
+               while (GMC_BUFSIZE - devc->buflen - 1 > 0) {
+                       len = serial_read(serial, devc->buf + devc->buflen, 1);
+                       if (len < 1)
+                               break;
+                       buf = *(devc->buf + devc->buflen);
+                       sr_spew("read 0x%02x/%d/%d", buf, buf, buf & MASK_6BITS);
+                       devc->buf[devc->buflen] &= MASK_6BITS;
+                       devc->buflen += len;
+
+                       if (devc->buflen == 14) {
+                               devc->response_pending = FALSE;
+                               sr_spew("gmc_mh_2x_receive_data processing msg");
+                               process_msg14(sdi);
+                               devc->buflen = 0;
+                       }
+               }
+       }
+
+       /* If number of samples or time limit reached, stop acquisition. */
+       if (devc->limit_samples && (devc->num_samples >= devc->limit_samples))
+               sdi->driver->dev_acquisition_stop(sdi, cb_data);
+
+       if (devc->limit_msec) {
+               elapsed_s = g_timer_elapsed(devc->elapsed_msec, NULL);
+               if ((elapsed_s * 1000) >= devc->limit_msec)
+                       sdi->driver->dev_acquisition_stop(sdi, cb_data);
+       }
+
+       /* Request next data set, if required */
+       if (sdi->status == SR_ST_ACTIVE) {
+               if (devc->response_pending) {
+                       gint64 elapsed_us = g_get_monotonic_time() - devc->req_sent_at;
+                       if (elapsed_us > 1*1000*1000) /* Timeout! */
+                               devc->response_pending = FALSE;
+               }
+               if (!devc->response_pending) {
+                       devc->cmd_seq++;
+                       if (devc->cmd_seq % 10 == 0) {
+                               if (req_stat14(sdi, FALSE) != SR_OK)
+                                       return FALSE;
+                       }
+                       else if (req_meas14(sdi) != SR_OK)
+                               return FALSE;
+               }
+       }
+
+       return TRUE;
+}
+
+/** Create 14 (42) byte command for Metrahit 2x multimeter in bidir mode.
+ *
+ *  Actually creates 42 bytes due to the encoding method used.
+ *  @param[in] addr Device address (0=adapter, 1..15 multimeter; for byte 0).
+ *  @param[in] func Function code (byte 3).
+ *  @param[in] params Further parameters (9 bytes)
+ *  @param[out] buf Buffer to create msg in (42 bytes).
+ */
+void create_cmd_14(guchar addr, guchar func, guchar* params, guchar* buf)
+{
+       uint8_t dta[14];        /* Unencoded message */
+       int cnt;
+
+       if (!params || !buf)
+               return;
+
+       /* 0: Address */
+       dta[0] = ((addr << 2) | 0x03) & MASK_6BITS;
+
+       /* 1-3: Set command header */
+       dta[1] = 0x2b;
+       dta[2] = 0x3f;
+       dta[3] = func;
+
+       /* 4-12: Copy further parameters */
+       for (cnt = 0; cnt < 9; cnt++)
+               dta[cnt+4] = (params[cnt] & MASK_6BITS);
+
+       /* 13: Checksum (b complement) */
+       dta[13] = calc_chksum_14(dta);
+
+       /* The whole message is packed into 3 bytes per byte now (lower 6 bits only) the most
+        * peculiar way I have ever seen. Possibly to improve IR communication? */
+       for (cnt = 0; cnt < 14; cnt++) {
+               buf[3*cnt] = (dta[cnt] & 0x01 ? 0x0f : 0) | (dta[cnt] & 0x02 ? 0xf0 : 0);
+               buf[3*cnt + 1] = (dta[cnt] & 0x04 ? 0x0f : 0) | (dta[cnt] & 0x08 ? 0xf0 : 0);
+               buf[3*cnt + 2] = (dta[cnt] & 0x10 ? 0x0f : 0) | (dta[cnt] & 0x20 ? 0xf0 : 0);
+       }
+}
+
+/** Request one measurement from 2x multimeter (msg 8).
+ *
+ */
+int req_meas14(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+       uint8_t params[9];
+       uint8_t msg[42];
+
+       if (!sdi || !(devc = sdi->priv) || !(serial = sdi->conn))
+               return SR_ERR;
+
+       memset(params, 0, sizeof(params));
+       params[0] = 0;
+       devc->cmd_idx = 0;
+       create_cmd_14(devc->addr, 8, params, msg);
+       devc->req_sent_at = g_get_monotonic_time();
+       if (serial_write(serial, msg, sizeof(msg)) == -1) {
+               return SR_ERR;
+       }
+
+       devc->response_pending = TRUE;
+
+       return SR_OK;
+}
+
+/** Request status from 2x multimeter (msg 3).
+ *  @param[in] power_on Try to power on powered off multimeter by sending additional messages.
+ */
+int req_stat14(const struct sr_dev_inst *sdi, gboolean power_on)
+{
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+       uint8_t params[9];
+       uint8_t msg[42];
+
+       if (!sdi || !(devc = sdi->priv) || !(serial = sdi->conn))
+               return SR_ERR;
+
+       memset(params, 0, sizeof(params));
+       params[0] = 0;
+       devc->cmd_idx = 0;
+       create_cmd_14(devc->addr, 3, params, msg);
+
+       if (power_on) {
+               sr_info("Write some data and wait 3s to turn on powered off device...");
+               if (serial_write(serial, msg, sizeof(msg)) < 0)
+                       return SR_ERR;
+               g_usleep(1*1000*1000);
+               if (serial_write(serial, msg, sizeof(msg)) < 0)
+                       return SR_ERR;
+               g_usleep(1*1000*1000);
+               if (serial_write(serial, msg, sizeof(msg)) < 0)
+                       return SR_ERR;
+               g_usleep(1*1000*1000);
+               serial_flush(serial);
+       }
+
+       /* Write message and wait for reply */
+       devc->req_sent_at = g_get_monotonic_time();
+       if (serial_write(serial, msg, sizeof(msg)) == -1) {
+               return SR_ERR;
+       }
+
+       devc->response_pending = TRUE;
+
+       return SR_OK;
+}
+
+/** Decode model in "send mode".
+ *
+ * @param[in] mcode Model code.
+ * @return Model code.
+ */
+SR_PRIV int gmc_decode_model_sm(uint8_t mcode)
+{
+       if (mcode > 0xf) {
+               sr_err("decode_model(%d): Model code 0..15 expected!", mcode);
+               return METRAHIT_NONE;
+       }
+
+       switch(mcode) {
+       case 0x04: /* 0100b */
+               return METRAHIT_12S;
+       case 0x08: /* 1000b */
+               return METRAHIT_13S14A;
+       case 0x09: /* 1001b */
+               return METRAHIT_14S;
+       case 0x0A: /* 1010b */
+               return METRAHIT_15S;
+       case 0x0B: /* 1011b */
+               return METRAHIT_16S;
+       case 0x06: /* 0110b (undocumented by GMC!) */
+               return METRAHIT_16I;
+       case 0x07: /* 0111b (undocumented by GMC!) */
+               return METRAHIT_16T;
+       case 0x0D: /* 1101b */
+               return METRAHIT_18S;
+       case 0x02: /* 0010b */
+               return METRAHIT_22SM;
+       case 0x03: /* 0011b */
+               return METRAHIT_23S;
+       case 0x0F: /* 1111b */
+               return METRAHIT_24S;
+       case 0x05: /* 0101b */
+               return METRAHIT_25S;
+       case 0x01: /* 0001b */
+               return METRAHIT_26SM;
+       case 0x0C: /* 1100b */
+               return METRAHIT_28S;
+       case 0x0E: /* 1110b */
+               return METRAHIT_29S;
+       default:
+               sr_err("Unknown model code %d!", mcode);
+               return METRAHIT_NONE;
+       }
+}
+
+/** Convert GMC model code in bidirectional mode to sigrok-internal one.
+ *
+ *  @param[in] mcode Model code.
+ *
+ *  @return Model code.
+ */
+SR_PRIV int gmc_decode_model_bd(uint8_t mcode)
+{
+       switch (mcode & 0x1f) {
+       case 2:
+               if (mcode & 0x20)
+                       return METRAHIT_22M;
+               else
+                       return METRAHIT_22S;
+       case 3:
+               return METRAHIT_23S;
+       case 4:
+               return METRAHIT_24S;
+       case 5:
+               return METRAHIT_25S;
+       case 1:
+               if (mcode & 0x20)
+                       return METRAHIT_26M;
+               else
+                       return METRAHIT_26S;
+       case 12:
+               return METRAHIT_28S;
+       case 14:
+               return METRAHIT_29S;
+       default:
+               sr_err("Unknown model code %d!", mcode);
+               return METRAHIT_NONE;
+       }
+}
+
+/** Convert sigrok-internal model code to string.
+ *
+ *  @param[in] mcode Model code.
+ *
+ *  @return Model code string.
+ */
+SR_PRIV const char *gmc_model_str(enum model mcode)
+{
+       switch (mcode) {
+       case METRAHIT_NONE:
+               return "-uninitialized model variable-";
+       case METRAHIT_12S:
+               return "METRAHit 12S";
+       case METRAHIT_13S14A:
+               return "METRAHit 13S/14A";
+       case METRAHIT_14S:
+               return "METRAHit 14S";
+       case METRAHIT_15S:
+               return "METRAHit 15S";
+       case METRAHIT_16S:
+               return "METRAHit 16S";
+       case METRAHIT_16I:
+               return "METRAHit 16I/16L";
+       case METRAHIT_16T:
+               return "METRAHit 16T/16U/KMM2002";
+       case METRAHIT_18S:
+               return "METRAHit 18S";
+       case METRAHIT_22SM:
+               return "METRAHit 22S/M";
+       case METRAHIT_22S:
+               return "METRAHit 22S";
+       case METRAHIT_22M:
+               return "METRAHit 22M";
+       case METRAHIT_23S:
+               return "METRAHit 23S";
+       case METRAHIT_24S:
+               return "METRAHit 24S";
+       case METRAHIT_25S:
+               return "METRAHit 25S";
+       case METRAHIT_26SM:
+               return "METRAHit 26S/M";
+       case METRAHIT_26S:
+               return "METRAHit 26S";
+       case METRAHIT_26M:
+               return "METRAHit 26M";
+       case METRAHIT_28S:
+               return "METRAHit 28S";
+       case METRAHIT_29S:
+               return "METRAHit 29S";
+       default:
+               return "Unknown model code";
+       }
+}
+
+
+/** @copydoc sr_dev_driver.config_set
+ */
+SR_PRIV int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
+                      const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       uint8_t params[9];
+       uint8_t msg[42];
+
+       (void)cg;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       if (!(devc = sdi->priv)) {
+               sr_err("sdi->priv was NULL.");
+               return SR_ERR_BUG;
+       }
+
+       switch (key) {
+       case SR_CONF_POWER_OFF:
+               if (devc->model < METRAHIT_2X)
+                       return SR_ERR_NA;
+               if (!g_variant_get_boolean(data))
+                       return SR_ERR;
+               sr_info("Powering device off.");
+
+               memset(params, 0, sizeof(params));
+               params[0] = 5;
+               params[1] = 5;
+               create_cmd_14(devc->addr, 6, params, msg);
+               if (serial_write(sdi->conn, msg, sizeof(msg)) == -1)
+                       return SR_ERR;
+               else
+                       g_usleep(2000000); /* Wait to ensure transfer before interface switched off. */
+               break;
+       case SR_CONF_LIMIT_MSEC:
+               if (g_variant_get_uint64(data) == 0) {
+                       sr_err("LIMIT_MSEC can't be 0.");
+                       return SR_ERR;
+               }
+               devc->limit_msec = g_variant_get_uint64(data);
+               sr_dbg("Setting time limit to %" PRIu64 "ms.",
+                       devc->limit_msec);
+               break;
+       case SR_CONF_LIMIT_SAMPLES:
+               devc->limit_samples = g_variant_get_uint64(data);
+               sr_dbg("Setting sample limit to %" PRIu64 ".",
+                       devc->limit_samples);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
diff --git a/src/hardware/gmc-mh-1x-2x/protocol.h b/src/hardware/gmc-mh-1x-2x/protocol.h
new file mode 100644 (file)
index 0000000..aa19be3
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013, 2014 Matthias Heidbrink <m-sigrok@heidbrink.biz>
+ *
+ * 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
+ *  Gossen Metrawatt Metrahit 1x/2x drivers
+ *  @internal
+ */
+
+#ifndef LIBSIGROK_HARDWARE_GMC_MH_1X_2X_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_GMC_MH_1X_2X_PROTOCOL_H
+
+#include <stdint.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "gmc-mh-1x-2x"
+
+#define GMC_BUFSIZE  266
+
+/** Message ID bits 4, 5 */
+#define MSGID_MASK  0x30 /**< Mask to get message ID bits */
+#define MSGID_INF   0x00 /**< Start of message with device info */
+#define MSGID_D10   0x10 /**< Start of data message, non-displayed intermediate */
+#define MSGID_DTA   0x20 /**< Start of data message, displayed, averaged */
+#define MSGID_DATA  0x30 /**< Data byte in message */
+
+#define MSGC_MASK   0x0f  /**< Mask to get message byte contents in send mode */
+
+#define MSGSRC_MASK 0xc0 /**< Mask to get bits related to message source */
+
+#define bc(x) (x & MSGC_MASK) /**< Get contents from a byte */
+
+#define MASK_6BITS  0x3f /**< Mask lower six bits. */
+
+/**
+ * Internal multimeter model codes. In opposite to the multimeter models from
+ * protocol (see decode_model()), these codes allow working with ranges.
+ */
+enum model {
+       METRAHIT_NONE           = 0,  /**< Value for uninitialized variable */
+       METRAHIT_12S            = 12,
+       METRAHIT_13S14A         = 13,
+       METRAHIT_14S            = 14,
+       METRAHIT_15S            = 15,
+       METRAHIT_16S            = 16,
+       METRAHIT_16I            = 17, /**< Metrahit 16I, L */
+       METRAHIT_16T            = 18, /**< Metrahit 16T, U, KMM2002 */
+       METRAHIT_16X = METRAHIT_16T,  /**< All Metrahit 16 */
+       /* A Metrahit 17 exists, but seems not to have an IR interface. */
+       METRAHIT_18S            = 19,
+       METRAHIT_2X             = 20, /**< For model type comparisons */
+       METRAHIT_22SM           = METRAHIT_2X + 1,      /**< Send mode */
+       METRAHIT_22S            = METRAHIT_22SM + 1,    /**< Bidi mode */
+       METRAHIT_22M            = METRAHIT_22S + 1,     /**< Bidi mode */
+       METRAHIT_23S            = METRAHIT_22M + 1,
+       METRAHIT_24S            = METRAHIT_23S + 1,
+       METRAHIT_25S            = METRAHIT_24S + 1,
+       METRAHIT_26SM           = METRAHIT_25S + 1,     /**< Send mode */
+       METRAHIT_26S            = METRAHIT_26SM + 1,    /**< Bidi mode */
+       METRAHIT_26M            = METRAHIT_26S + 1,     /**< Bidi mode */
+       METRAHIT_28S            = METRAHIT_26M + 1,
+       METRAHIT_29S            = METRAHIT_28S + 1,
+};
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+       /* Model-specific information */
+       enum model model;       /**< Model code. */
+
+       /* Acquisition settings */
+       uint64_t limit_samples; /**< Target number of samples */
+       uint64_t limit_msec;    /**< Target sampling time */
+
+       /* Opaque pointer passed in by frontend. */
+       void *cb_data;
+
+       /* Operational state */
+       gboolean settings_ok;   /**< Settings msg received yet. */
+       int msg_type;       /**< Message type (MSGID_INF, ...). */
+       int msg_len;        /**< Message lengh (valid when msg, curr. type known).*/
+       int mq;             /**< Measured quantity */
+       int unit;           /**< Measured unit */
+       uint64_t mqflags;       /**< Measured quantity flags */
+       float value;            /**< Measured value */
+       float scale;            /**< Scale for value. */
+       int8_t scale1000;   /**< Additional scale factor 1000x. */
+       gboolean vmains_29S;    /**< Measured ctmv is V mains (29S only). */
+       int addr;           /**< Device address (1..15). */
+       int cmd_idx;        /**< Parameter "Idx" (Index) of current command, if required. */
+       int cmd_seq;        /**< Command sequence. Used to query status every n messages. */
+       gboolean autorng;   /**< Auto range enabled. */
+       float ubatt;        /**< Battery voltage. */
+       uint8_t fw_ver_maj; /**< Firmware version major. */
+       uint8_t fw_ver_min; /**< Firmware version minor. */
+       int64_t req_sent_at;    /**< Request sent. */
+       gboolean response_pending; /**< Request sent, response is pending. */
+
+       /* Temporary state across callbacks */
+       uint64_t num_samples;   /**< Current #samples for limit_samples */
+       GTimer *elapsed_msec;   /**< Used for sampling with limit_msec  */
+       uint8_t buf[GMC_BUFSIZE];       /**< Buffer for read callback */
+       int buflen;                     /**< Data len in buf */
+};
+
+/* Forward declarations */
+SR_PRIV int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg);
+SR_PRIV void create_cmd_14(guchar addr, guchar func, guchar* params, guchar* buf);
+SR_PRIV void dump_msg14(guchar* buf, gboolean raw);
+SR_PRIV int gmc_decode_model_bd(uint8_t mcode);
+SR_PRIV int gmc_decode_model_sm(uint8_t mcode);
+SR_PRIV int gmc_mh_1x_2x_receive_data(int fd, int revents, void *cb_data);
+SR_PRIV int gmc_mh_2x_receive_data(int fd, int revents, void *cb_data);
+SR_PRIV const char *gmc_model_str(enum model mcode);
+SR_PRIV int process_msg14(struct sr_dev_inst *sdi);
+SR_PRIV int req_meas14(const struct sr_dev_inst *sdi);
+SR_PRIV int req_stat14(const struct sr_dev_inst *sdi, gboolean power_on);
+
+#endif
diff --git a/src/hardware/hameg-hmo/api.c b/src/hardware/hameg-hmo/api.c
new file mode 100644 (file)
index 0000000..ff045f1
--- /dev/null
@@ -0,0 +1,806 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * 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 <stdlib.h>
+#include "protocol.h"
+
+#define SERIALCOMM "115200/8n1/flow=1"
+
+SR_PRIV struct sr_dev_driver hameg_hmo_driver_info;
+static struct sr_dev_driver *di = &hameg_hmo_driver_info;
+
+static const char *manufacturers[] = {
+       "HAMEG",
+};
+
+static const int32_t hwopts[] = {
+       SR_CONF_CONN,
+       SR_CONF_SERIALCOMM,
+};
+
+enum {
+       CG_INVALID = -1,
+       CG_NONE,
+       CG_ANALOG,
+       CG_DIGITAL,
+};
+
+static int init(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static int check_manufacturer(const char *manufacturer)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(manufacturers); ++i)
+               if (!strcmp(manufacturer, manufacturers[i]))
+                       return SR_OK;
+
+       return SR_ERR;
+}
+
+static struct sr_dev_inst *hmo_probe_serial_device(struct sr_scpi_dev_inst *scpi)
+{
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       struct sr_scpi_hw_info *hw_info;
+
+       sdi = NULL;
+       devc = NULL;
+       hw_info = NULL;
+
+       if (sr_scpi_get_hw_id(scpi, &hw_info) != SR_OK) {
+               sr_info("Couldn't get IDN response.");
+               goto fail;
+       }
+
+       if (check_manufacturer(hw_info->manufacturer) != SR_OK)
+               goto fail;
+
+       if (!(sdi = sr_dev_inst_new(0, SR_ST_ACTIVE,
+                                   hw_info->manufacturer, hw_info->model,
+                                   hw_info->firmware_version))) {
+               goto fail;
+       }
+       sr_scpi_hw_info_free(hw_info);
+       hw_info = NULL;
+
+       if (!(devc = g_try_malloc0(sizeof(struct dev_context))))
+               goto fail;
+
+       sdi->driver = di;
+       sdi->priv = devc;
+       sdi->inst_type = SR_INST_SCPI;
+       sdi->conn = scpi;
+
+       if (hmo_init_device(sdi) != SR_OK)
+               goto fail;
+
+       sr_scpi_close(sdi->conn);
+
+       sdi->status = SR_ST_INACTIVE;
+
+       return sdi;
+
+fail:
+       if (hw_info)
+               sr_scpi_hw_info_free(hw_info);
+       if (sdi)
+               sr_dev_inst_free(sdi);
+       if (devc)
+               g_free(devc);
+
+       return NULL;
+}
+
+static GSList *scan(GSList *options)
+{
+       return sr_scpi_scan(di->priv, options, hmo_probe_serial_device);
+}
+
+static GSList *dev_list(void)
+{
+       return ((struct drv_context *)(di->priv))->instances;
+}
+
+static void clear_helper(void *priv)
+{
+       unsigned int i;
+       struct dev_context *devc;
+       struct scope_config *model;
+
+       devc = priv;
+       model = devc->model_config;
+
+       hmo_scope_state_free(devc->model_state);
+
+       for (i = 0; i < model->analog_channels; ++i)
+               g_slist_free(devc->analog_groups[i].channels);
+
+       for (i = 0; i < model->digital_pods; ++i) {
+               g_slist_free(devc->digital_groups[i].channels);
+               g_free(devc->digital_groups[i].name);
+       }
+
+       g_free(devc->analog_groups);
+       g_free(devc->digital_groups);
+
+       g_free(devc);
+}
+
+static int dev_clear(void)
+{
+       return std_dev_clear(di, clear_helper);
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+       if (sdi->status != SR_ST_ACTIVE && sr_scpi_open(sdi->conn) != SR_OK)
+               return SR_ERR;
+
+       if (hmo_scope_state_get(sdi) != SR_OK)
+               return SR_ERR;
+
+       sdi->status = SR_ST_ACTIVE;
+
+       return SR_OK;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+       if (sdi->status == SR_ST_INACTIVE)
+               return SR_OK;
+
+       sr_scpi_close(sdi->conn);
+
+       sdi->status = SR_ST_INACTIVE;
+
+       return SR_OK;
+}
+
+static int cleanup(void)
+{
+       dev_clear();
+
+       return SR_OK;
+}
+
+static int check_channel_group(struct dev_context *devc,
+                            const struct sr_channel_group *cg)
+{
+       unsigned int i;
+       struct scope_config *model;
+
+       model = devc->model_config;
+
+       if (!cg)
+               return CG_NONE;
+
+       for (i = 0; i < model->analog_channels; ++i)
+               if (cg == &devc->analog_groups[i])
+                       return CG_ANALOG;
+
+       for (i = 0; i < model->digital_pods; ++i)
+               if (cg == &devc->digital_groups[i])
+                       return CG_DIGITAL;
+
+       sr_err("Invalid channel group specified.");
+
+       return CG_INVALID;
+}
+
+static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
+                     const struct sr_channel_group *cg)
+{
+       int ret, cg_type;
+       unsigned int i;
+       struct dev_context *devc;
+       struct scope_config *model;
+       struct scope_state *state;
+
+       if (!sdi || !(devc = sdi->priv))
+               return SR_ERR_ARG;
+
+       if ((cg_type = check_channel_group(devc, cg)) == CG_INVALID)
+               return SR_ERR;
+
+       ret = SR_ERR_NA;
+       model = devc->model_config;
+       state = devc->model_state;
+
+       switch (key) {
+       case SR_CONF_NUM_TIMEBASE:
+               *data = g_variant_new_int32(model->num_xdivs);
+               ret = SR_OK;
+               break;
+       case SR_CONF_TIMEBASE:
+               *data = g_variant_new("(tt)", (*model->timebases)[state->timebase][0],
+                                     (*model->timebases)[state->timebase][1]);
+               ret = SR_OK;
+               break;
+       case SR_CONF_NUM_VDIV:
+               if (cg_type == CG_NONE) {
+                       sr_err("No channel group specified.");
+                       return SR_ERR_CHANNEL_GROUP;
+               } else if (cg_type == CG_ANALOG) {
+                       for (i = 0; i < model->analog_channels; ++i) {
+                               if (cg != &devc->analog_groups[i])
+                                       continue;
+                               *data = g_variant_new_int32(model->num_ydivs);
+                               ret = SR_OK;
+                               break;
+                       }
+
+               } else {
+                       ret = SR_ERR_NA;
+               }
+               break;
+       case SR_CONF_VDIV:
+               if (cg_type == CG_NONE) {
+                       sr_err("No channel group specified.");
+                       return SR_ERR_CHANNEL_GROUP;
+               } else if (cg_type == CG_ANALOG) {
+                       for (i = 0; i < model->analog_channels; ++i) {
+                               if (cg != &devc->analog_groups[i])
+                                       continue;
+                               *data = g_variant_new("(tt)",
+                                                     (*model->vdivs)[state->analog_channels[i].vdiv][0],
+                                                     (*model->vdivs)[state->analog_channels[i].vdiv][1]);
+                               ret = SR_OK;
+                               break;
+                       }
+
+               } else {
+                       ret = SR_ERR_NA;
+               }
+               break;
+       case SR_CONF_TRIGGER_SOURCE:
+               *data = g_variant_new_string((*model->trigger_sources)[state->trigger_source]);
+               ret = SR_OK;
+               break;
+       case SR_CONF_TRIGGER_SLOPE:
+               *data = g_variant_new_string((*model->trigger_slopes)[state->trigger_slope]);
+               ret = SR_OK;
+               break;
+       case SR_CONF_HORIZ_TRIGGERPOS:
+               *data = g_variant_new_double(state->horiz_triggerpos);
+               ret = SR_OK;
+               break;
+       case SR_CONF_COUPLING:
+               if (cg_type == CG_NONE) {
+                       sr_err("No channel group specified.");
+                       return SR_ERR_CHANNEL_GROUP;
+               } else if (cg_type == CG_ANALOG) {
+                       for (i = 0; i < model->analog_channels; ++i) {
+                               if (cg != &devc->analog_groups[i])
+                                       continue;
+                               *data = g_variant_new_string((*model->coupling_options)[state->analog_channels[i].coupling]);
+                               ret = SR_OK;
+                               break;
+                       }
+
+               } else {
+                       ret = SR_ERR_NA;
+               }
+               break;
+       case SR_CONF_SAMPLERATE:
+               *data = g_variant_new_uint64(state->sample_rate);
+               ret = SR_OK;
+               break;
+       default:
+               ret = SR_ERR_NA;
+       }
+
+       return ret;
+}
+
+static GVariant *build_tuples(const uint64_t (*array)[][2], unsigned int n)
+{
+       unsigned int i;
+       GVariant *rational[2];
+       GVariantBuilder gvb;
+
+       g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
+
+       for (i = 0; i < n; i++) {
+               rational[0] = g_variant_new_uint64((*array)[i][0]);
+               rational[1] = g_variant_new_uint64((*array)[i][1]);
+
+               /* FIXME: Valgrind reports a memory leak here. */
+               g_variant_builder_add_value(&gvb, g_variant_new_tuple(rational, 2));
+       }
+
+       return g_variant_builder_end(&gvb);
+}
+
+static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
+                     const struct sr_channel_group *cg)
+{
+       int ret, cg_type;
+       unsigned int i, j;
+       char command[MAX_COMMAND_SIZE], float_str[30];
+       struct dev_context *devc;
+       struct scope_config *model;
+       struct scope_state *state;
+       const char *tmp;
+       uint64_t p, q;
+       double tmp_d;
+       gboolean update_sample_rate;
+
+       if (!sdi || !(devc = sdi->priv))
+               return SR_ERR_ARG;
+
+       if ((cg_type = check_channel_group(devc, cg)) == CG_INVALID)
+               return SR_ERR;
+
+       model = devc->model_config;
+       state = devc->model_state;
+       update_sample_rate = FALSE;
+
+       ret = SR_ERR_NA;
+
+       switch (key) {
+       case SR_CONF_LIMIT_FRAMES:
+               devc->frame_limit = g_variant_get_uint64(data);
+               ret = SR_OK;
+               break;
+       case SR_CONF_TRIGGER_SOURCE:
+               tmp = g_variant_get_string(data, NULL);
+               for (i = 0; (*model->trigger_sources)[i]; i++) {
+                       if (g_strcmp0(tmp, (*model->trigger_sources)[i]) != 0)
+                               continue;
+                       state->trigger_source = i;
+                       g_snprintf(command, sizeof(command),
+                                  (*model->scpi_dialect)[SCPI_CMD_SET_TRIGGER_SOURCE],
+                                  (*model->trigger_sources)[i]);
+
+                       ret = sr_scpi_send(sdi->conn, command);
+                       break;
+               }
+               break;
+       case SR_CONF_VDIV:
+               if (cg_type == CG_NONE) {
+                       sr_err("No channel group specified.");
+                       return SR_ERR_CHANNEL_GROUP;
+               }
+
+               g_variant_get(data, "(tt)", &p, &q);
+
+               for (i = 0; i < model->num_vdivs; i++) {
+                       if (p != (*model->vdivs)[i][0] ||
+                           q != (*model->vdivs)[i][1])
+                               continue;
+                       for (j = 1; j <= model->analog_channels; ++j) {
+                               if (cg != &devc->analog_groups[j - 1])
+                                       continue;
+                               state->analog_channels[j - 1].vdiv = i;
+                               g_ascii_formatd(float_str, sizeof(float_str), "%E", (float) p / q);
+                               g_snprintf(command, sizeof(command),
+                                          (*model->scpi_dialect)[SCPI_CMD_SET_VERTICAL_DIV],
+                                          j, float_str);
+
+                               if (sr_scpi_send(sdi->conn, command) != SR_OK ||
+                                   sr_scpi_get_opc(sdi->conn) != SR_OK)
+                                       return SR_ERR;
+
+                               break;
+                       }
+
+                       ret = SR_OK;
+                       break;
+               }
+               break;
+       case SR_CONF_TIMEBASE:
+               g_variant_get(data, "(tt)", &p, &q);
+
+               for (i = 0; i < model->num_timebases; i++) {
+                       if (p != (*model->timebases)[i][0] ||
+                           q != (*model->timebases)[i][1])
+                               continue;
+                       state->timebase = i;
+                       g_ascii_formatd(float_str, sizeof(float_str), "%E", (float) p / q);
+                       g_snprintf(command, sizeof(command),
+                                  (*model->scpi_dialect)[SCPI_CMD_SET_TIMEBASE],
+                                  float_str);
+
+                       ret = sr_scpi_send(sdi->conn, command);
+                       update_sample_rate = TRUE;
+                       break;
+               }
+               break;
+       case SR_CONF_HORIZ_TRIGGERPOS:
+               tmp_d = g_variant_get_double(data);
+
+               if (tmp_d < 0.0 || tmp_d > 1.0)
+                       return SR_ERR;
+
+               state->horiz_triggerpos = tmp_d;
+               tmp_d = -(tmp_d - 0.5) *
+                       ((double) (*model->timebases)[state->timebase][0] /
+                       (*model->timebases)[state->timebase][1])
+                        * model->num_xdivs;
+
+               g_ascii_formatd(float_str, sizeof(float_str), "%E", tmp_d);
+               g_snprintf(command, sizeof(command),
+                          (*model->scpi_dialect)[SCPI_CMD_SET_HORIZ_TRIGGERPOS],
+                          float_str);
+
+               ret = sr_scpi_send(sdi->conn, command);
+               break;
+       case SR_CONF_TRIGGER_SLOPE:
+               tmp = g_variant_get_string(data, NULL);
+
+               if (!tmp || !(tmp[0] == 'f' || tmp[0] == 'r'))
+                       return SR_ERR_ARG;
+
+               state->trigger_slope = (tmp[0] == 'r') ? 0 : 1;
+
+               g_snprintf(command, sizeof(command),
+                          (*model->scpi_dialect)[SCPI_CMD_SET_TRIGGER_SLOPE],
+                          (state->trigger_slope == 0) ? "POS" : "NEG");
+
+               ret = sr_scpi_send(sdi->conn, command);
+               break;
+       case SR_CONF_COUPLING:
+               if (cg_type == CG_NONE) {
+                       sr_err("No channel group specified.");
+                       return SR_ERR_CHANNEL_GROUP;
+               }
+
+               tmp = g_variant_get_string(data, NULL);
+
+               for (i = 0; (*model->coupling_options)[i]; i++) {
+                       if (strcmp(tmp, (*model->coupling_options)[i]) != 0)
+                               continue;
+                       for (j = 1; j <= model->analog_channels; ++j) {
+                               if (cg != &devc->analog_groups[j - 1])
+                                       continue;
+                               state->analog_channels[j-1].coupling = i;
+
+                               g_snprintf(command, sizeof(command),
+                                          (*model->scpi_dialect)[SCPI_CMD_SET_COUPLING],
+                                          j, tmp);
+
+                               if (sr_scpi_send(sdi->conn, command) != SR_OK ||
+                                   sr_scpi_get_opc(sdi->conn) != SR_OK)
+                                       return SR_ERR;
+                               break;
+                       }
+
+                       ret = SR_OK;
+                       break;
+               }
+               break;
+       default:
+               ret = SR_ERR_NA;
+               break;
+       }
+
+       if (ret == SR_OK)
+               ret = sr_scpi_get_opc(sdi->conn);
+
+       if (ret == SR_OK && update_sample_rate)
+               ret = hmo_update_sample_rate(sdi);
+
+       return ret;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+                      const struct sr_channel_group *cg)
+{
+       int cg_type;
+       struct dev_context *devc;
+       struct scope_config *model;
+
+       if (!sdi || !(devc = sdi->priv))
+               return SR_ERR_ARG;
+
+       if ((cg_type = check_channel_group(devc, cg)) == CG_INVALID)
+               return SR_ERR;
+
+       model = devc->model_config;
+
+       switch (key) {
+       case SR_CONF_DEVICE_OPTIONS:
+               if (cg_type == CG_NONE) {
+                       *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               model->hw_caps, model->num_hwcaps,
+                               sizeof(int32_t));
+               } else if (cg_type == CG_ANALOG) {
+                       *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               model->analog_hwcaps, model->num_analog_hwcaps,
+                               sizeof(int32_t));
+               } else {
+                       *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               NULL, 0, sizeof(int32_t));
+               }
+               break;
+       case SR_CONF_COUPLING:
+               if (cg_type == CG_NONE)
+                       return SR_ERR_CHANNEL_GROUP;
+               *data = g_variant_new_strv(*model->coupling_options,
+                          g_strv_length((char **)*model->coupling_options));
+               break;
+       case SR_CONF_TRIGGER_SOURCE:
+               *data = g_variant_new_strv(*model->trigger_sources,
+                          g_strv_length((char **)*model->trigger_sources));
+               break;
+       case SR_CONF_TRIGGER_SLOPE:
+               *data = g_variant_new_strv(*model->trigger_slopes,
+                          g_strv_length((char **)*model->trigger_slopes));
+               break;
+       case SR_CONF_TIMEBASE:
+               *data = build_tuples(model->timebases, model->num_timebases);
+               break;
+       case SR_CONF_VDIV:
+               if (cg_type == CG_NONE)
+                       return SR_ERR_CHANNEL_GROUP;
+               *data = build_tuples(model->vdivs, model->num_vdivs);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+SR_PRIV int hmo_request_data(const struct sr_dev_inst *sdi)
+{
+       char command[MAX_COMMAND_SIZE];
+       struct sr_channel *ch;
+       struct dev_context *devc;
+       struct scope_config *model;
+
+       devc = sdi->priv;
+       model = devc->model_config;
+
+       ch = devc->current_channel->data;
+
+       switch (ch->type) {
+       case SR_CHANNEL_ANALOG:
+               g_snprintf(command, sizeof(command),
+                          (*model->scpi_dialect)[SCPI_CMD_GET_ANALOG_DATA],
+                          ch->index + 1);
+               break;
+       case SR_CHANNEL_LOGIC:
+               g_snprintf(command, sizeof(command),
+                          (*model->scpi_dialect)[SCPI_CMD_GET_DIG_DATA],
+                          ch->index < 8 ? 1 : 2);
+               break;
+       default:
+               sr_err("Invalid channel type.");
+               break;
+       }
+
+       return sr_scpi_send(sdi->conn, command);
+}
+
+static int hmo_check_channels(GSList *channels)
+{
+       GSList *l;
+       struct sr_channel *ch;
+       gboolean enabled_pod1, enabled_pod2, enabled_chan3, enabled_chan4;
+
+       enabled_pod1 = enabled_pod2 = enabled_chan3 = enabled_chan4 = FALSE;
+
+       for (l = channels; l; l = l->next) {
+               ch = l->data;
+               switch (ch->type) {
+               case SR_CHANNEL_ANALOG:
+                       if (ch->index == 2)
+                               enabled_chan3 = TRUE;
+                       else if (ch->index == 3)
+                               enabled_chan4 = TRUE;
+                       break;
+               case SR_CHANNEL_LOGIC:
+                       if (ch->index < 8)
+                               enabled_pod1 = TRUE;
+                       else
+                               enabled_pod2 = TRUE;
+                       break;
+               default:
+                       return SR_ERR;
+               }
+       }
+
+       if ((enabled_pod1 && enabled_chan3) ||
+           (enabled_pod2 && enabled_chan4))
+               return SR_ERR;
+
+       return SR_OK;
+}
+
+static int hmo_setup_channels(const struct sr_dev_inst *sdi)
+{
+       GSList *l;
+       unsigned int i;
+       gboolean *pod_enabled, setup_changed;
+       char command[MAX_COMMAND_SIZE];
+       struct scope_state *state;
+       struct scope_config *model;
+       struct sr_channel *ch;
+       struct dev_context *devc;
+       struct sr_scpi_dev_inst *scpi;
+
+       devc = sdi->priv;
+       scpi = sdi->conn;
+       state = devc->model_state;
+       model = devc->model_config;
+       setup_changed = FALSE;
+
+       pod_enabled = g_try_malloc0(sizeof(gboolean) * model->digital_pods);
+
+       for (l = sdi->channels; l; l = l->next) {
+               ch = l->data;
+               switch (ch->type) {
+               case SR_CHANNEL_ANALOG:
+                       if (ch->enabled == state->analog_channels[ch->index].state)
+                               break;
+                       g_snprintf(command, sizeof(command),
+                                  (*model->scpi_dialect)[SCPI_CMD_SET_ANALOG_CHAN_STATE],
+                                  ch->index + 1, ch->enabled);
+
+                       if (sr_scpi_send(scpi, command) != SR_OK)
+                               return SR_ERR;
+                       state->analog_channels[ch->index].state = ch->enabled;
+                       setup_changed = TRUE;
+                       break;
+               case SR_CHANNEL_LOGIC:
+                       /*
+                        * A digital POD needs to be enabled for every group of
+                        * 8 channels.
+                        */
+                       if (ch->enabled)
+                               pod_enabled[ch->index < 8 ? 0 : 1] = TRUE;
+
+                       if (ch->enabled == state->digital_channels[ch->index])
+                               break;
+                       g_snprintf(command, sizeof(command),
+                                  (*model->scpi_dialect)[SCPI_CMD_SET_DIG_CHAN_STATE],
+                                  ch->index, ch->enabled);
+
+                       if (sr_scpi_send(scpi, command) != SR_OK)
+                               return SR_ERR;
+
+                       state->digital_channels[ch->index] = ch->enabled;
+                       setup_changed = TRUE;
+                       break;
+               default:
+                       return SR_ERR;
+               }
+       }
+
+       for (i = 1; i <= model->digital_pods; ++i) {
+               if (state->digital_pods[i - 1] == pod_enabled[i - 1])
+                       continue;
+               g_snprintf(command, sizeof(command),
+                          (*model->scpi_dialect)[SCPI_CMD_SET_DIG_POD_STATE],
+                          i, pod_enabled[i - 1]);
+               if (sr_scpi_send(scpi, command) != SR_OK)
+                       return SR_ERR;
+               state->digital_pods[i - 1] = pod_enabled[i - 1];
+               setup_changed = TRUE;
+       }
+
+       g_free(pod_enabled);
+
+       if (setup_changed && hmo_update_sample_rate(sdi) != SR_OK)
+               return SR_ERR;
+
+       return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+       GSList *l;
+       gboolean digital_added;
+       struct sr_channel *ch;
+       struct dev_context *devc;
+       struct sr_scpi_dev_inst *scpi;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       scpi = sdi->conn;
+       devc = sdi->priv;
+       digital_added = FALSE;
+
+       for (l = sdi->channels; l; l = l->next) {
+               ch = l->data;
+               if (!ch->enabled)
+                       continue;
+               /* Only add a single digital channel. */
+               if (ch->type != SR_CHANNEL_LOGIC || !digital_added) {
+                       devc->enabled_channels = g_slist_append(
+                                       devc->enabled_channels, ch);
+                       if (ch->type == SR_CHANNEL_LOGIC)
+                               digital_added = TRUE;
+               }
+       }
+
+       if (!devc->enabled_channels)
+               return SR_ERR;
+
+       if (hmo_check_channels(devc->enabled_channels) != SR_OK) {
+               sr_err("Invalid channel configuration specified!");
+               return SR_ERR_NA;
+       }
+
+       if (hmo_setup_channels(sdi) != SR_OK) {
+               sr_err("Failed to setup channel configuration!");
+               return SR_ERR;
+       }
+
+       sr_scpi_source_add(sdi->session, scpi, G_IO_IN, 50,
+                       hmo_receive_data, (void *)sdi);
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(cb_data, LOG_PREFIX);
+
+       devc->current_channel = devc->enabled_channels;
+
+       return hmo_request_data(sdi);
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct dev_context *devc;
+       struct sr_scpi_dev_inst *scpi;
+       struct sr_datafeed_packet packet;
+
+       (void)cb_data;
+
+       packet.type = SR_DF_END;
+       packet.payload = NULL;
+       sr_session_send(sdi, &packet);
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       devc = sdi->priv;
+
+       devc->num_frames = 0;
+       g_slist_free(devc->enabled_channels);
+       devc->enabled_channels = NULL;
+       scpi = sdi->conn;
+       sr_scpi_source_remove(sdi->session, scpi);
+
+       return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver hameg_hmo_driver_info = {
+       .name = "hameg-hmo",
+       .longname = "Hameg HMO",
+       .api_version = 1,
+       .init = init,
+       .cleanup = cleanup,
+       .scan = scan,
+       .dev_list = dev_list,
+       .dev_clear = dev_clear,
+       .config_get = config_get,
+       .config_set = config_set,
+       .config_list = config_list,
+       .dev_open = dev_open,
+       .dev_close = dev_close,
+       .dev_acquisition_start = dev_acquisition_start,
+       .dev_acquisition_stop = dev_acquisition_stop,
+       .priv = NULL,
+};
diff --git a/src/hardware/hameg-hmo/protocol.c b/src/hardware/hameg-hmo/protocol.c
new file mode 100644 (file)
index 0000000..afa6efe
--- /dev/null
@@ -0,0 +1,741 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * 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 "protocol.h"
+
+static const char *hameg_scpi_dialect[] = {
+       [SCPI_CMD_GET_DIG_DATA]             = ":POD%d:DATA?",
+       [SCPI_CMD_GET_TIMEBASE]             = ":TIM:SCAL?",
+       [SCPI_CMD_SET_TIMEBASE]             = ":TIM:SCAL %s",
+       [SCPI_CMD_GET_COUPLING]             = ":CHAN%d:COUP?",
+       [SCPI_CMD_SET_COUPLING]             = ":CHAN%d:COUP %s",
+       [SCPI_CMD_GET_SAMPLE_RATE]          = ":ACQ:SRAT?",
+       [SCPI_CMD_GET_SAMPLE_RATE_LIVE]     = ":%s:DATA:POINTS?",
+       [SCPI_CMD_GET_ANALOG_DATA]          = ":CHAN%d:DATA?",
+       [SCPI_CMD_GET_VERTICAL_DIV]         = ":CHAN%d:SCAL?",
+       [SCPI_CMD_SET_VERTICAL_DIV]         = ":CHAN%d:SCAL %s",
+       [SCPI_CMD_GET_DIG_POD_STATE]        = ":POD%d:STAT?",
+       [SCPI_CMD_SET_DIG_POD_STATE]        = ":POD%d:STAT %d",
+       [SCPI_CMD_GET_TRIGGER_SLOPE]        = ":TRIG:A:EDGE:SLOP?",
+       [SCPI_CMD_SET_TRIGGER_SLOPE]        = ":TRIG:A:EDGE:SLOP %s",
+       [SCPI_CMD_GET_TRIGGER_SOURCE]       = ":TRIG:A:SOUR?",
+       [SCPI_CMD_SET_TRIGGER_SOURCE]       = ":TRIG:A:SOUR %s",
+       [SCPI_CMD_GET_DIG_CHAN_STATE]       = ":LOG%d:STAT?",
+       [SCPI_CMD_SET_DIG_CHAN_STATE]       = ":LOG%d:STAT %d",
+       [SCPI_CMD_GET_VERTICAL_OFFSET]      = ":CHAN%d:POS?",
+       [SCPI_CMD_GET_HORIZ_TRIGGERPOS]     = ":TIM:POS?",
+       [SCPI_CMD_SET_HORIZ_TRIGGERPOS]     = ":TIM:POS %s",
+       [SCPI_CMD_GET_ANALOG_CHAN_STATE]    = ":CHAN%d:STAT?",
+       [SCPI_CMD_SET_ANALOG_CHAN_STATE]    = ":CHAN%d:STAT %d",
+};
+
+static const int32_t hmo_hwcaps[] = {
+       SR_CONF_OSCILLOSCOPE,
+       SR_CONF_TRIGGER_SOURCE,
+       SR_CONF_TIMEBASE,
+       SR_CONF_NUM_TIMEBASE,
+       SR_CONF_TRIGGER_SLOPE,
+       SR_CONF_HORIZ_TRIGGERPOS,
+       SR_CONF_SAMPLERATE,
+       SR_CONF_LIMIT_FRAMES,
+};
+
+static const int32_t hmo_analog_caps[] = {
+       SR_CONF_NUM_VDIV,
+       SR_CONF_COUPLING,
+       SR_CONF_VDIV,
+};
+
+static const char *hmo_coupling_options[] = {
+       "AC",
+       "ACL",
+       "DC",
+       "DCL",
+       "GND",
+       NULL,
+};
+
+static const char *scope_trigger_slopes[] = {
+       "POS",
+       "NEG",
+       NULL,
+};
+
+static const char *hmo_compact2_trigger_sources[] = {
+       "CH1",
+       "CH2",
+       "LINE",
+       "EXT",
+       "D0",
+       "D1",
+       "D2",
+       "D3",
+       "D4",
+       "D5",
+       "D6",
+       "D7",
+       NULL,
+};
+
+static const char *hmo_compact4_trigger_sources[] = {
+       "CH1",
+       "CH2",
+       "CH3",
+       "CH4",
+       "LINE",
+       "EXT",
+       "D0",
+       "D1",
+       "D2",
+       "D3",
+       "D4",
+       "D5",
+       "D6",
+       "D7",
+       NULL,
+};
+
+static const uint64_t hmo_timebases[][2] = {
+       /* nanoseconds */
+       { 2, 1000000000 },
+       { 5, 1000000000 },
+       { 10, 1000000000 },
+       { 20, 1000000000 },
+       { 50, 1000000000 },
+       { 100, 1000000000 },
+       { 200, 1000000000 },
+       { 500, 1000000000 },
+       /* microseconds */
+       { 1, 1000000 },
+       { 2, 1000000 },
+       { 5, 1000000 },
+       { 10, 1000000 },
+       { 20, 1000000 },
+       { 50, 1000000 },
+       { 100, 1000000 },
+       { 200, 1000000 },
+       { 500, 1000000 },
+       /* milliseconds */
+       { 1, 1000 },
+       { 2, 1000 },
+       { 5, 1000 },
+       { 10, 1000 },
+       { 20, 1000 },
+       { 50, 1000 },
+       { 100, 1000 },
+       { 200, 1000 },
+       { 500, 1000 },
+       /* seconds */
+       { 1, 1 },
+       { 2, 1 },
+       { 5, 1 },
+       { 10, 1 },
+       { 20, 1 },
+       { 50, 1 },
+};
+
+static const uint64_t hmo_vdivs[][2] = {
+       /* millivolts */
+       { 1, 1000 },
+       { 2, 1000 },
+       { 5, 1000 },
+       { 10, 1000 },
+       { 20, 1000 },
+       { 50, 1000 },
+       { 100, 1000 },
+       { 200, 1000 },
+       { 500, 1000 },
+       /* volts */
+       { 1, 1 },
+       { 2, 1 },
+       { 5, 1 },
+       { 10, 1 },
+};
+
+static const char *scope_analog_channel_names[] = {
+       "CH1",
+       "CH2",
+       "CH3",
+       "CH4",
+};
+
+static const char *scope_digital_channel_names[] = {
+       "D0",
+       "D1",
+       "D2",
+       "D3",
+       "D4",
+       "D5",
+       "D6",
+       "D7",
+       "D8",
+       "D9",
+       "D10",
+       "D11",
+       "D12",
+       "D13",
+       "D14",
+       "D15",
+};
+
+static struct scope_config scope_models[] = {
+       {
+               .name = {"HMO722", "HMO1022", "HMO1522", "HMO2022", NULL},
+               .analog_channels = 2,
+               .digital_channels = 8,
+               .digital_pods = 1,
+
+               .analog_names = &scope_analog_channel_names,
+               .digital_names = &scope_digital_channel_names,
+
+               .hw_caps = &hmo_hwcaps,
+               .num_hwcaps = ARRAY_SIZE(hmo_hwcaps),
+
+               .analog_hwcaps = &hmo_analog_caps,
+               .num_analog_hwcaps = ARRAY_SIZE(hmo_analog_caps),
+
+               .coupling_options = &hmo_coupling_options,
+               .trigger_sources = &hmo_compact2_trigger_sources,
+               .trigger_slopes = &scope_trigger_slopes,
+
+               .timebases = &hmo_timebases,
+               .num_timebases = ARRAY_SIZE(hmo_timebases),
+
+               .vdivs = &hmo_vdivs,
+               .num_vdivs = ARRAY_SIZE(hmo_vdivs),
+
+               .num_xdivs = 12,
+               .num_ydivs = 8,
+
+               .scpi_dialect = &hameg_scpi_dialect,
+       },
+       {
+               .name = {"HMO724", "HMO1024", "HMO1524", "HMO2024", NULL},
+               .analog_channels = 4,
+               .digital_channels = 8,
+               .digital_pods = 1,
+
+               .analog_names = &scope_analog_channel_names,
+               .digital_names = &scope_digital_channel_names,
+
+               .hw_caps = &hmo_hwcaps,
+               .num_hwcaps = ARRAY_SIZE(hmo_hwcaps),
+
+               .analog_hwcaps = &hmo_analog_caps,
+               .num_analog_hwcaps = ARRAY_SIZE(hmo_analog_caps),
+
+               .coupling_options = &hmo_coupling_options,
+               .trigger_sources = &hmo_compact4_trigger_sources,
+               .trigger_slopes = &scope_trigger_slopes,
+
+               .timebases = &hmo_timebases,
+               .num_timebases = ARRAY_SIZE(hmo_timebases),
+
+               .vdivs = &hmo_vdivs,
+               .num_vdivs = ARRAY_SIZE(hmo_vdivs),
+
+               .num_xdivs = 12,
+               .num_ydivs = 8,
+
+               .scpi_dialect = &hameg_scpi_dialect,
+       },
+};
+
+static void scope_state_dump(struct scope_config *config,
+                            struct scope_state *state)
+{
+       unsigned int i;
+       char *tmp;
+
+       for (i = 0; i < config->analog_channels; ++i) {
+               tmp = sr_voltage_string((*config->vdivs)[state->analog_channels[i].vdiv][0],
+                                            (*config->vdivs)[state->analog_channels[i].vdiv][1]);
+               sr_info("State of analog channel  %d -> %s : %s (coupling) %s (vdiv) %2.2e (offset)",
+                       i + 1, state->analog_channels[i].state ? "On" : "Off",
+                       (*config->coupling_options)[state->analog_channels[i].coupling],
+                       tmp, state->analog_channels[i].vertical_offset);
+       }
+
+       for (i = 0; i < config->digital_channels; ++i) {
+               sr_info("State of digital channel %d -> %s", i,
+                       state->digital_channels[i] ? "On" : "Off");
+       }
+
+       for (i = 0; i < config->digital_pods; ++i) {
+               sr_info("State of digital POD %d -> %s", i,
+                       state->digital_pods[i] ? "On" : "Off");
+       }
+
+       tmp = sr_period_string((*config->timebases)[state->timebase][0] *
+                              (*config->timebases)[state->timebase][1]);
+       sr_info("Current timebase: %s", tmp);
+       g_free(tmp);
+
+       tmp = sr_samplerate_string(state->sample_rate);
+       sr_info("Current samplerate: %s", tmp);
+       g_free(tmp);
+
+       sr_info("Current trigger: %s (source), %s (slope) %.2f (offset)",
+               (*config->trigger_sources)[state->trigger_source],
+               (*config->trigger_slopes)[state->trigger_slope],
+               state->horiz_triggerpos);
+}
+
+static int scope_state_get_array_option(struct sr_scpi_dev_inst *scpi,
+               const char *command, const char *(*array)[], int *result)
+{
+       char *tmp;
+       unsigned int i;
+
+       if (sr_scpi_get_string(scpi, command, &tmp) != SR_OK) {
+               g_free(tmp);
+               return SR_ERR;
+       }
+
+       for (i = 0; (*array)[i]; ++i) {
+               if (!g_strcmp0(tmp, (*array)[i])) {
+                       *result = i;
+                       g_free(tmp);
+                       tmp = NULL;
+                       break;
+               }
+       }
+
+       if (tmp) {
+               g_free(tmp);
+               return SR_ERR;
+       }
+
+       return SR_OK;
+}
+
+static int analog_channel_state_get(struct sr_scpi_dev_inst *scpi,
+                                   struct scope_config *config,
+                                   struct scope_state *state)
+{
+       unsigned int i, j;
+       float tmp_float;
+       char command[MAX_COMMAND_SIZE];
+
+       for (i = 0; i < config->analog_channels; ++i) {
+               g_snprintf(command, sizeof(command),
+                          (*config->scpi_dialect)[SCPI_CMD_GET_ANALOG_CHAN_STATE],
+                          i + 1);
+
+               if (sr_scpi_get_bool(scpi, command,
+                                    &state->analog_channels[i].state) != SR_OK)
+                       return SR_ERR;
+
+               g_snprintf(command, sizeof(command),
+                          (*config->scpi_dialect)[SCPI_CMD_GET_VERTICAL_DIV],
+                          i + 1);
+
+               if (sr_scpi_get_float(scpi, command, &tmp_float) != SR_OK)
+                       return SR_ERR;
+               for (j = 0; j < config->num_vdivs; j++) {
+                       if (tmp_float == ((float) (*config->vdivs)[j][0] /
+                                         (*config->vdivs)[j][1])) {
+                               state->analog_channels[i].vdiv = j;
+                               break;
+                       }
+               }
+               if (i == config->num_vdivs)
+                       return SR_ERR;
+
+               g_snprintf(command, sizeof(command),
+                          (*config->scpi_dialect)[SCPI_CMD_GET_VERTICAL_OFFSET],
+                          i + 1);
+
+               if (sr_scpi_get_float(scpi, command,
+                                    &state->analog_channels[i].vertical_offset) != SR_OK)
+                       return SR_ERR;
+
+               g_snprintf(command, sizeof(command),
+                          (*config->scpi_dialect)[SCPI_CMD_GET_COUPLING],
+                          i + 1);
+
+               if (scope_state_get_array_option(scpi, command, config->coupling_options,
+                                        &state->analog_channels[i].coupling) != SR_OK)
+                       return SR_ERR;
+       }
+
+       return SR_OK;
+}
+
+static int digital_channel_state_get(struct sr_scpi_dev_inst *scpi,
+                                    struct scope_config *config,
+                                    struct scope_state *state)
+{
+       unsigned int i;
+       char command[MAX_COMMAND_SIZE];
+
+       for (i = 0; i < config->digital_channels; ++i) {
+               g_snprintf(command, sizeof(command),
+                          (*config->scpi_dialect)[SCPI_CMD_GET_DIG_CHAN_STATE],
+                          i);
+
+               if (sr_scpi_get_bool(scpi, command,
+                                    &state->digital_channels[i]) != SR_OK)
+                       return SR_ERR;
+       }
+
+       for (i = 0; i < config->digital_pods; ++i) {
+               g_snprintf(command, sizeof(command),
+                          (*config->scpi_dialect)[SCPI_CMD_GET_DIG_POD_STATE],
+                          i + 1);
+
+               if (sr_scpi_get_bool(scpi, command,
+                                    &state->digital_pods[i]) != SR_OK)
+                       return SR_ERR;
+       }
+
+       return SR_OK;
+}
+
+SR_PRIV int hmo_update_sample_rate(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct scope_state *state;
+       struct scope_config *config;
+
+       int tmp;
+       unsigned int i;
+       float tmp_float;
+       gboolean channel_found;
+       char tmp_str[MAX_COMMAND_SIZE];
+       char chan_name[20];
+
+       devc = sdi->priv;
+       config = devc->model_config;
+       state = devc->model_state;
+       channel_found = FALSE;
+
+       for (i = 0; i < config->analog_channels; ++i) {
+               if (state->analog_channels[i].state) {
+                       g_snprintf(chan_name, sizeof(chan_name), "CHAN%d", i + 1);
+                       g_snprintf(tmp_str, sizeof(tmp_str),
+                                  (*config->scpi_dialect)[SCPI_CMD_GET_SAMPLE_RATE_LIVE],
+                                  chan_name);
+                       channel_found = TRUE;
+                       break;
+               }
+       }
+
+       if (!channel_found) {
+               for (i = 0; i < config->digital_pods; i++) {
+                       if (state->digital_pods[i]) {
+                               g_snprintf(chan_name, sizeof(chan_name), "POD%d", i);
+                               g_snprintf(tmp_str, sizeof(tmp_str),
+                                          (*config->scpi_dialect)[SCPI_CMD_GET_SAMPLE_RATE_LIVE],
+                                          chan_name);
+                               channel_found = TRUE;
+                               break;
+                       }
+               }
+       }
+
+       /* No channel is active, ask the instrument for the sample rate
+        * in single shot mode */
+       if (!channel_found) {
+               if (sr_scpi_get_float(sdi->conn,
+                                     (*config->scpi_dialect)[SCPI_CMD_GET_SAMPLE_RATE],
+                                     &tmp_float) != SR_OK)
+                       return SR_ERR;
+
+               state->sample_rate = tmp_float;
+       } else {
+               if (sr_scpi_get_int(sdi->conn, tmp_str, &tmp) != SR_OK)
+                       return SR_ERR;
+               state->sample_rate = tmp / (((float) (*config->timebases)[state->timebase][0] /
+                                            (*config->timebases)[state->timebase][1]) *
+                                           config->num_xdivs);
+       }
+
+       return SR_OK;
+}
+
+SR_PRIV int hmo_scope_state_get(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct scope_state *state;
+       struct scope_config *config;
+       float tmp_float;
+       unsigned int i;
+
+       devc = sdi->priv;
+       config = devc->model_config;
+       state = devc->model_state;
+
+       sr_info("Fetching scope state");
+
+       if (analog_channel_state_get(sdi->conn, config, state) != SR_OK)
+               return SR_ERR;
+
+       if (digital_channel_state_get(sdi->conn, config, state) != SR_OK)
+               return SR_ERR;
+
+       if (sr_scpi_get_float(sdi->conn,
+                       (*config->scpi_dialect)[SCPI_CMD_GET_TIMEBASE],
+                       &tmp_float) != SR_OK)
+               return SR_ERR;
+
+       for (i = 0; i < config->num_timebases; i++) {
+               if (tmp_float == ((float) (*config->timebases)[i][0] /
+                                 (*config->timebases)[i][1])) {
+                       state->timebase = i;
+                       break;
+               }
+       }
+       if (i == config->num_timebases)
+               return SR_ERR;
+
+       if (sr_scpi_get_float(sdi->conn,
+                       (*config->scpi_dialect)[SCPI_CMD_GET_HORIZ_TRIGGERPOS],
+                       &tmp_float) != SR_OK)
+               return SR_ERR;
+       state->horiz_triggerpos = tmp_float /
+               (((double) (*config->timebases)[state->timebase][0] /
+                 (*config->timebases)[state->timebase][1]) * config->num_xdivs);
+       state->horiz_triggerpos -= 0.5;
+       state->horiz_triggerpos *= -1;
+
+       if (scope_state_get_array_option(sdi->conn,
+                       (*config->scpi_dialect)[SCPI_CMD_GET_TRIGGER_SOURCE],
+                       config->trigger_sources, &state->trigger_source) != SR_OK)
+               return SR_ERR;
+
+       if (scope_state_get_array_option(sdi->conn,
+               (*config->scpi_dialect)[SCPI_CMD_GET_TRIGGER_SLOPE],
+               config->trigger_slopes, &state->trigger_slope) != SR_OK)
+               return SR_ERR;
+
+       if (hmo_update_sample_rate(sdi) != SR_OK)
+               return SR_ERR;
+
+       sr_info("Fetching finished.");
+
+       scope_state_dump(config, state);
+
+       return SR_OK;
+}
+
+static struct scope_state *scope_state_new(struct scope_config *config)
+{
+       struct scope_state *state;
+
+       if (!(state = g_try_malloc0(sizeof(struct scope_state))))
+               return NULL;
+
+       if (!(state->analog_channels = g_try_malloc0_n(config->analog_channels,
+                                   sizeof(struct analog_channel_state))))
+           goto fail;
+
+       if (!(state->digital_channels = g_try_malloc0_n(
+                       config->digital_channels, sizeof(gboolean))))
+           goto fail;
+
+       if (!(state->digital_pods = g_try_malloc0_n(config->digital_pods,
+                                                    sizeof(gboolean))))
+           goto fail;
+
+       return state;
+
+fail:
+       if (state->analog_channels)
+               g_free(state->analog_channels);
+       if (state->digital_channels)
+               g_free(state->digital_channels);
+       if (state->digital_pods)
+               g_free(state->digital_pods);
+       g_free(state);
+
+       return NULL;
+}
+
+SR_PRIV void hmo_scope_state_free(struct scope_state *state)
+{
+       g_free(state->analog_channels);
+       g_free(state->digital_channels);
+       g_free(state->digital_pods);
+       g_free(state);
+}
+
+SR_PRIV int hmo_init_device(struct sr_dev_inst *sdi)
+{
+       char tmp[25];
+       int model_index;
+       unsigned int i, j;
+       struct sr_channel *ch;
+       struct dev_context *devc;
+
+       devc = sdi->priv;
+       model_index = -1;
+
+       /* Find the exact model. */
+       for (i = 0; i < ARRAY_SIZE(scope_models); i++) {
+               for (j = 0; scope_models[i].name[j]; j++) {
+                       if (!strcmp(sdi->model, scope_models[i].name[j])) {
+                               model_index = i;
+                               break;
+                       }
+               }
+               if (model_index != -1)
+                       break;
+       }
+
+       if (model_index == -1) {
+               sr_dbg("Unsupported HMO device.");
+               return SR_ERR_NA;
+       }
+
+       if (!(devc->analog_groups = g_try_malloc0(sizeof(struct sr_channel_group) *
+                                                 scope_models[model_index].analog_channels)))
+                       return SR_ERR_MALLOC;
+
+       if (!(devc->digital_groups = g_try_malloc0(sizeof(struct sr_channel_group) *
+                                                  scope_models[model_index].digital_pods)))
+                       return SR_ERR_MALLOC;
+
+       /* Add analog channels. */
+       for (i = 0; i < scope_models[model_index].analog_channels; i++) {
+               if (!(ch = sr_channel_new(i, SR_CHANNEL_ANALOG, TRUE,
+                          (*scope_models[model_index].analog_names)[i])))
+                       return SR_ERR_MALLOC;
+               sdi->channels = g_slist_append(sdi->channels, ch);
+
+               devc->analog_groups[i].name =
+                       (char *)(*scope_models[model_index].analog_names)[i];
+               devc->analog_groups[i].channels = g_slist_append(NULL, ch);
+
+               sdi->channel_groups = g_slist_append(sdi->channel_groups,
+                                                  &devc->analog_groups[i]);
+       }
+
+       /* Add digital channel groups. */
+       for (i = 0; i < scope_models[model_index].digital_pods; ++i) {
+               g_snprintf(tmp, 25, "POD%d", i);
+               devc->digital_groups[i].name = g_strdup(tmp);
+               sdi->channel_groups = g_slist_append(sdi->channel_groups,
+                                  &devc->digital_groups[i < 8 ? 0 : 1]);
+       }
+
+       /* Add digital channels. */
+       for (i = 0; i < scope_models[model_index].digital_channels; i++) {
+               if (!(ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE,
+                          (*scope_models[model_index].digital_names)[i])))
+                       return SR_ERR_MALLOC;
+               sdi->channels = g_slist_append(sdi->channels, ch);
+
+               devc->digital_groups[i < 8 ? 0 : 1].channels = g_slist_append(
+                       devc->digital_groups[i < 8 ? 0 : 1].channels, ch);
+       }
+
+       devc->model_config = &scope_models[model_index];
+       devc->frame_limit = 0;
+
+       if (!(devc->model_state = scope_state_new(devc->model_config)))
+               return SR_ERR_MALLOC;
+
+       return SR_OK;
+}
+
+SR_PRIV int hmo_receive_data(int fd, int revents, void *cb_data)
+{
+       struct sr_channel *ch;
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       struct sr_datafeed_packet packet;
+       GArray *data;
+       struct sr_datafeed_analog analog;
+       struct sr_datafeed_logic logic;
+
+       (void)fd;
+
+       if (!(sdi = cb_data))
+               return TRUE;
+
+       if (!(devc = sdi->priv))
+               return TRUE;
+
+       if (revents == G_IO_IN) {
+               ch = devc->current_channel->data;
+
+               switch (ch->type) {
+               case SR_CHANNEL_ANALOG:
+                       if (sr_scpi_get_floatv(sdi->conn, NULL, &data) != SR_OK) {
+                               if (data)
+                                       g_array_free(data, TRUE);
+
+                               return TRUE;
+                       }
+
+                       packet.type = SR_DF_FRAME_BEGIN;
+                       sr_session_send(sdi, &packet);
+
+                       analog.channels = g_slist_append(NULL, ch);
+                       analog.num_samples = data->len;
+                       analog.data = (float *) data->data;
+                       analog.mq = SR_MQ_VOLTAGE;
+                       analog.unit = SR_UNIT_VOLT;
+                       analog.mqflags = 0;
+                       packet.type = SR_DF_ANALOG;
+                       packet.payload = &analog;
+                       sr_session_send(cb_data, &packet);
+                       g_slist_free(analog.channels);
+                       g_array_free(data, TRUE);
+                       break;
+               case SR_CHANNEL_LOGIC:
+                       if (sr_scpi_get_uint8v(sdi->conn, NULL, &data) != SR_OK) {
+                               if (data)
+                                       g_free(data);
+                               return TRUE;
+                       }
+
+                       packet.type = SR_DF_FRAME_BEGIN;
+                       sr_session_send(sdi, &packet);
+
+                       logic.length = data->len;
+                       logic.unitsize = 1;
+                       logic.data = data->data;
+                       packet.type = SR_DF_LOGIC;
+                       packet.payload = &logic;
+                       sr_session_send(cb_data, &packet);
+                       g_array_free(data, TRUE);
+                       break;
+               default:
+                       sr_err("Invalid channel type.");
+                       break;
+               }
+
+               packet.type = SR_DF_FRAME_END;
+               sr_session_send(sdi, &packet);
+
+               if (devc->current_channel->next) {
+                       devc->current_channel = devc->current_channel->next;
+                       hmo_request_data(sdi);
+               } else if (++devc->num_frames == devc->frame_limit) {
+                       sdi->driver->dev_acquisition_stop(sdi, cb_data);
+               } else {
+                       devc->current_channel = devc->enabled_channels;
+                       hmo_request_data(sdi);
+               }
+       }
+
+       return TRUE;
+}
diff --git a/src/hardware/hameg-hmo/protocol.h b/src/hardware/hameg-hmo/protocol.h
new file mode 100644 (file)
index 0000000..bdf70fc
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * 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/>.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_HAMEG_HMO_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_HAMEG_HMO_PROTOCOL_H
+
+#include <glib.h>
+#include <stdint.h>
+#include <string.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "hameg-hmo"
+
+#define MAX_INSTRUMENT_VERSIONS 10
+#define MAX_COMMAND_SIZE 31
+
+struct scope_config {
+       const char *name[MAX_INSTRUMENT_VERSIONS];
+       const uint8_t analog_channels;
+       const uint8_t digital_channels;
+       const uint8_t digital_pods;
+
+       const char *(*analog_names)[];
+       const char *(*digital_names)[];
+
+       const int32_t (*hw_caps)[];
+       const uint8_t num_hwcaps;
+
+       const int32_t (*analog_hwcaps)[];
+       const uint8_t num_analog_hwcaps;
+
+       const char *(*coupling_options)[];
+       const uint8_t num_coupling_options;
+
+       const char *(*trigger_sources)[];
+       const uint8_t num_trigger_sources;
+
+       const char *(*trigger_slopes)[];
+
+       const uint64_t (*timebases)[][2];
+       const uint8_t num_timebases;
+
+       const uint64_t (*vdivs)[][2];
+       const uint8_t num_vdivs;
+
+       const uint8_t num_xdivs;
+       const uint8_t num_ydivs;
+
+       const char *(*scpi_dialect)[];
+};
+
+struct analog_channel_state {
+       int coupling;
+
+       int vdiv;
+       float vertical_offset;
+
+       gboolean state;
+};
+
+struct scope_state {
+       struct analog_channel_state *analog_channels;
+       gboolean *digital_channels;
+       gboolean *digital_pods;
+
+       int timebase;
+       float horiz_triggerpos;
+
+       int trigger_source;
+       int trigger_slope;
+       uint64_t sample_rate;
+};
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+       void *model_config;
+       void *model_state;
+
+       struct sr_channel_group *analog_groups;
+       struct sr_channel_group *digital_groups;
+
+       GSList *enabled_channels;
+       GSList *current_channel;
+       uint64_t num_frames;
+
+       uint64_t frame_limit;
+};
+
+SR_PRIV int hmo_init_device(struct sr_dev_inst *sdi);
+SR_PRIV int hmo_request_data(const struct sr_dev_inst *sdi);
+SR_PRIV int hmo_receive_data(int fd, int revents, void *cb_data);
+
+SR_PRIV struct scope_state *hmo_scope_state_new(struct scope_config *config);
+SR_PRIV void hmo_scope_state_free(struct scope_state *state);
+SR_PRIV int hmo_scope_state_get(struct sr_dev_inst *sdi);
+SR_PRIV int hmo_update_sample_rate(const struct sr_dev_inst *sdi);
+
+#endif
diff --git a/src/hardware/hantek-dso/api.c b/src/hardware/hantek-dso/api.c
new file mode 100644 (file)
index 0000000..c948e42
--- /dev/null
@@ -0,0 +1,976 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert@biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/time.h>
+#include <inttypes.h>
+#include <glib.h>
+#include <libusb.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "dso.h"
+
+/* Max time in ms before we want to check on USB events */
+/* TODO tune this properly */
+#define TICK 1
+
+#define NUM_TIMEBASE  10
+#define NUM_VDIV      8
+
+static const int32_t scanopts[] = {
+       SR_CONF_CONN,
+};
+
+static const int32_t devopts[] = {
+       SR_CONF_OSCILLOSCOPE,
+       SR_CONF_LIMIT_FRAMES,
+       SR_CONF_CONTINUOUS,
+       SR_CONF_TIMEBASE,
+       SR_CONF_BUFFERSIZE,
+       SR_CONF_TRIGGER_SOURCE,
+       SR_CONF_TRIGGER_SLOPE,
+       SR_CONF_HORIZ_TRIGGERPOS,
+       SR_CONF_FILTER,
+       SR_CONF_VDIV,
+       SR_CONF_COUPLING,
+       SR_CONF_NUM_TIMEBASE,
+       SR_CONF_NUM_VDIV,
+};
+
+static const char *channel_names[] = {
+       "CH1", "CH2",
+       NULL,
+};
+
+static const uint64_t buffersizes_32k[] = {
+       10240, 32768,
+};
+static const uint64_t buffersizes_512k[] = {
+       10240, 524288,
+};
+static const uint64_t buffersizes_14k[] = {
+       10240, 14336,
+};
+
+static const struct dso_profile dev_profiles[] = {
+       {       0x04b4, 0x2090, 0x04b5, 0x2090,
+               "Hantek", "DSO-2090",
+               buffersizes_32k,
+               FIRMWARE_DIR "/hantek-dso-2090.fw" },
+       {       0x04b4, 0x2150, 0x04b5, 0x2150,
+               "Hantek", "DSO-2150",
+               buffersizes_32k,
+               FIRMWARE_DIR "/hantek-dso-2150.fw" },
+       {       0x04b4, 0x2250, 0x04b5, 0x2250,
+               "Hantek", "DSO-2250",
+               buffersizes_512k,
+               FIRMWARE_DIR "/hantek-dso-2250.fw" },
+       {       0x04b4, 0x5200, 0x04b5, 0x5200,
+               "Hantek", "DSO-5200",
+               buffersizes_14k,
+               FIRMWARE_DIR "/hantek-dso-5200.fw" },
+       {       0x04b4, 0x520a, 0x04b5, 0x520a,
+               "Hantek", "DSO-5200A",
+               buffersizes_512k,
+               FIRMWARE_DIR "/hantek-dso-5200A.fw" },
+       { 0, 0, 0, 0, 0, 0, 0, 0 },
+};
+
+static const uint64_t timebases[][2] = {
+       /* microseconds */
+       { 10, 1000000 },
+       { 20, 1000000 },
+       { 40, 1000000 },
+       { 100, 1000000 },
+       { 200, 1000000 },
+       { 400, 1000000 },
+       /* milliseconds */
+       { 1, 1000 },
+       { 2, 1000 },
+       { 4, 1000 },
+       { 10, 1000 },
+       { 20, 1000 },
+       { 40, 1000 },
+       { 100, 1000 },
+       { 200, 1000 },
+       { 400, 1000 },
+};
+
+static const uint64_t vdivs[][2] = {
+       /* millivolts */
+       { 10, 1000 },
+       { 20, 1000 },
+       { 50, 1000 },
+       { 100, 1000 },
+       { 200, 1000 },
+       { 500, 1000 },
+       /* volts */
+       { 1, 1 },
+       { 2, 1 },
+       { 5, 1 },
+};
+
+static const char *trigger_sources[] = {
+       "CH1",
+       "CH2",
+       "EXT",
+       /* TODO: forced */
+};
+
+static const char *filter_targets[] = {
+       "CH1",
+       "CH2",
+       /* TODO: "TRIGGER", */
+};
+
+static const char *coupling[] = {
+       "AC",
+       "DC",
+       "GND",
+};
+
+SR_PRIV struct sr_dev_driver hantek_dso_driver_info;
+static struct sr_dev_driver *di = &hantek_dso_driver_info;
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data);
+
+static struct sr_dev_inst *dso_dev_new(int index, const struct dso_profile *prof)
+{
+       struct sr_dev_inst *sdi;
+       struct sr_channel *ch;
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       int i;
+
+       sdi = sr_dev_inst_new(index, SR_ST_INITIALIZING,
+               prof->vendor, prof->model, NULL);
+       if (!sdi)
+               return NULL;
+       sdi->driver = di;
+
+       /*
+        * Add only the real channels -- EXT isn't a source of data, only
+        * a trigger source internal to the device.
+        */
+       for (i = 0; channel_names[i]; i++) {
+               if (!(ch = sr_channel_new(i, SR_CHANNEL_ANALOG, TRUE,
+                               channel_names[i])))
+                       return NULL;
+               sdi->channels = g_slist_append(sdi->channels, ch);
+       }
+
+       if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+               sr_err("Device context malloc failed.");
+               return NULL;
+       }
+
+       devc->profile = prof;
+       devc->dev_state = IDLE;
+       devc->timebase = DEFAULT_TIMEBASE;
+       devc->ch1_enabled = TRUE;
+       devc->ch2_enabled = TRUE;
+       devc->voltage_ch1 = DEFAULT_VOLTAGE;
+       devc->voltage_ch2 = DEFAULT_VOLTAGE;
+       devc->coupling_ch1 = DEFAULT_COUPLING;
+       devc->coupling_ch2 = DEFAULT_COUPLING;
+       devc->voffset_ch1 = DEFAULT_VERT_OFFSET;
+       devc->voffset_ch2 = DEFAULT_VERT_OFFSET;
+       devc->voffset_trigger = DEFAULT_VERT_TRIGGERPOS;
+       devc->framesize = DEFAULT_FRAMESIZE;
+       devc->triggerslope = SLOPE_POSITIVE;
+       devc->triggersource = g_strdup(DEFAULT_TRIGGER_SOURCE);
+       devc->triggerposition = DEFAULT_HORIZ_TRIGGERPOS;
+       sdi->priv = devc;
+       drvc = di->priv;
+       drvc->instances = g_slist_append(drvc->instances, sdi);
+
+       return sdi;
+}
+
+static int configure_channels(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_channel *ch;
+       const GSList *l;
+       int p;
+
+       devc = sdi->priv;
+
+       g_slist_free(devc->enabled_channels);
+       devc->ch1_enabled = devc->ch2_enabled = FALSE;
+       for (l = sdi->channels, p = 0; l; l = l->next, p++) {
+               ch = l->data;
+               if (p == 0)
+                       devc->ch1_enabled = ch->enabled;
+               else
+                       devc->ch2_enabled = ch->enabled;
+               if (ch->enabled)
+                       devc->enabled_channels = g_slist_append(devc->enabled_channels, ch);
+       }
+
+       return SR_OK;
+}
+
+static void clear_dev_context(void *priv)
+{
+       struct dev_context *devc;
+
+       devc = priv;
+       g_free(devc->triggersource);
+       g_slist_free(devc->enabled_channels);
+
+}
+
+static int dev_clear(void)
+{
+       return std_dev_clear(di, clear_dev_context);
+}
+
+static int init(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       struct sr_dev_inst *sdi;
+       struct sr_usb_dev_inst *usb;
+       struct sr_config *src;
+       const struct dso_profile *prof;
+       GSList *l, *devices, *conn_devices;
+       struct libusb_device_descriptor des;
+       libusb_device **devlist;
+       int devcnt, ret, i, j;
+       const char *conn;
+
+       drvc = di->priv;
+
+       devcnt = 0;
+       devices = 0;
+
+       conn = NULL;
+       for (l = options; l; l = l->next) {
+               src = l->data;
+               if (src->key == SR_CONF_CONN) {
+                       conn = g_variant_get_string(src->data, NULL);
+                       break;
+               }
+       }
+       if (conn)
+               conn_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn);
+       else
+               conn_devices = NULL;
+
+       /* Find all Hantek DSO devices and upload firmware to all of them. */
+       libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
+       for (i = 0; devlist[i]; i++) {
+               if (conn) {
+                       usb = NULL;
+                       for (l = conn_devices; l; l = l->next) {
+                               usb = l->data;
+                               if (usb->bus == libusb_get_bus_number(devlist[i])
+                                       && usb->address == libusb_get_device_address(devlist[i]))
+                                       break;
+                       }
+                       if (!l)
+                               /* This device matched none of the ones that
+                                * matched the conn specification. */
+                               continue;
+               }
+
+               if ((ret = libusb_get_device_descriptor(devlist[i], &des))) {
+                       sr_err("Failed to get device descriptor: %s.",
+                                       libusb_error_name(ret));
+                       continue;
+               }
+
+               prof = NULL;
+               for (j = 0; dev_profiles[j].orig_vid; j++) {
+                       if (des.idVendor == dev_profiles[j].orig_vid
+                               && des.idProduct == dev_profiles[j].orig_pid) {
+                               /* Device matches the pre-firmware profile. */
+                               prof = &dev_profiles[j];
+                               sr_dbg("Found a %s %s.", prof->vendor, prof->model);
+                               sdi = dso_dev_new(devcnt, prof);
+                               devices = g_slist_append(devices, sdi);
+                               devc = sdi->priv;
+                               if (ezusb_upload_firmware(devlist[i], USB_CONFIGURATION,
+                                               prof->firmware) == SR_OK)
+                                       /* Remember when the firmware on this device was updated */
+                                       devc->fw_updated = g_get_monotonic_time();
+                               else
+                                       sr_err("Firmware upload failed for "
+                                               "device %d.", devcnt);
+                               /* Dummy USB address of 0xff will get overwritten later. */
+                               sdi->conn = sr_usb_dev_inst_new(
+                                               libusb_get_bus_number(devlist[i]), 0xff, NULL);
+                               devcnt++;
+                               break;
+                       } else if (des.idVendor == dev_profiles[j].fw_vid
+                               && des.idProduct == dev_profiles[j].fw_pid) {
+                               /* Device matches the post-firmware profile. */
+                               prof = &dev_profiles[j];
+                               sr_dbg("Found a %s %s.", prof->vendor, prof->model);
+                               sdi = dso_dev_new(devcnt, prof);
+                               sdi->status = SR_ST_INACTIVE;
+                               devices = g_slist_append(devices, sdi);
+                               devc = sdi->priv;
+                               sdi->inst_type = SR_INST_USB;
+                               sdi->conn = sr_usb_dev_inst_new(
+                                               libusb_get_bus_number(devlist[i]),
+                                               libusb_get_device_address(devlist[i]), NULL);
+                               devcnt++;
+                               break;
+                       }
+               }
+               if (!prof)
+                       /* not a supported VID/PID */
+                       continue;
+       }
+       libusb_free_device_list(devlist, 1);
+
+       return devices;
+}
+
+static GSList *dev_list(void)
+{
+       return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_usb_dev_inst *usb;
+       int64_t timediff_us, timediff_ms;
+       int err;
+
+       devc = sdi->priv;
+       usb = sdi->conn;
+
+       /*
+        * If the firmware was recently uploaded, wait up to MAX_RENUM_DELAY_MS
+        * for the FX2 to renumerate.
+        */
+       err = SR_ERR;
+       if (devc->fw_updated > 0) {
+               sr_info("Waiting for device to reset.");
+               /* Takes >= 300ms for the FX2 to be gone from the USB bus. */
+               g_usleep(300 * 1000);
+               timediff_ms = 0;
+               while (timediff_ms < MAX_RENUM_DELAY_MS) {
+                       if ((err = dso_open(sdi)) == SR_OK)
+                               break;
+                       g_usleep(100 * 1000);
+                       timediff_us = g_get_monotonic_time() - devc->fw_updated;
+                       timediff_ms = timediff_us / 1000;
+                       sr_spew("Waited %" PRIi64 " ms.", timediff_ms);
+               }
+               sr_info("Device came back after %d ms.", timediff_ms);
+       } else {
+               err = dso_open(sdi);
+       }
+
+       if (err != SR_OK) {
+               sr_err("Unable to open device.");
+               return SR_ERR;
+       }
+
+       err = libusb_claim_interface(usb->devhdl, USB_INTERFACE);
+       if (err != 0) {
+               sr_err("Unable to claim interface: %s.",
+                          libusb_error_name(err));
+               return SR_ERR;
+       }
+
+       return SR_OK;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+       dso_close(sdi);
+
+       return SR_OK;
+}
+
+static int cleanup(void)
+{
+       return dev_clear();
+}
+
+static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct sr_usb_dev_inst *usb;
+       char str[128];
+
+       (void)cg;
+
+       switch (id) {
+       case SR_CONF_CONN:
+               if (!sdi || !sdi->conn)
+                       return SR_ERR_ARG;
+               usb = sdi->conn;
+               if (usb->address == 255)
+                       /* Device still needs to re-enumerate after firmware
+                        * upload, so we don't know its (future) address. */
+                       return SR_ERR;
+               snprintf(str, 128, "%d.%d", usb->bus, usb->address);
+               *data = g_variant_new_string(str);
+               break;
+       case SR_CONF_NUM_TIMEBASE:
+               *data = g_variant_new_int32(NUM_TIMEBASE);
+               break;
+       case SR_CONF_NUM_VDIV:
+               *data = g_variant_new_int32(NUM_VDIV);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       double tmp_double;
+       uint64_t tmp_u64, p, q;
+       int tmp_int, ret;
+       unsigned int i;
+       const char *tmp_str;
+       char **targets;
+
+       (void)cg;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       ret = SR_OK;
+       devc = sdi->priv;
+       switch (id) {
+       case SR_CONF_LIMIT_FRAMES:
+               devc->limit_frames = g_variant_get_uint64(data);
+               break;
+       case SR_CONF_TRIGGER_SLOPE:
+               tmp_str = g_variant_get_string(data, NULL);
+               if (!tmp_str || !(tmp_str[0] == 'f' || tmp_str[0] == 'r'))
+                       return SR_ERR_ARG;
+               devc->triggerslope = (tmp_str[0] == 'r')
+                       ? SLOPE_POSITIVE : SLOPE_NEGATIVE;
+               break;
+       case SR_CONF_HORIZ_TRIGGERPOS:
+               tmp_double = g_variant_get_double(data);
+               if (tmp_double < 0.0 || tmp_double > 1.0) {
+                       sr_err("Trigger position should be between 0.0 and 1.0.");
+                       ret = SR_ERR_ARG;
+               } else
+                       devc->triggerposition = tmp_double;
+               break;
+       case SR_CONF_BUFFERSIZE:
+               tmp_u64 = g_variant_get_uint64(data);
+               for (i = 0; i < 2; i++) {
+                       if (devc->profile->buffersizes[i] == tmp_u64) {
+                               devc->framesize = tmp_u64;
+                               break;
+                       }
+               }
+               if (i == 2)
+                       ret = SR_ERR_ARG;
+               break;
+       case SR_CONF_TIMEBASE:
+               g_variant_get(data, "(tt)", &p, &q);
+               tmp_int = -1;
+               for (i = 0; i < ARRAY_SIZE(timebases); i++) {
+                       if (timebases[i][0] == p && timebases[i][1] == q) {
+                               tmp_int = i;
+                               break;
+                       }
+               }
+               if (tmp_int >= 0)
+                       devc->timebase = tmp_int;
+               else
+                       ret = SR_ERR_ARG;
+               break;
+       case SR_CONF_TRIGGER_SOURCE:
+               tmp_str = g_variant_get_string(data, NULL);
+               for (i = 0; trigger_sources[i]; i++) {
+                       if (!strcmp(tmp_str, trigger_sources[i])) {
+                               devc->triggersource = g_strdup(tmp_str);
+                               break;
+                       }
+               }
+               if (trigger_sources[i] == 0)
+                       ret = SR_ERR_ARG;
+               break;
+       case SR_CONF_FILTER:
+               tmp_str = g_variant_get_string(data, NULL);
+               devc->filter_ch1 = devc->filter_ch2 = devc->filter_trigger = 0;
+               targets = g_strsplit(tmp_str, ",", 0);
+               for (i = 0; targets[i]; i++) {
+                       if (targets[i] == '\0')
+                               /* Empty filter string can be used to clear them all. */
+                               ;
+                       else if (!strcmp(targets[i], "CH1"))
+                               devc->filter_ch1 = TRUE;
+                       else if (!strcmp(targets[i], "CH2"))
+                               devc->filter_ch2 = TRUE;
+                       else if (!strcmp(targets[i], "TRIGGER"))
+                               devc->filter_trigger = TRUE;
+                       else {
+                               sr_err("Invalid filter target %s.", targets[i]);
+                               ret = SR_ERR_ARG;
+                       }
+               }
+               g_strfreev(targets);
+               break;
+       case SR_CONF_VDIV:
+               /* TODO: Not supporting vdiv per channel yet. */
+               g_variant_get(data, "(tt)", &p, &q);
+               tmp_int = -1;
+               for (i = 0; i < ARRAY_SIZE(vdivs); i++) {
+                       if (vdivs[i][0] == p && vdivs[i][1] == q) {
+                               tmp_int = i;
+                               break;
+                       }
+               }
+               if (tmp_int >= 0) {
+                       devc->voltage_ch1 = tmp_int;
+                       devc->voltage_ch2 = tmp_int;
+               } else
+                       ret = SR_ERR_ARG;
+               break;
+       case SR_CONF_COUPLING:
+               tmp_str = g_variant_get_string(data, NULL);
+               /* TODO: Not supporting coupling per channel yet. */
+               for (i = 0; coupling[i]; i++) {
+                       if (!strcmp(tmp_str, coupling[i])) {
+                               devc->coupling_ch1 = i;
+                               devc->coupling_ch2 = i;
+                               break;
+                       }
+               }
+               if (coupling[i] == 0)
+                       ret = SR_ERR_ARG;
+               break;
+       default:
+               ret = SR_ERR_NA;
+               break;
+       }
+
+       return ret;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       GVariant *tuple, *rational[2];
+       GVariantBuilder gvb;
+       unsigned int i;
+
+       (void)cg;
+
+       switch (key) {
+       case SR_CONF_SCAN_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               scanopts, ARRAY_SIZE(scanopts), sizeof(int32_t));
+               break;
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               devopts, ARRAY_SIZE(devopts), sizeof(int32_t));
+               break;
+       case SR_CONF_BUFFERSIZE:
+               if (!sdi)
+                       return SR_ERR_ARG;
+               devc = sdi->priv;
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT64,
+                               devc->profile->buffersizes, 2, sizeof(uint64_t));
+               break;
+       case SR_CONF_COUPLING:
+               *data = g_variant_new_strv(coupling, ARRAY_SIZE(coupling));
+               break;
+       case SR_CONF_VDIV:
+               g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
+               for (i = 0; i < ARRAY_SIZE(vdivs); i++) {
+                       rational[0] = g_variant_new_uint64(vdivs[i][0]);
+                       rational[1] = g_variant_new_uint64(vdivs[i][1]);
+                       tuple = g_variant_new_tuple(rational, 2);
+                       g_variant_builder_add_value(&gvb, tuple);
+               }
+               *data = g_variant_builder_end(&gvb);
+               break;
+       case SR_CONF_FILTER:
+               *data = g_variant_new_strv(filter_targets,
+                               ARRAY_SIZE(filter_targets));
+               break;
+       case SR_CONF_TIMEBASE:
+               g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
+               for (i = 0; i < ARRAY_SIZE(timebases); i++) {
+                       rational[0] = g_variant_new_uint64(timebases[i][0]);
+                       rational[1] = g_variant_new_uint64(timebases[i][1]);
+                       tuple = g_variant_new_tuple(rational, 2);
+                       g_variant_builder_add_value(&gvb, tuple);
+               }
+               *data = g_variant_builder_end(&gvb);
+               break;
+       case SR_CONF_TRIGGER_SOURCE:
+               *data = g_variant_new_strv(trigger_sources,
+                               ARRAY_SIZE(trigger_sources));
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static void send_chunk(struct sr_dev_inst *sdi, unsigned char *buf,
+               int num_samples)
+{
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_analog analog;
+       struct dev_context *devc;
+       float ch1, ch2, range;
+       int num_channels, data_offset, i;
+
+       devc = sdi->priv;
+       num_channels = (devc->ch1_enabled && devc->ch2_enabled) ? 2 : 1;
+       packet.type = SR_DF_ANALOG;
+       packet.payload = &analog;
+       /* TODO: support for 5xxx series 9-bit samples */
+       analog.channels = devc->enabled_channels;
+       analog.num_samples = num_samples;
+       analog.mq = SR_MQ_VOLTAGE;
+       analog.unit = SR_UNIT_VOLT;
+       /* TODO: Check malloc return value. */
+       analog.data = g_try_malloc(analog.num_samples * sizeof(float) * num_channels);
+       data_offset = 0;
+       for (i = 0; i < analog.num_samples; i++) {
+               /*
+                * The device always sends data for both channels. If a channel
+                * is disabled, it contains a copy of the enabled channel's
+                * data. However, we only send the requested channels to
+                * the bus.
+                *
+                * Voltage values are encoded as a value 0-255 (0-512 on the
+                * DSO-5200*), where the value is a point in the range
+                * represented by the vdiv setting. There are 8 vertical divs,
+                * so e.g. 500mV/div represents 4V peak-to-peak where 0 = -2V
+                * and 255 = +2V.
+                */
+               /* TODO: Support for DSO-5xxx series 9-bit samples. */
+               if (devc->ch1_enabled) {
+                       range = ((float)vdivs[devc->voltage_ch1][0] / vdivs[devc->voltage_ch1][1]) * 8;
+                       ch1 = range / 255 * *(buf + i * 2 + 1);
+                       /* Value is centered around 0V. */
+                       ch1 -= range / 2;
+                       analog.data[data_offset++] = ch1;
+               }
+               if (devc->ch2_enabled) {
+                       range = ((float)vdivs[devc->voltage_ch2][0] / vdivs[devc->voltage_ch2][1]) * 8;
+                       ch2 = range / 255 * *(buf + i * 2);
+                       ch2 -= range / 2;
+                       analog.data[data_offset++] = ch2;
+               }
+       }
+       sr_session_send(devc->cb_data, &packet);
+}
+
+/*
+ * Called by libusb (as triggered by handle_event()) when a transfer comes in.
+ * Only channel data comes in asynchronously, and all transfers for this are
+ * queued up beforehand, so this just needs to chuck the incoming data onto
+ * the libsigrok session bus.
+ */
+static void receive_transfer(struct libusb_transfer *transfer)
+{
+       struct sr_datafeed_packet packet;
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       int num_samples, pre;
+
+       sdi = transfer->user_data;
+       devc = sdi->priv;
+       sr_spew("receive_transfer(): status %d received %d bytes.",
+                  transfer->status, transfer->actual_length);
+
+       if (transfer->actual_length == 0)
+               /* Nothing to send to the bus. */
+               return;
+
+       num_samples = transfer->actual_length / 2;
+
+       sr_spew("Got %d-%d/%d samples in frame.", devc->samp_received + 1,
+                  devc->samp_received + num_samples, devc->framesize);
+
+       /*
+        * The device always sends a full frame, but the beginning of the frame
+        * doesn't represent the trigger point. The offset at which the trigger
+        * happened came in with the capture state, so we need to start sending
+        * from there up the session bus. The samples in the frame buffer
+        * before that trigger point came after the end of the device's frame
+        * buffer was reached, and it wrapped around to overwrite up until the
+        * trigger point.
+        */
+       if (devc->samp_received < devc->trigger_offset) {
+               /* Trigger point not yet reached. */
+               if (devc->samp_received + num_samples < devc->trigger_offset) {
+                       /* The entire chunk is before the trigger point. */
+                       memcpy(devc->framebuf + devc->samp_buffered * 2,
+                                       transfer->buffer, num_samples * 2);
+                       devc->samp_buffered += num_samples;
+               } else {
+                       /*
+                        * This chunk hits or overruns the trigger point.
+                        * Store the part before the trigger fired, and
+                        * send the rest up to the session bus.
+                        */
+                       pre = devc->trigger_offset - devc->samp_received;
+                       memcpy(devc->framebuf + devc->samp_buffered * 2,
+                                       transfer->buffer, pre * 2);
+                       devc->samp_buffered += pre;
+
+                       /* The rest of this chunk starts with the trigger point. */
+                       sr_dbg("Reached trigger point, %d samples buffered.",
+                                  devc->samp_buffered);
+
+                       /* Avoid the corner case where the chunk ended at
+                        * exactly the trigger point. */
+                       if (num_samples > pre)
+                               send_chunk(sdi, transfer->buffer + pre * 2,
+                                               num_samples - pre);
+               }
+       } else {
+               /* Already past the trigger point, just send it all out. */
+               send_chunk(sdi, transfer->buffer,
+                               num_samples);
+       }
+
+       devc->samp_received += num_samples;
+
+       /* Everything in this transfer was either copied to the buffer or
+        * sent to the session bus. */
+       g_free(transfer->buffer);
+       libusb_free_transfer(transfer);
+
+       if (devc->samp_received >= devc->framesize) {
+               /* That was the last chunk in this frame. Send the buffered
+                * pre-trigger samples out now, in one big chunk. */
+               sr_dbg("End of frame, sending %d pre-trigger buffered samples.",
+                          devc->samp_buffered);
+               send_chunk(sdi, devc->framebuf, devc->samp_buffered);
+
+               /* Mark the end of this frame. */
+               packet.type = SR_DF_FRAME_END;
+               sr_session_send(devc->cb_data, &packet);
+
+               if (devc->limit_frames && ++devc->num_frames == devc->limit_frames) {
+                       /* Terminate session */
+                       devc->dev_state = STOPPING;
+               } else {
+                       devc->dev_state = NEW_CAPTURE;
+               }
+       }
+}
+
+static int handle_event(int fd, int revents, void *cb_data)
+{
+       const struct sr_dev_inst *sdi;
+       struct sr_datafeed_packet packet;
+       struct timeval tv;
+       struct dev_context *devc;
+       struct drv_context *drvc = di->priv;
+       int num_channels;
+       uint32_t trigger_offset;
+       uint8_t capturestate;
+
+       (void)fd;
+       (void)revents;
+
+       sdi = cb_data;
+       devc = sdi->priv;
+       if (devc->dev_state == STOPPING) {
+               /* We've been told to wind up the acquisition. */
+               sr_dbg("Stopping acquisition.");
+               /*
+                * TODO: Doesn't really cancel pending transfers so they might
+                * come in after SR_DF_END is sent.
+                */
+               usb_source_remove(sdi->session, drvc->sr_ctx);
+
+               packet.type = SR_DF_END;
+               sr_session_send(sdi, &packet);
+
+               devc->dev_state = IDLE;
+
+               return TRUE;
+       }
+
+       /* Always handle pending libusb events. */
+       tv.tv_sec = tv.tv_usec = 0;
+       libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
+
+       /* TODO: ugh */
+       if (devc->dev_state == NEW_CAPTURE) {
+               if (dso_capture_start(sdi) != SR_OK)
+                       return TRUE;
+               if (dso_enable_trigger(sdi) != SR_OK)
+                       return TRUE;
+//             if (dso_force_trigger(sdi) != SR_OK)
+//                     return TRUE;
+               sr_dbg("Successfully requested next chunk.");
+               devc->dev_state = CAPTURE;
+               return TRUE;
+       }
+       if (devc->dev_state != CAPTURE)
+               return TRUE;
+
+       if ((dso_get_capturestate(sdi, &capturestate, &trigger_offset)) != SR_OK)
+               return TRUE;
+
+       sr_dbg("Capturestate %d.", capturestate);
+       sr_dbg("Trigger offset 0x%.6x.", trigger_offset);
+       switch (capturestate) {
+       case CAPTURE_EMPTY:
+               if (++devc->capture_empty_count >= MAX_CAPTURE_EMPTY) {
+                       devc->capture_empty_count = 0;
+                       if (dso_capture_start(sdi) != SR_OK)
+                               break;
+                       if (dso_enable_trigger(sdi) != SR_OK)
+                               break;
+//                     if (dso_force_trigger(sdi) != SR_OK)
+//                             break;
+                       sr_dbg("Successfully requested next chunk.");
+               }
+               break;
+       case CAPTURE_FILLING:
+               /* No data yet. */
+               break;
+       case CAPTURE_READY_8BIT:
+               /* Remember where in the captured frame the trigger is. */
+               devc->trigger_offset = trigger_offset;
+
+               num_channels = (devc->ch1_enabled && devc->ch2_enabled) ? 2 : 1;
+               /* TODO: Check malloc return value. */
+               devc->framebuf = g_try_malloc(devc->framesize * num_channels * 2);
+               devc->samp_buffered = devc->samp_received = 0;
+
+               /* Tell the scope to send us the first frame. */
+               if (dso_get_channeldata(sdi, receive_transfer) != SR_OK)
+                       break;
+
+               /*
+                * Don't hit the state machine again until we're done fetching
+                * the data we just told the scope to send.
+                */
+               devc->dev_state = FETCH_DATA;
+
+               /* Tell the frontend a new frame is on the way. */
+               packet.type = SR_DF_FRAME_BEGIN;
+               sr_session_send(sdi, &packet);
+               break;
+       case CAPTURE_READY_9BIT:
+               /* TODO */
+               sr_err("Not yet supported.");
+               break;
+       case CAPTURE_TIMEOUT:
+               /* Doesn't matter, we'll try again next time. */
+               break;
+       default:
+               sr_dbg("Unknown capture state: %d.", capturestate);
+               break;
+       }
+
+       return TRUE;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct dev_context *devc;
+       struct drv_context *drvc = di->priv;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       devc = sdi->priv;
+       devc->cb_data = cb_data;
+
+       if (configure_channels(sdi) != SR_OK) {
+               sr_err("Failed to configure channels.");
+               return SR_ERR;
+       }
+
+       if (dso_init(sdi) != SR_OK)
+               return SR_ERR;
+
+       if (dso_capture_start(sdi) != SR_OK)
+               return SR_ERR;
+
+       devc->dev_state = CAPTURE;
+       usb_source_add(sdi->session, drvc->sr_ctx, TICK, handle_event, (void *)sdi);
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(cb_data, LOG_PREFIX);
+
+       return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct dev_context *devc;
+
+       (void)cb_data;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR;
+
+       devc = sdi->priv;
+       devc->dev_state = STOPPING;
+
+       return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver hantek_dso_driver_info = {
+       .name = "hantek-dso",
+       .longname = "Hantek DSO",
+       .api_version = 1,
+       .init = init,
+       .cleanup = cleanup,
+       .scan = scan,
+       .dev_list = dev_list,
+       .dev_clear = dev_clear,
+       .config_get = config_get,
+       .config_set = config_set,
+       .config_list = config_list,
+       .dev_open = dev_open,
+       .dev_close = dev_close,
+       .dev_acquisition_start = dev_acquisition_start,
+       .dev_acquisition_stop = dev_acquisition_stop,
+       .priv = NULL,
+};
diff --git a/src/hardware/hantek-dso/dso.c b/src/hardware/hantek-dso/dso.c
new file mode 100644 (file)
index 0000000..da5eb12
--- /dev/null
@@ -0,0 +1,787 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert@biot.com>
+ * With protocol information from the hantekdso project,
+ * Copyright (C) 2008 Oleg Khudyakov <prcoder@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 "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "dso.h"
+#include <string.h>
+#include <glib.h>
+#include <libusb.h>
+
+extern struct sr_dev_driver hantek_dso_driver_info;
+
+static int send_begin(const struct sr_dev_inst *sdi)
+{
+       struct sr_usb_dev_inst *usb;
+       int ret;
+       unsigned char buffer[] = {0x0f, 0x03, 0x03, 0x03, 0x68, 0xac, 0xfe,
+       0x00, 0x01, 0x00};
+
+       sr_dbg("Sending CTRL_BEGINCOMMAND.");
+
+       usb = sdi->conn;
+       if ((ret = libusb_control_transfer(usb->devhdl,
+                       LIBUSB_REQUEST_TYPE_VENDOR, CTRL_BEGINCOMMAND,
+                       0, 0, buffer, sizeof(buffer), 200)) != sizeof(buffer)) {
+               sr_err("Failed to send begincommand: %s.",
+                      libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+       return SR_OK;
+}
+
+static int send_bulkcmd(const struct sr_dev_inst *sdi, uint8_t *cmdstring, int cmdlen)
+{
+       struct sr_usb_dev_inst *usb;
+       int ret, tmp;
+
+       usb = sdi->conn;
+
+       if (send_begin(sdi) != SR_OK)
+               return SR_ERR;
+
+       if ((ret = libusb_bulk_transfer(usb->devhdl, DSO_EP_OUT, cmdstring,
+                       cmdlen, &tmp, 200)) != 0)
+               return SR_ERR;
+
+       return SR_OK;
+}
+
+static int dso_getmps(libusb_device *dev)
+{
+       struct libusb_device_descriptor des;
+       struct libusb_config_descriptor *conf_dsc;
+       const struct libusb_interface_descriptor *intf_dsc;
+       int mps;
+
+       if (libusb_get_device_descriptor(dev, &des) != 0)
+               return 0;
+
+       if (des.bNumConfigurations != 1)
+               return 0;
+
+       if (libusb_get_config_descriptor(dev, 0, &conf_dsc) != 0)
+               return 0;
+
+       mps = 0;
+       intf_dsc = &(conf_dsc->interface[0].altsetting[0]);
+       if (intf_dsc->bNumEndpoints != 2)
+               goto err;
+
+       if ((intf_dsc->endpoint[0].bEndpointAddress & 0x8f) !=
+           (2 | LIBUSB_ENDPOINT_OUT))
+               /* The first endpoint should be 2 (outbound). */
+               goto err;
+
+       if ((intf_dsc->endpoint[1].bEndpointAddress & 0x8f) !=
+           (6 | LIBUSB_ENDPOINT_IN))
+               /* The second endpoint should be 6 (inbound). */
+               goto err;
+
+       mps = intf_dsc->endpoint[1].wMaxPacketSize;
+
+err:
+       if (conf_dsc)
+               libusb_free_config_descriptor(conf_dsc);
+
+       return mps;
+}
+
+SR_PRIV int dso_open(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct drv_context *drvc = hantek_dso_driver_info.priv;
+       struct sr_usb_dev_inst *usb;
+       struct libusb_device_descriptor des;
+       libusb_device **devlist;
+       int err, skip, i;
+
+       devc = sdi->priv;
+       usb = sdi->conn;
+
+       if (sdi->status == SR_ST_ACTIVE)
+               /* already in use */
+               return SR_ERR;
+
+       skip = 0;
+       libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
+       for (i = 0; devlist[i]; i++) {
+               if ((err = libusb_get_device_descriptor(devlist[i], &des))) {
+                       sr_err("Failed to get device descriptor: %s.",
+                              libusb_error_name(err));
+                       continue;
+               }
+
+               if (des.idVendor != devc->profile->fw_vid
+                   || des.idProduct != devc->profile->fw_pid)
+                       continue;
+
+               if (sdi->status == SR_ST_INITIALIZING) {
+                       if (skip != sdi->index) {
+                               /* Skip devices of this type that aren't the one we want. */
+                               skip += 1;
+                               continue;
+                       }
+               } else if (sdi->status == SR_ST_INACTIVE) {
+                       /*
+                        * This device is fully enumerated, so we need to find
+                        * this device by vendor, product, bus and address.
+                        */
+                       if (libusb_get_bus_number(devlist[i]) != usb->bus
+                               || libusb_get_device_address(devlist[i]) != usb->address)
+                               /* this is not the one */
+                               continue;
+               }
+
+               if (!(err = libusb_open(devlist[i], &usb->devhdl))) {
+                       if (usb->address == 0xff)
+                               /*
+                                * first time we touch this device after firmware upload,
+                                * so we don't know the address yet.
+                                */
+                               usb->address = libusb_get_device_address(devlist[i]);
+
+                       if (!(devc->epin_maxpacketsize = dso_getmps(devlist[i])))
+                               sr_err("Wrong endpoint profile.");
+                       else {
+                               sdi->status = SR_ST_ACTIVE;
+                               sr_info("Opened device %d on %d.%d interface %d.",
+                                       sdi->index, usb->bus,
+                                       usb->address, USB_INTERFACE);
+                       }
+               } else {
+                       sr_err("Failed to open device: %s.",
+                              libusb_error_name(err));
+               }
+
+               /* If we made it here, we handled the device (somehow). */
+               break;
+       }
+       libusb_free_device_list(devlist, 1);
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR;
+
+       return SR_OK;
+}
+
+SR_PRIV void dso_close(struct sr_dev_inst *sdi)
+{
+       struct sr_usb_dev_inst *usb;
+
+       usb = sdi->conn;
+
+       if (usb->devhdl == NULL)
+               return;
+
+       sr_info("Closing device %d on %d.%d interface %d.", sdi->index,
+               usb->bus, usb->address, USB_INTERFACE);
+       libusb_release_interface(usb->devhdl, USB_INTERFACE);
+       libusb_close(usb->devhdl);
+       usb->devhdl = NULL;
+       sdi->status = SR_ST_INACTIVE;
+
+}
+
+static int get_channel_offsets(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_usb_dev_inst *usb;
+       GString *gs;
+       int chan, v, ret;
+
+       sr_dbg("Getting channel offsets.");
+
+       devc = sdi->priv;
+       usb = sdi->conn;
+
+       ret = libusb_control_transfer(usb->devhdl,
+                       LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR,
+                       CTRL_READ_EEPROM, EEPROM_CHANNEL_OFFSETS, 0,
+                       (unsigned char *)&devc->channel_levels,
+                       sizeof(devc->channel_levels), 200);
+       if (ret != sizeof(devc->channel_levels)) {
+               sr_err("Failed to get channel offsets: %s.",
+                      libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+       /* Comes in as 16-bit numbers with the second byte always 0 on
+        * the DSO-2090. Guessing this is supposed to be big-endian,
+        * since that's how voltage offsets are submitted back to the DSO.
+        * Convert to host order now, so we can use them natively.
+        */
+       for (chan = 0; chan < 2; chan++) {
+               for (v = 0; v < 9; v++) {
+                       devc->channel_levels[chan][v][0] =
+                               g_ntohs(devc->channel_levels[chan][v][0]);
+                       devc->channel_levels[chan][v][1] =
+                               g_ntohs(devc->channel_levels[chan][v][1]);
+               }
+       }
+
+       if (sr_log_loglevel_get() >= SR_LOG_DBG) {
+               gs = g_string_sized_new(128);
+               for (chan = 0; chan < 2; chan++) {
+                       g_string_printf(gs, "CH%d:", chan + 1);
+                       for (v = 0; v < 9; v++) {
+                               g_string_append_printf(gs, " %.4x-%.4x",
+                                       devc->channel_levels[chan][v][0],
+                                       devc->channel_levels[chan][v][1]);
+                       }
+                       sr_dbg("%s", gs->str);
+               }
+               g_string_free(gs, TRUE);
+       }
+
+       return SR_OK;
+}
+
+static int dso_set_trigger_samplerate(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_usb_dev_inst *usb;
+       int ret, tmp;
+       uint8_t cmdstring[12];
+       uint16_t timebase_small[] = { 0xffff, 0xfffc, 0xfff7, 0xffe8, 0xffce,
+               0xff9c, 0xff07, 0xfe0d, 0xfc19, 0xf63d, 0xec79, 0xd8f1 };
+       uint16_t timebase_large[] = { 0xffff, 0x0000, 0xfffc, 0xfff7, 0xffe8,
+               0xffce, 0xff9d, 0xff07, 0xfe0d, 0xfc19, 0xf63d, 0xec79 };
+
+       sr_dbg("Preparing CMD_SET_TRIGGER_SAMPLERATE.");
+
+       devc = sdi->priv;
+       usb = sdi->conn;
+
+       memset(cmdstring, 0, sizeof(cmdstring));
+       /* Command */
+       cmdstring[0] = CMD_SET_TRIGGER_SAMPLERATE;
+
+       /* Trigger source */
+       sr_dbg("Trigger source %s.", devc->triggersource);
+       if (!strcmp("CH2", devc->triggersource))
+               tmp = 0;
+       else if (!strcmp("CH1", devc->triggersource))
+               tmp = 1;
+       else if (!strcmp("EXT", devc->triggersource))
+               tmp = 2;
+       else {
+               sr_err("Invalid trigger source: '%s'.", devc->triggersource);
+               return SR_ERR_ARG;
+       }
+       cmdstring[2] = tmp;
+
+       /* Frame size */
+       sr_dbg("Frame size: %d.", devc->framesize);
+       cmdstring[2] |= (devc->framesize == FRAMESIZE_SMALL ? 0x01 : 0x02) << 2;
+
+       /* Timebase fast */
+       sr_dbg("Time base index: %d.", devc->timebase);
+       if (devc->framesize == FRAMESIZE_SMALL) {
+               if (devc->timebase < TIME_20us)
+                       tmp = 0;
+               else if (devc->timebase == TIME_20us)
+                       tmp = 1;
+               else if (devc->timebase == TIME_40us)
+                       tmp = 2;
+               else if (devc->timebase == TIME_100us)
+                       tmp = 3;
+               else if (devc->timebase >= TIME_200us)
+                       tmp = 4;
+       } else {
+               if (devc->timebase < TIME_40us) {
+                       sr_err("Timebase < 40us only supported with 10K buffer.");
+                       return SR_ERR_ARG;
+               }
+               else if (devc->timebase == TIME_40us)
+                       tmp = 0;
+               else if (devc->timebase == TIME_100us)
+                       tmp = 2;
+               else if (devc->timebase == TIME_200us)
+                       tmp = 3;
+               else if (devc->timebase >= TIME_400us)
+                       tmp = 4;
+       }
+       cmdstring[2] |= (tmp & 0x07) << 5;
+
+       /* Enabled channels: 00=CH1 01=CH2 10=both */
+       sr_dbg("Channels CH1=%d CH2=%d", devc->ch1_enabled, devc->ch2_enabled);
+       tmp = (((devc->ch2_enabled ? 1 : 0) << 1) + (devc->ch1_enabled ? 1 : 0)) - 1;
+       cmdstring[3] = tmp;
+
+       /* Fast rates channel */
+       /* TODO: Is this right? */
+       tmp = devc->timebase < TIME_10us ? 1 : 0;
+       cmdstring[3] |= tmp << 2;
+
+       /* Trigger slope: 0=positive 1=negative */
+       /* TODO: Does this work? */
+       sr_dbg("Trigger slope: %d.", devc->triggerslope);
+       cmdstring[3] |= (devc->triggerslope == SLOPE_NEGATIVE ? 1 : 0) << 3;
+
+       /* Timebase slow */
+       if (devc->timebase < TIME_100us)
+               tmp = 0;
+       else if (devc->timebase > TIME_400ms)
+               tmp = 0xffed;
+       else {
+               if (devc->framesize == FRAMESIZE_SMALL)
+                       tmp = timebase_small[devc->timebase - 3];
+               else
+                       tmp = timebase_large[devc->timebase - 3];
+       }
+       cmdstring[4] = tmp & 0xff;
+       cmdstring[5] = (tmp >> 8) & 0xff;
+
+       /* Horizontal trigger position */
+       sr_dbg("Trigger position: %3.2f.", devc->triggerposition);
+       tmp = 0x77fff + 0x8000 * devc->triggerposition;
+       cmdstring[6] = tmp & 0xff;
+       cmdstring[7] = (tmp >> 8) & 0xff;
+       cmdstring[10] = (tmp >> 16) & 0xff;
+
+       if (send_begin(sdi) != SR_OK)
+               return SR_ERR;
+
+       if ((ret = libusb_bulk_transfer(usb->devhdl, DSO_EP_OUT,
+                       cmdstring, sizeof(cmdstring), &tmp, 100)) != 0) {
+               sr_err("Failed to set trigger/samplerate: %s.",
+                      libusb_error_name(ret));
+               return SR_ERR;
+       }
+       sr_dbg("Sent CMD_SET_TRIGGER_SAMPLERATE.");
+
+       return SR_OK;
+}
+
+static int dso_set_filters(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_usb_dev_inst *usb;
+       int ret, tmp;
+       uint8_t cmdstring[8];
+
+       sr_dbg("Preparing CMD_SET_FILTERS.");
+
+       devc = sdi->priv;
+       usb = sdi->conn;
+
+       memset(cmdstring, 0, sizeof(cmdstring));
+       cmdstring[0] = CMD_SET_FILTERS;
+       cmdstring[1] = 0x0f;
+       if (devc->filter_ch1) {
+               sr_dbg("Turning on CH1 filter.");
+               cmdstring[2] |= 0x80;
+       }
+       if (devc->filter_ch2) {
+               sr_dbg("Turning on CH2 filter.");
+               cmdstring[2] |= 0x40;
+       }
+       if (devc->filter_trigger) {
+               /* TODO: supported on the DSO-2090? */
+               sr_dbg("Turning on trigger filter.");
+               cmdstring[2] |= 0x20;
+       }
+
+       if (send_begin(sdi) != SR_OK)
+               return SR_ERR;
+
+       if ((ret = libusb_bulk_transfer(usb->devhdl, DSO_EP_OUT,
+                       cmdstring, sizeof(cmdstring), &tmp, 100)) != 0) {
+               sr_err("Failed to set filters: %s.", libusb_error_name(ret));
+               return SR_ERR;
+       }
+       sr_dbg("Sent CMD_SET_FILTERS.");
+
+       return SR_OK;
+}
+
+static int dso_set_voltage(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_usb_dev_inst *usb;
+       int ret, tmp;
+       uint8_t cmdstring[8];
+
+       sr_dbg("Preparing CMD_SET_VOLTAGE.");
+
+       devc = sdi->priv;
+       usb = sdi->conn;
+
+       memset(cmdstring, 0, sizeof(cmdstring));
+       cmdstring[0] = CMD_SET_VOLTAGE;
+       cmdstring[1] = 0x0f;
+       cmdstring[2] = 0x30;
+
+       /* CH1 volts/div is encoded in bits 0-1 */
+       sr_dbg("CH1 vdiv index: %d.", devc->voltage_ch1);
+       switch (devc->voltage_ch1) {
+       case VDIV_1V:
+       case VDIV_100MV:
+       case VDIV_10MV:
+               cmdstring[2] |= 0x00;
+               break;
+       case VDIV_2V:
+       case VDIV_200MV:
+       case VDIV_20MV:
+               cmdstring[2] |= 0x01;
+               break;
+       case VDIV_5V:
+       case VDIV_500MV:
+       case VDIV_50MV:
+               cmdstring[2] |= 0x02;
+               break;
+       }
+
+       /* CH2 volts/div is encoded in bits 2-3 */
+       sr_dbg("CH2 vdiv index: %d.", devc->voltage_ch2);
+       switch (devc->voltage_ch2) {
+       case VDIV_1V:
+       case VDIV_100MV:
+       case VDIV_10MV:
+               cmdstring[2] |= 0x00;
+               break;
+       case VDIV_2V:
+       case VDIV_200MV:
+       case VDIV_20MV:
+               cmdstring[2] |= 0x04;
+               break;
+       case VDIV_5V:
+       case VDIV_500MV:
+       case VDIV_50MV:
+               cmdstring[2] |= 0x08;
+               break;
+       }
+
+       if (send_begin(sdi) != SR_OK)
+               return SR_ERR;
+
+       if ((ret = libusb_bulk_transfer(usb->devhdl, DSO_EP_OUT,
+                       cmdstring, sizeof(cmdstring), &tmp, 100)) != 0) {
+               sr_err("Failed to set voltage: %s.", libusb_error_name(ret));
+               return SR_ERR;
+       }
+       sr_dbg("Sent CMD_SET_VOLTAGE.");
+
+       return SR_OK;
+}
+
+static int dso_set_relays(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_usb_dev_inst *usb;
+       GString *gs;
+       int ret, i;
+       uint8_t relays[17] = { 0x00, 0x04, 0x08, 0x02, 0x20, 0x40, 0x10, 0x01,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+       sr_dbg("Preparing CTRL_SETRELAYS.");
+
+       devc = sdi->priv;
+       usb = sdi->conn;
+
+       if (devc->voltage_ch1 < VDIV_1V)
+               relays[1] = ~relays[1];
+
+       if (devc->voltage_ch1 < VDIV_100MV)
+               relays[2] = ~relays[2];
+
+       sr_dbg("CH1 coupling: %d.", devc->coupling_ch1);
+       if (devc->coupling_ch1 != COUPLING_AC)
+               relays[3] = ~relays[3];
+
+       if (devc->voltage_ch2 < VDIV_1V)
+               relays[4] = ~relays[4];
+
+       if (devc->voltage_ch2 < VDIV_100MV)
+               relays[5] = ~relays[5];
+
+       sr_dbg("CH2 coupling: %d.", devc->coupling_ch1);
+       if (devc->coupling_ch2 != COUPLING_AC)
+               relays[6] = ~relays[6];
+
+       if (!strcmp(devc->triggersource, "EXT"))
+               relays[7] = ~relays[7];
+
+       if (sr_log_loglevel_get() >= SR_LOG_DBG) {
+               gs = g_string_sized_new(128);
+               g_string_printf(gs, "Relays:");
+               for (i = 0; i < 17; i++)
+                       g_string_append_printf(gs, " %.2x", relays[i]);
+               sr_dbg("%s", gs->str);
+               g_string_free(gs, TRUE);
+       }
+
+       if ((ret = libusb_control_transfer(usb->devhdl,
+                       LIBUSB_REQUEST_TYPE_VENDOR, CTRL_SETRELAYS,
+                       0, 0, relays, 17, 100)) != sizeof(relays)) {
+               sr_err("Failed to set relays: %s.", libusb_error_name(ret));
+               return SR_ERR;
+       }
+       sr_dbg("Sent CTRL_SETRELAYS.");
+
+       return SR_OK;
+}
+
+static int dso_set_voffsets(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_usb_dev_inst *usb;
+       int offset, ret;
+       uint16_t *ch_levels;
+       uint8_t offsets[17];
+
+       sr_dbg("Preparing CTRL_SETOFFSET.");
+
+       devc = sdi->priv;
+       usb = sdi->conn;
+
+       memset(offsets, 0, sizeof(offsets));
+       /* Channel 1 */
+       ch_levels = devc->channel_levels[0][devc->voltage_ch1];
+       offset = (ch_levels[1] - ch_levels[0]) * devc->voffset_ch1 + ch_levels[0];
+       offsets[0] = (offset >> 8) | 0x20;
+       offsets[1] = offset & 0xff;
+       sr_dbg("CH1 offset: %3.2f (%.2x%.2x).", devc->voffset_ch1,
+              offsets[0], offsets[1]);
+
+       /* Channel 2 */
+       ch_levels = devc->channel_levels[1][devc->voltage_ch2];
+       offset = (ch_levels[1] - ch_levels[0]) * devc->voffset_ch2 + ch_levels[0];
+       offsets[2] = (offset >> 8) | 0x20;
+       offsets[3] = offset & 0xff;
+       sr_dbg("CH2 offset: %3.2f (%.2x%.2x).", devc->voffset_ch2,
+              offsets[2], offsets[3]);
+
+       /* Trigger */
+       offset = MAX_VERT_TRIGGER * devc->voffset_trigger;
+       offsets[4] = (offset >> 8) | 0x20;
+       offsets[5] = offset & 0xff;
+       sr_dbg("Trigger offset: %3.2f (%.2x%.2x).", devc->voffset_trigger,
+                       offsets[4], offsets[5]);
+
+       if ((ret = libusb_control_transfer(usb->devhdl,
+                       LIBUSB_REQUEST_TYPE_VENDOR, CTRL_SETOFFSET,
+                       0, 0, offsets, sizeof(offsets), 100)) != sizeof(offsets)) {
+               sr_err("Failed to set offsets: %s.", libusb_error_name(ret));
+               return SR_ERR;
+       }
+       sr_dbg("Sent CTRL_SETOFFSET.");
+
+       return SR_OK;
+}
+
+SR_PRIV int dso_enable_trigger(const struct sr_dev_inst *sdi)
+{
+       struct sr_usb_dev_inst *usb;
+       int ret, tmp;
+       uint8_t cmdstring[2];
+
+       sr_dbg("Sending CMD_ENABLE_TRIGGER.");
+
+       usb = sdi->conn;
+
+       memset(cmdstring, 0, sizeof(cmdstring));
+       cmdstring[0] = CMD_ENABLE_TRIGGER;
+       cmdstring[1] = 0x00;
+
+       if (send_begin(sdi) != SR_OK)
+               return SR_ERR;
+
+       if ((ret = libusb_bulk_transfer(usb->devhdl, DSO_EP_OUT,
+                       cmdstring, sizeof(cmdstring), &tmp, 100)) != 0) {
+               sr_err("Failed to enable trigger: %s.", libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+       return SR_OK;
+}
+
+SR_PRIV int dso_force_trigger(const struct sr_dev_inst *sdi)
+{
+       struct sr_usb_dev_inst *usb;
+       int ret, tmp;
+       uint8_t cmdstring[2];
+
+       sr_dbg("Sending CMD_FORCE_TRIGGER.");
+
+       usb = sdi->conn;
+
+       memset(cmdstring, 0, sizeof(cmdstring));
+       cmdstring[0] = CMD_FORCE_TRIGGER;
+       cmdstring[1] = 0x00;
+
+       if (send_begin(sdi) != SR_OK)
+               return SR_ERR;
+
+       if ((ret = libusb_bulk_transfer(usb->devhdl, DSO_EP_OUT,
+                       cmdstring, sizeof(cmdstring), &tmp, 100)) != 0) {
+               sr_err("Failed to force trigger: %s.", libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+       return SR_OK;
+}
+
+SR_PRIV int dso_init(const struct sr_dev_inst *sdi)
+{
+
+       sr_dbg("Initializing DSO.");
+
+       if (get_channel_offsets(sdi) != SR_OK)
+               return SR_ERR;
+
+       if (dso_set_trigger_samplerate(sdi) != SR_OK)
+               return SR_ERR;
+
+       if (dso_set_filters(sdi) != SR_OK)
+               return SR_ERR;
+
+       if (dso_set_voltage(sdi) != SR_OK)
+               return SR_ERR;
+
+       if (dso_set_relays(sdi) != SR_OK)
+               return SR_ERR;
+
+       if (dso_set_voffsets(sdi) != SR_OK)
+               return SR_ERR;
+
+       if (dso_enable_trigger(sdi) != SR_OK)
+               return SR_ERR;
+
+       return SR_OK;
+}
+
+SR_PRIV int dso_get_capturestate(const struct sr_dev_inst *sdi,
+               uint8_t *capturestate, uint32_t *trigger_offset)
+{
+       struct sr_usb_dev_inst *usb;
+       int ret, tmp, i;
+       unsigned int bitvalue, toff;
+       uint8_t cmdstring[2], inbuf[512];
+
+       sr_dbg("Sending CMD_GET_CAPTURESTATE.");
+
+       usb = sdi->conn;
+
+       cmdstring[0] = CMD_GET_CAPTURESTATE;
+       cmdstring[1] = 0;
+
+       if ((ret = send_bulkcmd(sdi, cmdstring, sizeof(cmdstring))) != SR_OK) {
+               sr_dbg("Failed to send get_capturestate command: %s.",
+                      libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+       if ((ret = libusb_bulk_transfer(usb->devhdl, DSO_EP_IN,
+                       inbuf, 512, &tmp, 100)) != 0) {
+               sr_dbg("Failed to get capturestate: %s.",
+                      libusb_error_name(ret));
+               return SR_ERR;
+       }
+       *capturestate = inbuf[0];
+       toff = (inbuf[1] << 16) | (inbuf[3] << 8) | inbuf[2];
+
+       /*
+        * This conversion comes from the openhantek project.
+        * Each set bit in the 24-bit value inverts all bits with a lower
+        * value. No idea why the device reports the trigger point this way.
+        */
+       bitvalue = 1;
+       for (i = 0; i < 24; i++) {
+               /* Each set bit inverts all bits with a lower value. */
+               if(toff & bitvalue)
+                       toff ^= bitvalue - 1;
+               bitvalue <<= 1;
+       }
+       *trigger_offset = toff;
+
+       return SR_OK;
+}
+
+SR_PRIV int dso_capture_start(const struct sr_dev_inst *sdi)
+{
+       int ret;
+       uint8_t cmdstring[2];
+
+       sr_dbg("Sending CMD_CAPTURE_START.");
+
+       cmdstring[0] = CMD_CAPTURE_START;
+       cmdstring[1] = 0;
+
+       if ((ret = send_bulkcmd(sdi, cmdstring, sizeof(cmdstring))) != SR_OK) {
+               sr_err("Failed to send capture_start command: %s.",
+                      libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+       return SR_OK;
+}
+
+SR_PRIV int dso_get_channeldata(const struct sr_dev_inst *sdi,
+               libusb_transfer_cb_fn cb)
+{
+       struct dev_context *devc;
+       struct sr_usb_dev_inst *usb;
+       struct libusb_transfer *transfer;
+       int num_transfers, ret, i;
+       uint8_t cmdstring[2];
+       unsigned char *buf;
+
+       sr_dbg("Sending CMD_GET_CHANNELDATA.");
+
+       devc = sdi->priv;
+       usb = sdi->conn;
+
+       cmdstring[0] = CMD_GET_CHANNELDATA;
+       cmdstring[1] = 0;
+
+       if ((ret = send_bulkcmd(sdi, cmdstring, sizeof(cmdstring))) != SR_OK) {
+               sr_err("Failed to get channel data: %s.",
+                      libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+       /* TODO: DSO-2xxx only. */
+       num_transfers = devc->framesize *
+                       sizeof(unsigned short) / devc->epin_maxpacketsize;
+       sr_dbg("Queueing up %d transfers.", num_transfers);
+       for (i = 0; i < num_transfers; i++) {
+               if (!(buf = g_try_malloc(devc->epin_maxpacketsize))) {
+                       sr_err("Failed to malloc USB endpoint buffer.");
+                       return SR_ERR_MALLOC;
+               }
+               transfer = libusb_alloc_transfer(0);
+               libusb_fill_bulk_transfer(transfer, usb->devhdl, DSO_EP_IN, buf,
+                               devc->epin_maxpacketsize, cb, (void *)sdi, 40);
+               if ((ret = libusb_submit_transfer(transfer)) != 0) {
+                       sr_err("Failed to submit transfer: %s.",
+                              libusb_error_name(ret));
+                       /* TODO: Free them all. */
+                       libusb_free_transfer(transfer);
+                       g_free(buf);
+                       return SR_ERR;
+               }
+       }
+
+       return SR_OK;
+}
diff --git a/src/hardware/hantek-dso/dso.h b/src/hardware/hantek-dso/dso.h
new file mode 100644 (file)
index 0000000..edccb72
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert@biot.com>
+ * With protocol information from the hantekdso project,
+ * Copyright (C) 2008 Oleg Khudyakov <prcoder@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_HANTEK_DSO_DSO_H
+#define LIBSIGROK_HARDWARE_HANTEK_DSO_DSO_H
+
+#define LOG_PREFIX "hantek-dso"
+
+#define USB_INTERFACE           0
+#define USB_CONFIGURATION       1
+#define DSO_EP_IN               0x86
+#define DSO_EP_OUT              0x02
+
+/* FX2 renumeration delay in ms */
+#define MAX_RENUM_DELAY_MS      3000
+
+#define MAX_CAPTURE_EMPTY       3
+
+#define DEFAULT_VOLTAGE         VDIV_500MV
+#define DEFAULT_FRAMESIZE       FRAMESIZE_SMALL
+#define DEFAULT_TIMEBASE        TIME_100us
+#define DEFAULT_TRIGGER_SOURCE  "CH1"
+#define DEFAULT_COUPLING        COUPLING_DC
+#define DEFAULT_HORIZ_TRIGGERPOS 0.5
+#define DEFAULT_VERT_OFFSET     0.5
+#define DEFAULT_VERT_TRIGGERPOS 0.5
+
+#define MAX_VERT_TRIGGER        0xfe
+
+/* Hantek DSO-specific protocol values */
+#define EEPROM_CHANNEL_OFFSETS  0x08
+
+/* All models have this for their "fast" mode. */
+#define FRAMESIZE_SMALL         10240
+
+enum control_requests {
+       CTRL_READ_EEPROM = 0xa2,
+       CTRL_GETSPEED = 0xb2,
+       CTRL_BEGINCOMMAND = 0xb3,
+       CTRL_SETOFFSET = 0xb4,
+       CTRL_SETRELAYS = 0xb5,
+};
+
+enum dso_commands {
+       CMD_SET_FILTERS = 0,
+       CMD_SET_TRIGGER_SAMPLERATE,
+       CMD_FORCE_TRIGGER,
+       CMD_CAPTURE_START,
+       CMD_ENABLE_TRIGGER,
+       CMD_GET_CHANNELDATA,
+       CMD_GET_CAPTURESTATE,
+       CMD_SET_VOLTAGE,
+       /* unused */
+       CMD_SET_LOGICALDATA,
+       CMD_GET_LOGICALDATA,
+};
+
+/* Must match the coupling table. */
+enum couplings {
+       COUPLING_AC = 0,
+       COUPLING_DC,
+       /* TODO not used, how to enable? */
+       COUPLING_GND,
+};
+
+/* Must match the timebases table. */
+enum time_bases {
+       TIME_10us = 0,
+       TIME_20us,
+       TIME_40us,
+       TIME_100us,
+       TIME_200us,
+       TIME_400us,
+       TIME_1ms,
+       TIME_2ms,
+       TIME_4ms,
+       TIME_10ms,
+       TIME_20ms,
+       TIME_40ms,
+       TIME_100ms,
+       TIME_200ms,
+       TIME_400ms,
+};
+
+/* Must match the vdivs table. */
+enum {
+       VDIV_10MV,
+       VDIV_20MV,
+       VDIV_50MV,
+       VDIV_100MV,
+       VDIV_200MV,
+       VDIV_500MV,
+       VDIV_1V,
+       VDIV_2V,
+       VDIV_5V,
+};
+
+enum trigger_slopes {
+       SLOPE_POSITIVE = 0,
+       SLOPE_NEGATIVE,
+};
+
+enum trigger_sources {
+       TRIGGER_CH2 = 0,
+       TRIGGER_CH1,
+       TRIGGER_EXT,
+};
+
+enum capturestates {
+       CAPTURE_EMPTY = 0,
+       CAPTURE_FILLING = 1,
+       CAPTURE_READY_8BIT = 2,
+       CAPTURE_READY_9BIT = 7,
+       CAPTURE_TIMEOUT = 127,
+       CAPTURE_UNKNOWN = 255,
+};
+
+enum triggermodes {
+       TRIGGERMODE_AUTO,
+       TRIGGERMODE_NORMAL,
+       TRIGGERMODE_SINGLE,
+};
+
+enum states {
+       IDLE,
+       NEW_CAPTURE,
+       CAPTURE,
+       FETCH_DATA,
+       STOPPING,
+};
+
+struct dso_profile {
+       /* VID/PID after cold boot */
+       uint16_t orig_vid;
+       uint16_t orig_pid;
+       /* VID/PID after firmware upload */
+       uint16_t fw_vid;
+       uint16_t fw_pid;
+       char *vendor;
+       char *model;
+       const uint64_t *buffersizes;
+       char *firmware;
+};
+
+struct dev_context {
+       const struct dso_profile *profile;
+       void *cb_data;
+       uint64_t limit_frames;
+       uint64_t num_frames;
+       GSList *enabled_channels;
+       /* We can't keep track of an FX2-based device after upgrading
+        * the firmware (it re-enumerates into a different device address
+        * after the upgrade) this is like a global lock. No device will open
+        * until a proper delay after the last device was upgraded.
+        */
+       int64_t fw_updated;
+       int epin_maxpacketsize;
+       int capture_empty_count;
+       int dev_state;
+
+       /* Oscilloscope settings. */
+       int timebase;
+       gboolean ch1_enabled;
+       gboolean ch2_enabled;
+       int voltage_ch1;
+       int voltage_ch2;
+       int coupling_ch1;
+       int coupling_ch2;
+       // voltage offset (vertical position)
+       float voffset_ch1;
+       float voffset_ch2;
+       float voffset_trigger;
+       uint16_t channel_levels[2][9][2];
+       unsigned int framesize;
+       gboolean filter_ch1;
+       gboolean filter_ch2;
+       gboolean filter_trigger;
+       int triggerslope;
+       char *triggersource;
+       float triggerposition;
+       int triggermode;
+
+       /* Frame transfer */
+       unsigned int samp_received;
+       unsigned int samp_buffered;
+       unsigned int trigger_offset;
+       unsigned char *framebuf;
+};
+
+SR_PRIV int dso_open(struct sr_dev_inst *sdi);
+SR_PRIV void dso_close(struct sr_dev_inst *sdi);
+SR_PRIV int dso_enable_trigger(const struct sr_dev_inst *sdi);
+SR_PRIV int dso_force_trigger(const struct sr_dev_inst *sdi);
+SR_PRIV int dso_init(const struct sr_dev_inst *sdi);
+SR_PRIV int dso_get_capturestate(const struct sr_dev_inst *sdi,
+               uint8_t *capturestate, uint32_t *trigger_offset);
+SR_PRIV int dso_capture_start(const struct sr_dev_inst *sdi);
+SR_PRIV int dso_get_channeldata(const struct sr_dev_inst *sdi,
+               libusb_transfer_cb_fn cb);
+
+#endif
diff --git a/src/hardware/ikalogic-scanalogic2/api.c b/src/hardware/ikalogic-scanalogic2/api.c
new file mode 100644 (file)
index 0000000..b4c697f
--- /dev/null
@@ -0,0 +1,537 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Marc Schink <sigrok-dev@marcschink.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 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"
+
+static const int hwcaps[] = {
+       SR_CONF_LOGIC_ANALYZER,
+       SR_CONF_SAMPLERATE,
+       SR_CONF_LIMIT_SAMPLES,
+       SR_CONF_TRIGGER_MATCH,
+       SR_CONF_CAPTURE_RATIO,
+};
+
+static const int32_t trigger_matches[] = {
+       SR_TRIGGER_RISING,
+       SR_TRIGGER_FALLING,
+       SR_TRIGGER_EDGE,
+};
+
+SR_PRIV const uint64_t sl2_samplerates[NUM_SAMPLERATES] = {
+       SR_KHZ(1.25),
+       SR_KHZ(10),
+       SR_KHZ(50),
+       SR_KHZ(100),
+       SR_KHZ(250),
+       SR_KHZ(500),
+       SR_MHZ(1),
+       SR_MHZ(2.5),
+       SR_MHZ(5),
+       SR_MHZ(10),
+       SR_MHZ(20),
+};
+
+static const char *channel_names[NUM_CHANNELS + 1] = {
+       "0", "1", "2", "3",
+       NULL,
+};
+
+SR_PRIV struct sr_dev_driver ikalogic_scanalogic2_driver_info;
+static struct sr_dev_driver *di = &ikalogic_scanalogic2_driver_info;
+
+static int init(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+       GSList *usb_devices, *devices, *l;
+       struct drv_context *drvc;
+       struct sr_dev_inst *sdi;
+       struct sr_channel *ch;
+       struct dev_context *devc;
+       struct sr_usb_dev_inst *usb;
+       struct device_info dev_info;
+       int ret, device_index, i;
+       char *fw_ver_str;
+
+       (void)options;
+
+       devices = NULL;
+       drvc = di->priv;
+       drvc->instances = NULL;
+       device_index = 0;
+
+       usb_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, USB_VID_PID);
+
+       if (usb_devices == NULL)
+               return NULL;
+
+       for (l = usb_devices; l; l = l->next) {
+               usb = l->data;
+
+               if ((ret = sl2_get_device_info(*usb, &dev_info)) < 0) {
+                       sr_warn("Failed to get device information: %d.", ret);
+                       sr_usb_dev_inst_free(usb);
+                       continue;
+               }
+
+               if (!(devc = g_try_malloc(sizeof(struct dev_context)))) {
+                       sr_err("Device instance malloc failed.");
+                       sr_usb_dev_inst_free(usb);
+                       continue;
+               }
+
+               if (!(devc->xfer_in = libusb_alloc_transfer(0))) {
+                       sr_err("Transfer malloc failed.");
+                       sr_usb_dev_inst_free(usb);
+                       g_free(devc);
+                       continue;
+               }
+
+               if (!(devc->xfer_out = libusb_alloc_transfer(0))) {
+                       sr_err("Transfer malloc failed.");
+                       sr_usb_dev_inst_free(usb);
+                       libusb_free_transfer(devc->xfer_in);
+                       g_free(devc);
+                       continue;
+               }
+
+               fw_ver_str = g_strdup_printf("%u.%u", dev_info.fw_ver_major,
+                       dev_info.fw_ver_minor);
+               if (!fw_ver_str) {
+                       sr_err("Firmware string malloc failed.");
+                       sr_usb_dev_inst_free(usb);
+                       libusb_free_transfer(devc->xfer_in);
+                       libusb_free_transfer(devc->xfer_out);
+                       g_free(devc);
+                       continue;
+               }
+
+               sdi = sr_dev_inst_new(device_index, SR_ST_INACTIVE, VENDOR_NAME,
+                       MODEL_NAME, fw_ver_str);
+               g_free(fw_ver_str);
+               if (!sdi) {
+                       sr_err("sr_dev_inst_new failed.");
+                       sr_usb_dev_inst_free(usb);
+                       libusb_free_transfer(devc->xfer_in);
+                       libusb_free_transfer(devc->xfer_out);
+                       g_free(devc);
+                       continue;
+               }
+
+               sdi->priv = devc;
+               sdi->driver = di;
+               sdi->inst_type = SR_INST_USB;
+               sdi->conn = usb;
+
+               for (i = 0; channel_names[i]; i++) {
+                       ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE,
+                               channel_names[i]);
+                       sdi->channels = g_slist_append(sdi->channels, ch);
+                       devc->channels[i] = ch;
+               }
+
+               devc->state = STATE_IDLE;
+               devc->next_state = STATE_IDLE;
+
+               /* Set default samplerate. */
+               sl2_set_samplerate(sdi, DEFAULT_SAMPLERATE);
+
+               /* Set default capture ratio. */
+               devc->capture_ratio = 0;
+
+               /* Set default after trigger delay. */
+               devc->after_trigger_delay = 0;
+
+               memset(devc->xfer_buf_in, 0, LIBUSB_CONTROL_SETUP_SIZE +
+                       PACKET_LENGTH);
+               memset(devc->xfer_buf_out, 0, LIBUSB_CONTROL_SETUP_SIZE +
+                       PACKET_LENGTH);
+
+               libusb_fill_control_setup(devc->xfer_buf_in,
+                       USB_REQUEST_TYPE_IN, USB_HID_GET_REPORT,
+                       USB_HID_REPORT_TYPE_FEATURE, USB_INTERFACE,
+                       PACKET_LENGTH);
+               libusb_fill_control_setup(devc->xfer_buf_out,
+                       USB_REQUEST_TYPE_OUT, USB_HID_SET_REPORT,
+                       USB_HID_REPORT_TYPE_FEATURE, USB_INTERFACE,
+                       PACKET_LENGTH);
+
+               devc->xfer_data_in = devc->xfer_buf_in +
+                       LIBUSB_CONTROL_SETUP_SIZE;
+               devc->xfer_data_out = devc->xfer_buf_out +
+                       LIBUSB_CONTROL_SETUP_SIZE;
+
+               drvc->instances = g_slist_append(drvc->instances, sdi);
+               devices = g_slist_append(devices, sdi);
+
+               device_index++;
+       }
+
+       g_slist_free(usb_devices);
+
+       return devices;
+}
+
+static GSList *dev_list(void)
+{
+       return ((struct drv_context *)(di->priv))->instances;
+}
+
+static void clear_dev_context(void *priv)
+{
+       struct dev_context *devc;
+
+       devc = priv;
+
+       sr_dbg("Device context cleared.");
+
+       libusb_free_transfer(devc->xfer_in);
+       libusb_free_transfer(devc->xfer_out);
+       g_free(devc);
+}
+
+static int dev_clear(void)
+{
+       return std_dev_clear(di, &clear_dev_context);
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       struct sr_usb_dev_inst *usb;
+       uint8_t buffer[PACKET_LENGTH];
+       int ret;
+
+       if (!(drvc = di->priv)) {
+               sr_err("Driver was not initialized.");
+               return SR_ERR;
+       }
+
+       usb = sdi->conn;
+       devc = sdi->priv;
+
+       if (sr_usb_open(drvc->sr_ctx->libusb_ctx, usb) != SR_OK)
+               return SR_ERR;
+
+       /*
+        * Determine if a kernel driver is active on this interface and, if so,
+        * detach it.
+        */
+       if (libusb_kernel_driver_active(usb->devhdl, USB_INTERFACE) == 1) {
+               ret = libusb_detach_kernel_driver(usb->devhdl, USB_INTERFACE);
+               if (ret < 0) {
+                       sr_err("Failed to detach kernel driver: %s.",
+                               libusb_error_name(ret));
+                       return SR_ERR;
+               }
+       }
+
+       if ((ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE)) < 0) {
+               sr_err("Failed to claim interface: %s.",
+                       libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+       libusb_fill_control_transfer(devc->xfer_in, usb->devhdl,
+               devc->xfer_buf_in, sl2_receive_transfer_in,
+               sdi, USB_TIMEOUT);
+
+       libusb_fill_control_transfer(devc->xfer_out, usb->devhdl,
+               devc->xfer_buf_out, sl2_receive_transfer_out,
+               sdi, USB_TIMEOUT);
+
+       memset(buffer, 0, sizeof(buffer));
+
+       buffer[0] = CMD_RESET;
+       if ((ret = sl2_transfer_out(usb->devhdl, buffer)) != PACKET_LENGTH) {
+               sr_err("Device reset failed: %s.", libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+       /*
+        * Set the device to idle state. If the device is not in idle state it
+        * possibly will reset itself after a few seconds without being used
+        * and thereby close the connection.
+        */
+       buffer[0] = CMD_IDLE;
+       if ((ret = sl2_transfer_out(usb->devhdl, buffer)) != PACKET_LENGTH) {
+               sr_err("Failed to set device in idle state: %s.",
+                       libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+       sdi->status = SR_ST_ACTIVE;
+
+       return SR_OK;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+       struct sr_usb_dev_inst *usb;
+
+       if (!di->priv) {
+               sr_err("Driver was not initialized.");
+               return SR_ERR;
+       }
+
+       usb = sdi->conn;
+
+       if (!usb->devhdl)
+               return SR_OK;
+
+       libusb_release_interface(usb->devhdl, USB_INTERFACE);
+       libusb_close(usb->devhdl);
+
+       usb->devhdl = NULL;
+       sdi->status = SR_ST_INACTIVE;
+
+       return SR_OK;
+}
+
+static int cleanup(void)
+{
+       return dev_clear();
+}
+
+static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       int ret;
+
+       (void)cg;
+
+       ret = SR_OK;
+       devc = sdi->priv;
+
+       switch (key) {
+       case SR_CONF_SAMPLERATE:
+               *data = g_variant_new_uint64(devc->samplerate);
+               break;
+       case SR_CONF_CAPTURE_RATIO:
+               *data = g_variant_new_uint64(devc->capture_ratio);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return ret;
+}
+
+static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       uint64_t samplerate, limit_samples, capture_ratio;
+       int ret;
+
+       (void)cg;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       ret = SR_OK;
+
+       switch (key) {
+       case SR_CONF_LIMIT_SAMPLES:
+               limit_samples = g_variant_get_uint64(data);
+               ret = sl2_set_limit_samples(sdi, limit_samples);
+               break;
+       case SR_CONF_SAMPLERATE:
+               samplerate = g_variant_get_uint64(data);
+               ret = sl2_set_samplerate(sdi, samplerate);
+               break;
+       case SR_CONF_CAPTURE_RATIO:
+               capture_ratio = g_variant_get_uint64(data);
+               ret = sl2_set_capture_ratio(sdi, capture_ratio);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return ret;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       GVariant *gvar, *grange[2];
+       GVariantBuilder gvb;
+       int ret;
+
+       (void)sdi;
+       (void)cg;
+
+       ret = SR_OK;
+
+       switch (key) {
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, hwcaps,
+                       ARRAY_SIZE(hwcaps), sizeof(int32_t));
+               break;
+       case SR_CONF_SAMPLERATE:
+               g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
+               gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"),
+                       sl2_samplerates, ARRAY_SIZE(sl2_samplerates),
+                       sizeof(uint64_t));
+               g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar);
+               *data = g_variant_builder_end(&gvb);
+               break;
+       case SR_CONF_TRIGGER_MATCH:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               trigger_matches, ARRAY_SIZE(trigger_matches),
+                               sizeof(int32_t));
+               break;
+       case SR_CONF_LIMIT_SAMPLES:
+               grange[0] = g_variant_new_uint64(0);
+               grange[1] = g_variant_new_uint64(MAX_SAMPLES);
+               *data = g_variant_new_tuple(grange, 2);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return ret;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       uint16_t trigger_bytes, tmp;
+       unsigned int i, j;
+       int ret;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       devc = sdi->priv;
+       drvc = di->priv;
+
+       devc->cb_data = cb_data;
+       devc->wait_data_ready_locked = TRUE;
+       devc->stopping_in_progress = FALSE;
+       devc->transfer_error = FALSE;
+       devc->samples_processed = 0;
+       devc->channel = 0;
+       devc->sample_packet = 0;
+
+       /*
+        * The trigger must be configured first because the calculation of the
+        * pre and post trigger samples depends on a configured trigger.
+        */
+       sl2_convert_trigger(sdi);
+       sl2_calculate_trigger_samples(sdi);
+
+       trigger_bytes = devc->pre_trigger_bytes + devc->post_trigger_bytes;
+
+       /* Calculate the number of expected sample packets. */
+       devc->num_sample_packets = trigger_bytes / PACKET_NUM_SAMPLE_BYTES;
+
+       /* Round up the number of expected sample packets. */
+       if (trigger_bytes % PACKET_NUM_SAMPLE_BYTES != 0)
+               devc->num_sample_packets++;
+
+       devc->num_enabled_channels = 0;
+
+       /*
+        * Count the number of enabled channels and number them for a sequential
+        * access.
+        */
+       for (i = 0, j = 0; i < NUM_CHANNELS; i++) {
+               if (devc->channels[i]->enabled) {
+                       devc->num_enabled_channels++;
+                       devc->channel_map[j] = i;
+                       j++;
+               }
+       }
+
+       sr_dbg("Number of enabled channels: %i.", devc->num_enabled_channels);
+
+       /* Set up the transfer buffer for the acquisition. */
+       devc->xfer_data_out[0] = CMD_SAMPLE;
+       devc->xfer_data_out[1] = 0x00;
+
+       tmp = GUINT16_TO_LE(devc->pre_trigger_bytes);
+       memcpy(devc->xfer_data_out + 2, &tmp, sizeof(tmp));
+
+       tmp = GUINT16_TO_LE(devc->post_trigger_bytes);
+       memcpy(devc->xfer_data_out + 4, &tmp, sizeof(tmp));
+
+       devc->xfer_data_out[6] = devc->samplerate_id;
+       devc->xfer_data_out[7] = devc->trigger_type;
+       devc->xfer_data_out[8] = devc->trigger_channel;
+       devc->xfer_data_out[9] = 0x00;
+
+       tmp = GUINT16_TO_LE(devc->after_trigger_delay);
+       memcpy(devc->xfer_data_out + 10, &tmp, sizeof(tmp));
+
+       if ((ret = libusb_submit_transfer(devc->xfer_out)) != 0) {
+               sr_err("Submit transfer failed: %s.", libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+       usb_source_add(sdi->session, drvc->sr_ctx, 100,
+                       ikalogic_scanalogic2_receive_data, (void *)sdi);
+
+       sr_dbg("Acquisition started successfully.");
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(cb_data, LOG_PREFIX);
+
+       devc->next_state = STATE_SAMPLE;
+
+       return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       (void)cb_data;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       sr_dbg("Stopping acquisition.");
+
+       sdi->status = SR_ST_STOPPING;
+
+       return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver ikalogic_scanalogic2_driver_info = {
+       .name = "ikalogic-scanalogic2",
+       .longname = "IKALOGIC Scanalogic-2",
+       .api_version = 1,
+       .init = init,
+       .cleanup = cleanup,
+       .scan = scan,
+       .dev_list = dev_list,
+       .dev_clear = dev_clear,
+       .config_get = config_get,
+       .config_set = config_set,
+       .config_list = config_list,
+       .dev_open = dev_open,
+       .dev_close = dev_close,
+       .dev_acquisition_start = dev_acquisition_start,
+       .dev_acquisition_stop = dev_acquisition_stop,
+       .priv = NULL,
+};
diff --git a/src/hardware/ikalogic-scanalogic2/protocol.c b/src/hardware/ikalogic-scanalogic2/protocol.c
new file mode 100644 (file)
index 0000000..663ff52
--- /dev/null
@@ -0,0 +1,764 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Marc Schink <sigrok-dev@marcschink.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 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"
+
+extern struct sr_dev_driver ikalogic_scanalogic2_driver_info;
+static struct sr_dev_driver *di = &ikalogic_scanalogic2_driver_info;
+
+extern uint64_t sl2_samplerates[NUM_SAMPLERATES];
+
+static void stop_acquisition(struct sr_dev_inst *sdi)
+{
+       struct drv_context *drvc = sdi->driver->priv;
+       struct dev_context *devc;
+       struct sr_datafeed_packet packet;
+
+       devc = sdi->priv;
+
+       /* Remove USB file descriptors from polling. */
+       usb_source_remove(sdi->session, drvc->sr_ctx);
+
+       packet.type = SR_DF_END;
+       sr_session_send(devc->cb_data, &packet);
+
+       sdi->status = SR_ST_ACTIVE;
+}
+
+static void abort_acquisition(struct sr_dev_inst *sdi)
+{
+       struct drv_context *drvc = sdi->driver->priv;
+       struct dev_context *devc;
+       struct sr_datafeed_packet packet;
+
+       devc = sdi->priv;
+
+       /* Remove USB file descriptors from polling. */
+       usb_source_remove(sdi->session, drvc->sr_ctx);
+
+       packet.type = SR_DF_END;
+       sr_session_send(devc->cb_data, &packet);
+
+       sdi->driver->dev_close(sdi);
+}
+
+static void buffer_sample_data(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       unsigned int offset, packet_length;
+
+       devc = sdi->priv;
+
+       if (devc->channels[devc->channel]->enabled) {
+               offset = devc->sample_packet * PACKET_NUM_SAMPLE_BYTES;
+
+               /*
+                * Determine the packet length to ensure that the last packet
+                * will not exceed the buffer size.
+                */
+               packet_length = MIN(PACKET_NUM_SAMPLE_BYTES,
+                       MAX_DEV_SAMPLE_BYTES - offset);
+
+               /*
+                * Skip the first 4 bytes of the source buffer because they
+                * contain channel and packet information only.
+                */
+               memcpy(devc->sample_buffer[devc->channel] + offset,
+                       devc->xfer_data_in + 4, packet_length);
+       }
+}
+
+static void process_sample_data(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_logic logic;
+       uint8_t i, j, tmp, buffer[PACKET_NUM_SAMPLES], *ptr[NUM_CHANNELS];
+       uint16_t offset, n = 0;
+       int8_t k;
+
+       devc = sdi->priv;
+       offset = devc->sample_packet * PACKET_NUM_SAMPLE_BYTES;
+
+       /*
+        * Array of pointers to the sample data of all channels up to the last
+        * enabled one for an uniform access to them. Note that the currently
+        * received samples always belong to the last enabled channel.
+        */
+       for (i = 0; i < devc->num_enabled_channels - 1; i++)
+               ptr[i] = devc->sample_buffer[devc->channel_map[i]] + offset;
+
+       /*
+        * Skip the first 4 bytes of the buffer because they contain channel
+        * and packet information only.
+        */
+       ptr[i] = devc->xfer_data_in + 4;
+
+       for (i = 0; i < PACKET_NUM_SAMPLE_BYTES; i++) {
+               /* Stop processing if all requested samples are processed. */
+               if (devc->samples_processed == devc->limit_samples)
+                       break;
+
+               k = 7;
+
+               if (devc->samples_processed == 0) {
+                       /*
+                        * Adjust the position of the first sample to be
+                        * processed because possibly more samples than
+                        * necessary might have been acquired. This is because
+                        * the number of acquired samples is always rounded up
+                        * to a multiple of 8.
+                        */
+                       k = k - (devc->pre_trigger_bytes * 8) +
+                               devc->pre_trigger_samples;
+
+                       sr_dbg("Start processing at sample: %d.", 7 - k);
+
+                       /*
+                        * Send the trigger before the first sample is
+                        * processed if no pre trigger samples were calculated
+                        * through the capture ratio.
+                        */
+                       if (devc->trigger_type != TRIGGER_TYPE_NONE &&
+                                       devc->pre_trigger_samples == 0) {
+                               packet.type = SR_DF_TRIGGER;
+                               sr_session_send(devc->cb_data, &packet);
+                       }
+               }
+
+               for (; k >= 0; k--) {
+                       /*
+                        * Stop processing if all requested samples are
+                        * processed.
+                        */
+                       if (devc->samples_processed == devc->limit_samples)
+                               break;
+
+                       buffer[n] = 0;
+
+                       /*
+                        * Extract the current sample for each enabled channel
+                        * and store them in the buffer.
+                        */
+                       for (j = 0; j < devc->num_enabled_channels; j++) {
+                               tmp = (ptr[j][i] & (1 << k)) >> k;
+                               buffer[n] |= tmp << devc->channel_map[j];
+                       }
+
+                       n++;
+                       devc->samples_processed++;
+
+                       /*
+                        * Send all processed samples and the trigger if the
+                        * number of processed samples reaches the calculated
+                        * number of pre trigger samples.
+                        */
+                       if (devc->samples_processed == devc->pre_trigger_samples &&
+                                       devc->trigger_type != TRIGGER_TYPE_NONE) {
+                               packet.type = SR_DF_LOGIC;
+                               packet.payload = &logic;
+                               logic.length = n;
+                               logic.unitsize = 1;
+                               logic.data = buffer;
+                               sr_session_send(devc->cb_data, &packet);
+
+                               packet.type = SR_DF_TRIGGER;
+                               sr_session_send(devc->cb_data, &packet);
+
+                               n = 0;
+                       }
+               }
+       }
+
+       if (n > 0) {
+               packet.type = SR_DF_LOGIC;
+               packet.payload = &logic;
+               logic.length = n;
+               logic.unitsize = 1;
+               logic.data = buffer;
+               sr_session_send(devc->cb_data, &packet);
+       }
+}
+
+SR_PRIV int ikalogic_scanalogic2_receive_data(int fd, int revents, void *cb_data)
+{
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       struct drv_context *drvc;
+       struct timeval tv;
+       int64_t current_time, time_elapsed;
+       int ret = 0;
+
+       (void)fd;
+       (void)revents;
+
+       if (!(sdi = cb_data))
+               return TRUE;
+
+       if (!(devc = sdi->priv))
+               return TRUE;
+
+       drvc = di->priv;
+       current_time = g_get_monotonic_time();
+
+       if (devc->state == STATE_WAIT_DATA_READY &&
+                       !devc->wait_data_ready_locked) {
+               time_elapsed = current_time - devc->wait_data_ready_time;
+
+               /*
+                * Check here for stopping in addition to the transfer
+                * callback functions to avoid waiting until the
+                * WAIT_DATA_READY_INTERVAL has expired.
+                */
+               if (sdi->status == SR_ST_STOPPING) {
+                       if (!devc->stopping_in_progress) {
+                               devc->next_state = STATE_RESET_AND_IDLE;
+                               devc->stopping_in_progress = TRUE;
+                               ret = libusb_submit_transfer(devc->xfer_in);
+                       }
+               } else if (time_elapsed >= WAIT_DATA_READY_INTERVAL) {
+                       devc->wait_data_ready_locked = TRUE;
+                       ret = libusb_submit_transfer(devc->xfer_in);
+               }
+       }
+
+       if (ret != 0) {
+               sr_err("Submit transfer failed: %s.", libusb_error_name(ret));
+               abort_acquisition(sdi);
+               return TRUE;
+       }
+
+       tv.tv_sec = 0;
+       tv.tv_usec = 0;
+
+       libusb_handle_events_timeout_completed(drvc->sr_ctx->libusb_ctx, &tv,
+               NULL);
+
+       /* Check if an error occurred on a transfer. */
+       if (devc->transfer_error)
+               abort_acquisition(sdi);
+
+       return TRUE;
+}
+
+SR_PRIV void sl2_receive_transfer_in( struct libusb_transfer *transfer)
+{
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       uint8_t last_channel;
+       int ret = 0;
+
+       sdi = transfer->user_data;
+       devc = sdi->priv;
+
+       if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
+               sr_err("Transfer to device failed: %i.", transfer->status);
+               devc->transfer_error = TRUE;
+               return;
+       }
+
+       if (sdi->status == SR_ST_STOPPING && !devc->stopping_in_progress) {
+               devc->next_state = STATE_RESET_AND_IDLE;
+               devc->stopping_in_progress = TRUE;
+
+               if (libusb_submit_transfer(devc->xfer_in) != 0) {
+                       sr_err("Submit transfer failed: %s.",
+                               libusb_error_name(ret));
+                       devc->transfer_error = TRUE;
+               }
+
+               return;
+       }
+
+       if (devc->state != devc->next_state)
+               sr_spew("State changed from %i to %i.",
+                       devc->state, devc->next_state);
+       devc->state = devc->next_state;
+
+       if (devc->state == STATE_WAIT_DATA_READY) {
+               /* Check if the received data are a valid device status. */
+               if (devc->xfer_data_in[0] == 0x05) {
+                       if (devc->xfer_data_in[1] == STATUS_WAITING_FOR_TRIGGER)
+                               sr_dbg("Waiting for trigger.");
+                       else if (devc->xfer_data_in[1] == STATUS_SAMPLING)
+                               sr_dbg("Sampling in progress.");
+               }
+
+               /*
+                * Check if the received data are a valid device status and the
+                * sample data are ready.
+                */
+               if (devc->xfer_data_in[0] == 0x05 &&
+                               devc->xfer_data_in[1] == STATUS_DATA_READY) {
+                       devc->next_state = STATE_RECEIVE_DATA;
+                       ret = libusb_submit_transfer(transfer);
+               } else {
+                       devc->wait_data_ready_locked = FALSE;
+                       devc->wait_data_ready_time = g_get_monotonic_time();
+               }
+       } else if (devc->state == STATE_RECEIVE_DATA) {
+               last_channel = devc->channel_map[devc->num_enabled_channels - 1];
+
+               if (devc->channel < last_channel) {
+                       buffer_sample_data(sdi);
+               } else if (devc->channel == last_channel) {
+                       process_sample_data(sdi);
+               } else {
+                       /*
+                        * Stop acquisition because all samples of enabled
+                        * channels are processed.
+                        */
+                       devc->next_state = STATE_RESET_AND_IDLE;
+               }
+
+               devc->sample_packet++;
+               devc->sample_packet %= devc->num_sample_packets;
+
+               if (devc->sample_packet == 0)
+                       devc->channel++;
+
+               ret = libusb_submit_transfer(transfer);
+       } else if (devc->state == STATE_RESET_AND_IDLE) {
+               /* Check if the received data are a valid device status. */
+               if (devc->xfer_data_in[0] == 0x05) {
+                       if (devc->xfer_data_in[1] == STATUS_DEVICE_READY) {
+                               devc->next_state = STATE_IDLE;
+                               devc->xfer_data_out[0] = CMD_IDLE;
+                       } else {
+                               devc->next_state = STATE_WAIT_DEVICE_READY;
+                               devc->xfer_data_out[0] = CMD_RESET;
+                       }
+
+                       ret = libusb_submit_transfer(devc->xfer_out);
+               } else {
+                       /*
+                        * The received device status is invalid which
+                        * indicates that the device is not ready to accept
+                        * commands. Request a new device status until a valid
+                        * device status is received.
+                        */
+                       ret = libusb_submit_transfer(transfer);
+               }
+       } else if (devc->state == STATE_WAIT_DEVICE_READY) {
+               /* Check if the received data are a valid device status. */
+               if (devc->xfer_data_in[0] == 0x05) {
+                       if (devc->xfer_data_in[1] == STATUS_DEVICE_READY) {
+                               devc->next_state = STATE_IDLE;
+                               devc->xfer_data_out[0] = CMD_IDLE;
+                       } else {
+                               /*
+                                * The received device status is valid but the
+                                * device is not ready. Probably the device did
+                                * not recognize the last reset. Reset the
+                                * device again.
+                                */
+                               devc->xfer_data_out[0] = CMD_RESET;
+                       }
+
+                       ret = libusb_submit_transfer(devc->xfer_out);
+               } else {
+                       /*
+                        * The device is not ready and therefore not able to
+                        * change to the idle state. Request a new device
+                        * status until the device is ready.
+                        */
+                       ret = libusb_submit_transfer(transfer);
+               }
+       }
+
+       if (ret != 0) {
+               sr_err("Submit transfer failed: %s.", libusb_error_name(ret));
+               devc->transfer_error = TRUE;
+       }
+}
+
+SR_PRIV void sl2_receive_transfer_out( struct libusb_transfer *transfer)
+{
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       int ret = 0;
+
+       sdi = transfer->user_data;
+       devc = sdi->priv;
+
+       if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
+               sr_err("Transfer to device failed: %i.", transfer->status);
+               devc->transfer_error = TRUE;
+               return;
+       }
+
+       if (sdi->status == SR_ST_STOPPING && !devc->stopping_in_progress) {
+               devc->next_state = STATE_RESET_AND_IDLE;
+               devc->stopping_in_progress = TRUE;
+
+               if (libusb_submit_transfer(devc->xfer_in) != 0) {
+                       sr_err("Submit transfer failed: %s.",
+                               libusb_error_name(ret));
+
+                       devc->transfer_error = TRUE;
+               }
+
+               return;
+       }
+
+       if (devc->state != devc->next_state)
+               sr_spew("State changed from %i to %i.",
+                       devc->state, devc->next_state);
+       devc->state = devc->next_state;
+
+       if (devc->state == STATE_IDLE) {
+               stop_acquisition(sdi);
+       } else if (devc->state == STATE_SAMPLE) {
+               devc->next_state = STATE_WAIT_DATA_READY;
+               ret = libusb_submit_transfer(devc->xfer_in);
+       } else if (devc->state == STATE_WAIT_DEVICE_READY) {
+               ret = libusb_submit_transfer(devc->xfer_in);
+       }
+
+       if (ret != 0) {
+               sr_err("Submit transfer failed: %s.", libusb_error_name(ret));
+               devc->transfer_error = TRUE;
+       }
+}
+
+SR_PRIV int sl2_set_samplerate(const struct sr_dev_inst *sdi,
+               uint64_t samplerate)
+{
+       struct dev_context *devc;
+       unsigned int i;
+
+       devc = sdi->priv;
+
+       for (i = 0; i < NUM_SAMPLERATES; i++) {
+               if (sl2_samplerates[i] == samplerate) {
+                       devc->samplerate = samplerate;
+                       devc->samplerate_id = NUM_SAMPLERATES - i - 1;
+                       return SR_OK;
+               }
+       }
+
+       return SR_ERR_ARG;
+}
+
+SR_PRIV int sl2_set_limit_samples(const struct sr_dev_inst *sdi,
+                                 uint64_t limit_samples)
+{
+       struct dev_context *devc;
+
+       devc = sdi->priv;
+
+       if (limit_samples == 0) {
+               sr_err("Invalid number of limit samples: %" PRIu64 ".",
+                       limit_samples);
+               return SR_ERR_ARG;
+       }
+
+       if (limit_samples > MAX_SAMPLES)
+               limit_samples = MAX_SAMPLES;
+
+       sr_dbg("Limit samples set to %" PRIu64 ".", limit_samples);
+
+       devc->limit_samples = limit_samples;
+
+       return SR_OK;
+}
+
+SR_PRIV int sl2_convert_trigger(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_trigger *trigger;
+       struct sr_trigger_stage *stage;
+       struct sr_trigger_match *match;
+       const GSList *l, *m;
+       int num_triggers_anyedge;
+
+       devc = sdi->priv;
+
+       /* Disable the trigger by default. */
+       devc->trigger_channel = TRIGGER_CHANNEL_0;
+       devc->trigger_type = TRIGGER_TYPE_NONE;
+
+       if (!(trigger = sr_session_trigger_get(sdi->session)))
+               return SR_OK;
+
+       if (g_slist_length(trigger->stages) > 1) {
+               sr_err("This device only supports 1 trigger stage.");
+               return SR_ERR;
+       }
+
+       num_triggers_anyedge = 0;
+       for (l = trigger->stages; l; l = l->next) {
+               stage = l->data;
+               for (m = stage->matches; m; m = m->next) {
+                       match = m->data;
+                       if (!match->channel->enabled)
+                               /* Ignore disabled channels with a trigger. */
+                               continue;
+                       devc->trigger_channel = match->channel->index + 1;
+                       switch (match->match) {
+                       case SR_TRIGGER_RISING:
+                               devc->trigger_type = TRIGGER_TYPE_POSEDGE;
+                               break;
+                       case SR_TRIGGER_FALLING:
+                               devc->trigger_type = TRIGGER_TYPE_NEGEDGE;
+                               break;
+                       case SR_TRIGGER_EDGE:
+                               devc->trigger_type = TRIGGER_TYPE_ANYEDGE;
+                               num_triggers_anyedge++;
+                               break;
+                       }
+               }
+       }
+
+       /*
+        * Set trigger to any edge on all channels if the trigger for each
+        * channel is set to any edge.
+        */
+       if (num_triggers_anyedge == NUM_CHANNELS) {
+               devc->trigger_channel = TRIGGER_CHANNEL_ALL;
+               devc->trigger_type = TRIGGER_TYPE_ANYEDGE;
+       }
+
+       sr_dbg("Trigger set to channel 0x%02x and type 0x%02x.",
+               devc->trigger_channel, devc->trigger_type);
+
+       return SR_OK;
+}
+
+SR_PRIV int sl2_set_capture_ratio(const struct sr_dev_inst *sdi,
+                                 uint64_t capture_ratio)
+{
+       struct dev_context *devc;
+
+       devc = sdi->priv;
+
+       if (capture_ratio > 100) {
+               sr_err("Invalid capture ratio: %" PRIu64 " %%.", capture_ratio);
+               return SR_ERR_ARG;
+       }
+
+       sr_info("Capture ratio set to %" PRIu64 " %%.", capture_ratio);
+
+       devc->capture_ratio = capture_ratio;
+
+       return SR_OK;
+}
+
+SR_PRIV int sl2_set_after_trigger_delay(const struct sr_dev_inst *sdi,
+                                       uint64_t after_trigger_delay)
+{
+       struct dev_context *devc;
+
+       devc = sdi->priv;
+
+       if (after_trigger_delay > MAX_AFTER_TRIGGER_DELAY) {
+               sr_err("Invalid after trigger delay: %" PRIu64 " ms.",
+                       after_trigger_delay);
+               return SR_ERR_ARG;
+       }
+
+       sr_info("After trigger delay set to %" PRIu64 " ms.",
+               after_trigger_delay);
+
+       devc->after_trigger_delay = after_trigger_delay;
+
+       return SR_OK;
+}
+
+SR_PRIV void sl2_calculate_trigger_samples(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       uint64_t pre_trigger_samples, post_trigger_samples;
+       uint16_t pre_trigger_bytes, post_trigger_bytes;
+       uint8_t cr;
+
+       devc = sdi->priv;
+       cr = devc->capture_ratio;
+
+       /* Ignore the capture ratio if no trigger is enabled. */
+       if (devc->trigger_type == TRIGGER_TYPE_NONE)
+               cr = 0;
+
+       pre_trigger_samples = (devc->limit_samples * cr) / 100;
+       post_trigger_samples = (devc->limit_samples * (100 - cr)) / 100;
+
+       /*
+        * Increase the number of post trigger samples by one to compensate the
+        * possible loss of a sample through integer rounding.
+        */
+       if (pre_trigger_samples + post_trigger_samples != devc->limit_samples)
+               post_trigger_samples++;
+
+       /*
+        * The device requires the number of samples in multiples of 8 which
+        * will also be called sample bytes in the following.
+        */
+       pre_trigger_bytes = pre_trigger_samples / 8;
+       post_trigger_bytes = post_trigger_samples / 8;
+
+       /*
+        * Round up the number of sample bytes to ensure that at least the
+        * requested number of samples will be acquired. Note that due to this
+        * rounding the buffer to store these sample bytes needs to be at least
+        * one sample byte larger than the minimal number of sample bytes
+        * needed to store the requested samples.
+        */
+       if (pre_trigger_samples % 8 != 0)
+               pre_trigger_bytes++;
+
+       if (post_trigger_samples % 8 != 0)
+               post_trigger_bytes++;
+
+       sr_info("Pre trigger samples: %" PRIu64 ".", pre_trigger_samples);
+       sr_info("Post trigger samples: %" PRIu64 ".", post_trigger_samples);
+       sr_dbg("Pre trigger sample bytes: %" PRIu16 ".", pre_trigger_bytes);
+       sr_dbg("Post trigger sample bytes: %" PRIu16 ".", post_trigger_bytes);
+
+       devc->pre_trigger_samples = pre_trigger_samples;
+       devc->pre_trigger_bytes = pre_trigger_bytes;
+       devc->post_trigger_bytes = post_trigger_bytes;
+}
+
+SR_PRIV int sl2_get_device_info(struct sr_usb_dev_inst usb,
+               struct device_info *dev_info)
+{
+       struct drv_context *drvc;
+       uint8_t buffer[PACKET_LENGTH];
+       int ret;
+
+       drvc = di->priv;
+
+       if (!dev_info)
+               return SR_ERR_ARG;
+
+       if (sr_usb_open(drvc->sr_ctx->libusb_ctx, &usb) != SR_OK)
+               return SR_ERR;
+
+       /*
+        * Determine if a kernel driver is active on this interface and, if so,
+        * detach it.
+        */
+       if (libusb_kernel_driver_active(usb.devhdl, USB_INTERFACE) == 1) {
+               ret = libusb_detach_kernel_driver(usb.devhdl,
+                       USB_INTERFACE);
+
+               if (ret < 0) {
+                       sr_err("Failed to detach kernel driver: %s.",
+                               libusb_error_name(ret));
+                       libusb_close(usb.devhdl);
+                       return SR_ERR;
+               }
+       }
+
+       ret = libusb_claim_interface(usb.devhdl, USB_INTERFACE);
+
+       if (ret) {
+               sr_err("Failed to claim interface: %s.",
+                       libusb_error_name(ret));
+               libusb_close(usb.devhdl);
+               return SR_ERR;
+       }
+
+       memset(buffer, 0, sizeof(buffer));
+
+       /*
+        * Reset the device to ensure it is in a proper state to request the
+        * device information.
+        */
+       buffer[0] = CMD_RESET;
+       if ((ret = sl2_transfer_out(usb.devhdl, buffer)) != PACKET_LENGTH) {
+               sr_err("Resetting of device failed: %s.",
+                       libusb_error_name(ret));
+               libusb_release_interface(usb.devhdl, USB_INTERFACE);
+               libusb_close(usb.devhdl);
+               return SR_ERR;
+       }
+
+       buffer[0] = CMD_INFO;
+       if ((ret = sl2_transfer_out(usb.devhdl, buffer)) != PACKET_LENGTH) {
+               sr_err("Requesting of device information failed: %s.",
+                       libusb_error_name(ret));
+               libusb_release_interface(usb.devhdl, USB_INTERFACE);
+               libusb_close(usb.devhdl);
+               return SR_ERR;
+       }
+
+       if ((ret = sl2_transfer_in(usb.devhdl, buffer)) != PACKET_LENGTH) {
+               sr_err("Receiving of device information failed: %s.",
+                       libusb_error_name(ret));
+               libusb_release_interface(usb.devhdl, USB_INTERFACE);
+               libusb_close(usb.devhdl);
+               return SR_ERR;
+       }
+
+       memcpy(&(dev_info->serial), buffer + 1, sizeof(uint32_t));
+       dev_info->serial = GUINT32_FROM_LE(dev_info->serial);
+
+       dev_info->fw_ver_major = buffer[5];
+       dev_info->fw_ver_minor = buffer[6];
+
+       buffer[0] = CMD_RESET;
+       if ((ret = sl2_transfer_out(usb.devhdl, buffer)) != PACKET_LENGTH) {
+               sr_err("Device reset failed: %s.", libusb_error_name(ret));
+               libusb_release_interface(usb.devhdl, USB_INTERFACE);
+               libusb_close(usb.devhdl);
+               return SR_ERR;
+       }
+
+       /*
+        * Set the device to idle state. If the device is not in idle state it
+        * possibly will reset itself after a few seconds without being used
+        * and thereby close the connection.
+        */
+       buffer[0] = CMD_IDLE;
+       if ((ret = sl2_transfer_out(usb.devhdl, buffer)) != PACKET_LENGTH) {
+               sr_err("Failed to set device in idle state: %s.",
+                       libusb_error_name(ret));
+               libusb_release_interface(usb.devhdl, USB_INTERFACE);
+               libusb_close(usb.devhdl);
+               return SR_ERR;
+       }
+
+       ret = libusb_release_interface(usb.devhdl, USB_INTERFACE);
+
+       if (ret < 0) {
+               sr_err("Failed to release interface: %s.",
+                       libusb_error_name(ret));
+               libusb_close(usb.devhdl);
+               return SR_ERR;
+       }
+
+       libusb_close(usb.devhdl);
+
+       return SR_OK;
+}
+
+SR_PRIV int sl2_transfer_in(libusb_device_handle *dev_handle, uint8_t *data)
+{
+       return libusb_control_transfer(dev_handle, USB_REQUEST_TYPE_IN,
+               USB_HID_GET_REPORT, USB_HID_REPORT_TYPE_FEATURE, USB_INTERFACE,
+               (unsigned char *)data, PACKET_LENGTH, USB_TIMEOUT);
+}
+
+SR_PRIV int sl2_transfer_out(libusb_device_handle *dev_handle, uint8_t *data)
+{
+       return libusb_control_transfer(dev_handle, USB_REQUEST_TYPE_OUT,
+               USB_HID_SET_REPORT, USB_HID_REPORT_TYPE_FEATURE, USB_INTERFACE,
+               (unsigned char *)data, PACKET_LENGTH, USB_TIMEOUT);
+}
diff --git a/src/hardware/ikalogic-scanalogic2/protocol.h b/src/hardware/ikalogic-scanalogic2/protocol.h
new file mode 100644 (file)
index 0000000..5e7c7b3
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Marc Schink <sigrok-dev@marcschink.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 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_IKALOGIC_SCANALOGIC2_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_IKALOGIC_SCANALOGIC2_PROTOCOL_H
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "ikalogic-scanalogic2"
+
+#define VENDOR_NAME                    "IKALOGIC"
+#define MODEL_NAME                     "Scanalogic-2"
+
+#define USB_VID_PID                    "20a0.4123"
+#define USB_INTERFACE                  0
+#define USB_TIMEOUT                    5000
+
+#define USB_REQUEST_TYPE_IN            (LIBUSB_REQUEST_TYPE_CLASS | \
+       LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_IN)
+
+#define USB_REQUEST_TYPE_OUT           (LIBUSB_REQUEST_TYPE_CLASS | \
+       LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT)
+
+#define USB_HID_GET_REPORT             0x01
+#define USB_HID_SET_REPORT             0x09
+#define USB_HID_REPORT_TYPE_FEATURE    0x300
+
+#define NUM_SAMPLERATES                        11
+#define NUM_CHANNELS                   4
+
+/*
+ * Number of sample bytes and samples the device can acquire. Note that the
+ * vendor software can acquire 32736 sample bytes only but the device is capable
+ * to acquire up to 32766 sample bytes.
+ */
+#define MAX_DEV_SAMPLE_BYTES           32766
+#define MAX_DEV_SAMPLES                        (MAX_INT_SAMPLE_BYTES * 8)
+
+/* Number of sample bytes and samples the driver can acquire. */
+#define MAX_SAMPLE_BYTES               (MAX_DEV_SAMPLE_BYTES - 1)
+#define MAX_SAMPLES                    (MAX_SAMPLE_BYTES * 8)
+
+/* Maximum time that the trigger can be delayed in milliseconds. */
+#define MAX_AFTER_TRIGGER_DELAY                65000
+
+#define PACKET_LENGTH                  128
+
+/* Number of sample bytes per packet where a sample byte contains 8 samples. */
+#define PACKET_NUM_SAMPLE_BYTES                124
+
+/* Number of samples per packet. */
+#define PACKET_NUM_SAMPLES             (PACKET_NUM_SAMPLE_BYTES * 8)
+
+#define DEFAULT_SAMPLERATE             SR_KHZ(1.25)
+
+/*
+ * Time interval between the last status of available data received and the
+ * moment when the next status request will be sent in microseconds.
+ */
+#define WAIT_DATA_READY_INTERVAL       1500000
+
+#define CMD_SAMPLE                     0x01
+#define CMD_RESET                      0x02
+#define CMD_IDLE                       0x07
+#define CMD_INFO                       0x0a
+
+#define TRIGGER_CHANNEL_ALL            0x00
+#define TRIGGER_CHANNEL_0              0x01
+#define TRIGGER_CHANNEL_1              0x02
+#define TRIGGER_CHANNEL_2              0x03
+
+#define TRIGGER_TYPE_NEGEDGE           0x00
+#define TRIGGER_TYPE_POSEDGE           0x01
+#define TRIGGER_TYPE_ANYEDGE           0x02
+#define TRIGGER_TYPE_NONE              0x03
+
+#define STATUS_DATA_READY              0x60
+#define STATUS_WAITING_FOR_TRIGGER     0x61
+#define STATUS_SAMPLING                        0x62
+#define STATUS_DEVICE_READY            0x63
+
+struct device_info {
+       /* Serial number of the device. */
+       uint32_t serial;
+
+       /* Major version of the firmware. */
+       uint8_t fw_ver_major;
+
+       /* Minor version of the firmware. */
+       uint8_t fw_ver_minor;
+};
+
+enum {
+       STATE_IDLE = 0,
+       STATE_SAMPLE,
+       STATE_WAIT_DATA_READY,
+       STATE_RECEIVE_DATA,
+       STATE_RESET_AND_IDLE,
+       STATE_WAIT_DEVICE_READY
+};
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+       /* Current selected samplerate. */
+       uint64_t samplerate;
+
+       /* Device specific identifier for the current samplerate. */
+       uint8_t samplerate_id;
+
+       /* Current sampling limit. */
+       uint64_t limit_samples;
+
+       /* Calculated number of pre-trigger samples. */
+       uint64_t pre_trigger_samples;
+
+       /* Number of pre- and post-trigger sample bytes to acquire. */
+       uint16_t pre_trigger_bytes;
+       uint16_t post_trigger_bytes;
+
+       /* Device specific settings for the trigger. */
+       uint8_t trigger_channel;
+       uint8_t trigger_type;
+
+       unsigned int capture_ratio;
+
+       /* Time that the trigger will be delayed in milliseconds. */
+       uint16_t after_trigger_delay;
+
+       void *cb_data;
+
+       /* Array to provide an index based access to all channels. */
+       const struct sr_channel *channels[NUM_CHANNELS];
+
+       struct libusb_transfer *xfer_in, *xfer_out;
+
+       /*
+        * Buffer to store setup and payload data for incoming and outgoing
+        * transfers.
+        */
+       uint8_t xfer_buf_in[LIBUSB_CONTROL_SETUP_SIZE + PACKET_LENGTH];
+       uint8_t xfer_buf_out[LIBUSB_CONTROL_SETUP_SIZE + PACKET_LENGTH];
+
+       /* Pointers to the payload of incoming and outgoing transfers. */
+       uint8_t *xfer_data_in, *xfer_data_out;
+
+       /* Current state of the state machine */
+       unsigned int state;
+
+       /* Next state of the state machine. */
+       unsigned int next_state;
+
+       /*
+        * Locking variable to ensure that no status about available data will
+        * be requested until the last status was received.
+        */
+       gboolean wait_data_ready_locked;
+
+       /*
+        * Time when the last response about the status of available data was
+        * received.
+        */
+       int64_t wait_data_ready_time;
+
+       /*
+        * Indicates that stopping of the acquisition is currently in progress.
+        */
+       gboolean stopping_in_progress;
+
+       /*
+        * Buffer which contains the samples received from the device for each
+        * channel except the last one. The samples of the last channel will be
+        * processed directly after they will be received.
+        */
+       uint8_t sample_buffer[NUM_CHANNELS - 1][MAX_DEV_SAMPLE_BYTES];
+
+       /* Expected number of sample packets for each channel. */
+       uint16_t num_sample_packets;
+
+       /* Number of samples already processed. */
+       uint64_t samples_processed;
+
+       /* Sample packet number that is currently processed. */
+       uint16_t sample_packet;
+
+       /* Channel number that is currently processed. */
+       uint8_t channel;
+
+       /* Number of enabled channels. */
+       unsigned int num_enabled_channels;
+
+       /* Array to provide a sequential access to all enabled channel indices. */
+       uint8_t channel_map[NUM_CHANNELS];
+
+       /* Indicates whether a transfer failed. */
+       gboolean transfer_error;
+};
+
+SR_PRIV int ikalogic_scanalogic2_receive_data(int fd, int revents, void *cb_data);
+SR_PRIV void sl2_receive_transfer_in(struct libusb_transfer *transfer);
+SR_PRIV void sl2_receive_transfer_out(struct libusb_transfer *transfer);
+SR_PRIV int sl2_set_samplerate(const struct sr_dev_inst *sdi,
+               uint64_t samplerate);
+SR_PRIV int sl2_set_limit_samples(const struct sr_dev_inst *sdi,
+                                 uint64_t limit_samples);
+SR_PRIV int sl2_convert_trigger(const struct sr_dev_inst *sdi);
+SR_PRIV int sl2_set_capture_ratio(const struct sr_dev_inst *sdi,
+                                 uint64_t capture_ratio);
+SR_PRIV int sl2_set_after_trigger_delay(const struct sr_dev_inst *sdi,
+                                       uint64_t after_trigger_delay);
+SR_PRIV void sl2_calculate_trigger_samples(const struct sr_dev_inst *sdi);
+SR_PRIV int sl2_get_device_info(struct sr_usb_dev_inst usb,
+               struct device_info *dev_info);
+SR_PRIV int sl2_transfer_in(libusb_device_handle *dev_handle, uint8_t *data);
+SR_PRIV int sl2_transfer_out(libusb_device_handle *dev_handle, uint8_t *data);
+
+#endif
diff --git a/src/hardware/ikalogic-scanaplus/api.c b/src/hardware/ikalogic-scanaplus/api.c
new file mode 100644 (file)
index 0000000..3f82763
--- /dev/null
@@ -0,0 +1,438 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "protocol.h"
+
+#define USB_VENDOR_ID                  0x0403
+#define USB_DEVICE_ID                  0x6014
+#define USB_VENDOR_NAME                        "IKALOGIC"
+#define USB_MODEL_NAME                 "ScanaPLUS"
+#define USB_IPRODUCT                   "SCANAPLUS"
+
+#define SAMPLE_BUF_SIZE                        (8 * 1024 * 1024)
+
+static const int32_t hwcaps[] = {
+       SR_CONF_LOGIC_ANALYZER,
+       SR_CONF_SAMPLERATE,
+       SR_CONF_LIMIT_MSEC,
+       SR_CONF_LIMIT_SAMPLES,
+       SR_CONF_CONTINUOUS, // TODO?
+};
+
+/* Channels are numbered 1-9. */
+static const char *channel_names[] = {
+       "1", "2", "3", "4", "5", "6", "7", "8", "9",
+       NULL,
+};
+
+/* Note: The IKALOGIC ScanaPLUS always samples at 100MHz. */
+static uint64_t samplerates[1] = { SR_MHZ(100) };
+
+SR_PRIV struct sr_dev_driver ikalogic_scanaplus_driver_info;
+static struct sr_dev_driver *di = &ikalogic_scanaplus_driver_info;
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data);
+
+static void clear_helper(void *priv)
+{
+       struct dev_context *devc;
+
+       devc = priv;
+
+       ftdi_free(devc->ftdic);
+       g_free(devc->compressed_buf);
+       g_free(devc->sample_buf);
+}
+
+static int dev_clear(void)
+{
+       return std_dev_clear(di, clear_helper);
+}
+
+static int init(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+       struct sr_dev_inst *sdi;
+       struct sr_channel *ch;
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       GSList *devices;
+       unsigned int i;
+       int ret;
+
+       (void)options;
+
+       drvc = di->priv;
+
+       devices = NULL;
+
+       /* Allocate memory for our private device context. */
+       if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+               sr_err("Device context malloc failed.");
+               goto err_free_nothing;
+       }
+
+       /* Allocate memory for the incoming compressed samples. */
+       if (!(devc->compressed_buf = g_try_malloc0(COMPRESSED_BUF_SIZE))) {
+               sr_err("compressed_buf malloc failed.");
+               goto err_free_devc;
+       }
+
+       /* Allocate memory for the uncompressed samples. */
+       if (!(devc->sample_buf = g_try_malloc0(SAMPLE_BUF_SIZE))) {
+               sr_err("sample_buf malloc failed.");
+               goto err_free_compressed_buf;
+       }
+
+       /* Allocate memory for the FTDI context (ftdic) and initialize it. */
+       if (!(devc->ftdic = ftdi_new())) {
+               sr_err("Failed to initialize libftdi.");
+               goto err_free_sample_buf;
+       }
+
+       /* Check for the device and temporarily open it. */
+       ret = ftdi_usb_open_desc(devc->ftdic, USB_VENDOR_ID, USB_DEVICE_ID,
+                                USB_IPRODUCT, NULL);
+       if (ret < 0) {
+               /* Log errors, except for -3 ("device not found"). */
+               if (ret != -3)
+                       sr_err("Failed to open device (%d): %s", ret,
+                              ftdi_get_error_string(devc->ftdic));
+               goto err_free_ftdic;
+       }
+
+       /* Register the device with libsigrok. */
+       sdi = sr_dev_inst_new(0, SR_ST_INITIALIZING,
+                       USB_VENDOR_NAME, USB_MODEL_NAME, NULL);
+       if (!sdi) {
+               sr_err("Failed to create device instance.");
+               goto err_close_ftdic;
+       }
+       sdi->driver = di;
+       sdi->priv = devc;
+
+       for (i = 0; channel_names[i]; i++) {
+               if (!(ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE,
+                                          channel_names[i])))
+                       return NULL;
+               sdi->channels = g_slist_append(sdi->channels, ch);
+       }
+
+       devices = g_slist_append(devices, sdi);
+       drvc->instances = g_slist_append(drvc->instances, sdi);
+
+       /* Close device. We'll reopen it again when we need it. */
+       scanaplus_close(devc);
+
+       return devices;
+
+err_close_ftdic:
+       scanaplus_close(devc);
+err_free_ftdic:
+       ftdi_free(devc->ftdic); /* NOT free() or g_free()! */
+err_free_sample_buf:
+       g_free(devc->sample_buf);
+err_free_compressed_buf:
+       g_free(devc->compressed_buf);
+err_free_devc:
+       g_free(devc);
+err_free_nothing:
+
+       return NULL;
+}
+
+static GSList *dev_list(void)
+{
+       return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       int ret;
+
+       devc = sdi->priv;
+
+       /* Select interface A, otherwise communication will fail. */
+       ret = ftdi_set_interface(devc->ftdic, INTERFACE_A);
+       if (ret < 0) {
+               sr_err("Failed to set FTDI interface A (%d): %s", ret,
+                      ftdi_get_error_string(devc->ftdic));
+               return SR_ERR;
+       }
+       sr_dbg("FTDI chip interface A set successfully.");
+
+       /* Open the device. */
+       ret = ftdi_usb_open_desc(devc->ftdic, USB_VENDOR_ID, USB_DEVICE_ID,
+                                USB_IPRODUCT, NULL);
+       if (ret < 0) {
+               sr_err("Failed to open device (%d): %s", ret,
+                      ftdi_get_error_string(devc->ftdic));
+               return SR_ERR;
+       }
+       sr_dbg("FTDI device opened successfully.");
+
+       /* Purge RX/TX buffers in the FTDI chip. */
+       if ((ret = ftdi_usb_purge_buffers(devc->ftdic)) < 0) {
+               sr_err("Failed to purge FTDI RX/TX buffers (%d): %s.",
+                      ret, ftdi_get_error_string(devc->ftdic));
+               goto err_dev_open_close_ftdic;
+       }
+       sr_dbg("FTDI chip buffers purged successfully.");
+
+       /* Reset the FTDI bitmode. */
+       ret = ftdi_set_bitmode(devc->ftdic, 0xff, BITMODE_RESET);
+       if (ret < 0) {
+               sr_err("Failed to reset the FTDI chip bitmode (%d): %s.",
+                      ret, ftdi_get_error_string(devc->ftdic));
+               goto err_dev_open_close_ftdic;
+       }
+       sr_dbg("FTDI chip bitmode reset successfully.");
+
+       /* Set FTDI bitmode to "sync FIFO". */
+       ret = ftdi_set_bitmode(devc->ftdic, 0xff, BITMODE_SYNCFF);
+       if (ret < 0) {
+               sr_err("Failed to put FTDI chip into sync FIFO mode (%d): %s.",
+                      ret, ftdi_get_error_string(devc->ftdic));
+               goto err_dev_open_close_ftdic;
+       }
+       sr_dbg("FTDI chip sync FIFO mode entered successfully.");
+
+       /* Set the FTDI latency timer to 2. */
+       ret = ftdi_set_latency_timer(devc->ftdic, 2);
+       if (ret < 0) {
+               sr_err("Failed to set FTDI latency timer (%d): %s.",
+                      ret, ftdi_get_error_string(devc->ftdic));
+               goto err_dev_open_close_ftdic;
+       }
+       sr_dbg("FTDI chip latency timer set successfully.");
+
+       /* Set the FTDI read data chunk size to 64kB. */
+       ret = ftdi_read_data_set_chunksize(devc->ftdic, 64 * 1024);
+       if (ret < 0) {
+               sr_err("Failed to set FTDI read data chunk size (%d): %s.",
+                      ret, ftdi_get_error_string(devc->ftdic));
+               goto err_dev_open_close_ftdic;
+       }
+       sr_dbg("FTDI chip read data chunk size set successfully.");
+
+       /* Get the ScanaPLUS device ID from the FTDI EEPROM. */
+       if ((ret = scanaplus_get_device_id(devc)) < 0) {
+               sr_err("Failed to get ScanaPLUS device ID: %d.", ret);
+               goto err_dev_open_close_ftdic;
+       }
+       sr_dbg("Received ScanaPLUS device ID successfully: %02x %02x %02x.",
+              devc->devid[0], devc->devid[1], devc->devid[2]);
+
+       sdi->status = SR_ST_ACTIVE;
+
+       return SR_OK;
+
+err_dev_open_close_ftdic:
+       scanaplus_close(devc);
+       return SR_ERR;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+       int ret;
+       struct dev_context *devc;
+
+       ret = SR_OK;
+       devc = sdi->priv;
+
+       if (sdi->status == SR_ST_ACTIVE) {
+               sr_dbg("Status ACTIVE, closing device.");
+               ret = scanaplus_close(devc);
+       } else {
+               sr_spew("Status not ACTIVE, nothing to do.");
+       }
+
+       sdi->status = SR_ST_INACTIVE;
+
+       return ret;
+}
+
+static int cleanup(void)
+{
+       return dev_clear();
+}
+
+static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       (void)sdi;
+       (void)cg;
+
+       switch (id) {
+       case SR_CONF_SAMPLERATE:
+               /* The ScanaPLUS samplerate is 100MHz and can't be changed. */
+               *data = g_variant_new_uint64(SR_MHZ(100));
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+
+       (void)cg;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       devc = sdi->priv;
+
+       switch (id) {
+       case SR_CONF_SAMPLERATE:
+               if (g_variant_get_uint64(data) != SR_MHZ(100)) {
+                       sr_err("ScanaPLUS only supports samplerate = 100MHz.");
+                       return SR_ERR_ARG;
+               }
+               /* Nothing to do, the ScanaPLUS samplerate is always 100MHz. */
+               break;
+       case SR_CONF_LIMIT_MSEC:
+               if (g_variant_get_uint64(data) == 0)
+                       return SR_ERR_ARG;
+               devc->limit_msec = g_variant_get_uint64(data);
+               break;
+       case SR_CONF_LIMIT_SAMPLES:
+               if (g_variant_get_uint64(data) == 0)
+                       return SR_ERR_ARG;
+               devc->limit_samples = g_variant_get_uint64(data);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       GVariant *gvar;
+       GVariantBuilder gvb;
+
+       (void)sdi;
+       (void)cg;
+
+       switch (key) {
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+               break;
+       case SR_CONF_SAMPLERATE:
+               g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
+               gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"),
+                               samplerates, ARRAY_SIZE(samplerates),
+                               sizeof(uint64_t));
+               g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar);
+               *data = g_variant_builder_end(&gvb);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+       int ret;
+       struct dev_context *devc;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       if (!(devc = sdi->priv))
+               return SR_ERR_BUG;
+
+       if (!devc->ftdic)
+               return SR_ERR_BUG;
+
+       /* TODO: Configure channels later (thresholds etc.). */
+
+       devc->cb_data = cb_data;
+
+       /* Properly reset internal variables before every new acquisition. */
+       devc->compressed_bytes_ignored = 0;
+       devc->samples_sent = 0;
+       devc->bytes_received = 0;
+
+       if ((ret = scanaplus_init(devc)) < 0)
+               return ret;
+
+       if ((ret = scanaplus_start_acquisition(devc)) < 0)
+               return ret;
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(sdi, LOG_PREFIX);
+
+       /* Hook up a dummy handler to receive data from the device. */
+       sr_session_source_add(sdi->session, -1, G_IO_IN, 0, scanaplus_receive_data, (void *)sdi);
+
+       return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct sr_datafeed_packet packet;
+
+       (void)cb_data;
+
+       sr_dbg("Stopping acquisition.");
+       sr_session_source_remove(sdi->session, -1);
+
+       /* Send end packet to the session bus. */
+       sr_dbg("Sending SR_DF_END.");
+       packet.type = SR_DF_END;
+       sr_session_send(sdi, &packet);
+
+       return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver ikalogic_scanaplus_driver_info = {
+       .name = "ikalogic-scanaplus",
+       .longname = "IKALOGIC ScanaPLUS",
+       .api_version = 1,
+       .init = init,
+       .cleanup = cleanup,
+       .scan = scan,
+       .dev_list = dev_list,
+       .dev_clear = dev_clear,
+       .config_get = config_get,
+       .config_set = config_set,
+       .config_list = config_list,
+       .dev_open = dev_open,
+       .dev_close = dev_close,
+       .dev_acquisition_start = dev_acquisition_start,
+       .dev_acquisition_stop = dev_acquisition_stop,
+       .priv = NULL,
+};
diff --git a/src/hardware/ikalogic-scanaplus/protocol.c b/src/hardware/ikalogic-scanaplus/protocol.c
new file mode 100644 (file)
index 0000000..3a834f7
--- /dev/null
@@ -0,0 +1,370 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "protocol.h"
+
+/*
+ * Logic level thresholds.
+ *
+ * For each of the two channel groups (1-4 and 5-9), the logic level
+ * threshold can be set independently.
+ *
+ * The threshold can be set to values that are usable for systems with
+ * different voltage levels, e.g. for 1.8V or 3.3V systems.
+ *
+ * The actual threshold value is always the middle of the values below.
+ * E.g. for a system voltage level of 1.8V, the threshold is at 0.9V. That
+ * means that values <= 0.9V are considered to be a logic 0/low, and
+ * values > 0.9V are considered to be a logic 1/high.
+ *
+ *  - 1.2V system: threshold = 0.6V
+ *  - 1.5V system: threshold = 0.75V
+ *  - 1.8V system: threshold = 0.9V
+ *  - 2.8V system: threshold = 1.4V
+ *  - 3.3V system: threshold = 1.65V
+ */
+#define THRESHOLD_1_2V_SYSTEM 0x2e
+#define THRESHOLD_1_5V_SYSTEM 0x39
+#define THRESHOLD_1_8V_SYSTEM 0x45
+#define THRESHOLD_2_8V_SYSTEM 0x6c
+#define THRESHOLD_3_3V_SYSTEM 0x7f
+
+static int scanaplus_write(struct dev_context *devc, uint8_t *buf, int size)
+{
+       int i, bytes_written;
+       GString *s;
+
+       /* Note: Caller checks devc, devc->ftdic, buf, size. */
+
+       s = g_string_sized_new(100);
+       g_string_printf(s, "Writing %d bytes: ", size);
+       for (i = 0; i < size; i++)
+               g_string_append_printf(s, "0x%02x ", buf[i]);
+       sr_spew("%s", s->str);
+       g_string_free(s, TRUE);
+
+       bytes_written = ftdi_write_data(devc->ftdic, buf, size);
+       if (bytes_written < 0) {
+               sr_err("Failed to write FTDI data (%d): %s.",
+                      bytes_written, ftdi_get_error_string(devc->ftdic));
+       } else if (bytes_written != size) {
+               sr_err("FTDI write error, only %d/%d bytes written: %s.",
+                      bytes_written, size, ftdi_get_error_string(devc->ftdic));
+       }
+
+       return bytes_written;
+}
+
+SR_PRIV int scanaplus_close(struct dev_context *devc)
+{
+       int ret;
+
+       /* Note: Caller checks devc and devc->ftdic. */
+
+       if ((ret = ftdi_usb_close(devc->ftdic)) < 0) {
+               sr_err("Failed to close FTDI device (%d): %s.",
+                      ret, ftdi_get_error_string(devc->ftdic));
+               return SR_ERR;
+       }
+
+       return SR_OK;
+}
+
+static void scanaplus_uncompress_block(struct dev_context *devc,
+                                      uint64_t num_bytes)
+{
+       uint64_t i, j;
+       uint8_t num_samples, low, high;
+
+       for (i = 0; i < num_bytes; i += 2) {
+               num_samples = devc->compressed_buf[i + 0] >> 1;
+
+               low = devc->compressed_buf[i + 0] & (1 << 0);
+               high = devc->compressed_buf[i + 1];
+
+               for (j = 0; j < num_samples; j++) {
+                       devc->sample_buf[devc->bytes_received++] = high;
+                       devc->sample_buf[devc->bytes_received++] = low;
+               }
+       }
+}
+
+static void send_samples(struct dev_context *devc, uint64_t samples_to_send)
+{
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_logic logic;
+
+       sr_spew("Sending %" PRIu64 " samples.", samples_to_send);
+
+       packet.type = SR_DF_LOGIC;
+       packet.payload = &logic;
+       logic.length = samples_to_send * 2;
+       logic.unitsize = 2; /* We need 2 bytes for 9 channels. */
+       logic.data = devc->sample_buf;
+       sr_session_send(devc->cb_data, &packet);
+
+       devc->samples_sent += samples_to_send;
+       devc->bytes_received -= samples_to_send * 2;
+}
+
+SR_PRIV int scanaplus_get_device_id(struct dev_context *devc)
+{
+       int ret;
+       uint16_t val1, val2;
+
+       /* FTDI EEPROM indices 16+17 contain the 3 device ID bytes. */
+       if ((ret = ftdi_read_eeprom_location(devc->ftdic, 16, &val1)) < 0) {
+               sr_err("Failed to read EEPROM index 16 (%d): %s.",
+                      ret, ftdi_get_error_string(devc->ftdic));
+               return SR_ERR;
+       }
+       if ((ret = ftdi_read_eeprom_location(devc->ftdic, 17, &val2)) < 0) {
+               sr_err("Failed to read EEPROM index 17 (%d): %s.",
+                      ret, ftdi_get_error_string(devc->ftdic));
+               return SR_ERR;
+       }
+
+       /*
+        * Note: Bit 7 of the three bytes must not be used, apparently.
+        *
+        * Even though the three bits can be either 0 or 1 (we've seen both
+        * in actual ScanaPLUS devices), the device ID as sent to the FPGA
+        * has bit 7 of each byte zero'd out.
+        *
+        * It is unknown whether bit 7 of these bytes has any meaning,
+        * whether it's used somewhere, or whether it can be simply ignored.
+        */
+       devc->devid[0] = ((val1 >> 0) & 0xff) & ~(1 << 7);
+       devc->devid[1] = ((val1 >> 8) & 0xff) & ~(1 << 7);
+       devc->devid[2] = ((val2 >> 0) & 0xff) & ~(1 << 7);
+
+       return SR_OK;
+}
+
+static int scanaplus_clear_device_id(struct dev_context *devc)
+{
+       uint8_t buf[2];
+
+       buf[0] = 0x8c;
+       buf[1] = 0x00;
+       if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
+               return SR_ERR;
+
+       buf[0] = 0x8e;
+       buf[1] = 0x00;
+       if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
+               return SR_ERR;
+
+       buf[0] = 0x8f;
+       buf[1] = 0x00;
+       if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
+               return SR_ERR;
+
+       return SR_OK;
+}
+
+static int scanaplus_send_device_id(struct dev_context *devc)
+{
+       uint8_t buf[2];
+
+       buf[0] = 0x8c;
+       buf[1] = devc->devid[0];
+       if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
+               return SR_ERR;
+
+       buf[0] = 0x8e;
+       buf[1] = devc->devid[1];
+       if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
+               return SR_ERR;
+
+       buf[0] = 0x8f;
+       buf[1] = devc->devid[2];
+       if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
+               return SR_ERR;
+
+       return SR_OK;
+}
+
+SR_PRIV int scanaplus_init(struct dev_context *devc)
+{
+       int i;
+       uint8_t buf[8];
+
+       buf[0] = 0x88;
+       buf[1] = 0x41;
+       if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
+               return SR_ERR;
+
+       buf[0] = 0x89;
+       buf[1] = 0x64;
+       buf[2] = 0x8a;
+       buf[3] = 0x64;
+       if (scanaplus_write(devc, (uint8_t *)&buf, 4) < 0)
+               return SR_ERR;
+
+       buf[0] = 0x88;
+       buf[1] = 0x41;
+       if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
+               return SR_ERR;
+
+       buf[0] = 0x88;
+       buf[1] = 0x40;
+       if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
+               return SR_ERR;
+
+       buf[0] = 0x8d;
+       buf[1] = 0x01;
+       buf[2] = 0x8d;
+       buf[3] = 0x05;
+       buf[4] = 0x8d;
+       buf[5] = 0x01;
+       buf[6] = 0x8d;
+       buf[7] = 0x02;
+       if (scanaplus_write(devc, (uint8_t *)&buf, 8) < 0)
+               return SR_ERR;
+
+       for (i = 0; i < 57; i++) {
+               buf[0] = 0x8d;
+               buf[1] = 0x06;
+               if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
+                       return SR_ERR;
+
+               buf[0] = 0x8d;
+               buf[1] = 0x02;
+               if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
+                       return SR_ERR;
+       }
+
+       if (scanaplus_send_device_id(devc) < 0)
+               return SR_ERR;
+
+       buf[0] = 0x88;
+       buf[1] = 0x40;
+       if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
+               return SR_ERR;
+
+       return SR_OK;
+}
+
+SR_PRIV int scanaplus_start_acquisition(struct dev_context *devc)
+{
+       uint8_t buf[4];
+
+       /* Threshold and differential channel settings not yet implemented. */
+
+       buf[0] = 0x89;
+       buf[1] = 0x7f; /* Logic level threshold for channels 1-4. */
+       buf[2] = 0x8a;
+       buf[3] = 0x7f; /* Logic level threshold for channels 5-9. */
+       if (scanaplus_write(devc, (uint8_t *)&buf, 4) < 0)
+               return SR_ERR;
+
+       buf[0] = 0x88;
+       buf[1] = 0x40; /* Special config of channels 5/6 and 7/8. */
+       /* 0x40: normal, 0x50: ch56 diff, 0x48: ch78 diff, 0x58: ch5678 diff */
+       if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
+               return SR_ERR;
+
+       if (scanaplus_clear_device_id(devc) < 0)
+               return SR_ERR;
+
+       if (scanaplus_send_device_id(devc) < 0)
+               return SR_ERR;
+
+       return SR_OK;
+}
+
+SR_PRIV int scanaplus_receive_data(int fd, int revents, void *cb_data)
+{
+       int bytes_read;
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       uint64_t max, n;
+
+       (void)fd;
+       (void)revents;
+
+       if (!(sdi = cb_data))
+               return TRUE;
+
+       if (!(devc = sdi->priv))
+               return TRUE;
+
+       if (!devc->ftdic)
+               return TRUE;
+
+       /* Get a block of data. */
+       bytes_read = ftdi_read_data(devc->ftdic, devc->compressed_buf,
+                                   COMPRESSED_BUF_SIZE);
+       if (bytes_read < 0) {
+               sr_err("Failed to read FTDI data (%d): %s.",
+                      bytes_read, ftdi_get_error_string(devc->ftdic));
+               sdi->driver->dev_acquisition_stop(sdi, sdi);
+               return FALSE;
+       }
+       if (bytes_read == 0) {
+               sr_spew("Received 0 bytes, nothing to do.");
+               return TRUE;
+       }
+
+       /*
+        * After a ScanaPLUS acquisition starts, a bunch of samples will be
+        * returned as all-zero, no matter which signals are actually present
+        * on the channels. This is probably due to the FPGA reconfiguring some
+        * of its internal state/config during this time.
+        *
+        * As far as we know there is apparently no way for the PC-side to
+        * know when this "reconfiguration" starts or ends. The FTDI chip
+        * will return all-zero "dummy" samples during this time, which is
+        * indistinguishable from actual all-zero samples.
+        *
+        * We currently simply ignore the first 64kB of data after an
+        * acquisition starts. Empirical tests have shown that the
+        * "reconfigure" time is a lot less than that usually.
+        */
+       if (devc->compressed_bytes_ignored < COMPRESSED_BUF_SIZE) {
+               /* Ignore the first 64kB of data of every acquisition. */
+               sr_spew("Ignoring first 64kB chunk of data.");
+               devc->compressed_bytes_ignored += COMPRESSED_BUF_SIZE;
+               return TRUE;
+       }
+
+       /* TODO: Handle bytes_read which is not a multiple of 2? */
+       scanaplus_uncompress_block(devc, bytes_read);
+
+       n = devc->samples_sent + (devc->bytes_received / 2);
+       max = (SR_MHZ(100) / 1000) * devc->limit_msec;
+
+       if (devc->limit_samples && (n >= devc->limit_samples)) {
+               send_samples(devc, devc->limit_samples - devc->samples_sent);
+               sr_info("Requested number of samples reached.");
+               sdi->driver->dev_acquisition_stop(sdi, cb_data);
+               return TRUE;
+       } else if (devc->limit_msec && (n >= max)) {
+               send_samples(devc, max - devc->samples_sent);
+               sr_info("Requested time limit reached.");
+               sdi->driver->dev_acquisition_stop(sdi, cb_data);
+               return TRUE;
+       } else {
+               send_samples(devc, devc->bytes_received / 2);
+       }
+
+       return TRUE;
+}
diff --git a/src/hardware/ikalogic-scanaplus/protocol.h b/src/hardware/ikalogic-scanaplus/protocol.h
new file mode 100644 (file)
index 0000000..1df0517
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#ifndef LIBSIGROK_HARDWARE_IKALOGIC_SCANAPLUS_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_IKALOGIC_SCANAPLUS_PROTOCOL_H
+
+#include <stdint.h>
+#include <string.h>
+#include <glib.h>
+#include <ftdi.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "ikalogic-scanaplus"
+
+#define COMPRESSED_BUF_SIZE            (64 * 1024)
+
+/* Private, per-device-instance driver context. */
+struct dev_context {
+       /** FTDI device context (used by libftdi). */
+       struct ftdi_context *ftdic;
+
+       /** The current sampling limit (in ms). */
+       uint64_t limit_msec;
+
+       /** The current sampling limit (in number of samples). */
+       uint64_t limit_samples;
+
+       void *cb_data;
+
+       uint8_t *compressed_buf;
+       uint64_t compressed_bytes_ignored;
+       uint8_t *sample_buf;
+       uint64_t bytes_received;
+       uint64_t samples_sent;
+
+       /** ScanaPLUS unique device ID (3 bytes). */
+       uint8_t devid[3];
+};
+
+SR_PRIV int scanaplus_close(struct dev_context *devc);
+SR_PRIV int scanaplus_get_device_id(struct dev_context *devc);
+SR_PRIV int scanaplus_init(struct dev_context *devc);
+SR_PRIV int scanaplus_start_acquisition(struct dev_context *devc);
+SR_PRIV int scanaplus_receive_data(int fd, int revents, void *cb_data);
+
+#endif
diff --git a/src/hardware/kecheng-kc-330b/api.c b/src/hardware/kecheng-kc-330b/api.c
new file mode 100644 (file)
index 0000000..71bdc01
--- /dev/null
@@ -0,0 +1,575 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert@biot.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 <string.h>
+#include "protocol.h"
+
+#define USB_CONN "1041.8101"
+#define VENDOR "Kecheng"
+#define USB_INTERFACE 0
+
+static const int32_t hwcaps[] = {
+       SR_CONF_SOUNDLEVELMETER,
+       SR_CONF_LIMIT_SAMPLES,
+       SR_CONF_CONTINUOUS,
+       SR_CONF_DATALOG,
+       SR_CONF_SPL_WEIGHT_FREQ,
+       SR_CONF_SPL_WEIGHT_TIME,
+       SR_CONF_DATA_SOURCE,
+};
+
+SR_PRIV const uint64_t kecheng_kc_330b_sample_intervals[][2] = {
+       { 1, 8 },
+       { 1, 2 },
+       { 1, 1 },
+       { 2, 1 },
+       { 5, 1 },
+       { 10, 1 },
+       { 60, 1 },
+};
+
+static const char *weight_freq[] = {
+       "A",
+       "C",
+};
+
+static const char *weight_time[] = {
+       "F",
+       "S",
+};
+
+static const char *data_sources[] = {
+       "Live",
+       "Memory",
+};
+
+SR_PRIV struct sr_dev_driver kecheng_kc_330b_driver_info;
+static struct sr_dev_driver *di = &kecheng_kc_330b_driver_info;
+
+
+static int init(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static int scan_kecheng(struct sr_usb_dev_inst *usb, char **model)
+{
+       struct drv_context *drvc;
+       int len, ret;
+       unsigned char cmd, buf[32];
+
+       drvc = di->priv;
+       if (sr_usb_open(drvc->sr_ctx->libusb_ctx, usb) != SR_OK)
+               return SR_ERR;
+
+       cmd = CMD_IDENTIFY;
+       ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, &cmd, 1, &len, 5);
+       if (ret != 0) {
+               libusb_close(usb->devhdl);
+               sr_dbg("Failed to send Identify command: %s", libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+       ret = libusb_bulk_transfer(usb->devhdl, EP_IN, buf, 32, &len, 10);
+       if (ret != 0) {
+               libusb_close(usb->devhdl);
+               sr_dbg("Failed to receive response: %s", libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+       libusb_close(usb->devhdl);
+       usb->devhdl = NULL;
+
+       if (len < 2 || buf[0] != (CMD_IDENTIFY | 0x80) || buf[1] > 30) {
+               sr_dbg("Invalid response to Identify command");
+               return SR_ERR;
+       }
+
+       buf[buf[1] + 2] = '\x0';
+       *model = g_strndup((const gchar *)buf + 2, 30);
+
+       return SR_OK;
+}
+
+static GSList *scan(GSList *options)
+{
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       struct sr_dev_inst *sdi;
+       struct sr_channel *ch;
+       GSList *usb_devices, *devices, *l;
+       char *model;
+
+       (void)options;
+
+       drvc = di->priv;
+       drvc->instances = NULL;
+
+       devices = NULL;
+       if ((usb_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, USB_CONN))) {
+               /* We have a list of sr_usb_dev_inst matching the connection
+                * string. Wrap them in sr_dev_inst and we're done. */
+               for (l = usb_devices; l; l = l->next) {
+                       if (scan_kecheng(l->data, &model) != SR_OK)
+                               continue;
+                       if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, VENDOR,
+                                       model, NULL)))
+                               return NULL;
+                       g_free(model);
+                       sdi->driver = di;
+                       sdi->inst_type = SR_INST_USB;
+                       sdi->conn = l->data;
+                       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "SPL")))
+                               return NULL;
+                       sdi->channels = g_slist_append(sdi->channels, ch);
+
+                       if (!(devc = g_try_malloc(sizeof(struct dev_context)))) {
+                               sr_dbg("Device context malloc failed.");
+                               return NULL;
+                       }
+                       sdi->priv = devc;
+                       devc->limit_samples = 0;
+                       /* The protocol provides no way to read the current
+                        * settings, so we'll enforce these. */
+                       devc->sample_interval = DEFAULT_SAMPLE_INTERVAL;
+                       devc->alarm_low = DEFAULT_ALARM_LOW;
+                       devc->alarm_high = DEFAULT_ALARM_HIGH;
+                       devc->mqflags = DEFAULT_WEIGHT_TIME | DEFAULT_WEIGHT_FREQ;
+                       devc->data_source = DEFAULT_DATA_SOURCE;
+                       devc->config_dirty = FALSE;
+
+                       /* TODO: Set date/time? */
+
+                       drvc->instances = g_slist_append(drvc->instances, sdi);
+                       devices = g_slist_append(devices, sdi);
+               }
+               g_slist_free(usb_devices);
+       } else
+               g_slist_free_full(usb_devices, g_free);
+
+       return devices;
+}
+
+static GSList *dev_list(void)
+{
+       return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+       struct drv_context *drvc;
+       struct sr_usb_dev_inst *usb;
+       int ret;
+
+       if (!(drvc = di->priv)) {
+               sr_err("Driver was not initialized.");
+               return SR_ERR;
+       }
+
+       usb = sdi->conn;
+
+       if (sr_usb_open(drvc->sr_ctx->libusb_ctx, usb) != SR_OK)
+               return SR_ERR;
+
+       if ((ret = libusb_set_configuration(usb->devhdl, 1))) {
+               sr_err("Failed to set configuration: %s.", libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+       if ((ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE))) {
+               sr_err("Failed to claim interface: %s.", libusb_error_name(ret));
+               return SR_ERR;
+       }
+       sdi->status = SR_ST_ACTIVE;
+
+       return ret;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_usb_dev_inst *usb;
+
+       if (!di->priv) {
+               sr_err("Driver was not initialized.");
+               return SR_ERR;
+       }
+
+       usb = sdi->conn;
+
+       if (!usb->devhdl)
+               /*  Nothing to do. */
+               return SR_OK;
+
+       /* This allows a frontend to configure the device without ever
+        * doing an acquisition step. */
+       devc = sdi->priv;
+       if (!devc->config_dirty)
+               kecheng_kc_330b_configure(sdi);
+
+       libusb_release_interface(usb->devhdl, USB_INTERFACE);
+       libusb_close(usb->devhdl);
+       usb->devhdl = NULL;
+       sdi->status = SR_ST_INACTIVE;
+
+       return SR_OK;
+}
+
+static int cleanup(void)
+{
+       int ret;
+       struct drv_context *drvc;
+
+       if (!(drvc = di->priv))
+               /* Can get called on an unused driver, doesn't matter. */
+               return SR_OK;
+
+
+       ret = std_dev_clear(di, NULL);
+       g_free(drvc);
+       di->priv = NULL;
+
+       return ret;
+}
+
+static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       GVariant *rational[2];
+       const uint64_t *si;
+
+       (void)cg;
+
+       devc = sdi->priv;
+       switch (key) {
+       case SR_CONF_LIMIT_SAMPLES:
+               *data = g_variant_new_uint64(devc->limit_samples);
+               break;
+       case SR_CONF_SAMPLE_INTERVAL:
+               si = kecheng_kc_330b_sample_intervals[devc->sample_interval];
+               rational[0] = g_variant_new_uint64(si[0]);
+               rational[1] = g_variant_new_uint64(si[1]);
+               *data = g_variant_new_tuple(rational, 2);
+               break;
+       case SR_CONF_DATALOG:
+               /* There really isn't a way to be sure the device is logging. */
+               return SR_ERR_NA;
+               break;
+       case SR_CONF_SPL_WEIGHT_FREQ:
+               if (devc->mqflags & SR_MQFLAG_SPL_FREQ_WEIGHT_A)
+                       *data = g_variant_new_string("A");
+               else
+                       *data = g_variant_new_string("C");
+               break;
+       case SR_CONF_SPL_WEIGHT_TIME:
+               if (devc->mqflags & SR_MQFLAG_SPL_TIME_WEIGHT_F)
+                       *data = g_variant_new_string("F");
+               else
+                       *data = g_variant_new_string("S");
+               break;
+       case SR_CONF_DATA_SOURCE:
+               if (devc->data_source == DATA_SOURCE_LIVE)
+                       *data = g_variant_new_string("Live");
+               else
+                       *data = g_variant_new_string("Memory");
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       uint64_t p, q;
+       unsigned int i;
+       int tmp, ret;
+       const char *tmp_str;
+
+       (void)cg;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       if (!di->priv) {
+               sr_err("Driver was not initialized.");
+               return SR_ERR;
+       }
+
+       devc = sdi->priv;
+       ret = SR_OK;
+       switch (key) {
+       case SR_CONF_LIMIT_SAMPLES:
+               devc->limit_samples = g_variant_get_uint64(data);
+               sr_dbg("Setting sample limit to %" PRIu64 ".",
+                      devc->limit_samples);
+               break;
+       case SR_CONF_SAMPLE_INTERVAL:
+               g_variant_get(data, "(tt)", &p, &q);
+               for (i = 0; i < ARRAY_SIZE(kecheng_kc_330b_sample_intervals); i++) {
+                       if (kecheng_kc_330b_sample_intervals[i][0] != p || kecheng_kc_330b_sample_intervals[i][1] != q)
+                               continue;
+                       devc->sample_interval = i;
+                       devc->config_dirty = TRUE;
+                       break;
+               }
+               if (i == ARRAY_SIZE(kecheng_kc_330b_sample_intervals))
+                       ret = SR_ERR_ARG;
+               break;
+       case SR_CONF_SPL_WEIGHT_FREQ:
+               tmp_str = g_variant_get_string(data, NULL);
+               if (!strcmp(tmp_str, "A"))
+                       tmp = SR_MQFLAG_SPL_FREQ_WEIGHT_A;
+               else if (!strcmp(tmp_str, "C"))
+                       tmp = SR_MQFLAG_SPL_FREQ_WEIGHT_C;
+               else
+                       return SR_ERR_ARG;
+               devc->mqflags &= ~(SR_MQFLAG_SPL_FREQ_WEIGHT_A | SR_MQFLAG_SPL_FREQ_WEIGHT_C);
+               devc->mqflags |= tmp;
+               devc->config_dirty = TRUE;
+               break;
+       case SR_CONF_SPL_WEIGHT_TIME:
+               tmp_str = g_variant_get_string(data, NULL);
+               if (!strcmp(tmp_str, "F"))
+                       tmp = SR_MQFLAG_SPL_TIME_WEIGHT_F;
+               else if (!strcmp(tmp_str, "S"))
+                       tmp = SR_MQFLAG_SPL_TIME_WEIGHT_S;
+               else
+                       return SR_ERR_ARG;
+               devc->mqflags &= ~(SR_MQFLAG_SPL_TIME_WEIGHT_F | SR_MQFLAG_SPL_TIME_WEIGHT_S);
+               devc->mqflags |= tmp;
+               devc->config_dirty = TRUE;
+               break;
+       case SR_CONF_DATA_SOURCE:
+               tmp_str = g_variant_get_string(data, NULL);
+               if (!strcmp(tmp_str, "Live"))
+                       devc->data_source = DATA_SOURCE_LIVE;
+               else if (!strcmp(tmp_str, "Memory"))
+                       devc->data_source = DATA_SOURCE_MEMORY;
+               else
+                       return SR_ERR;
+               devc->config_dirty = TRUE;
+               break;
+       default:
+               ret = SR_ERR_NA;
+       }
+
+       return ret;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       GVariant *tuple, *rational[2];
+       GVariantBuilder gvb;
+       unsigned int i;
+
+       (void)sdi;
+       (void)cg;
+
+       switch (key) {
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+               break;
+       case SR_CONF_SAMPLE_INTERVAL:
+               g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
+               for (i = 0; i < ARRAY_SIZE(kecheng_kc_330b_sample_intervals); i++) {
+                       rational[0] = g_variant_new_uint64(kecheng_kc_330b_sample_intervals[i][0]);
+                       rational[1] = g_variant_new_uint64(kecheng_kc_330b_sample_intervals[i][1]);
+                       tuple = g_variant_new_tuple(rational, 2);
+                       g_variant_builder_add_value(&gvb, tuple);
+               }
+               *data = g_variant_builder_end(&gvb);
+               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_DATA_SOURCE:
+               *data = g_variant_new_strv(data_sources, ARRAY_SIZE(data_sources));
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi,
+               void *cb_data)
+{
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_meta meta;
+       struct sr_config *src;
+       struct sr_usb_dev_inst *usb;
+       GVariant *gvar, *rational[2];
+       const uint64_t *si;
+       int stored_mqflags, req_len, buf_len, len, ret;
+       unsigned char buf[9];
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       drvc = di->priv;
+       devc = sdi->priv;
+       usb = sdi->conn;
+
+       devc->cb_data = cb_data;
+       devc->num_samples = 0;
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(cb_data, LOG_PREFIX);
+
+       if (devc->data_source == DATA_SOURCE_LIVE) {
+               /* Force configuration. */
+               kecheng_kc_330b_configure(sdi);
+
+               if (kecheng_kc_330b_status_get(sdi, &ret) != SR_OK)
+                       return SR_ERR;
+               if (ret != DEVICE_ACTIVE) {
+                       sr_err("Device is inactive");
+                       /* Still continue though, since the device will
+                        * just return 30.0 until the user hits the button
+                        * on the device -- and then start feeding good
+                        * samples back. */
+               }
+       } else {
+               if (kecheng_kc_330b_log_info_get(sdi, buf) != SR_OK)
+                       return SR_ERR;
+               stored_mqflags = buf[4] ? SR_MQFLAG_SPL_TIME_WEIGHT_S : SR_MQFLAG_SPL_TIME_WEIGHT_F;
+               stored_mqflags |= buf[5] ? SR_MQFLAG_SPL_FREQ_WEIGHT_C : SR_MQFLAG_SPL_FREQ_WEIGHT_A;
+               devc->stored_samples = (buf[7] << 8) | buf[8];
+               if (devc->stored_samples == 0) {
+                       /* Notify frontend of empty log by sending start/end packets. */
+                       packet.type = SR_DF_END;
+                       sr_session_send(cb_data, &packet);
+                       return SR_OK;
+               }
+
+               if (devc->limit_samples && devc->limit_samples < devc->stored_samples)
+                       devc->stored_samples = devc->limit_samples;
+
+               si = kecheng_kc_330b_sample_intervals[buf[1]];
+               rational[0] = g_variant_new_uint64(si[0]);
+               rational[1] = g_variant_new_uint64(si[1]);
+               gvar = g_variant_new_tuple(rational, 2);
+               src = sr_config_new(SR_CONF_SAMPLE_INTERVAL, gvar);
+               packet.type = SR_DF_META;
+               packet.payload = &meta;
+               meta.config = g_slist_append(NULL, src);
+               sr_session_send(devc->cb_data, &packet);
+               g_free(src);
+       }
+
+       if (!(devc->xfer = libusb_alloc_transfer(0)))
+               return SR_ERR;
+
+       usb_source_add(sdi->session, drvc->sr_ctx, 10,
+               kecheng_kc_330b_handle_events, (void *)sdi);
+
+       if (devc->data_source == DATA_SOURCE_LIVE) {
+               buf[0] = CMD_GET_LIVE_SPL;
+               buf_len = 1;
+               devc->state = LIVE_SPL_WAIT;
+               devc->last_live_request = g_get_monotonic_time() / 1000;
+               req_len = 3;
+       } else {
+               buf[0] = CMD_GET_LOG_DATA;
+               buf[1] = 0;
+               buf[2] = 0;
+               buf_len = 4;
+               devc->state = LOG_DATA_WAIT;
+               if (devc->stored_samples < 63)
+                       buf[3] = devc->stored_samples;
+               else
+                       buf[3] = 63;
+               /* Command ack byte + 2 bytes per sample. */
+               req_len = 1 + buf[3] * 2;
+       }
+
+       ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, buf, buf_len, &len, 5);
+       if (ret != 0 || len != 1) {
+               sr_dbg("Failed to start acquisition: %s", libusb_error_name(ret));
+               libusb_free_transfer(devc->xfer);
+               return SR_ERR;
+       }
+
+       libusb_fill_bulk_transfer(devc->xfer, usb->devhdl, EP_IN, devc->buf,
+                       req_len, kecheng_kc_330b_receive_transfer, (void *)sdi, 15);
+       if (libusb_submit_transfer(devc->xfer) != 0) {
+               libusb_free_transfer(devc->xfer);
+               return SR_ERR;
+       }
+
+       return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct dev_context *devc;
+
+       (void)cb_data;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       /* Signal USB transfer handler to clean up and stop. */
+       sdi->status = SR_ST_STOPPING;
+
+       devc = sdi->priv;
+       if (devc->data_source == DATA_SOURCE_MEMORY && devc->config_dirty) {
+               /* The protocol doesn't have a command to clear stored data;
+                * it clears it whenever new configuration is set. That means
+                * we can't just configure the device any time we want when
+                * it's in DATA_SOURCE_MEMORY mode. The only safe time to do
+                * it is now, when we're sure we've pulled in all the stored
+                * data. */
+               kecheng_kc_330b_configure(sdi);
+       }
+
+       return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver kecheng_kc_330b_driver_info = {
+       .name = "kecheng-kc-330b",
+       .longname = "Kecheng KC-330B",
+       .api_version = 1,
+       .init = init,
+       .cleanup = cleanup,
+       .scan = scan,
+       .dev_list = 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,
+       .priv = NULL,
+};
diff --git a/src/hardware/kecheng-kc-330b/protocol.c b/src/hardware/kecheng-kc-330b/protocol.c
new file mode 100644 (file)
index 0000000..caf896a
--- /dev/null
@@ -0,0 +1,338 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert@biot.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 <string.h>
+#include "protocol.h"
+
+extern struct sr_dev_driver kecheng_kc_330b_driver_info;
+static struct sr_dev_driver *di = &kecheng_kc_330b_driver_info;
+extern const uint64_t kecheng_kc_330b_sample_intervals[][2];
+
+SR_PRIV int kecheng_kc_330b_handle_events(int fd, int revents, void *cb_data)
+{
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       struct sr_datafeed_packet packet;
+       struct sr_dev_inst *sdi;
+       struct sr_usb_dev_inst *usb;
+       struct timeval tv;
+       const uint64_t *intv_entry;
+       gint64 now, interval;
+       int offset, len, ret;
+       unsigned char buf[4];
+
+       (void)fd;
+       (void)revents;
+
+       drvc = di->priv;
+       sdi = cb_data;
+       devc = sdi->priv;
+       usb = sdi->conn;
+
+       memset(&tv, 0, sizeof(struct timeval));
+       libusb_handle_events_timeout_completed(drvc->sr_ctx->libusb_ctx, &tv,
+                                              NULL);
+
+       if (sdi->status == SR_ST_STOPPING) {
+               libusb_free_transfer(devc->xfer);
+               usb_source_remove(sdi->session, drvc->sr_ctx);
+               packet.type = SR_DF_END;
+               sr_session_send(cb_data, &packet);
+               sdi->status = SR_ST_ACTIVE;
+               return TRUE;
+       }
+
+       if (devc->state == LIVE_SPL_IDLE) {
+               /* Request samples at the interval rate. */
+               now = g_get_monotonic_time() / 1000;
+               intv_entry = kecheng_kc_330b_sample_intervals[devc->sample_interval];
+               interval = intv_entry[0] * 1000 / intv_entry[1];
+               if (now - devc->last_live_request > interval) {
+                       buf[0] = CMD_GET_LIVE_SPL;
+                       ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, buf, 1, &len, 5);
+                       if (ret != 0 || len != 1) {
+                               sr_dbg("Failed to request new acquisition: %s",
+                                               libusb_error_name(ret));
+                               sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi,
+                                               devc->cb_data);
+                               return TRUE;
+                       }
+                       libusb_submit_transfer(devc->xfer);
+                       devc->last_live_request = now;
+                       devc->state = LIVE_SPL_WAIT;
+               }
+       } else if (devc->state == LIVE_SPL_IDLE) {
+               buf[0] = CMD_GET_LOG_DATA;
+               offset = devc->num_samples / 63;
+               buf[1] = (offset >> 8) & 0xff;
+               buf[2] = offset & 0xff;
+               if (devc->stored_samples - devc->num_samples > 63)
+                       buf[3] = 63;
+               else
+                       /* Last chunk. */
+                       buf[3] = devc->stored_samples - devc->num_samples;
+               ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, buf, 4, &len, 5);
+               if (ret != 0 || len != 4) {
+                       sr_dbg("Failed to request next chunk: %s",
+                                       libusb_error_name(ret));
+                       sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi,
+                                       devc->cb_data);
+                       return TRUE;
+               }
+               libusb_submit_transfer(devc->xfer);
+               devc->state = LIVE_SPL_WAIT;
+       }
+
+       return TRUE;
+}
+
+static void send_data(const struct sr_dev_inst *sdi, void *buf, unsigned int buf_len)
+{
+       struct dev_context *devc;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_analog analog;
+
+       devc = sdi->priv;
+
+       memset(&analog, 0, sizeof(struct sr_datafeed_analog));
+       analog.mq = SR_MQ_SOUND_PRESSURE_LEVEL;
+       analog.mqflags = devc->mqflags;
+       analog.unit = SR_UNIT_DECIBEL_SPL;
+       analog.channels = sdi->channels;
+       analog.num_samples = buf_len;
+       analog.data = buf;
+       packet.type = SR_DF_ANALOG;
+       packet.payload = &analog;
+       sr_session_send(devc->cb_data, &packet);
+
+}
+
+SR_PRIV void kecheng_kc_330b_receive_transfer(struct libusb_transfer *transfer)
+{
+       struct dev_context *devc;
+       struct sr_dev_inst *sdi;
+       float fvalue[64];
+       int packet_has_error, num_samples, i;
+
+       sdi = transfer->user_data;
+       devc = sdi->priv;
+
+       packet_has_error = FALSE;
+       switch (transfer->status) {
+       case LIBUSB_TRANSFER_NO_DEVICE:
+               /* USB device was unplugged. */
+               sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi,
+                               devc->cb_data);
+               return;
+       case LIBUSB_TRANSFER_COMPLETED:
+       case LIBUSB_TRANSFER_TIMED_OUT: /* We may have received some data though */
+               break;
+       default:
+               packet_has_error = TRUE;
+               break;
+       }
+
+       if (packet_has_error)
+               return;
+
+       if (devc->state == LIVE_SPL_WAIT) {
+               if (transfer->actual_length != 3 || transfer->buffer[0] != 0x88) {
+                       sr_dbg("Received invalid SPL packet.");
+               } else {
+                       fvalue[0] = ((transfer->buffer[1] << 8) + transfer->buffer[2]) / 10.0;
+                       send_data(sdi, fvalue, 1);
+                       devc->num_samples++;
+                       if (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
+                               sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi,
+                                               devc->cb_data);
+                       } else {
+                               /* let USB event handler fire off another
+                                * request when the time is right. */
+                               devc->state = LIVE_SPL_IDLE;
+                       }
+               }
+       } else if (devc->state == LOG_DATA_WAIT) {
+               if (transfer->actual_length < 1 || !(transfer->actual_length & 0x01)) {
+                       sr_dbg("Received invalid stored SPL packet.");
+               } else {
+                       num_samples = (transfer->actual_length - 1) / 2;
+                       for (i = 0; i < num_samples; i++) {
+                               fvalue[i] = transfer->buffer[1 + i * 2] << 8;
+                               fvalue[i] += transfer->buffer[1 + i * 2 + 1];
+                               fvalue[i] /= 10.0;
+                       }
+                       send_data(sdi, fvalue, 1);
+                       devc->num_samples += num_samples;
+                       if (devc->num_samples >= devc->stored_samples) {
+                               sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi,
+                                               devc->cb_data);
+                       } else {
+                               /* let USB event handler fire off another
+                                * request when the time is right. */
+                               devc->state = LOG_DATA_IDLE;
+                       }
+               }
+       }
+
+}
+
+SR_PRIV int kecheng_kc_330b_configure(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_usb_dev_inst *usb;
+       int len, ret;
+       unsigned char buf[7];
+
+       sr_dbg("Configuring device.");
+
+       usb = sdi->conn;
+       devc = sdi->priv;
+
+       buf[0] = CMD_CONFIGURE;
+       buf[1] = devc->sample_interval;
+       buf[2] = devc->alarm_low;
+       buf[3] = devc->alarm_high;
+       buf[4] = devc->mqflags & SR_MQFLAG_SPL_TIME_WEIGHT_F ? 0 : 1;
+       buf[5] = devc->mqflags & SR_MQFLAG_SPL_FREQ_WEIGHT_A ? 0 : 1;
+       buf[6] = devc->data_source;
+       ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, buf, 7, &len, 5);
+       if (ret != 0 || len != 7) {
+               sr_dbg("Failed to configure device: %s", libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+       /* The configure command ack takes about 32ms to come in. */
+       ret = libusb_bulk_transfer(usb->devhdl, EP_IN, buf, 1, &len, 40);
+       if (ret != 0 || len != 1) {
+               sr_dbg("Failed to configure device (no ack): %s", libusb_error_name(ret));
+               return SR_ERR;
+       }
+       if (buf[0] != (CMD_CONFIGURE | 0x80)) {
+               sr_dbg("Failed to configure device: invalid response 0x%2.x", buf[0]);
+               return SR_ERR;
+       }
+
+       devc->config_dirty = FALSE;
+
+       return SR_OK;
+}
+
+SR_PRIV int kecheng_kc_330b_set_date_time(struct sr_dev_inst *sdi)
+{
+       struct sr_usb_dev_inst *usb;
+       GDateTime *dt;
+       int len, ret;
+       unsigned char buf[7];
+
+       sr_dbg("Setting device date/time.");
+
+       usb = sdi->conn;
+
+       dt = g_date_time_new_now_local();
+       buf[0] = CMD_SET_DATE_TIME;
+       buf[1] = g_date_time_get_year(dt) - 2000;
+       buf[2] = g_date_time_get_month(dt);
+       buf[3] = g_date_time_get_day_of_month(dt);
+       buf[4] = g_date_time_get_hour(dt);
+       buf[5] = g_date_time_get_minute(dt);
+       buf[6] = g_date_time_get_second(dt);
+       g_date_time_unref(dt);
+       ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, buf, 7, &len, 5);
+       if (ret != 0 || len != 7) {
+               sr_dbg("Failed to set date/time: %s", libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+       ret = libusb_bulk_transfer(usb->devhdl, EP_IN, buf, 1, &len, 10);
+       if (ret != 0 || len != 1) {
+               sr_dbg("Failed to set date/time (no ack): %s", libusb_error_name(ret));
+               return SR_ERR;
+       }
+       if (buf[0] != (CMD_SET_DATE_TIME | 0x80)) {
+               sr_dbg("Failed to set date/time: invalid response 0x%2.x", buf[0]);
+               return SR_ERR;
+       }
+
+       return SR_OK;
+}
+
+SR_PRIV int kecheng_kc_330b_status_get(const struct sr_dev_inst *sdi,
+               int *status)
+{
+       struct sr_usb_dev_inst *usb;
+       int len, ret;
+       unsigned char buf;
+
+       sr_dbg("Getting device status.");
+
+       usb = sdi->conn;
+       buf = CMD_GET_STATUS;
+       ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, &buf, 1, &len, 5);
+       if (ret != 0 || len != 1) {
+               sr_dbg("Failed to get status: %s", libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+       ret = libusb_bulk_transfer(usb->devhdl, EP_IN, &buf, 1, &len, 10);
+       if (ret != 0 || len != 1) {
+               sr_dbg("Failed to get status (no ack): %s", libusb_error_name(ret));
+               return SR_ERR;
+       }
+       /* Need either 0x84 or 0xa4. */
+       if (buf != (CMD_GET_STATUS | 0x80) && buf != (CMD_GET_STATUS | 0xa0)) {
+               sr_dbg("Failed to get status: invalid response 0x%2.x", buf);
+               return SR_ERR;
+       }
+
+       if (buf & 0x20)
+               *status = DEVICE_INACTIVE;
+       else
+               *status = DEVICE_ACTIVE;
+
+       return SR_OK;
+}
+
+SR_PRIV int kecheng_kc_330b_log_info_get(const struct sr_dev_inst *sdi,
+               unsigned char *buf)
+{
+       struct sr_usb_dev_inst *usb;
+       int len, ret;
+
+       sr_dbg("Getting logging info.");
+
+       usb = sdi->conn;
+       buf[0] = CMD_GET_LOG_INFO;
+       ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, buf, 1, &len, 5);
+       if (ret != 0 || len != 1) {
+               sr_dbg("Failed to get status: %s", libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+       ret = libusb_bulk_transfer(usb->devhdl, EP_IN, buf, 9, &len, 10);
+       if (ret != 0 || len != 9) {
+               sr_dbg("Failed to get status (no ack): %s", libusb_error_name(ret));
+               return SR_ERR;
+       }
+       if (buf[0] != (CMD_GET_LOG_INFO | 0x80) || buf[1] > 6) {
+               sr_dbg("Failed to get log info: invalid response 0x%2.x", buf[0]);
+               return SR_ERR;
+       }
+
+       return SR_OK;
+}
diff --git a/src/hardware/kecheng-kc-330b/protocol.h b/src/hardware/kecheng-kc-330b/protocol.h
new file mode 100644 (file)
index 0000000..09152b9
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert@biot.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_KECHENG_KC_330B_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_KECHENG_KC_330B_PROTOCOL_H
+
+#include <stdint.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "kecheng-kc-330b"
+
+#define EP_IN 0x80 | 1
+#define EP_OUT 2
+
+/* 500ms */
+#define DEFAULT_SAMPLE_INTERVAL 0
+#define DEFAULT_ALARM_LOW 40
+#define DEFAULT_ALARM_HIGH 120
+#define DEFAULT_WEIGHT_TIME SR_MQFLAG_SPL_TIME_WEIGHT_F
+#define DEFAULT_WEIGHT_FREQ SR_MQFLAG_SPL_FREQ_WEIGHT_A
+/* Live */
+#define DEFAULT_DATA_SOURCE DATA_SOURCE_LIVE
+
+enum {
+       LIVE_SPL_IDLE,
+       LIVE_SPL_WAIT,
+       LOG_DATA_IDLE,
+       LOG_DATA_WAIT,
+};
+
+enum {
+       CMD_CONFIGURE = 0x01,
+       CMD_IDENTIFY = 0x02,
+       CMD_SET_DATE_TIME = 0x03,
+       CMD_GET_STATUS = 0x04,
+       CMD_GET_LOG_INFO = 0x05,
+       CMD_GET_LOG_DATA = 0x07,
+       CMD_GET_LIVE_SPL = 0x08,
+};
+
+enum {
+       DATA_SOURCE_LIVE,
+       DATA_SOURCE_MEMORY,
+};
+
+enum {
+       DEVICE_ACTIVE,
+       DEVICE_INACTIVE,
+};
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+       /* Acquisition settings */
+       uint64_t limit_samples;
+       int sample_interval;
+       int alarm_low;
+       int alarm_high;
+       uint64_t mqflags;
+       int data_source;
+
+       /* Operational state */
+       int state;
+       gboolean config_dirty;
+       uint64_t num_samples;
+       uint64_t stored_samples;
+       void *cb_data;
+       struct libusb_transfer *xfer;
+       unsigned char buf[128];
+
+       /* Temporary state across callbacks */
+       gint64 last_live_request;
+
+};
+
+SR_PRIV int kecheng_kc_330b_handle_events(int fd, int revents, void *cb_data);
+SR_PRIV void kecheng_kc_330b_receive_transfer(struct libusb_transfer *transfer);
+SR_PRIV int kecheng_kc_330b_configure(const struct sr_dev_inst *sdi);
+SR_PRIV int kecheng_kc_330b_set_date_time(struct sr_dev_inst *sdi);
+SR_PRIV int kecheng_kc_330b_recording_get(const struct sr_dev_inst *sdi,
+               gboolean *tmp);
+SR_PRIV int kecheng_kc_330b_status_get(const struct sr_dev_inst *sdi,
+               int *status);
+SR_PRIV int kecheng_kc_330b_log_info_get(const struct sr_dev_inst *sdi,
+               unsigned char *buf);
+
+#endif
diff --git a/src/hardware/lascar-el-usb/api.c b/src/hardware/lascar-el-usb/api.c
new file mode 100644 (file)
index 0000000..04f844b
--- /dev/null
@@ -0,0 +1,490 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert@biot.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 <glib.h>
+#include <libusb.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "protocol.h"
+
+SR_PRIV struct sr_dev_driver lascar_el_usb_driver_info;
+static struct sr_dev_driver *di = &lascar_el_usb_driver_info;
+
+static const int32_t hwopts[] = {
+       SR_CONF_CONN,
+};
+
+static const int32_t hwcaps[] = {
+       SR_CONF_THERMOMETER,
+       SR_CONF_HYGROMETER,
+       SR_CONF_DATALOG,
+       SR_CONF_LIMIT_SAMPLES,
+};
+
+static int init(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+       struct drv_context *drvc;
+       struct sr_dev_inst *sdi;
+       struct sr_usb_dev_inst *usb;
+       struct sr_config *src;
+       GSList *usb_devices, *devices, *l;
+       const char *conn;
+
+       drvc = di->priv;
+
+       conn = NULL;
+       for (l = options; l; l = l->next) {
+               src = l->data;
+               switch (src->key) {
+               case SR_CONF_CONN:
+                       conn = g_variant_get_string(src->data, NULL);
+                       break;
+               }
+       }
+       if (!conn)
+               return NULL;
+
+       devices = NULL;
+       if ((usb_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn))) {
+               /* We have a list of sr_usb_dev_inst matching the connection
+                * string. Wrap them in sr_dev_inst and we're done. */
+               for (l = usb_devices; l; l = l->next) {
+                       usb = l->data;
+                       if (!(sdi = lascar_scan(usb->bus, usb->address))) {
+                               /* Not a Lascar EL-USB. */
+                               g_free(usb);
+                               continue;
+                       }
+                       sdi->inst_type = SR_INST_USB;
+                       sdi->conn = usb;
+                       drvc->instances = g_slist_append(drvc->instances, sdi);
+                       devices = g_slist_append(devices, sdi);
+               }
+               g_slist_free(usb_devices);
+       } else
+               g_slist_free_full(usb_devices, g_free);
+
+       return devices;
+}
+
+static GSList *dev_list(void)
+{
+       return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+       struct drv_context *drvc;
+       struct sr_usb_dev_inst *usb;
+       int ret;
+
+       if (!(drvc = di->priv)) {
+               sr_err("Driver was not initialized.");
+               return SR_ERR;
+       }
+
+       usb = sdi->conn;
+
+       if (sr_usb_open(drvc->sr_ctx->libusb_ctx, usb) != SR_OK)
+               return SR_ERR;
+
+       if ((ret = libusb_claim_interface(usb->devhdl, LASCAR_INTERFACE))) {
+               sr_err("Failed to claim interface: %s.", libusb_error_name(ret));
+               return SR_ERR;
+       }
+       sdi->status = SR_ST_ACTIVE;
+
+       return ret;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+       struct sr_usb_dev_inst *usb;
+
+       if (!di->priv) {
+               sr_err("Driver was not initialized.");
+               return SR_ERR;
+       }
+
+       usb = sdi->conn;
+
+       if (!usb->devhdl)
+               /*  Nothing to do. */
+               return SR_OK;
+
+       libusb_release_interface(usb->devhdl, LASCAR_INTERFACE);
+       libusb_close(usb->devhdl);
+       usb->devhdl = NULL;
+       sdi->status = SR_ST_INACTIVE;
+
+       return SR_OK;
+}
+
+static int cleanup(void)
+{
+       int ret;
+       struct drv_context *drvc;
+
+       if (!(drvc = di->priv))
+               /* Can get called on an unused driver, doesn't matter. */
+               return SR_OK;
+
+
+       ret = std_dev_clear(di, NULL);
+       g_free(drvc);
+       di->priv = NULL;
+
+       return ret;
+}
+
+static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       struct sr_usb_dev_inst *usb;
+       int ret;
+       char str[128];
+
+       (void)cg;
+
+       devc = sdi->priv;
+       switch (id) {
+       case SR_CONF_CONN:
+               if (!sdi || !sdi->conn)
+                       return SR_ERR_ARG;
+               usb = sdi->conn;
+               snprintf(str, 128, "%d.%d", usb->bus, usb->address);
+               *data = g_variant_new_string(str);
+               break;
+       case SR_CONF_DATALOG:
+               if (!sdi)
+                       return SR_ERR_ARG;
+               if ((ret = lascar_is_logging(sdi)) == -1)
+                       return SR_ERR;
+               *data = g_variant_new_boolean(ret ? TRUE : FALSE);
+               break;
+       case SR_CONF_LIMIT_SAMPLES:
+               *data = g_variant_new_uint64(devc->limit_samples);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       int ret;
+
+       (void)cg;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       if (!di->priv) {
+               sr_err("Driver was not initialized.");
+               return SR_ERR;
+       }
+
+       devc = sdi->priv;
+       ret = SR_OK;
+       switch (id) {
+       case SR_CONF_DATALOG:
+               if (g_variant_get_boolean(data)) {
+                       /* Start logging. */
+                       ret = lascar_start_logging(sdi);
+               } else {
+                       /* Stop logging. */
+                       ret = lascar_stop_logging(sdi);
+               }
+               break;
+       case SR_CONF_LIMIT_SAMPLES:
+               devc->limit_samples = g_variant_get_uint64(data);
+               sr_dbg("Setting sample limit to %" PRIu64 ".",
+                      devc->limit_samples);
+               break;
+       default:
+               ret = SR_ERR_NA;
+       }
+
+       return ret;
+}
+
+static int config_list(int 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_INT32,
+                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+               break;
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static void mark_xfer(struct libusb_transfer *xfer)
+{
+
+       if (xfer->status == LIBUSB_TRANSFER_COMPLETED)
+               xfer->user_data = GINT_TO_POINTER(1);
+       else
+               xfer->user_data = GINT_TO_POINTER(-1);
+
+}
+
+/* The Lascar software, in its infinite ignorance, reads a set of four
+ * bytes from the device config struct and interprets it as a float.
+ * That only works because they only use windows, and only on x86. However
+ * we may be running on any architecture, any operating system. So we have
+ * to convert these four bytes as the Lascar software would on windows/x86,
+ * to the local representation of a float.
+ * The source format is little-endian, with IEEE 754-2008 BINARY32 encoding. */
+static float binary32_le_to_float(unsigned char *buf)
+{
+       GFloatIEEE754 f;
+
+       f.v_float = 0;
+       f.mpn.sign = (buf[3] & 0x80) ? 1 : 0;
+       f.mpn.biased_exponent = (buf[3] << 1) | (buf[2] >> 7);
+       f.mpn.mantissa = buf[0] | (buf[1] << 8) | ((buf[2] & 0x7f) << 16);
+
+       return f.v_float;
+}
+
+static int lascar_proc_config(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_usb_dev_inst *usb;
+       int dummy, ret;
+
+       devc = sdi->priv;
+       usb = sdi->conn;
+
+       if (lascar_get_config(usb->devhdl, devc->config, &dummy) != SR_OK)
+               return SR_ERR;
+
+       ret = SR_OK;
+       switch (devc->profile->logformat) {
+       case LOG_TEMP_RH:
+               devc->sample_size = 2;
+               devc->temp_unit = devc->config[0x2e] | (devc->config[0x2f] << 8);
+               if (devc->temp_unit != 0 && devc->temp_unit != 1) {
+                       sr_dbg("invalid temperature unit %d", devc->temp_unit);
+                       /* Default to Celcius, we're all adults here. */
+                       devc->temp_unit = 0;
+               } else
+                       sr_dbg("temperature unit is %s", devc->temp_unit
+                                       ? "Fahrenheit" : "Celcius");
+               break;
+       case LOG_CO:
+               devc->sample_size = 2;
+               devc->co_high = binary32_le_to_float(devc->config + 0x24);
+               devc->co_low = binary32_le_to_float(devc->config + 0x28);
+               sr_dbg("EL-USB-CO calibration high %f low %f", devc->co_high,
+                               devc->co_low);
+               break;
+       default:
+               ret = SR_ERR_ARG;
+       }
+       devc->logged_samples = devc->config[0x1e] | (devc->config[0x1f] << 8);
+       sr_dbg("device log contains %d samples.", devc->logged_samples);
+
+       return ret;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_meta meta;
+       struct sr_config *src;
+       struct dev_context *devc;
+       struct drv_context *drvc;
+       struct sr_usb_dev_inst *usb;
+       struct libusb_transfer *xfer_in, *xfer_out;
+       struct timeval tv;
+       uint64_t interval;
+       int ret;
+       unsigned char cmd[3], resp[4], *buf;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       if (!di->priv) {
+               sr_err("Driver was not initialized.");
+               return SR_ERR;
+       }
+
+       drvc = di->priv;
+       devc = sdi->priv;
+       usb = sdi->conn;
+       devc->cb_data = cb_data;
+
+       if (lascar_proc_config(sdi) != SR_OK)
+               return SR_ERR;
+
+       sr_dbg("Starting log retrieval.");
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(cb_data, LOG_PREFIX);
+
+       interval = (devc->config[0x1c] | (devc->config[0x1d] << 8)) * 1000;
+       packet.type = SR_DF_META;
+       packet.payload = &meta;
+       src = sr_config_new(SR_CONF_SAMPLE_INTERVAL, g_variant_new_uint64(interval));
+       meta.config = g_slist_append(NULL, src);
+       sr_session_send(devc->cb_data, &packet);
+       g_free(src);
+
+       if (devc->logged_samples == 0) {
+               /* This ensures the frontend knows the session is done. */
+               packet.type = SR_DF_END;
+               sr_session_send(devc->cb_data, &packet);
+               return SR_OK;
+       }
+
+       if (!(xfer_in = libusb_alloc_transfer(0)) ||
+                       !(xfer_out = libusb_alloc_transfer(0)))
+               return SR_ERR;
+
+       libusb_control_transfer(usb->devhdl, LIBUSB_REQUEST_TYPE_VENDOR,
+                       0x00, 0xffff, 0x00, NULL, 0, 50);
+       libusb_control_transfer(usb->devhdl, LIBUSB_REQUEST_TYPE_VENDOR,
+                       0x02, 0x0002, 0x00, NULL, 0, 50);
+       libusb_control_transfer(usb->devhdl, LIBUSB_REQUEST_TYPE_VENDOR,
+                       0x02, 0x0001, 0x00, NULL, 0, 50);
+
+
+       /* Flush input. The F321 requires this. */
+       while (libusb_bulk_transfer(usb->devhdl, LASCAR_EP_IN, resp,
+                       256, &ret, 5) == 0 && ret > 0)
+               ;
+
+       libusb_fill_bulk_transfer(xfer_in, usb->devhdl, LASCAR_EP_IN,
+                       resp, sizeof(resp), mark_xfer, 0, 10000);
+       if (libusb_submit_transfer(xfer_in) != 0) {
+               libusb_free_transfer(xfer_in);
+               libusb_free_transfer(xfer_out);
+               return SR_ERR;
+       }
+
+       cmd[0] = 0x03;
+       cmd[1] = 0xff;
+       cmd[2] = 0xff;
+       libusb_fill_bulk_transfer(xfer_out, usb->devhdl, LASCAR_EP_OUT,
+                       cmd, 3, mark_xfer, 0, 100);
+       if (libusb_submit_transfer(xfer_out) != 0) {
+               libusb_free_transfer(xfer_in);
+               libusb_free_transfer(xfer_out);
+               return SR_ERR;
+       }
+
+       tv.tv_sec = 0;
+       tv.tv_usec = 0;
+       while (!xfer_in->user_data || !xfer_out->user_data) {
+               g_usleep(5000);
+               libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
+       }
+       if (xfer_in->user_data != GINT_TO_POINTER(1) ||
+                       xfer_in->user_data != GINT_TO_POINTER(1)) {
+               sr_dbg("no response to log transfer request");
+               libusb_free_transfer(xfer_in);
+               libusb_free_transfer(xfer_out);
+               return SR_ERR;
+       }
+       if (xfer_in->actual_length != 3 || xfer_in->buffer[0] != 2) {
+               sr_dbg("invalid response to log transfer request");
+               libusb_free_transfer(xfer_in);
+               libusb_free_transfer(xfer_out);
+               return SR_ERR;
+       }
+       devc->log_size = xfer_in->buffer[1] + (xfer_in->buffer[2] << 8);
+       libusb_free_transfer(xfer_out);
+
+       usb_source_add(sdi->session, drvc->sr_ctx, 100,
+                       lascar_el_usb_handle_events, (void *)sdi);
+
+       buf = g_try_malloc(4096);
+       libusb_fill_bulk_transfer(xfer_in, usb->devhdl, LASCAR_EP_IN,
+                       buf, 4096, lascar_el_usb_receive_transfer, cb_data, 100);
+       if ((ret = libusb_submit_transfer(xfer_in) != 0)) {
+               sr_err("Unable to submit transfer: %s.", libusb_error_name(ret));
+               libusb_free_transfer(xfer_in);
+               g_free(buf);
+               return SR_ERR;
+       }
+
+       return SR_OK;
+}
+
+SR_PRIV int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       (void)cb_data;
+
+       if (!di->priv) {
+               sr_err("Driver was not initialized.");
+               return SR_ERR;
+       }
+
+       if (sdi->status != SR_ST_ACTIVE) {
+               sr_err("Device inactive, can't stop acquisition.");
+               return SR_ERR;
+       }
+
+       sdi->status = SR_ST_STOPPING;
+       /* TODO: free ongoing transfers? */
+
+       return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver lascar_el_usb_driver_info = {
+       .name = "lascar-el-usb",
+       .longname = "Lascar EL-USB",
+       .api_version = 1,
+       .init = init,
+       .cleanup = cleanup,
+       .scan = scan,
+       .dev_list = 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,
+       .priv = NULL,
+};
diff --git a/src/hardware/lascar-el-usb/protocol.c b/src/hardware/lascar-el-usb/protocol.c
new file mode 100644 (file)
index 0000000..49c5cd0
--- /dev/null
@@ -0,0 +1,656 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert@biot.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 <stdlib.h>
+#include <sys/time.h>
+#include <string.h>
+#include <math.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "protocol.h"
+
+extern struct sr_dev_driver lascar_el_usb_driver_info;
+static struct sr_dev_driver *di = &lascar_el_usb_driver_info;
+
+static const struct elusb_profile profiles[] = {
+       { 1, "EL-USB-1", LOG_UNSUPPORTED },
+       { 2, "EL-USB-1", LOG_UNSUPPORTED },
+       { 3, "EL-USB-2", LOG_TEMP_RH },
+       { 4, "EL-USB-3", LOG_UNSUPPORTED },
+       { 5, "EL-USB-4", LOG_UNSUPPORTED },
+       { 6, "EL-USB-3", LOG_UNSUPPORTED },
+       { 7, "EL-USB-4", LOG_UNSUPPORTED },
+       { 8, "EL-USB-LITE", LOG_UNSUPPORTED },
+       { 9, "EL-USB-CO", LOG_CO },
+       { 10, "EL-USB-TC", LOG_UNSUPPORTED },
+       { 11, "EL-USB-CO300", LOG_CO },
+       { 12, "EL-USB-2-LCD", LOG_TEMP_RH },
+       { 13, "EL-USB-2+", LOG_TEMP_RH },
+       { 14, "EL-USB-1-PRO", LOG_UNSUPPORTED },
+       { 15, "EL-USB-TC-LCD", LOG_UNSUPPORTED },
+       { 16, "EL-USB-2-LCD+", LOG_TEMP_RH },
+       { 17, "EL-USB-5", LOG_UNSUPPORTED },
+       { 18, "EL-USB-1-RCG", LOG_UNSUPPORTED },
+       { 19, "EL-USB-1-LCD", LOG_UNSUPPORTED },
+       { 20, "EL-OEM-3", LOG_UNSUPPORTED },
+       { 21, "EL-USB-1-LCD", LOG_UNSUPPORTED },
+       { 0, NULL, 0 }
+};
+
+
+static libusb_device_handle *lascar_open(struct libusb_device *dev)
+{
+       libusb_device_handle *dev_hdl;
+       int ret;
+
+       if ((ret = libusb_open(dev, &dev_hdl)) != 0) {
+               sr_dbg("failed to open device for scan: %s",
+                               libusb_error_name(ret));
+               return NULL;
+       }
+
+       /* Some of these fail, but it needs doing -- some sort of mode
+        * setup for the SILabs F32x. */
+       libusb_control_transfer(dev_hdl, LIBUSB_REQUEST_TYPE_VENDOR,
+                       0x00, 0xffff, 0x00, NULL, 0, 50);
+       libusb_control_transfer(dev_hdl, LIBUSB_REQUEST_TYPE_VENDOR,
+                       0x02, 0x0002, 0x00, NULL, 0, 50);
+       libusb_control_transfer(dev_hdl, LIBUSB_REQUEST_TYPE_VENDOR,
+                       0x02, 0x0001, 0x00, NULL, 0, 50);
+
+       return dev_hdl;
+}
+
+static void mark_xfer(struct libusb_transfer *xfer)
+{
+
+       xfer->user_data = GINT_TO_POINTER(1);
+
+}
+
+SR_PRIV int lascar_get_config(libusb_device_handle *dev_hdl,
+               unsigned char *configblock, int *configlen)
+{
+       struct drv_context *drvc;
+       struct libusb_transfer *xfer_in, *xfer_out;
+       struct timeval tv;
+       int64_t start;
+       int buflen;
+       unsigned char cmd[3], buf[MAX_CONFIGBLOCK_SIZE];
+
+       sr_spew("Reading config block.");
+
+       drvc = di->priv;
+       *configlen = 0;
+
+       if (!(xfer_in = libusb_alloc_transfer(0)) ||
+                       !(xfer_out = libusb_alloc_transfer(0)))
+               return SR_ERR;
+
+       /* Flush anything the F321 still has queued. */
+       while (libusb_bulk_transfer(dev_hdl, LASCAR_EP_IN, buf, 256, &buflen,
+                       5) == 0 && buflen > 0)
+               ;
+
+       /* Keep a read request waiting in the wings, ready to pounce
+        * the moment the device sends something. */
+       libusb_fill_bulk_transfer(xfer_in, dev_hdl, LASCAR_EP_IN,
+                       buf, 256, mark_xfer, 0, 10000);
+       if (libusb_submit_transfer(xfer_in) != 0)
+               goto cleanup;
+
+       /* Request device configuration structure. */
+       cmd[0] = 0x00;
+       cmd[1] = 0xff;
+       cmd[2] = 0xff;
+       libusb_fill_bulk_transfer(xfer_out, dev_hdl, LASCAR_EP_OUT,
+                       cmd, 3, mark_xfer, 0, 100);
+       if (libusb_submit_transfer(xfer_out) != 0)
+               goto cleanup;
+
+       tv.tv_sec = 0;
+       tv.tv_usec = 0;
+       start = g_get_monotonic_time();
+       while (!xfer_in->user_data || !xfer_out->user_data) {
+               if (g_get_monotonic_time() - start > SCAN_TIMEOUT) {
+                       start = 0;
+                       break;
+               }
+               g_usleep(5000);
+               libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
+       }
+       if (!start) {
+               sr_dbg("no response");
+               goto cleanup;
+       }
+       if (xfer_in->actual_length != 3) {
+               sr_dbg("expected 3-byte header, got %d bytes", xfer_in->actual_length);
+               goto cleanup;
+       }
+
+       /* Got configuration structure header. */
+       sr_spew("Response to config request: 0x%.2x 0x%.2x 0x%.2x ",
+                       buf[0], buf[1], buf[2]);
+       buflen = buf[1] | (buf[2] << 8);
+       if (buf[0] != 0x02 || buflen > MAX_CONFIGBLOCK_SIZE) {
+               sr_dbg("Invalid response to config request: "
+                               "0x%.2x 0x%.2x 0x%.2x ", buf[0], buf[1], buf[2]);
+               libusb_close(dev_hdl);
+               goto cleanup;
+       }
+
+       /* Get configuration structure. */
+       xfer_in->length = buflen;
+       xfer_in->user_data = 0;
+       if (libusb_submit_transfer(xfer_in) != 0)
+               goto cleanup;
+       while (!xfer_in->user_data) {
+               if (g_get_monotonic_time() - start > SCAN_TIMEOUT) {
+                       start = 0;
+                       break;
+               }
+               g_usleep(5000);
+               libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
+       }
+       if (!start) {
+               sr_dbg("Timeout waiting for configuration structure.");
+               goto cleanup;
+       }
+       if (xfer_in->actual_length != buflen) {
+               sr_dbg("expected %d-byte structure, got %d bytes", buflen,
+                               xfer_in->actual_length);
+               goto cleanup;
+       }
+
+       memcpy(configblock, buf, buflen);
+       *configlen = buflen;
+
+cleanup:
+       if (!xfer_in->user_data || !xfer_in->user_data) {
+               if (!xfer_in->user_data)
+                       libusb_cancel_transfer(xfer_in);
+               if (!xfer_out->user_data)
+                       libusb_cancel_transfer(xfer_out);
+               start = g_get_monotonic_time();
+               while (!xfer_in->user_data || !xfer_out->user_data) {
+                       if (g_get_monotonic_time() - start > 10000)
+                               break;
+                       g_usleep(1000);
+                       libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
+               }
+       }
+       libusb_free_transfer(xfer_in);
+       libusb_free_transfer(xfer_out);
+
+       return *configlen ? SR_OK : SR_ERR;
+}
+
+static int lascar_save_config(libusb_device_handle *dev_hdl,
+               unsigned char *config, int configlen)
+{
+       struct drv_context *drvc;
+       struct libusb_transfer *xfer_in, *xfer_out;
+       struct timeval tv;
+       int64_t start;
+       int buflen, ret;
+       unsigned char cmd[3], buf[256];
+
+       sr_spew("Writing config block.");
+
+       drvc = di->priv;
+
+       if (!(xfer_in = libusb_alloc_transfer(0)) ||
+                       !(xfer_out = libusb_alloc_transfer(0)))
+               return SR_ERR;
+
+       /* Flush anything the F321 still has queued. */
+       while (libusb_bulk_transfer(dev_hdl, LASCAR_EP_IN, buf, 256, &buflen,
+                       5) == 0 && buflen > 0)
+               ;
+       ret = SR_OK;
+
+       /* Keep a read request waiting in the wings, ready to pounce
+        * the moment the device sends something. */
+       libusb_fill_bulk_transfer(xfer_in, dev_hdl, LASCAR_EP_IN,
+                       buf, 256, mark_xfer, 0, 10000);
+       if (libusb_submit_transfer(xfer_in) != 0) {
+               ret = SR_ERR;
+               goto cleanup;
+       }
+
+       /* Request device configuration structure. */
+       cmd[0] = 0x01;
+       cmd[1] = configlen & 0xff;
+       cmd[2] = (configlen >> 8) & 0xff;
+       libusb_fill_bulk_transfer(xfer_out, dev_hdl, LASCAR_EP_OUT,
+                       cmd, 3, mark_xfer, 0, 100);
+       if (libusb_submit_transfer(xfer_out) != 0) {
+               ret = SR_ERR;
+               goto cleanup;
+       }
+       tv.tv_sec = 0;
+       tv.tv_usec = 0;
+       while (!xfer_out->user_data) {
+               g_usleep(5000);
+               libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
+       }
+
+       libusb_fill_bulk_transfer(xfer_out, dev_hdl, LASCAR_EP_OUT,
+                       config, configlen, mark_xfer, 0, 100);
+       if (libusb_submit_transfer(xfer_out) != 0) {
+               ret = SR_ERR;
+               goto cleanup;
+       }
+       while (!xfer_in->user_data || !xfer_out->user_data) {
+               g_usleep(5000);
+               libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
+       }
+
+       if (xfer_in->actual_length != 1 || buf[0] != 0xff) {
+               sr_dbg("unexpected response after transfer");
+               ret = SR_ERR;
+       }
+
+cleanup:
+       if (!xfer_in->user_data || !xfer_in->user_data) {
+               if (!xfer_in->user_data)
+                       libusb_cancel_transfer(xfer_in);
+               if (!xfer_out->user_data)
+                       libusb_cancel_transfer(xfer_out);
+               start = g_get_monotonic_time();
+               while (!xfer_in->user_data || !xfer_out->user_data) {
+                       if (g_get_monotonic_time() - start > 10000)
+                               break;
+                       g_usleep(1000);
+                       libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
+               }
+       }
+       libusb_free_transfer(xfer_in);
+       libusb_free_transfer(xfer_out);
+
+       return ret;
+}
+
+static struct sr_dev_inst *lascar_identify(unsigned char *config)
+{
+       struct dev_context *devc;
+       const struct elusb_profile *profile;
+       struct sr_dev_inst *sdi;
+       struct sr_channel *ch;
+       int modelid, i;
+       char firmware[5];
+
+       modelid = config[0];
+       sdi = NULL;
+       if (modelid) {
+               profile = NULL;
+               for (i = 0; profiles[i].modelid; i++) {
+                       if (profiles[i].modelid == modelid) {
+                               profile = &profiles[i];
+                               break;
+                       }
+               }
+               if (!profile) {
+                       sr_dbg("unknown EL-USB modelid %d", modelid);
+                       return NULL;
+               }
+
+               i = config[52] | (config[53] << 8);
+               memcpy(firmware, config + 0x30, 4);
+               firmware[4] = '\0';
+               sr_dbg("found %s with firmware version %s serial %d",
+                               profile->modelname, firmware, i);
+
+               if (profile->logformat == LOG_UNSUPPORTED) {
+                       sr_dbg("unsupported EL-USB logformat for %s", profile->modelname);
+                       return NULL;
+               }
+
+               if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, LASCAR_VENDOR,
+                               profile->modelname, firmware)))
+                       return NULL;
+               sdi->driver = di;
+
+               if (profile->logformat == LOG_TEMP_RH) {
+                       /* Model this as two channels: temperature and humidity. */
+                       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "Temp")))
+                               return NULL;
+                       sdi->channels = g_slist_append(NULL, ch);
+                       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "Hum")))
+                               return NULL;
+                       sdi->channels = g_slist_append(sdi->channels, ch);
+               } else if (profile->logformat == LOG_CO) {
+                       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "CO")))
+                               return NULL;
+                       sdi->channels = g_slist_append(NULL, ch);
+               } else {
+                       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1")))
+                               return NULL;
+                       sdi->channels = g_slist_append(NULL, ch);
+               }
+
+               if (!(devc = g_try_malloc0(sizeof(struct dev_context))))
+                       return NULL;
+               sdi->priv = devc;
+               devc->profile = profile;
+       }
+
+       return sdi;
+}
+
+SR_PRIV struct sr_dev_inst *lascar_scan(int bus, int address)
+{
+       struct drv_context *drvc;
+       struct sr_dev_inst *sdi;
+       struct libusb_device **devlist;
+       struct libusb_device_descriptor des;
+       libusb_device_handle *dev_hdl;
+       int dummy, ret, i;
+       unsigned char config[MAX_CONFIGBLOCK_SIZE];
+
+       drvc = di->priv;
+       sdi = NULL;
+
+       libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
+       for (i = 0; devlist[i]; i++) {
+               if ((ret = libusb_get_device_descriptor(devlist[i], &des))) {
+                       sr_err("Failed to get device descriptor: %d.", ret);
+                       continue;
+               }
+
+               if (libusb_get_bus_number(devlist[i]) != bus ||
+                               libusb_get_device_address(devlist[i]) != address)
+                       continue;
+
+               if (!(dev_hdl = lascar_open(devlist[i])))
+                       continue;
+
+               if (lascar_get_config(dev_hdl, config, &dummy) != SR_OK)
+                       continue;
+
+               libusb_close(dev_hdl);
+               sdi = lascar_identify(config);
+       }
+
+       return sdi;
+}
+
+static void lascar_el_usb_dispatch(struct sr_dev_inst *sdi, unsigned char *buf,
+               int buflen)
+{
+       struct dev_context *devc;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_analog analog;
+       struct sr_channel *ch;
+       float *temp, *rh;
+       uint16_t s;
+       int samples, samples_left, i, j;
+
+       devc = sdi->priv;
+
+       samples = buflen / devc->sample_size;
+       samples_left = devc->logged_samples - devc->rcvd_samples;
+       if (samples_left < samples)
+               samples = samples_left;
+       switch (devc->profile->logformat) {
+       case LOG_TEMP_RH:
+               packet.type = SR_DF_ANALOG;
+               packet.payload = &analog;
+               analog.mqflags = 0;
+               if (!(temp = g_try_malloc(sizeof(float) * samples)))
+                       break;
+               if (!(rh = g_try_malloc(sizeof(float) * samples)))
+                       break;
+               for (i = 0, j = 0; i < samples; i++) {
+                       /* Both Celcius and Fahrenheit stored at base -40. */
+                       if (devc->temp_unit == 0)
+                               /* Celcius is stored in half-degree increments. */
+                               temp[j] = buf[i * 2] / 2 - 40;
+                       else
+                               temp[j] = buf[i * 2] - 40;
+
+                       rh[j] = buf[i * 2 + 1] / 2;
+
+                       if (temp[j] == 0.0 && rh[j] == 0.0)
+                               /* Skip invalid measurement. */
+                               continue;
+                       j++;
+               }
+               analog.num_samples = j;
+
+               ch = sdi->channels->data;
+               if (ch->enabled) {
+                       analog.channels = g_slist_append(NULL, ch);
+                       analog.mq = SR_MQ_TEMPERATURE;
+                       if (devc->temp_unit == 1)
+                               analog.unit = SR_UNIT_FAHRENHEIT;
+                       else
+                               analog.unit = SR_UNIT_CELSIUS;
+                       analog.data = temp;
+                       sr_session_send(devc->cb_data, &packet);
+               }
+
+               ch = sdi->channels->next->data;
+               if (ch->enabled) {
+                       analog.channels = g_slist_append(NULL, ch);
+                       analog.mq = SR_MQ_RELATIVE_HUMIDITY;
+                       analog.unit = SR_UNIT_PERCENTAGE;
+                       analog.data = rh;
+                       sr_session_send(devc->cb_data, &packet);
+               }
+
+               g_free(temp);
+               g_free(rh);
+               break;
+       case LOG_CO:
+               packet.type = SR_DF_ANALOG;
+               packet.payload = &analog;
+               analog.channels = sdi->channels;
+               analog.num_samples = samples;
+               analog.mq = SR_MQ_CARBON_MONOXIDE;
+               analog.unit = SR_UNIT_CONCENTRATION;
+               analog.mqflags = 0;
+               if (!(analog.data = g_try_malloc(sizeof(float) * samples)))
+                       break;
+               for (i = 0; i < samples; i++) {
+                       s = (buf[i * 2] << 8) | buf[i * 2 + 1];
+                       analog.data[i] = (s * devc->co_high + devc->co_low) / 1000000;
+                       if (analog.data[i] < 0.0)
+                               analog.data[i] = 0.0;
+               }
+               sr_session_send(devc->cb_data, &packet);
+               g_free(analog.data);
+               break;
+       default:
+               /* How did we even get this far? */
+               break;
+       }
+       devc->rcvd_samples += samples;
+
+}
+
+SR_PRIV int lascar_el_usb_handle_events(int fd, int revents, void *cb_data)
+{
+       struct drv_context *drvc = di->priv;
+       struct sr_datafeed_packet packet;
+       struct sr_dev_inst *sdi;
+       struct timeval tv;
+
+       (void)fd;
+       (void)revents;
+
+       sdi = cb_data;
+
+       if (sdi->status == SR_ST_STOPPING) {
+               usb_source_remove(sdi->session, drvc->sr_ctx);
+
+               packet.type = SR_DF_END;
+               sr_session_send(cb_data, &packet);
+       }
+
+       memset(&tv, 0, sizeof(struct timeval));
+       libusb_handle_events_timeout_completed(drvc->sr_ctx->libusb_ctx, &tv,
+                                              NULL);
+
+       return TRUE;
+}
+
+SR_PRIV void lascar_el_usb_receive_transfer(struct libusb_transfer *transfer)
+{
+       struct dev_context *devc;
+       struct sr_dev_inst *sdi;
+       int ret;
+       gboolean packet_has_error;
+
+       sdi = transfer->user_data;
+       devc = sdi->priv;
+
+       packet_has_error = FALSE;
+       switch (transfer->status) {
+       case LIBUSB_TRANSFER_NO_DEVICE:
+               /* USB device was unplugged. */
+               dev_acquisition_stop(sdi, sdi);
+               return;
+       case LIBUSB_TRANSFER_COMPLETED:
+       case LIBUSB_TRANSFER_TIMED_OUT: /* We may have received some data though */
+               break;
+       default:
+               packet_has_error = TRUE;
+               break;
+       }
+
+       if (!packet_has_error) {
+               if (devc->rcvd_samples < devc->logged_samples)
+                       lascar_el_usb_dispatch(sdi, transfer->buffer,
+                                       transfer->actual_length);
+               devc->rcvd_bytes += transfer->actual_length;
+               sr_spew("received %d/%d bytes (%d/%d samples)",
+                               devc->rcvd_bytes, devc->log_size,
+                               devc->rcvd_samples, devc->logged_samples);
+               if (devc->rcvd_bytes >= devc->log_size)
+                       dev_acquisition_stop(sdi, sdi);
+       }
+
+       if (sdi->status == SR_ST_ACTIVE) {
+               /* Send the same request again. */
+               if ((ret = libusb_submit_transfer(transfer) != 0)) {
+                       sr_err("Unable to resubmit transfer: %s.",
+                              libusb_error_name(ret));
+                       g_free(transfer->buffer);
+                       libusb_free_transfer(transfer);
+                       dev_acquisition_stop(sdi, sdi);
+               }
+       } else {
+               /* This was the last transfer we're going to receive, so
+                * clean up now. */
+               g_free(transfer->buffer);
+               libusb_free_transfer(transfer);
+       }
+
+}
+
+static int get_flags(unsigned char *configblock)
+{
+       int flags;
+
+       flags = (configblock[32] | (configblock[33] << 8)) & 0x1fff;
+       sr_spew("Read flags (0x%.4x).", flags);
+
+       return flags;
+}
+
+static int set_flags(unsigned char *configblock, int flags)
+{
+
+       sr_spew("Setting flags to 0x%.4x.", flags);
+       configblock[32] = flags & 0xff;
+       configblock[33] = (flags >> 8) & 0x1f;
+
+       return flags;
+}
+
+SR_PRIV int lascar_is_logging(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_usb_dev_inst *usb;
+       int dummy, flags, ret;
+
+       devc = sdi->priv;
+       usb = sdi->conn;
+
+       if (lascar_get_config(usb->devhdl, devc->config, &dummy) != SR_OK)
+               return -1;
+
+       flags = get_flags(devc->config);
+       if (flags & 0x0100)
+               ret = 1;
+       else
+               ret = 0;
+
+       return ret;
+}
+
+SR_PRIV int lascar_start_logging(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_usb_dev_inst *usb;
+       int len, flags, ret;
+
+       devc = sdi->priv;
+       usb = sdi->conn;
+
+       if (lascar_get_config(usb->devhdl, devc->config, &len) != SR_OK)
+               return SR_ERR;
+
+       /* Turn on logging. */
+       flags = get_flags(devc->config);
+       flags |= 0x0100;
+       set_flags(devc->config, flags);
+
+       /* Start logging in 0 seconds. */
+       memset(devc->config + 24, 0, 4);
+
+       ret = lascar_save_config(usb->devhdl, devc->config, len);
+       sr_info("Started internal logging.");
+
+       return ret;
+}
+
+SR_PRIV int lascar_stop_logging(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_usb_dev_inst *usb;
+       int len, flags, ret;
+
+       devc = sdi->priv;
+       usb = sdi->conn;
+
+       if (lascar_get_config(usb->devhdl, devc->config, &len) != SR_OK)
+               return SR_ERR;
+
+       flags = get_flags(devc->config);
+       flags &= ~0x0100;
+       set_flags(devc->config, flags);
+
+       ret = lascar_save_config(usb->devhdl, devc->config, len);
+       sr_info("Stopped internal logging.");
+
+       return ret;
+}
diff --git a/src/hardware/lascar-el-usb/protocol.h b/src/hardware/lascar-el-usb/protocol.h
new file mode 100644 (file)
index 0000000..a94bd8a
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert@biot.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_LASCAR_EL_USB_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_LASCAR_EL_USB_PROTOCOL_H
+
+#include <stdint.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "lascar-el-usb"
+
+#define LASCAR_VENDOR "Lascar"
+#define LASCAR_INTERFACE 0
+#define LASCAR_EP_IN 0x82
+#define LASCAR_EP_OUT 2
+/* Max 100ms for a device to positively identify. */
+#define SCAN_TIMEOUT 100000
+#define MAX_CONFIGBLOCK_SIZE 256
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+       void *cb_data;
+       const struct elusb_profile *profile;
+       /* Generic EL-USB */
+       unsigned char config[MAX_CONFIGBLOCK_SIZE];
+       unsigned int log_size;
+       unsigned int rcvd_bytes;
+       unsigned int sample_size;
+       unsigned int logged_samples;
+       unsigned int rcvd_samples;
+       uint64_t limit_samples;
+       /* Model-specific */
+       /* EL-USB-CO: these are something like scaling and calibration values
+        * fixed per device, used to convert the sample values to CO ppm. */
+       float co_high;
+       float co_low;
+       /* Temperature units as stored in the device config. */
+       int temp_unit;
+};
+
+enum {
+       LOG_UNSUPPORTED,
+       LOG_TEMP_RH,
+       LOG_CO,
+};
+
+struct elusb_profile {
+       int modelid;
+       char *modelname;
+       int logformat;
+};
+
+SR_PRIV int lascar_get_config(libusb_device_handle *dev_hdl,
+               unsigned char *configblock, int *configlen);
+SR_PRIV struct sr_dev_inst *lascar_scan(int bus, int address);
+SR_PRIV int lascar_el_usb_handle_events(int fd, int revents, void *cb_data);
+SR_PRIV void lascar_el_usb_receive_transfer(struct libusb_transfer *transfer);
+SR_PRIV int lascar_start_logging(const struct sr_dev_inst *sdi);
+SR_PRIV int lascar_stop_logging(const struct sr_dev_inst *sdi);
+SR_PRIV int lascar_is_logging(const struct sr_dev_inst *sdi);
+SR_PRIV int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data);
+
+#endif
diff --git a/src/hardware/link-mso19/api.c b/src/hardware/link-mso19/api.c
new file mode 100644 (file)
index 0000000..13c2972
--- /dev/null
@@ -0,0 +1,497 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2011 Daniel Ribeiro <drwyrm@gmail.com>
+ * Copyright (C) 2012 Renato Caldas <rmsc@fe.up.pt>
+ * Copyright (C) 2013 Lior Elazary <lelazary@yahoo.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 "protocol.h"
+
+static const int32_t hwcaps[] = {
+       SR_CONF_OSCILLOSCOPE,
+       SR_CONF_LOGIC_ANALYZER,
+       SR_CONF_SAMPLERATE,
+       SR_CONF_TRIGGER_TYPE,
+       SR_CONF_TRIGGER_SLOPE,
+       SR_CONF_HORIZ_TRIGGERPOS,
+//      SR_CONF_CAPTURE_RATIO,
+       SR_CONF_LIMIT_SAMPLES,
+//      SR_CONF_RLE,
+};
+
+/*
+ * Channels are numbered 0 to 7.
+ *
+ * See also: http://www.linkinstruments.com/images/mso19_1113.gif
+ */
+SR_PRIV const char *mso19_channel_names[NUM_CHANNELS + 1] = {
+       /* Note: DSO needs to be first. */
+       "DSO", "0", "1", "2", "3", "4", "5", "6", "7", NULL,
+};
+
+static const uint64_t samplerates[] = {
+       SR_HZ(100),
+       SR_MHZ(200),
+       SR_HZ(100),
+};
+
+SR_PRIV struct sr_dev_driver link_mso19_driver_info;
+static struct sr_dev_driver *di = &link_mso19_driver_info;
+
+/* TODO: Use sr_dev_inst to store connection handle & use std_dev_clear(). */
+static int dev_clear(void)
+{
+       GSList *l;
+       struct sr_dev_inst *sdi;
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       int ret = SR_OK;
+
+       if (!(drvc = di->priv))
+               return SR_OK;
+
+       /* Properly close and free all devices. */
+       for (l = drvc->instances; l; l = l->next) {
+               if (!(sdi = l->data)) {
+                       /* Log error, but continue cleaning up the rest. */
+                       sr_err("%s: sdi was NULL, continuing", __func__);
+                       ret = SR_ERR_BUG;
+                       continue;
+               }
+               if (!(devc = sdi->priv)) {
+                       /* Log error, but continue cleaning up the rest. */
+                       sr_err("%s: sdi->priv was NULL, continuing", __func__);
+                       ret = SR_ERR_BUG;
+                       continue;
+               }
+               std_serial_dev_close(sdi);
+               sr_serial_dev_inst_free(devc->serial);
+               sr_dev_inst_free(sdi);
+       }
+       g_slist_free(drvc->instances);
+       drvc->instances = NULL;
+
+       return ret;
+}
+
+static int init(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+       int i;
+       GSList *devices = NULL;
+       const char *conn = NULL;
+       const char *serialcomm = NULL;
+       GSList *l;
+       struct sr_config *src;
+       struct udev *udev;
+       int chtype;
+
+       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)
+               conn = SERIALCONN;
+       if (serialcomm == NULL)
+               serialcomm = SERIALCOMM;
+
+       udev = udev_new();
+       if (!udev) {
+               sr_err("Failed to initialize udev.");
+       }
+
+       struct udev_enumerate *enumerate = udev_enumerate_new(udev);
+       udev_enumerate_add_match_subsystem(enumerate, "usb-serial");
+       udev_enumerate_scan_devices(enumerate);
+       struct udev_list_entry *devs = udev_enumerate_get_list_entry(enumerate);
+       struct udev_list_entry *dev_list_entry;
+       for (dev_list_entry = devs;
+            dev_list_entry != NULL;
+            dev_list_entry = udev_list_entry_get_next(dev_list_entry)) {
+               const char *syspath = udev_list_entry_get_name(dev_list_entry);
+               struct udev_device *dev =
+                   udev_device_new_from_syspath(udev, syspath);
+               const char *sysname = udev_device_get_sysname(dev);
+               struct udev_device *parent =
+                   udev_device_get_parent_with_subsystem_devtype(dev, "usb",
+                                                                 "usb_device");
+
+               if (!parent) {
+                       sr_err("Unable to find parent usb device for %s",
+                              sysname);
+                       continue;
+               }
+
+               const char *idVendor =
+                   udev_device_get_sysattr_value(parent, "idVendor");
+               const char *idProduct =
+                   udev_device_get_sysattr_value(parent, "idProduct");
+               if (strcmp(USB_VENDOR, idVendor)
+                   || strcmp(USB_PRODUCT, idProduct))
+                       continue;
+
+               const char *iSerial =
+                   udev_device_get_sysattr_value(parent, "serial");
+               const char *iProduct =
+                   udev_device_get_sysattr_value(parent, "product");
+
+               char path[32];
+               snprintf(path, sizeof(path), "/dev/%s", sysname);
+               conn = path;
+
+               size_t s = strcspn(iProduct, " ");
+               char product[32];
+               char manufacturer[32];
+               if (s > sizeof(product) ||
+                   strlen(iProduct) - s > sizeof(manufacturer)) {
+                       sr_err("Could not parse iProduct: %s.", iProduct);
+                       continue;
+               }
+               strncpy(product, iProduct, s);
+               product[s] = 0;
+               strcpy(manufacturer, iProduct + s + 1);
+
+               //Create the device context and set its params
+               struct dev_context *devc;
+               if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+                       sr_err("Device context malloc failed.");
+                       return devices;
+               }
+
+               if (mso_parse_serial(iSerial, iProduct, devc) != SR_OK) {
+                       sr_err("Invalid iSerial: %s.", iSerial);
+                       g_free(devc);
+                       return devices;
+               }
+
+               char hwrev[32];
+               sprintf(hwrev, "r%d", devc->hwrev);
+               devc->ctlbase1 = 0;
+               devc->protocol_trigger.spimode = 0;
+               for (i = 0; i < 4; i++) {
+                       devc->protocol_trigger.word[i] = 0;
+                       devc->protocol_trigger.mask[i] = 0xff;
+               }
+
+               if (!(devc->serial = sr_serial_dev_inst_new(conn, serialcomm))) {
+                       g_free(devc);
+                       return devices;
+               }
+
+               struct sr_dev_inst *sdi = sr_dev_inst_new(0, SR_ST_INACTIVE,
+                                               manufacturer, product, hwrev);
+
+               if (!sdi) {
+                       sr_err("Unable to create device instance for %s",
+                              sysname);
+                       sr_dev_inst_free(sdi);
+                       g_free(devc);
+                       return devices;
+               }
+
+               sdi->driver = di;
+               sdi->priv = devc;
+
+               for (i = 0; i < NUM_CHANNELS; i++) {
+                       struct sr_channel *ch;
+                       chtype = (i == 0) ? SR_CHANNEL_ANALOG : SR_CHANNEL_LOGIC;
+                       if (!(ch = sr_channel_new(i, chtype, TRUE,
+                                                  mso19_channel_names[i])))
+                               return 0;
+                       sdi->channels = g_slist_append(sdi->channels, ch);
+               }
+
+               //Add the driver
+               struct drv_context *drvc = di->priv;
+               drvc->instances = g_slist_append(drvc->instances, sdi);
+               devices = g_slist_append(devices, sdi);
+       }
+
+       return devices;
+}
+
+static GSList *dev_list(void)
+{
+       return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+       int ret;
+       struct dev_context *devc;
+
+       devc = sdi->priv;
+
+       if (serial_open(devc->serial, SERIAL_RDWR) != SR_OK)
+               return SR_ERR;
+
+       sdi->status = SR_ST_ACTIVE;
+
+       /* FIXME: discard serial buffer */
+       mso_check_trigger(devc->serial, &devc->trigger_state);
+       sr_dbg("Trigger state: 0x%x.", devc->trigger_state);
+
+       ret = mso_reset_adc(sdi);
+       if (ret != SR_OK)
+               return ret;
+
+       mso_check_trigger(devc->serial, &devc->trigger_state);
+       sr_dbg("Trigger state: 0x%x.", devc->trigger_state);
+
+       //    ret = mso_reset_fsm(sdi);
+       //    if (ret != SR_OK)
+       //            return ret;
+       //    return SR_ERR;
+
+       return SR_OK;
+}
+
+static int cleanup(void)
+{
+       return dev_clear();
+}
+
+static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+
+       (void)cg;
+
+       switch (id) {
+       case SR_CONF_SAMPLERATE:
+               if (sdi) {
+                       devc = sdi->priv;
+                       *data = g_variant_new_uint64(devc->cur_rate);
+               } else
+                       return SR_ERR;
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       int ret;
+       struct dev_context *devc;
+       uint64_t num_samples;
+       const char *slope;
+       int trigger_pos;
+       double pos;
+
+       (void)cg;
+       devc = sdi->priv;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       switch (id) {
+       case SR_CONF_SAMPLERATE:
+               // FIXME
+               return mso_configure_rate(sdi, g_variant_get_uint64(data));
+               ret = SR_OK;
+               break;
+       case SR_CONF_LIMIT_SAMPLES:
+               num_samples = g_variant_get_uint64(data);
+               if (num_samples != 1024) {
+                       sr_err("Only 1024 samples are supported.");
+                       ret = SR_ERR_ARG;
+               } else {
+                       devc->limit_samples = num_samples;
+                       sr_dbg("setting limit_samples to %i\n",
+                              num_samples);
+                       ret = SR_OK;
+               }
+               break;
+       case SR_CONF_CAPTURE_RATIO:
+               ret = SR_OK;
+               break;
+       case SR_CONF_TRIGGER_SLOPE:
+               slope = g_variant_get_string(data, NULL);
+
+               if (!slope || !(slope[0] == 'f' || slope[0] == 'r'))
+                       sr_err("Invalid trigger slope");
+                       ret = SR_ERR_ARG;
+               } else {
+                       devc->trigger_slope = (slope[0] == 'r')
+                               ? SLOPE_POSITIVE : SLOPE_NEGATIVE;
+                       ret = SR_OK;
+               }
+               break;
+       case SR_CONF_HORIZ_TRIGGERPOS:
+               pos = g_variant_get_double(data);
+               if (pos < 0 || pos > 255) {
+                       sr_err("Trigger position (%f) should be between 0 and 255.", pos);
+                       ret = SR_ERR_ARG;
+               } else {
+                       trigger_pos = (int)pos;
+                       devc->trigger_holdoff[0] = trigger_pos & 0xff;
+                       ret = SR_OK;
+               }
+               break;
+       case SR_CONF_RLE:
+               ret = SR_OK;
+               break;
+       default:
+               ret = SR_ERR_NA;
+               break;
+       }
+
+       return ret;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       GVariant *gvar;
+       GVariantBuilder gvb;
+
+       (void)cg;
+       (void)sdi;
+
+       switch (key) {
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+               break;
+       case SR_CONF_SAMPLERATE:
+               g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
+               gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), samplerates,
+                               ARRAY_SIZE(samplerates), sizeof(uint64_t));
+               g_variant_builder_add(&gvb, "{sv}", "samplerate-steps", gvar);
+               *data = g_variant_builder_end(&gvb);
+               break;
+       case SR_CONF_TRIGGER_TYPE:
+               *data = g_variant_new_string(TRIGGER_TYPE);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct dev_context *devc;
+       int ret = SR_ERR;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       devc = sdi->priv;
+
+       if (mso_configure_channels(sdi) != SR_OK) {
+               sr_err("Failed to configure channels.");
+               return SR_ERR;
+       }
+
+       /* FIXME: No need to do full reconfigure every time */
+//      ret = mso_reset_fsm(sdi);
+//      if (ret != SR_OK)
+//              return ret;
+
+       /* FIXME: ACDC Mode */
+       devc->ctlbase1 &= 0x7f;
+//      devc->ctlbase1 |= devc->acdcmode;
+
+       ret = mso_configure_rate(sdi, devc->cur_rate);
+       if (ret != SR_OK)
+               return ret;
+
+       /* set dac offset */
+       ret = mso_dac_out(sdi, devc->dac_offset);
+       if (ret != SR_OK)
+               return ret;
+
+       ret = mso_configure_threshold_level(sdi);
+       if (ret != SR_OK)
+               return ret;
+
+       ret = mso_configure_trigger(sdi);
+       if (ret != SR_OK)
+               return ret;
+
+       /* END of config hardware part */
+       ret = mso_arm(sdi);
+       if (ret != SR_OK)
+               return ret;
+
+       /* Start acquisition on the device. */
+       mso_check_trigger(devc->serial, &devc->trigger_state);
+       ret = mso_check_trigger(devc->serial, NULL);
+       if (ret != SR_OK)
+               return ret;
+
+       /* Reset trigger state. */
+       devc->trigger_state = 0x00;
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(cb_data, LOG_PREFIX);
+
+       /* Our first channel is analog, the other 8 are of type 'logic'. */
+       /* TODO. */
+
+       serial_source_add(sdi->session, devc->serial, G_IO_IN, -1,
+                       mso_receive_data, cb_data);
+
+       return SR_OK;
+}
+
+/* This stops acquisition on ALL devices, ignoring dev_index. */
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       (void)cb_data;
+
+       stop_acquisition(sdi);
+
+       return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver link_mso19_driver_info = {
+       .name = "link-mso19",
+       .longname = "Link Instruments MSO-19",
+       .api_version = 1,
+       .init = init,
+       .cleanup = cleanup,
+       .scan = scan,
+       .dev_list = dev_list,
+       .dev_clear = dev_clear,
+       .config_get = config_get,
+       .config_set = config_set,
+       .config_list = config_list,
+       .dev_open = dev_open,
+       .dev_close = std_serial_dev_close,
+       .dev_acquisition_start = dev_acquisition_start,
+       .dev_acquisition_stop = dev_acquisition_stop,
+       .priv = NULL,
+};
diff --git a/src/hardware/link-mso19/protocol.c b/src/hardware/link-mso19/protocol.c
new file mode 100644 (file)
index 0000000..5f7aa71
--- /dev/null
@@ -0,0 +1,474 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2011 Daniel Ribeiro <drwyrm@gmail.com>
+ * Copyright (C) 2012 Renato Caldas <rmsc@fe.up.pt>
+ * Copyright (C) 2013 Lior Elazary <lelazary@yahoo.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 "protocol.h"
+
+/* serial protocol */
+#define mso_trans(a, v) \
+       (((v) & 0x3f) | (((v) & 0xc0) << 6) | (((a) & 0xf) << 8) | \
+       ((~(v) & 0x20) << 1) | ((~(v) & 0x80) << 7))
+
+static const char mso_head[] = { 0x40, 0x4c, 0x44, 0x53, 0x7e };
+static const char mso_foot[] = { 0x7e };
+
+extern SR_PRIV struct sr_dev_driver link_mso19_driver_info;
+static struct sr_dev_driver *di = &link_mso19_driver_info;
+
+SR_PRIV int mso_send_control_message(struct sr_serial_dev_inst *serial,
+                                    uint16_t payload[], int n)
+{
+       int i, w, ret, s = n * 2 + sizeof(mso_head) + sizeof(mso_foot);
+       char *p, *buf;
+
+       ret = SR_ERR;
+
+       if (serial->fd < 0)
+               goto ret;
+
+       if (!(buf = g_try_malloc(s))) {
+               sr_err("Failed to malloc message buffer.");
+               ret = SR_ERR_MALLOC;
+               goto ret;
+       }
+
+       p = buf;
+       memcpy(p, mso_head, sizeof(mso_head));
+       p += sizeof(mso_head);
+
+       for (i = 0; i < n; i++) {
+               *(uint16_t *) p = g_htons(payload[i]);
+               p += 2;
+       }
+       memcpy(p, mso_foot, sizeof(mso_foot));
+
+       w = 0;
+       while (w < s) {
+               ret = serial_write(serial, buf + w, s - w);
+               if (ret < 0) {
+                       ret = SR_ERR;
+                       goto free;
+               }
+               w += ret;
+       }
+       ret = SR_OK;
+free:
+       g_free(buf);
+ret:
+       return ret;
+}
+
+SR_PRIV int mso_configure_trigger(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc = sdi->priv;
+       uint16_t threshold_value = mso_calc_raw_from_mv(devc);
+
+       threshold_value = 0x153C;
+       uint8_t trigger_config = 0;
+
+       if (devc->trigger_slope)
+               trigger_config |= 0x04; //Trigger on falling edge
+
+       switch (devc->trigger_outsrc) {
+       case 1:
+               trigger_config |= 0x00; //Trigger pulse output
+               break;
+       case 2:
+               trigger_config |= 0x08; //PWM DAC from the pattern generator buffer
+               break;
+       case 3:
+               trigger_config |= 0x18; //White noise
+               break;
+       }
+
+       switch (devc->trigger_chan) {
+       case 0:
+               trigger_config |= 0x00; //DSO level trigger //b00000000
+               break;
+       case 1:
+               trigger_config |= 0x20; //DSO level trigger & width < trigger_width
+               break;
+       case 2:
+               trigger_config |= 0x40; //DSO level trigger & width >= trigger_width 
+               break;
+       case 3:
+               trigger_config |= 0x60; //LA combination trigger
+               break;
+       }
+
+       //Last bit of trigger config reg 4 needs to be 1 for trigger enable,
+       //otherwise the trigger is not enabled
+       if (devc->use_trigger)
+               trigger_config |= 0x80;
+
+       uint16_t ops[18];
+       ops[0] = mso_trans(3, threshold_value & 0xff);
+       //The trigger_config also holds the 2 MSB bits from the threshold value
+       ops[1] = mso_trans(4, trigger_config | ((threshold_value >> 8) & 0x03));
+       ops[2] = mso_trans(5, devc->la_trigger);
+       ops[3] = mso_trans(6, devc->la_trigger_mask);
+       ops[4] = mso_trans(7, devc->trigger_holdoff[0]);
+       ops[5] = mso_trans(8, devc->trigger_holdoff[1]);
+
+       ops[6] = mso_trans(11,
+                          devc->dso_trigger_width /
+                          SR_HZ_TO_NS(devc->cur_rate));
+
+       /* Select the SPI/I2C trigger config bank */
+       ops[7] = mso_trans(REG_CTL2, (devc->ctlbase2 | BITS_CTL2_BANK(2)));
+       /* Configure the SPI/I2C protocol trigger */
+       ops[8] = mso_trans(REG_PT_WORD(0), devc->protocol_trigger.word[0]);
+       ops[9] = mso_trans(REG_PT_WORD(1), devc->protocol_trigger.word[1]);
+       ops[10] = mso_trans(REG_PT_WORD(2), devc->protocol_trigger.word[2]);
+       ops[11] = mso_trans(REG_PT_WORD(3), devc->protocol_trigger.word[3]);
+       ops[12] = mso_trans(REG_PT_MASK(0), devc->protocol_trigger.mask[0]);
+       ops[13] = mso_trans(REG_PT_MASK(1), devc->protocol_trigger.mask[1]);
+       ops[14] = mso_trans(REG_PT_MASK(2), devc->protocol_trigger.mask[2]);
+       ops[15] = mso_trans(REG_PT_MASK(3), devc->protocol_trigger.mask[3]);
+       ops[16] = mso_trans(REG_PT_SPIMODE, devc->protocol_trigger.spimode);
+       /* Select the default config bank */
+       ops[17] = mso_trans(REG_CTL2, devc->ctlbase2);
+
+       return mso_send_control_message(devc->serial, ARRAY_AND_SIZE(ops));
+}
+
+SR_PRIV int mso_configure_threshold_level(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc = sdi->priv;
+
+       return mso_dac_out(sdi, la_threshold_map[devc->la_threshold]);
+}
+
+SR_PRIV int mso_read_buffer(struct sr_dev_inst *sdi)
+{
+       uint16_t ops[] = { mso_trans(REG_BUFFER, 0) };
+       struct dev_context *devc = sdi->priv;
+
+       sr_dbg("Requesting buffer dump.");
+       return mso_send_control_message(devc->serial, ARRAY_AND_SIZE(ops));
+}
+
+SR_PRIV int mso_arm(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc = sdi->priv;
+       uint16_t ops[] = {
+               mso_trans(REG_CTL1, devc->ctlbase1 | BIT_CTL1_RESETFSM),
+               mso_trans(REG_CTL1, devc->ctlbase1 | BIT_CTL1_ARM),
+               mso_trans(REG_CTL1, devc->ctlbase1),
+       };
+
+       sr_dbg("Requesting trigger arm.");
+       return mso_send_control_message(devc->serial, ARRAY_AND_SIZE(ops));
+}
+
+SR_PRIV int mso_force_capture(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc = sdi->priv;
+       uint16_t ops[] = {
+               mso_trans(REG_CTL1, devc->ctlbase1 | 8),
+               mso_trans(REG_CTL1, devc->ctlbase1),
+       };
+
+       sr_dbg("Requesting forced capture.");
+       return mso_send_control_message(devc->serial, ARRAY_AND_SIZE(ops));
+}
+
+SR_PRIV int mso_dac_out(const struct sr_dev_inst *sdi, uint16_t val)
+{
+       struct dev_context *devc = sdi->priv;
+       uint16_t ops[] = {
+               mso_trans(REG_DAC1, (val >> 8) & 0xff),
+               mso_trans(REG_DAC2, val & 0xff),
+               mso_trans(REG_CTL1, devc->ctlbase1 | BIT_CTL1_RESETADC),
+       };
+
+       sr_dbg("Setting dac word to 0x%x.", val);
+       return mso_send_control_message(devc->serial, ARRAY_AND_SIZE(ops));
+}
+
+SR_PRIV inline uint16_t mso_calc_raw_from_mv(struct dev_context * devc)
+{
+       return (uint16_t) (0x200 -
+                          ((devc->dso_trigger_voltage / devc->dso_probe_attn) /
+                           devc->vbit));
+}
+
+SR_PRIV int mso_parse_serial(const char *iSerial, const char *iProduct,
+                            struct dev_context *devc)
+{
+       unsigned int u1, u2, u3, u4, u5, u6;
+
+       (void)iProduct;
+
+       /* FIXME: This code is in the original app, but I think its
+        * used only for the GUI */
+       /*    if (strstr(iProduct, "REV_02") || strstr(iProduct, "REV_03"))
+          devc->num_sample_rates = 0x16;
+          else
+          devc->num_sample_rates = 0x10; */
+
+       /* parse iSerial */
+       if (iSerial[0] != '4' || sscanf(iSerial, "%5u%3u%3u%1u%1u%6u",
+                                       &u1, &u2, &u3, &u4, &u5, &u6) != 6)
+               return SR_ERR;
+       devc->hwmodel = u4;
+       devc->hwrev = u5;
+       devc->vbit = u1 / 10000;
+       if (devc->vbit == 0)
+               devc->vbit = 4.19195;
+       devc->dac_offset = u2;
+       if (devc->dac_offset == 0)
+               devc->dac_offset = 0x1ff;
+       devc->offset_range = u3;
+       if (devc->offset_range == 0)
+               devc->offset_range = 0x17d;
+
+       /*
+        * FIXME: There is more code on the original software to handle
+        * bigger iSerial strings, but as I can't test on my device
+        * I will not implement it yet
+        */
+
+       return SR_OK;
+}
+
+SR_PRIV int mso_reset_adc(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc = sdi->priv;
+       uint16_t ops[2];
+
+       ops[0] = mso_trans(REG_CTL1, (devc->ctlbase1 | BIT_CTL1_RESETADC));
+       ops[1] = mso_trans(REG_CTL1, devc->ctlbase1);
+       devc->ctlbase1 |= BIT_CTL1_ADC_UNKNOWN4;
+
+       sr_dbg("Requesting ADC reset.");
+       return mso_send_control_message(devc->serial, ARRAY_AND_SIZE(ops));
+}
+
+SR_PRIV int mso_reset_fsm(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc = sdi->priv;
+       uint16_t ops[1];
+
+       devc->ctlbase1 |= BIT_CTL1_RESETFSM;
+       ops[0] = mso_trans(REG_CTL1, devc->ctlbase1);
+
+       sr_dbg("Requesting ADC reset.");
+       return mso_send_control_message(devc->serial, ARRAY_AND_SIZE(ops));
+}
+
+SR_PRIV int mso_toggle_led(struct sr_dev_inst *sdi, int state)
+{
+       struct dev_context *devc = sdi->priv;
+       uint16_t ops[1];
+
+       devc->ctlbase1 &= ~BIT_CTL1_LED;
+       if (state)
+               devc->ctlbase1 |= BIT_CTL1_LED;
+       ops[0] = mso_trans(REG_CTL1, devc->ctlbase1);
+
+       sr_dbg("Requesting LED toggle.");
+       return mso_send_control_message(devc->serial, ARRAY_AND_SIZE(ops));
+}
+
+SR_PRIV void stop_acquisition(const struct sr_dev_inst *sdi)
+{
+       struct sr_datafeed_packet packet;
+       struct dev_context *devc;
+
+       devc = sdi->priv;
+       serial_source_remove(sdi->session, devc->serial);
+
+       /* Terminate session */
+       packet.type = SR_DF_END;
+       sr_session_send(sdi, &packet);
+}
+
+SR_PRIV int mso_clkrate_out(struct sr_serial_dev_inst *serial, uint16_t val)
+{
+       uint16_t ops[] = {
+               mso_trans(REG_CLKRATE1, (val >> 8) & 0xff),
+               mso_trans(REG_CLKRATE2, val & 0xff),
+       };
+
+       sr_dbg("Setting clkrate word to 0x%x.", val);
+       return mso_send_control_message(serial, ARRAY_AND_SIZE(ops));
+}
+
+SR_PRIV int mso_configure_rate(const struct sr_dev_inst *sdi, uint32_t rate)
+{
+       struct dev_context *devc = sdi->priv;
+       unsigned int i;
+       int ret = SR_ERR;
+
+       for (i = 0; i < ARRAY_SIZE(rate_map); i++) {
+               if (rate_map[i].rate == rate) {
+                       devc->ctlbase2 = rate_map[i].slowmode;
+                       ret = mso_clkrate_out(devc->serial, rate_map[i].val);
+                       if (ret == SR_OK)
+                               devc->cur_rate = rate;
+                       return ret;
+               }
+       }
+
+       if (ret != SR_OK)
+               sr_err("Unsupported rate.");
+
+       return ret;
+}
+
+SR_PRIV int mso_check_trigger(struct sr_serial_dev_inst *serial, uint8_t *info)
+{
+       uint16_t ops[] = { mso_trans(REG_TRIGGER, 0) };
+       int ret;
+
+       sr_dbg("Requesting trigger state.");
+       ret = mso_send_control_message(serial, ARRAY_AND_SIZE(ops));
+       if (info == NULL || ret != SR_OK)
+               return ret;
+
+       uint8_t buf = 0;
+       if (serial_read(serial, &buf, 1) != 1)  /* FIXME: Need timeout */
+               ret = SR_ERR;
+       if (!info)
+               *info = buf;
+
+       sr_dbg("Trigger state is: 0x%x.", *info);
+       return ret;
+}
+
+SR_PRIV int mso_receive_data(int fd, int revents, void *cb_data)
+{
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_logic logic;
+       struct sr_dev_inst *sdi;
+       GSList *l;
+       int i;
+
+       struct drv_context *drvc = di->priv;
+
+       /* Find this device's devc struct by its fd. */
+       struct dev_context *devc = NULL;
+       for (l = drvc->instances; l; l = l->next) {
+               sdi = l->data;
+               devc = sdi->priv;
+               if (devc->serial->fd == fd)
+                       break;
+               devc = NULL;
+       }
+       if (!devc)
+               /* Shouldn't happen. */
+               return TRUE;
+
+       (void)revents;
+
+       uint8_t in[1024];
+       size_t s = serial_read(devc->serial, in, sizeof(in));
+
+       if (s <= 0)
+               return FALSE;
+
+       /* Check if we triggered, then send a command that we are ready
+        * to read the data */
+       if (devc->trigger_state != MSO_TRIGGER_DATAREADY) {
+               devc->trigger_state = in[0];
+               if (devc->trigger_state == MSO_TRIGGER_DATAREADY) {
+                       mso_read_buffer(sdi);
+                       devc->buffer_n = 0;
+               } else {
+                       mso_check_trigger(devc->serial, NULL);
+               }
+               return TRUE;
+       }
+
+       /* the hardware always dumps 1024 samples, 24bits each */
+       if (devc->buffer_n < 3072) {
+               memcpy(devc->buffer + devc->buffer_n, in, s);
+               devc->buffer_n += s;
+       }
+       if (devc->buffer_n < 3072)
+               return TRUE;
+
+       /* do the conversion */
+       uint8_t logic_out[1024];
+       double analog_out[1024];
+       for (i = 0; i < 1024; i++) {
+               /* FIXME: Need to do conversion to mV */
+               analog_out[i] = (devc->buffer[i * 3] & 0x3f) |
+                   ((devc->buffer[i * 3 + 1] & 0xf) << 6);
+               (void)analog_out;
+               logic_out[i] = ((devc->buffer[i * 3 + 1] & 0x30) >> 4) |
+                   ((devc->buffer[i * 3 + 2] & 0x3f) << 2);
+       }
+
+       packet.type = SR_DF_LOGIC;
+       packet.payload = &logic;
+       logic.length = 1024;
+       logic.unitsize = 1;
+       logic.data = logic_out;
+       sr_session_send(cb_data, &packet);
+
+       devc->num_samples += 1024;
+
+       if (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
+               sr_info("Requested number of samples reached.");
+               sdi->driver->dev_acquisition_stop(sdi, cb_data);
+       }
+
+       return TRUE;
+}
+
+SR_PRIV int mso_configure_channels(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_channel *ch;
+       GSList *l;
+       char *tc;
+
+       devc = sdi->priv;
+
+       devc->la_trigger_mask = 0xFF;   //the mask for the LA_TRIGGER (bits set to 0 matter, those set to 1 are ignored).
+       devc->la_trigger = 0x00;        //The value of the LA byte that generates a trigger event (in that mode).
+       devc->dso_trigger_voltage = 3;
+       devc->dso_probe_attn = 1;
+       devc->trigger_outsrc = 0;
+       devc->trigger_chan = 3; //LA combination trigger
+       devc->use_trigger = FALSE;
+
+       for (l = sdi->channels; l; l = l->next) {
+               ch = (struct sr_channel *)l->data;
+               if (ch->enabled == FALSE)
+                       continue;
+
+               int channel_bit = 1 << (ch->index);
+               if (!(ch->trigger))
+                       continue;
+
+               devc->use_trigger = TRUE;
+               //Configure trigger mask and value.
+               for (tc = ch->trigger; *tc; tc++) {
+                       devc->la_trigger_mask &= ~channel_bit;
+                       if (*tc == '1')
+                               devc->la_trigger |= channel_bit;
+               }
+       }
+
+       return SR_OK;
+}
diff --git a/src/hardware/link-mso19/protocol.h b/src/hardware/link-mso19/protocol.h
new file mode 100644 (file)
index 0000000..809d7f8
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2011 Daniel Ribeiro <drwyrm@gmail.com>
+ * Copyright (C) 2012 Renato Caldas <rmsc@fe.up.pt>
+ * Copyright (C) 2013 Lior Elazary <lelazary@yahoo.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_LINK_MSO19_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_LINK_MSO19_PROTOCOL_H
+
+#include <stdint.h>
+#include <string.h>
+#include <glib.h>
+#include <libudev.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "link-mso19"
+
+#define USB_VENDOR             "3195"
+#define USB_PRODUCT            "f190"
+
+#define NUM_CHANNELS           (1 + 8)
+#define NUM_TRIGGER_STAGES     4
+#define TRIGGER_TYPE           "01"    //the first r/f is used for the whole group
+#define SERIALCOMM             "460800/8n1/flow=2"
+#define SERIALCONN             "/dev/ttyUSB0"
+#define CLOCK_RATE             SR_MHZ(100)
+#define MIN_NUM_SAMPLES                4
+
+#define MSO_TRIGGER_UNKNOWN    '!'
+#define MSO_TRIGGER_UNKNOWN1   '1'
+#define MSO_TRIGGER_UNKNOWN2   '2'
+#define MSO_TRIGGER_UNKNOWN3   '3'
+#define MSO_TRIGGER_WAIT       '4'
+#define MSO_TRIGGER_FIRED      '5'
+#define MSO_TRIGGER_DATAREADY  '6'
+
+enum trigger_slopes {
+       SLOPE_POSITIVE = 0,
+       SLOPE_NEGATIVE,
+};
+
+/* Structure for the pattern generator state */
+struct mso_patgen {
+       /* Pattern generator clock config */
+       uint16_t clock;
+       /* Buffer start address */
+       uint16_t start;
+       /* Buffer end address */
+       uint16_t end;
+       /* Pattern generator config */
+       uint8_t config;
+       /* Samples buffer */
+       uint8_t buffer[1024];
+       /* Input/output configuration for the samples buffer (?) */
+       uint8_t io[1024];
+       /* Number of loops for the pattern generator */
+       uint8_t loops;
+       /* Bit enable mask for the I/O lines */
+       uint8_t mask;
+};
+
+/* Data structure for the protocol trigger state */
+struct mso_prototrig {
+       /* Word match buffer */
+       uint8_t word[4];
+       /* Masks for the wordmatch buffer */
+       uint8_t mask[4];
+       /* SPI mode 0, 1, 2, 3. Set to 0 for I2C */
+       uint8_t spimode;
+};
+
+/* Private, per-device-instance driver context. */
+struct dev_context {
+       /* info */
+       uint8_t hwmodel;
+       uint8_t hwrev;
+       struct sr_serial_dev_inst *serial;
+//      uint8_t num_sample_rates;
+       /* calibration */
+       double vbit;
+       uint16_t dac_offset;
+       uint16_t offset_range;
+       uint64_t limit_samples;
+       uint64_t num_samples;
+       /* register cache */
+       uint8_t ctlbase1;
+       uint8_t ctlbase2;
+       /* state */
+       uint8_t la_threshold;
+       uint64_t cur_rate;
+       uint8_t dso_probe_attn;
+       int8_t use_trigger;
+       uint8_t trigger_chan;
+       uint8_t trigger_slope;
+       uint8_t trigger_outsrc;
+       uint8_t trigger_state;
+       uint8_t trigger_holdoff[2];
+       uint8_t la_trigger;
+       uint8_t la_trigger_mask;
+       double dso_trigger_voltage;
+       uint16_t dso_trigger_width;
+       struct mso_prototrig protocol_trigger;
+       void *cb_data;
+       uint16_t buffer_n;
+       char buffer[4096];
+};
+
+SR_PRIV int mso_parse_serial(const char *iSerial, const char *iProduct,
+                            struct dev_context *ctx);
+SR_PRIV int mso_check_trigger(struct sr_serial_dev_inst *serial,
+                             uint8_t * info);
+SR_PRIV int mso_reset_adc(struct sr_dev_inst *sdi);
+SR_PRIV int mso_clkrate_out(struct sr_serial_dev_inst *serial, uint16_t val);
+SR_PRIV int mso_configure_rate(const struct sr_dev_inst *sdi, uint32_t rate);
+SR_PRIV int mso_receive_data(int fd, int revents, void *cb_data);
+SR_PRIV int mso_configure_trigger(const struct sr_dev_inst *sdi);
+SR_PRIV int mso_configure_threshold_level(const struct sr_dev_inst *sdi);
+SR_PRIV int mso_read_buffer(struct sr_dev_inst *sdi);
+SR_PRIV int mso_arm(const struct sr_dev_inst *sdi);
+SR_PRIV int mso_force_capture(struct sr_dev_inst *sdi);
+SR_PRIV int mso_dac_out(const struct sr_dev_inst *sdi, uint16_t val);
+SR_PRIV inline uint16_t mso_calc_raw_from_mv(struct dev_context *devc);
+SR_PRIV int mso_reset_fsm(struct sr_dev_inst *sdi);
+SR_PRIV int mso_toggle_led(struct sr_dev_inst *sdi, int state);
+
+SR_PRIV int mso_configure_channels(const struct sr_dev_inst *sdi);
+SR_PRIV void stop_acquisition(const struct sr_dev_inst *sdi);
+
+/* bank agnostic registers */
+#define REG_CTL2               15
+
+/* bank 0 registers */
+#define REG_BUFFER             1
+#define REG_TRIGGER            2
+#define REG_CLKRATE1           9
+#define REG_CLKRATE2           10
+#define REG_DAC1               12
+#define REG_DAC2               13
+/* possibly bank agnostic: */
+#define REG_CTL1               14
+
+/* bank 2 registers (SPI/I2C protocol trigger) */
+#define REG_PT_WORD(x)         (x)
+#define REG_PT_MASK(x)         (x + 4)
+#define REG_PT_SPIMODE         8
+
+/* bits - REG_CTL1 */
+#define BIT_CTL1_RESETFSM      (1 << 0)
+#define BIT_CTL1_ARM           (1 << 1)
+#define BIT_CTL1_ADC_UNKNOWN4  (1 << 4)        /* adc enable? */
+#define BIT_CTL1_RESETADC      (1 << 6)
+#define BIT_CTL1_LED           (1 << 7)
+
+/* bits - REG_CTL2 */
+#define BITS_CTL2_BANK(x)      (x & 0x3)
+#define BIT_CTL2_SLOWMODE      (1 << 5)
+
+struct rate_map {
+       uint32_t rate;
+       uint16_t val;
+       uint8_t slowmode;
+};
+
+static const struct rate_map rate_map[] = {
+       { SR_MHZ(200), 0x0205, 0 },
+       { SR_MHZ(100), 0x0105, 0 },
+       { SR_MHZ(50),  0x0005, 0 },
+       { SR_MHZ(20),  0x0303, 0 },
+       { SR_MHZ(10),  0x0308, 0 },
+       { SR_MHZ(5),   0x030c, 0 },
+       { SR_MHZ(2),   0x0330, 0 },
+       { SR_MHZ(1),   0x0362, 0 },
+       { SR_KHZ(500), 0x03c6, 0 },
+       { SR_KHZ(200), 0x07f2, 0 },
+       { SR_KHZ(100), 0x0fe6, 0 },
+       { SR_KHZ(50),  0x1fce, 0 },
+       { SR_KHZ(20),  0x4f86, 0 },
+       { SR_KHZ(10),  0x9f0e, 0 },
+       { SR_KHZ(5),   0x03c7, 0x20 },
+       { SR_KHZ(2),   0x07f3, 0x20 },
+       { SR_KHZ(1),   0x0fe7, 0x20 },
+       { SR_HZ(500),  0x1fcf, 0x20 },
+       { SR_HZ(200),  0x4f87, 0x20 },
+       { SR_HZ(100),  0x9f0f, 0x20 },
+};
+
+/* FIXME: Determine corresponding voltages */
+static const uint16_t la_threshold_map[] = {
+       0x8600,
+       0x8770,
+       0x88ff,
+       0x8c70,
+       0x8eff,
+       0x8fff,
+};
+
+#endif
diff --git a/src/hardware/manson-hcs-3xxx/api.c b/src/hardware/manson-hcs-3xxx/api.c
new file mode 100644 (file)
index 0000000..faa093f
--- /dev/null
@@ -0,0 +1,430 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Uwe Hermann <uwe@hermann-uwe.de>
+ * Copyright (C) 2014 Matthias Heidbrink <m-sigrok@heidbrink.biz>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/** @file
+  *  <em>Manson HCS-3xxx Series</em> power supply driver
+  *  @internal
+  */
+
+#include "protocol.h"
+
+static const int32_t hwopts[] = {
+       SR_CONF_CONN,
+       SR_CONF_SERIALCOMM,
+};
+
+static const int32_t devopts[] = {
+       /* Device class */
+       SR_CONF_POWER_SUPPLY,
+       /* Aquisition modes. */
+       SR_CONF_LIMIT_SAMPLES,
+       SR_CONF_LIMIT_MSEC,
+       SR_CONF_CONTINUOUS,
+       /* Device configuration */
+       SR_CONF_OUTPUT_CURRENT,
+       SR_CONF_OUTPUT_CURRENT_MAX,
+       SR_CONF_OUTPUT_ENABLED,
+       SR_CONF_OUTPUT_VOLTAGE,
+       SR_CONF_OUTPUT_VOLTAGE_MAX,
+};
+
+/* Note: All models have one power supply output only. */
+static struct hcs_model models[] = {
+       { MANSON_HCS_3100, "HCS-3100",     "3100", { 1, 18, 0.1 }, { 0, 10,   0.10 } },
+       { MANSON_HCS_3102, "HCS-3102",     "3102", { 1, 36, 0.1 }, { 0,  5,   0.01 } },
+       { MANSON_HCS_3104, "HCS-3104",     "3104", { 1, 60, 0.1 }, { 0,  2.5, 0.01 } },
+       { MANSON_HCS_3150, "HCS-3150",     "3150", { 1, 18, 0.1 }, { 0, 15,   0.10 } },
+       { MANSON_HCS_3200, "HCS-3200",     "3200", { 1, 18, 0.1 }, { 0, 20,   0.10 } },
+       { MANSON_HCS_3202, "HCS-3202",     "3202", { 1, 36, 0.1 }, { 0, 10,   0.10 } },
+       { MANSON_HCS_3204, "HCS-3204",     "3204", { 1, 60, 0.1 }, { 0,  5,   0.01 } },
+       { MANSON_HCS_3300, "HCS-3300-USB", "3300", { 1, 16, 0.1 }, { 0, 30,   0.10 } },
+       { MANSON_HCS_3302, "HCS-3302-USB", "3302", { 1, 32, 0.1 }, { 0, 15,   0.10 } },
+       { MANSON_HCS_3304, "HCS-3304-USB", "3304", { 1, 60, 0.1 }, { 0,  8,   0.10 } },
+       { MANSON_HCS_3400, "HCS-3400-USB", "3400", { 1, 16, 0.1 }, { 0, 40,   0.10 } },
+       { MANSON_HCS_3402, "HCS-3402-USB", "3402", { 1, 32, 0.1 }, { 0, 20,   0.10 } },
+       { MANSON_HCS_3404, "HCS-3404-USB", "3404", { 1, 60, 0.1 }, { 0, 10,   0.10 } },
+       { MANSON_HCS_3600, "HCS-3600-USB", "3600", { 1, 16, 0.1 }, { 0, 60,   0.10 } },
+       { MANSON_HCS_3602, "HCS-3602-USB", "3602", { 1, 32, 0.1 }, { 0, 30,   0.10 } },
+       { MANSON_HCS_3604, "HCS-3604-USB", "3604", { 1, 60, 0.1 }, { 0, 15,   0.10 } },
+       { 0, NULL, NULL, { 0, 0, 0 }, { 0, 0, 0 }, },
+};
+
+SR_PRIV struct sr_dev_driver manson_hcs_3xxx_driver_info;
+static struct sr_dev_driver *di = &manson_hcs_3xxx_driver_info;
+
+static int dev_clear(void)
+{
+       return std_dev_clear(di, NULL);
+}
+
+static int init(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+       int i, model_id;
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       struct sr_dev_inst *sdi;
+       struct sr_config *src;
+       struct sr_channel *ch;
+       GSList *devices, *l;
+       const char *conn, *serialcomm;
+       struct sr_serial_dev_inst *serial;
+       char reply[50], **tokens, *dummy;
+
+       drvc = di->priv;
+       drvc->instances = NULL;
+       devices = NULL;
+       conn = NULL;
+       serialcomm = NULL;
+       devc = 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;
+               default:
+                       sr_err("Unknown option %d, skipping.", src->key);
+                       break;
+               }
+       }
+
+       if (!conn)
+               return NULL;
+       if (!serialcomm)
+               serialcomm = "9600/8n1";
+
+       if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
+               return NULL;
+
+       if (serial_open(serial, SERIAL_RDWR) != SR_OK)
+               return NULL;
+
+       serial_flush(serial);
+
+       sr_info("Probing serial port %s.", conn);
+
+       /* Get the device model. */
+       memset(&reply, 0, sizeof(reply));
+       if ((hcs_send_cmd(serial, "GMOD\r") < 0) ||
+           (hcs_read_reply(serial, 2, reply, sizeof(reply)) < 0))
+               return NULL;
+       tokens = g_strsplit((const gchar *)&reply, "\r", 2);
+
+       model_id = -1;
+       for (i = 0; models[i].id != NULL; i++) {
+               if (!strcmp(models[i].id, tokens[0]))
+                       model_id = i;
+       }
+       g_strfreev(tokens);
+
+       if (model_id < 0) {
+               sr_err("Unknown model id '%s' detected, aborting.", tokens[0]);
+               return NULL;
+       }
+
+       /* Init device instance, etc. */
+       if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "Manson",
+                                   models[model_id].name, NULL))) {
+               sr_err("Failed to create device instance.");
+               return NULL;
+       }
+
+       sdi->inst_type = SR_INST_SERIAL;
+       sdi->conn = serial;
+       sdi->driver = di;
+
+       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "CH1"))) {
+               sr_err("Failed to create channel.");
+               goto exit_err;
+       }
+       sdi->channels = g_slist_append(sdi->channels, ch);
+
+       devc = g_malloc0(sizeof(struct dev_context));
+       devc->model = &models[model_id];
+
+       sdi->priv = devc;
+
+       /* Get current voltage, current, status. */
+       if ((hcs_send_cmd(serial, "GETD\r") < 0) ||
+           (hcs_read_reply(serial, 2, reply, sizeof(reply)) < 0))
+               goto exit_err;
+       tokens = g_strsplit((const gchar *)&reply, "\r", 2);
+       if (hcs_parse_volt_curr_mode(sdi, tokens) < 0)
+               goto exit_err;
+       g_strfreev(tokens);
+
+       /* Get max. voltage and current. */
+       if ((hcs_send_cmd(serial, "GMAX\r") < 0) ||
+           (hcs_read_reply(serial, 2, reply, sizeof(reply)) < 0))
+               goto exit_err;
+       tokens = g_strsplit((const gchar *)&reply, "\r", 2);
+       devc->current_max_device = g_strtod(&tokens[0][3], &dummy) * devc->model->current[2];
+       tokens[0][3] = '\0';
+       devc->voltage_max_device = g_strtod(tokens[0], &dummy) * devc->model->voltage[2];
+       g_strfreev(tokens);
+
+       drvc->instances = g_slist_append(drvc->instances, sdi);
+       devices = g_slist_append(devices, sdi);
+
+       serial_close(serial);
+       if (!devices)
+               sr_serial_dev_inst_free(serial);
+
+       return devices;
+
+exit_err:
+       sr_dev_inst_free(sdi);
+       if (devc)
+               g_free(devc);
+       return NULL;
+}
+
+static GSList *dev_list(void)
+{
+       return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int cleanup(void)
+{
+       return dev_clear();
+}
+
+static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+
+       (void)cg;
+
+       if (!sdi)
+               return SR_ERR_ARG;
+
+       devc = sdi->priv;
+
+       switch (key) {
+       case SR_CONF_LIMIT_SAMPLES:
+               *data = g_variant_new_uint64(devc->limit_samples);
+               break;
+       case SR_CONF_LIMIT_MSEC:
+               *data = g_variant_new_uint64(devc->limit_msec);
+               break;
+       case SR_CONF_OUTPUT_CURRENT:
+               *data = g_variant_new_double(devc->current);
+               break;
+       case SR_CONF_OUTPUT_CURRENT_MAX:
+               *data = g_variant_new_double(devc->current_max);
+               break;
+       case SR_CONF_OUTPUT_ENABLED:
+               *data = g_variant_new_boolean(devc->output_enabled);
+               break;
+       case SR_CONF_OUTPUT_VOLTAGE:
+               *data = g_variant_new_double(devc->voltage);
+               break;
+       case SR_CONF_OUTPUT_VOLTAGE_MAX:
+               *data = g_variant_new_double(devc->voltage_max);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       gboolean bval;
+       gdouble dval;
+
+       (void)cg;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       devc = sdi->priv;
+
+       switch (key) {
+       case SR_CONF_LIMIT_MSEC:
+               if (g_variant_get_uint64(data) == 0)
+                       return SR_ERR_ARG;
+               devc->limit_msec = g_variant_get_uint64(data);
+               break;
+       case SR_CONF_LIMIT_SAMPLES:
+               if (g_variant_get_uint64(data) == 0)
+                       return SR_ERR_ARG;
+               devc->limit_samples = g_variant_get_uint64(data);
+               break;
+       case SR_CONF_OUTPUT_CURRENT_MAX:
+               dval = g_variant_get_double(data);
+               if (dval < devc->model->current[0] || dval > devc->current_max_device)
+                       return SR_ERR_ARG;
+
+               if ((hcs_send_cmd(sdi->conn, "CURR%03.0f\r",
+                       (dval / devc->model->current[2])) < 0) ||
+                   (hcs_read_reply(sdi->conn, 1, devc->buf, sizeof(devc->buf)) < 0))
+                       return SR_ERR;
+               devc->current_max = dval;
+               break;
+       case SR_CONF_OUTPUT_ENABLED:
+               bval = g_variant_get_boolean(data);
+               if (bval == devc->output_enabled) /* Nothing to do. */
+                       break;
+               if ((hcs_send_cmd(sdi->conn, "SOUT%1d\r", !bval) < 0) ||
+                   (hcs_read_reply(sdi->conn, 1, devc->buf, sizeof(devc->buf)) < 0))
+                       return SR_ERR;
+               devc->output_enabled = bval;
+               break;
+       case SR_CONF_OUTPUT_VOLTAGE_MAX:
+               dval = g_variant_get_double(data);
+               if (dval < devc->model->voltage[0] || dval > devc->voltage_max_device)
+                       return SR_ERR_ARG;
+
+               if ((hcs_send_cmd(sdi->conn, "VOLT%03.0f\r",
+                       (dval / devc->model->voltage[2])) < 0) ||
+                   (hcs_read_reply(sdi->conn, 1, devc->buf, sizeof(devc->buf)) < 0))
+                       return SR_ERR;
+               devc->voltage_max = dval;
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       GVariant *gvar;
+       GVariantBuilder gvb;
+       double dval;
+       int idx;
+
+       (void)cg;
+
+       if (!sdi)
+               return SR_ERR_ARG;
+       devc = sdi->priv;
+
+       switch (key) {
+       case SR_CONF_SCAN_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                       hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+               break;
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                       devopts, ARRAY_SIZE(devopts), sizeof(int32_t));
+               break;
+       case SR_CONF_OUTPUT_CURRENT_MAX:
+               g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
+               /* Min, max, step. */
+               for (idx = 0; idx < 3; idx++) {
+                       if (idx == 1)
+                               dval = devc->current_max_device;
+                       else
+                               dval = devc->model->current[idx];
+                       gvar = g_variant_new_double(dval);
+                       g_variant_builder_add_value(&gvb, gvar);
+               }
+               *data = g_variant_builder_end(&gvb);
+               break;
+       case SR_CONF_OUTPUT_VOLTAGE_MAX:
+               g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
+               /* Min, max, step. */
+               for (idx = 0; idx < 3; idx++) {
+                       if (idx == 1)
+                               dval = devc->voltage_max_device;
+                       else
+                               dval = devc->model->voltage[idx];
+                       gvar = g_variant_new_double(dval);
+                       g_variant_builder_add_value(&gvb, gvar);
+               }
+               *data = g_variant_builder_end(&gvb);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       devc = sdi->priv;
+       devc->cb_data = cb_data;
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(cb_data, LOG_PREFIX);
+
+       devc->starttime = g_get_monotonic_time();
+       devc->num_samples = 0;
+       devc->reply_pending = FALSE;
+       devc->req_sent_at = 0;
+
+       /* Poll every 10ms, or whenever some data comes in. */
+       serial = sdi->conn;
+       serial_source_add(sdi->session, serial, G_IO_IN, 10,
+                       hcs_receive_data, (void *)sdi);
+
+       return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       return std_serial_dev_acquisition_stop(sdi, cb_data,
+                       std_serial_dev_close, sdi->conn, LOG_PREFIX);
+}
+
+SR_PRIV struct sr_dev_driver manson_hcs_3xxx_driver_info = {
+       .name = "manson-hcs-3xxx",
+       .longname = "Manson HCS-3xxx",
+       .api_version = 1,
+       .init = init,
+       .cleanup = cleanup,
+       .scan = scan,
+       .dev_list = dev_list,
+       .dev_clear = dev_clear,
+       .config_get = config_get,
+       .config_set = config_set,
+       .config_list = config_list,
+       .dev_open = std_serial_dev_open,
+       .dev_close = std_serial_dev_close,
+       .dev_acquisition_start = dev_acquisition_start,
+       .dev_acquisition_stop = dev_acquisition_stop,
+       .priv = NULL,
+};
diff --git a/src/hardware/manson-hcs-3xxx/protocol.c b/src/hardware/manson-hcs-3xxx/protocol.c
new file mode 100644 (file)
index 0000000..f5199e7
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Uwe Hermann <uwe@hermann-uwe.de>
+ * Copyright (C) 2014 Matthias Heidbrink <m-sigrok@heidbrink.biz>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/** @file
+  *  <em>Manson HCS-3xxx Series</em> power supply driver
+  *  @internal
+  */
+
+#include "protocol.h"
+
+#define REQ_TIMEOUT_MS 500
+
+SR_PRIV int hcs_send_cmd(struct sr_serial_dev_inst *serial, const char *cmd, ...)
+{
+       int ret;
+       char cmdbuf[50];
+       char *cmd_esc;
+       va_list args;
+
+       va_start(args, cmd);
+       vsnprintf(cmdbuf, sizeof(cmdbuf), cmd, args);
+       va_end(args);
+
+       cmd_esc = g_strescape(cmdbuf, NULL);
+       sr_dbg("Sending '%s'.", cmd_esc);
+       g_free(cmd_esc);
+
+       if ((ret = serial_write_blocking(serial, cmdbuf, strlen(cmdbuf))) < 0) {
+               sr_err("Error sending command: %d.", ret);
+               return ret;
+       }
+
+       return ret;
+}
+
+/**
+ * Read data from interface into buffer blocking until @a lines number of \\r chars
+ * received.
+ * @param serial Previously initialized serial port structure.
+ * @param[in] lines Number of \\r-terminated lines to read (1-n).
+ * @param     buf Buffer for result. Contents is NUL-terminated on success.
+ * @param[in] buflen Buffer length (>0).
+ * @retval SR_OK Lines received and ending with "OK\r" (success).
+ * @retval SR_ERR Error.
+ * @retval SR_ERR_ARG Invalid argument.
+ */
+SR_PRIV int hcs_read_reply(struct sr_serial_dev_inst *serial, int lines, char* buf, int buflen)
+{
+       int l_recv = 0;
+       int bufpos = 0;
+       int retc;
+
+       if (!serial || (lines <= 0) || !buf || (buflen <= 0))
+               return SR_ERR_ARG;
+
+       while ((l_recv < lines) && (bufpos < (buflen + 1))) {
+               retc = serial_read_blocking(serial, &buf[bufpos], 1);
+               if (retc != 1)
+                       return SR_ERR;
+               if (buf[bufpos] == '\r')
+                       l_recv++;
+               bufpos++;
+       }
+       buf[bufpos] = '\0';
+
+       if ((l_recv == lines) && (g_str_has_suffix(buf, "OK\r")))
+               return SR_OK;
+       else
+               return SR_ERR;
+}
+
+/** Interpret result of GETD command. */
+SR_PRIV int hcs_parse_volt_curr_mode(struct sr_dev_inst *sdi, char **tokens)
+{
+       char *str;
+       double val;
+       struct dev_context *devc;
+
+       devc = sdi->priv;
+
+       /* Bytes 0-3: Voltage. */
+       str = g_strndup(tokens[0], 4);
+       val = g_ascii_strtod(str, NULL) / 100;
+       devc->voltage = val;
+       g_free(str);
+
+       /* Bytes 4-7: Current. */
+       str = g_strndup((tokens[0] + 4), 4);
+       val = g_ascii_strtod(str, NULL) / 100;
+       devc->current = val;
+       g_free(str);
+
+       /* Byte 8: Mode ('0' means CV, '1' means CC). */
+       devc->cc_mode = (tokens[0][8] == '1');
+
+       /* Output enabled? Works because voltage cannot be set to 0.0 directly. */
+       devc->output_enabled = devc->voltage != 0.0;
+
+       return SR_OK;
+}
+
+static void send_sample(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_analog analog;
+
+       devc = sdi->priv;
+
+       packet.type = SR_DF_ANALOG;
+       packet.payload = &analog;
+       analog.channels = sdi->channels;
+       analog.num_samples = 1;
+
+       analog.mq = SR_MQ_VOLTAGE;
+       analog.unit = SR_UNIT_VOLT;
+       analog.mqflags = SR_MQFLAG_DC;
+       analog.data = &devc->voltage;
+       sr_session_send(sdi, &packet);
+
+       analog.mq = SR_MQ_CURRENT;
+       analog.unit = SR_UNIT_AMPERE;
+       analog.mqflags = 0;
+       analog.data = &devc->current;
+       sr_session_send(sdi, &packet);
+
+       devc->num_samples++;
+}
+
+static int parse_reply(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       char *reply_esc, **tokens;
+       int retc;
+
+       devc = sdi->priv;
+
+       reply_esc = g_strescape(devc->buf, NULL);
+       sr_dbg("Received '%s'.", reply_esc);
+       g_free(reply_esc);
+
+       tokens = g_strsplit(devc->buf, "\r", 0);
+       retc = hcs_parse_volt_curr_mode(sdi, tokens);
+       g_strfreev(tokens);
+       if (retc < 0)
+               return SR_ERR;
+
+       send_sample(sdi);
+
+       return SR_OK;
+}
+
+static int handle_new_data(struct sr_dev_inst *sdi)
+{
+       int len;
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+
+       devc = sdi->priv;
+       serial = sdi->conn;
+
+       len = serial_read(serial, devc->buf + devc->buflen, 1);
+       if (len < 1)
+               return SR_ERR;
+
+       devc->buflen += len;
+       devc->buf[devc->buflen] = '\0';
+
+       /* Wait until we received an "OK\r" (among other bytes). */
+       if (!g_str_has_suffix(devc->buf, "OK\r"))
+               return SR_OK;
+
+       parse_reply(sdi);
+
+       devc->buf[0] = '\0';
+       devc->buflen = 0;
+
+       devc->reply_pending = FALSE;
+
+       return SR_OK;
+}
+
+/** Driver/serial data reception function. */
+SR_PRIV int hcs_receive_data(int fd, int revents, void *cb_data)
+{
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+       int64_t t, elapsed_us;
+
+       (void)fd;
+
+       if (!(sdi = cb_data))
+               return TRUE;
+
+       if (!(devc = sdi->priv))
+               return TRUE;
+
+       serial = sdi->conn;
+
+       if (revents == G_IO_IN) {
+               /* New data arrived. */
+               handle_new_data(sdi);
+       } else {
+               /* Timeout. */
+       }
+
+       if (devc->limit_samples && (devc->num_samples >= devc->limit_samples)) {
+               sr_info("Requested number of samples reached.");
+               sdi->driver->dev_acquisition_stop(sdi, cb_data);
+               return TRUE;
+       }
+
+       if (devc->limit_msec) {
+               t = (g_get_monotonic_time() - devc->starttime) / 1000;
+               if (t > (int64_t)devc->limit_msec) {
+                       sr_info("Requested time limit reached.");
+                       sdi->driver->dev_acquisition_stop(sdi, cb_data);
+                       return TRUE;
+               }
+       }
+
+       /* Request next packet, if required. */
+       if (sdi->status == SR_ST_ACTIVE) {
+               if (devc->reply_pending) {
+                       elapsed_us = g_get_monotonic_time() - devc->req_sent_at;
+                       if (elapsed_us > (REQ_TIMEOUT_MS * 1000))
+                               devc->reply_pending = FALSE;
+                       return TRUE;
+               }
+
+               /* Send command to get voltage, current, and mode (CC or CV). */
+               if (hcs_send_cmd(serial, "GETD\r") < 0)
+                       return TRUE;
+
+               devc->req_sent_at = g_get_monotonic_time();
+               devc->reply_pending = TRUE;
+       }
+
+       return TRUE;
+}
diff --git a/src/hardware/manson-hcs-3xxx/protocol.h b/src/hardware/manson-hcs-3xxx/protocol.h
new file mode 100644 (file)
index 0000000..b4441d0
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Uwe Hermann <uwe@hermann-uwe.de>
+ * Copyright (C) 2014 Matthias Heidbrink <m-sigrok@heidbrink.biz>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/** @file
+  *  <em>Manson HCS-3xxx Series</em> power supply driver
+  *  @internal
+  */
+
+#ifndef LIBSIGROK_HARDWARE_MANSON_HCS_3XXX_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_MANSON_HCS_3XXX_PROTOCOL_H
+
+#include <stdint.h>
+#include <string.h>
+#include <math.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "manson-hcs-3xxx"
+
+enum {
+       MANSON_HCS_3100,
+       MANSON_HCS_3102,
+       MANSON_HCS_3104,
+       MANSON_HCS_3150,
+       MANSON_HCS_3200,
+       MANSON_HCS_3202,
+       MANSON_HCS_3204,
+       MANSON_HCS_3300,
+       MANSON_HCS_3302,
+       MANSON_HCS_3304,
+       MANSON_HCS_3400,
+       MANSON_HCS_3402,
+       MANSON_HCS_3404,
+       MANSON_HCS_3600,
+       MANSON_HCS_3602,
+       MANSON_HCS_3604,
+};
+
+/** Information on a single model. */
+struct hcs_model {
+       int model_id;      /**< Model info */
+       char *name;        /**< Model name */
+       char *id;          /**< Model ID, like delivered by interface */
+       double voltage[3]; /**< Min, max, step */
+       double current[3]; /**< Min, max, step */
+};
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+       struct hcs_model *model; /**< Model informaion. */
+
+       uint64_t limit_samples;
+       uint64_t limit_msec;
+       uint64_t num_samples;
+       int64_t starttime;
+       int64_t req_sent_at;
+       gboolean reply_pending;
+
+       void *cb_data;
+
+       float current;          /**< Last current value [A] read from device. */
+       float current_max;      /**< Output current set. */
+       float current_max_device;/**< Device-provided maximum output current. */
+       float voltage;          /**< Last voltage value [V] read from device. */
+       float voltage_max;      /**< Output voltage set. */
+       float voltage_max_device;/**< Device-provided maximum output voltage. */
+       gboolean cc_mode;       /**< Device is in constant current mode (otherwise constant voltage). */
+
+       gboolean output_enabled; /**< Is the output enabled? */
+
+       char buf[50];
+       int buflen;
+};
+
+SR_PRIV int hcs_parse_volt_curr_mode(struct sr_dev_inst *sdi, char **tokens);
+SR_PRIV int hcs_read_reply(struct sr_serial_dev_inst *serial, int lines, char* buf, int buflen);
+SR_PRIV int hcs_send_cmd(struct sr_serial_dev_inst *serial, const char *cmd, ...);
+SR_PRIV int hcs_receive_data(int fd, int revents, void *cb_data);
+
+#endif
diff --git a/src/hardware/mic-985xx/api.c b/src/hardware/mic-985xx/api.c
new file mode 100644 (file)
index 0000000..6cfc5ef
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "protocol.h"
+
+static const int32_t hwopts[] = {
+       SR_CONF_CONN,
+       SR_CONF_SERIALCOMM,
+};
+
+static const int32_t hwcaps[] = {
+       SR_CONF_THERMOMETER,
+       SR_CONF_HYGROMETER,
+       SR_CONF_LIMIT_SAMPLES,
+       SR_CONF_LIMIT_MSEC,
+       SR_CONF_CONTINUOUS,
+};
+
+SR_PRIV struct sr_dev_driver mic_98581_driver_info;
+SR_PRIV struct sr_dev_driver mic_98583_driver_info;
+
+SR_PRIV const struct mic_dev_info mic_devs[] = {
+       {
+               "MIC", "98581", "38400/8n2", 32000, TRUE, FALSE, 6,
+               packet_valid_temp,
+               &mic_98581_driver_info, receive_data_MIC_98581,
+       },
+       {
+               "MIC", "98583", "38400/8n2", 32000, TRUE, TRUE, 10,
+               packet_valid_temp_hum,
+               &mic_98583_driver_info, receive_data_MIC_98583,
+       },
+};
+
+static int dev_clear(int idx)
+{
+       return std_dev_clear(mic_devs[idx].di, NULL);
+}
+
+static int init(struct sr_context *sr_ctx, int idx)
+{
+       sr_dbg("Selected '%s' subdriver.", mic_devs[idx].di->name);
+
+       return std_init(sr_ctx, mic_devs[idx].di, LOG_PREFIX);
+}
+
+static GSList *mic_scan(const char *conn, const char *serialcomm, int idx)
+{
+       struct sr_dev_inst *sdi;
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       struct sr_channel *ch;
+       struct sr_serial_dev_inst *serial;
+       GSList *devices;
+
+       if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
+               return NULL;
+
+       if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
+               return NULL;
+
+       drvc = mic_devs[idx].di->priv;
+       devices = NULL;
+       serial_flush(serial);
+
+       /* TODO: Query device type. */
+       // ret = mic_cmd_get_device_info(serial);
+
+       sr_info("Found device on port %s.", conn);
+
+       /* TODO: Fill in version from protocol response. */
+       if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, mic_devs[idx].vendor,
+                                   mic_devs[idx].device, NULL)))
+               goto scan_cleanup;
+
+       if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+               sr_err("Device context malloc failed.");
+               goto scan_cleanup;
+       }
+
+       sdi->inst_type = SR_INST_SERIAL;
+       sdi->conn = serial;
+
+       sdi->priv = devc;
+       sdi->driver = mic_devs[idx].di;
+
+       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "Temperature")))
+               goto scan_cleanup;
+       sdi->channels = g_slist_append(sdi->channels, ch);
+
+       if (mic_devs[idx].has_humidity) {
+               if (!(ch = sr_channel_new(1, SR_CHANNEL_ANALOG, TRUE, "Humidity")))
+                       goto scan_cleanup;
+               sdi->channels = g_slist_append(sdi->channels, ch);
+       }
+
+       drvc->instances = g_slist_append(drvc->instances, sdi);
+       devices = g_slist_append(devices, sdi);
+
+scan_cleanup:
+       serial_close(serial);
+
+       return devices;
+}
+
+static GSList *scan(GSList *options, int idx)
+{
+       struct sr_config *src;
+       GSList *l, *devices;
+       const char *conn, *serialcomm;
+
+       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 = mic_scan(conn, serialcomm, idx);
+       } else {
+               /* Try the default. */
+               devices = mic_scan(conn, mic_devs[idx].conn, idx);
+       }
+
+       return devices;
+}
+
+static GSList *dev_list(int idx)
+{
+       return ((struct drv_context *)(mic_devs[idx].di->priv))->instances;
+}
+
+static int cleanup(int idx)
+{
+       return dev_clear(idx);
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+
+       (void)cg;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       devc = sdi->priv;
+
+       switch (id) {
+       case SR_CONF_LIMIT_SAMPLES:
+               devc->limit_samples = g_variant_get_uint64(data);
+               sr_dbg("Setting sample limit to %" PRIu64 ".",
+                      devc->limit_samples);
+               break;
+       case SR_CONF_LIMIT_MSEC:
+               devc->limit_msec = g_variant_get_uint64(data);
+               sr_dbg("Setting time limit to %" PRIu64 "ms.",
+                      devc->limit_msec);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_list(int 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_INT32,
+                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+               break;
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi,
+                                   void *cb_data, int idx)
+{
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       devc = sdi->priv;
+       devc->cb_data = cb_data;
+       devc->num_samples = 0;
+       devc->starttime = g_get_monotonic_time();
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(cb_data, LOG_PREFIX);
+
+       /* Poll every 100ms, or whenever some data comes in. */
+       serial = sdi->conn;
+       serial_source_add(sdi->session, serial, G_IO_IN, 100,
+                     mic_devs[idx].receive_data, (void *)sdi);
+
+       return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       return std_serial_dev_acquisition_stop(sdi, cb_data, std_serial_dev_close,
+                       sdi->conn, LOG_PREFIX);
+}
+
+/* Driver-specific API function wrappers */
+#define HW_INIT(X) \
+static int init_##X(struct sr_context *sr_ctx) { return init(sr_ctx, X); }
+#define HW_CLEANUP(X) \
+static int cleanup_##X(void) { return cleanup(X); }
+#define HW_SCAN(X) \
+static GSList *scan_##X(GSList *options) { return scan(options, X); }
+#define HW_DEV_LIST(X) \
+static GSList *dev_list_##X(void) { return dev_list(X); }
+#define HW_DEV_CLEAR(X) \
+static int dev_clear_##X(void) { return dev_clear(X); }
+#define HW_DEV_ACQUISITION_START(X) \
+static int dev_acquisition_start_##X(const struct sr_dev_inst *sdi, \
+void *cb_data) { return dev_acquisition_start(sdi, cb_data, X); }
+
+/* Driver structs and API function wrappers */
+#define DRV(ID, ID_UPPER, NAME, LONGNAME) \
+HW_INIT(ID_UPPER) \
+HW_CLEANUP(ID_UPPER) \
+HW_SCAN(ID_UPPER) \
+HW_DEV_LIST(ID_UPPER) \
+HW_DEV_CLEAR(ID_UPPER) \
+HW_DEV_ACQUISITION_START(ID_UPPER) \
+SR_PRIV struct sr_dev_driver ID##_driver_info = { \
+       .name = NAME, \
+       .longname = LONGNAME, \
+       .api_version = 1, \
+       .init = init_##ID_UPPER, \
+       .cleanup = cleanup_##ID_UPPER, \
+       .scan = scan_##ID_UPPER, \
+       .dev_list = dev_list_##ID_UPPER, \
+       .dev_clear = dev_clear_##ID_UPPER, \
+       .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_##ID_UPPER, \
+       .dev_acquisition_stop = dev_acquisition_stop, \
+       .priv = NULL, \
+};
+
+DRV(mic_98581, MIC_98581, "mic-98581", "MIC 98581")
+DRV(mic_98583, MIC_98583, "mic-98583", "MIC 98583")
diff --git a/src/hardware/mic-985xx/protocol.c b/src/hardware/mic-985xx/protocol.c
new file mode 100644 (file)
index 0000000..ce5f020
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "protocol.h"
+
+static int mic_send(struct sr_serial_dev_inst *serial, const char *cmd)
+{
+       int ret;
+
+       if ((ret = serial_write(serial, cmd, strlen(cmd))) < 0) {
+               sr_err("Error sending '%s' command: %d.", cmd, ret);
+               return SR_ERR;
+       }
+
+       return SR_OK;
+}
+
+SR_PRIV int mic_cmd_get_device_info(struct sr_serial_dev_inst *serial)
+{
+       return mic_send(serial, "I\r");
+}
+
+static int mic_cmd_set_realtime_mode(struct sr_serial_dev_inst *serial)
+{
+       return mic_send(serial, "S 1 M 2 32 3\r");
+}
+
+SR_PRIV gboolean packet_valid_temp(const uint8_t *buf)
+{
+       if (buf[0] != 'v' || buf[1] != ' ' || buf[5] != '\r')
+               return FALSE;
+
+       if (!isdigit(buf[2]) || !isdigit(buf[3]) || !isdigit(buf[4]))
+               return FALSE;
+
+       return TRUE;
+}
+
+SR_PRIV gboolean packet_valid_temp_hum(const uint8_t *buf)
+{
+       if (buf[0] != 'v' || buf[1] != ' ' || buf[5] != ' ' || buf[9] != '\r')
+               return FALSE;
+
+       if (!isdigit(buf[2]) || !isdigit(buf[3]) || !isdigit(buf[4]))
+               return FALSE;
+
+       if (!isdigit(buf[6]) || !isdigit(buf[7]) || !isdigit(buf[8]))
+               return FALSE;
+
+       return TRUE;
+}
+
+static int packet_parse(const char *buf, int idx, float *temp, float *humidity)
+{
+       char tmp[4];
+
+       /* Packet format MIC98581: "v ttt\r". */
+       /* Packet format MIC98583: "v ttt hhh\r". */
+
+       /* TODO: Sanity check on buf. For now we assume well-formed ASCII. */
+
+       tmp[3] = '\0';
+
+       strncpy((char *)&tmp, &buf[2], 3);
+       *temp = g_ascii_strtoull((const char *)&tmp, NULL, 10) / 10;
+
+       if (mic_devs[idx].has_humidity) {
+               strncpy((char *)&tmp, &buf[6], 3);
+               *humidity = g_ascii_strtoull((const char *)&tmp, NULL, 10) / 10;
+       }
+
+       return SR_OK;
+}
+
+static int handle_packet(const uint8_t *buf, struct sr_dev_inst *sdi, int idx)
+{
+       float temperature, humidity;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_analog analog;
+       struct dev_context *devc;
+       GSList *l;
+       int ret;
+
+       (void)idx;
+
+       devc = sdi->priv;
+
+       ret = packet_parse((const char *)buf, idx, &temperature, &humidity);
+       if (ret < 0) {
+               sr_err("Failed to parse packet.");
+               return SR_ERR;
+       }
+
+       /* Clear 'analog', otherwise it'll contain random garbage. */
+       memset(&analog, 0, sizeof(struct sr_datafeed_analog));
+
+       /* Common values for both channels. */
+       packet.type = SR_DF_ANALOG;
+       packet.payload = &analog;
+       analog.num_samples = 1;
+
+       /* Temperature. */
+       l = g_slist_copy(sdi->channels);
+       l = g_slist_remove_link(l, g_slist_nth(l, 1));
+       analog.channels = l;
+       analog.mq = SR_MQ_TEMPERATURE;
+       analog.unit = SR_UNIT_CELSIUS; /* TODO: Use C/F correctly. */
+       analog.data = &temperature;
+       sr_session_send(devc->cb_data, &packet);
+       g_slist_free(l);
+
+       /* Humidity. */
+       if (mic_devs[idx].has_humidity) {
+               l = g_slist_copy(sdi->channels);
+               l = g_slist_remove_link(l, g_slist_nth(l, 0));
+               analog.channels = l;
+               analog.mq = SR_MQ_RELATIVE_HUMIDITY;
+               analog.unit = SR_UNIT_PERCENTAGE;
+               analog.data = &humidity;
+               sr_session_send(devc->cb_data, &packet);
+               g_slist_free(l);
+       }
+
+       devc->num_samples++;
+
+       return SR_OK;
+}
+
+static void handle_new_data(struct sr_dev_inst *sdi, int idx)
+{
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+       int len, i, offset = 0;
+
+       devc = sdi->priv;
+       serial = sdi->conn;
+
+       /* Try to get as much data as the buffer can hold. */
+       len = SERIAL_BUFSIZE - devc->buflen;
+       len = serial_read(serial, devc->buf + devc->buflen, len);
+       if (len < 1) {
+               sr_err("Serial port read error: %d.", len);
+               return;
+       }
+
+       devc->buflen += len;
+
+       /* Now look for packets in that data. */
+       while ((devc->buflen - offset) >= mic_devs[idx].packet_size) {
+               if (mic_devs[idx].packet_valid(devc->buf + offset)) {
+                       handle_packet(devc->buf + offset, sdi, idx);
+                       offset += mic_devs[idx].packet_size;
+               } else {
+                       offset++;
+               }
+       }
+
+       /* If we have any data left, move it to the beginning of our buffer. */
+       for (i = 0; i < devc->buflen - offset; i++)
+               devc->buf[i] = devc->buf[offset + i];
+       devc->buflen -= offset;
+}
+
+static int receive_data(int fd, int revents, int idx, void *cb_data)
+{
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       int64_t t;
+       static gboolean first_time = TRUE;
+       struct sr_serial_dev_inst *serial;
+
+       (void)fd;
+
+       if (!(sdi = cb_data))
+               return TRUE;
+
+       if (!(devc = sdi->priv))
+               return TRUE;
+
+       serial = sdi->conn;
+
+       if (revents == G_IO_IN) {
+               /* New data arrived. */
+               handle_new_data(sdi, idx);
+       } else {
+               /* Timeout. */
+               if (first_time) {
+                       mic_cmd_set_realtime_mode(serial);
+                       first_time = FALSE;
+               }
+       }
+
+       if (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
+               sr_info("Requested number of samples reached.");
+               sdi->driver->dev_acquisition_stop(sdi, cb_data);
+               return TRUE;
+       }
+
+       if (devc->limit_msec) {
+               t = (g_get_monotonic_time() - devc->starttime) / 1000;
+               if (t > (int64_t)devc->limit_msec) {
+                       sr_info("Requested time limit reached.");
+                       sdi->driver->dev_acquisition_stop(sdi, cb_data);
+                       return TRUE;
+               }
+       }
+
+       return TRUE;
+}
+
+#define RECEIVE_DATA(ID_UPPER) \
+SR_PRIV int receive_data_##ID_UPPER(int fd, int revents, void *cb_data) { \
+       return receive_data(fd, revents, ID_UPPER, cb_data); }
+
+/* Driver-specific receive_data() wrappers */
+RECEIVE_DATA(MIC_98581)
+RECEIVE_DATA(MIC_98583)
diff --git a/src/hardware/mic-985xx/protocol.h b/src/hardware/mic-985xx/protocol.h
new file mode 100644 (file)
index 0000000..279cca5
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#ifndef LIBSIGROK_HARDWARE_MIC_985XX_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_MIC_985XX_PROTOCOL_H
+
+#include <stdint.h>
+#include <string.h>
+#include <ctype.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "mic-985xx"
+
+/* Note: When adding entries here, don't forget to update MIC_DEV_COUNT. */
+enum {
+       MIC_98581,
+       MIC_98583,
+};
+
+#define MIC_DEV_COUNT 2
+
+struct mic_dev_info {
+       char *vendor;
+       char *device;
+       char *conn;
+       uint32_t max_sample_points;
+       gboolean has_temperature;
+       gboolean has_humidity;
+       uint8_t packet_size;
+       gboolean (*packet_valid)(const uint8_t *);
+       struct sr_dev_driver *di;
+       int (*receive_data)(int, int, void *);
+};
+
+extern SR_PRIV const struct mic_dev_info mic_devs[MIC_DEV_COUNT];
+
+#define SERIAL_BUFSIZE 256
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+       /** The current sampling limit (in number of samples). */
+       uint64_t limit_samples;
+
+       /** The current sampling limit (in ms). */
+       uint64_t limit_msec;
+
+       /** Opaque pointer passed in by the frontend. */
+       void *cb_data;
+
+       /** The current number of already received samples. */
+       uint64_t num_samples;
+
+       int64_t starttime;
+
+       uint8_t buf[SERIAL_BUFSIZE];
+       int bufoffset;
+       int buflen;
+};
+
+SR_PRIV gboolean packet_valid_temp(const uint8_t *buf);
+SR_PRIV gboolean packet_valid_temp_hum(const uint8_t *buf);
+
+SR_PRIV int receive_data_MIC_98581(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_MIC_98583(int fd, int revents, void *cb_data);
+
+SR_PRIV int mic_cmd_get_device_info(struct sr_serial_dev_inst *serial);
+
+#endif
diff --git a/src/hardware/motech-lps-30x/api.c b/src/hardware/motech-lps-30x/api.c
new file mode 100644 (file)
index 0000000..164a9cc
--- /dev/null
@@ -0,0 +1,860 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Matthias Heidbrink <m-sigrok@heidbrink.biz>
+ * Copyright (C) 2014 Bert Vermeulen <bert@biot.com> (code from atten-pps3xxx)
+ *
+ * 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
+ *  <em>Motech LPS-30x series</em> power supply driver
+ *  @internal
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <math.h>
+#include <string.h>
+
+#include "protocol.h"
+
+/* Forward declarations */
+SR_PRIV struct sr_dev_driver motech_lps_301_driver_info;
+SR_PRIV int lps_read_reply(struct sr_serial_dev_inst *serial, char **buf, int *buflen);
+SR_PRIV int lps_send_va(struct sr_serial_dev_inst *serial, const char* fmt, va_list args);
+SR_PRIV int lps_cmd_ok(struct sr_serial_dev_inst *serial, const char* fmt, ...);
+SR_PRIV int lps_cmd_reply(char* reply, struct sr_serial_dev_inst *serial, const char* fmt, ...);
+SR_PRIV int lps_query_status(struct sr_dev_inst* sdi);
+
+/* Serial communication parameters */
+#define SERIALCOMM "2400/8n1/dtr=1/rts=1/flow=0"
+
+#define VENDOR_MOTECH "Motech"
+
+/** Driver scanning options. */
+static const int32_t hwopts[] = {
+       SR_CONF_CONN,
+       SR_CONF_SERIALCOMM,
+};
+
+/** Hardware capabilities generic. */
+static const int32_t hwcaps[] = {
+       /* Device class */
+       SR_CONF_POWER_SUPPLY,
+       /* Aquisition modes. */
+       SR_CONF_LIMIT_SAMPLES,
+       SR_CONF_LIMIT_MSEC,
+       SR_CONF_CONTINUOUS,
+       /* Device configuration */
+       SR_CONF_OUTPUT_CHANNEL,
+};
+
+/** Hardware capabilities channel 1, 2. */
+static const int32_t hwcaps_ch12[] = {
+       SR_CONF_OUTPUT_VOLTAGE,
+       SR_CONF_OUTPUT_VOLTAGE_MAX,
+       SR_CONF_OUTPUT_CURRENT,
+       SR_CONF_OUTPUT_CURRENT_MAX,
+       SR_CONF_OUTPUT_ENABLED,
+};
+
+/** Hardware capabilities channel 3. (LPS-304/305 only). */
+static const int32_t hwcaps_ch3[] = {
+       SR_CONF_OUTPUT_VOLTAGE,
+       SR_CONF_OUTPUT_ENABLED,
+};
+
+static const char *channel_modes[] = {
+       "Independent",
+       "Track1",
+       "Track2",
+};
+
+static struct lps_modelspec models[] = {
+       { LPS_UNKNOWN, "Dummy", 0,
+               {
+
+               }
+       },
+       { LPS_301, "LPS-301", 1,
+               {
+                       /* Channel 1 */
+                       { { 0, 32, 0.01 }, { 0.005, 2, 0.001 } },
+               },
+       },
+       { LPS_302, "LPS-302", 1,
+               {
+                       /* Channel 1 */
+                       { { 0, 32, 0.01 }, { 0.005, 3, 0.001 } },
+               },
+       },
+       { LPS_303, "LPS-303", 1,
+               {
+                       /* Channel 1 */
+                       { { 0, 32, 0.01 }, { 0.005, 3, 0.001 } },
+               },
+       },
+       { LPS_304, "LPS-304", 3,
+               {
+                       /* Channel 1 */
+                       { { 0, 32, 0.01 }, { 0.005, 3, 0.001 } },
+                       /* Channel 2 */
+                       { { 0, 32, 0.01 }, { 0.005, 3, 0.001 } },
+                       /* Channel 3 */
+                       { { 5, 5, 0.0 }, { 0.005, 3, 0.001 } },
+               },
+       },
+       { LPS_305, "LPS-305", 3,
+               {
+                       /* Channel 1 */
+                       { { 0, 32, 0.01 }, { 0.005, 3, 0.001 } },
+                       /* Channel 2 */
+                       { { 0, 32, 0.01 }, { 0.005, 3, 0.001 } },
+                       /* Channel 3 */
+                       { { 3.3, 5, 1.7 }, { 0.005, 3, 0.001 } },
+               },
+       },
+};
+
+static int init_lps301(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, &motech_lps_301_driver_info, LOG_PREFIX);
+}
+
+/** Send command to device with va_list.
+ */
+SR_PRIV int lps_send_va(struct sr_serial_dev_inst *serial, const char* fmt, va_list args)
+{
+       int retc;
+       char auxfmt[LINELEN_MAX];
+       char buf[LINELEN_MAX];
+
+       snprintf(auxfmt, sizeof(auxfmt), "%s\r\n", fmt);
+       vsnprintf(buf, sizeof(buf), auxfmt, args);
+
+       sr_spew("lps_send_va: \"%s\"", buf);
+
+       retc = serial_write_nonblocking(serial, buf, strlen(buf));
+
+       if (retc < 0)
+               return SR_ERR;
+
+       return SR_OK;
+}
+
+/** Send command to device.
+ */
+SR_PRIV int lps_send_req(struct sr_serial_dev_inst *serial, const char* fmt, ...)
+{
+       int retc;
+       va_list args;
+
+       va_start(args, fmt);
+       retc = lps_send_va(serial, fmt, args);
+       va_end(args);
+
+       return retc;
+}
+
+/** Send command and consume simple OK reply. */
+SR_PRIV int lps_cmd_ok(struct sr_serial_dev_inst *serial, const char* fmt, ...)
+{
+       int retc;
+       va_list args;
+       char buf[LINELEN_MAX];
+       char* bufptr;
+       int  buflen;
+
+       /* Send command */
+       va_start(args, fmt);
+       retc = lps_send_va(serial, fmt, args);
+       va_end(args);
+
+       if (retc != SR_OK)
+               return SR_ERR;
+
+       /* Read reply */
+       buf[0] = '\0';
+       bufptr = buf;
+       buflen = sizeof(buf);
+       retc = lps_read_reply(serial, &bufptr, &buflen);
+       if ((retc == SR_OK) && (buflen == 0))
+               return SR_OK;
+
+       return SR_ERR;
+}
+
+/** Send command and read reply string.
+ *  \param reply Pointer to buffer of size LINELEN_MAX. Will be NUL-terminated.
+ */
+SR_PRIV int lps_cmd_reply(char* reply, struct sr_serial_dev_inst *serial, const char* fmt, ...)
+{
+       int retc;
+       va_list args;
+       char buf[LINELEN_MAX];
+       char* bufptr;
+       int  buflen;
+
+       reply[0] = '\0';
+
+       /* Send command */
+       va_start(args, fmt);
+       retc = lps_send_va(serial, fmt, args);
+       va_end(args);
+
+       if (retc != SR_OK)
+               return SR_ERR;
+
+       /* Read reply */
+       buf[0] = '\0';
+       bufptr = buf;
+       buflen = sizeof(buf);
+       retc = lps_read_reply(serial, &bufptr, &buflen);
+       if ((retc == SR_OK) && (buflen > 0)) {
+               strcpy(reply, buf);
+               return SR_OK;
+       }
+
+       return SR_ERR;
+}
+
+/** Process integer value returned by STATUS command. */
+SR_PRIV int lps_process_status(struct sr_dev_inst* sdi, int stat)
+{
+       struct dev_context* devc;
+       int tracking_mode;
+
+       devc = (struct dev_context*)sdi->priv;
+
+       sr_spew("Status: %d", stat);
+       devc->channel_status[0].cc_mode = (stat & 0x01) != 0;
+       sr_spew("Channel 1 %s mode", devc->channel_status[0].cc_mode?"CC":"CV");
+       if (devc->model->num_channels > 1) {
+               devc->channel_status[1].cc_mode = (stat & 0x02) != 0;
+               sr_spew("Channel 2 %s mode", devc->channel_status[1].cc_mode?"CC":"CV");
+
+               tracking_mode = (stat & 0x0c) >> 2;
+               switch (tracking_mode) {
+               case 0: devc->tracking_mode = 0;
+                       break;
+               case 2: devc->tracking_mode = 1;
+                       break;
+               case 3: devc->tracking_mode = 2;
+                       break;
+               default:
+                       sr_err("Illegal channel tracking mode %d!", tracking_mode);
+                       devc->tracking_mode = 0;
+                       break;
+               }
+
+               sr_spew("Channel tracking: %d", devc->tracking_mode);
+       }
+       devc->channel_status[0].output_enabled = devc->channel_status[1].output_enabled = stat&0x040?TRUE:FALSE;
+       sr_spew("Channel 1%s output: %s", devc->model->num_channels > 1?"+2":"", devc->channel_status[0].output_enabled?"ON":"OFF");
+       if (devc->model->num_channels > 2) {
+               devc->channel_status[2].output_enabled = stat&0x010?TRUE:FALSE;
+               devc->channel_status[2].output_voltage_last = stat&0x020?3.3:5;
+               sr_spew("Channel 3 output: %s, U=%02f V, overload=%d",
+                       devc->channel_status[2].output_enabled?"ON":"OFF",
+                       devc->channel_status[2].output_voltage_last,
+                       stat&0x080?1:0);
+       }
+       sr_spew("Fan=%d, beep=%d, CC output compensated=%d", stat&0x0100?1:0, stat&0x0200?1:0, stat&0x0400?1:0);
+
+       return SR_OK;
+}
+
+/** Send STATUS commend and process status string. */
+SR_PRIV int lps_query_status(struct sr_dev_inst* sdi)
+{
+       char buf[LINELEN_MAX];
+       int stat;
+       struct dev_context* devc;
+
+       devc = (struct dev_context*)sdi->priv;
+
+       devc->req_sent_at = g_get_real_time();
+
+       if (lps_cmd_reply(buf, sdi->conn, "STATUS") < 0) {
+               sr_err("%s: Failed to read status: %d %s", __func__, errno, strerror(errno));
+               return SR_ERR;
+       }
+
+       if (sr_atoi(buf, &stat) != SR_OK)
+               return SR_ERR;
+
+       return lps_process_status(sdi, stat);
+}
+
+static gint64 calc_timeout_ms(gint64 start_us)
+{
+       gint64 result = REQ_TIMEOUT_MS - ((g_get_real_time() - start_us) / 1000);
+
+       if (result < 0)
+               return 0;
+
+       return result;
+}
+
+/** Read message into buf until "OK" received.
+ *  \retval SR_OK Msg received; buf and buflen contain result, if any except OK.
+ *  \retval SR_ERR Error, including timeout.
+*/
+SR_PRIV int lps_read_reply(struct sr_serial_dev_inst *serial, char **buf, int *buflen)
+{
+       int retries;
+       char buf2[LINELEN_MAX];
+       char *buf2ptr;
+       int buf2len;
+       gint64 timeout_start;
+
+       *buf[0] = '\0';
+
+       /* Read one line. It is either a data message or "OK". */
+       timeout_start = g_get_real_time();
+       buf2len = *buflen;
+       /* Up to 5 tries because serial_readline() will consume only one CR or LF per
+        * call, but device sends up to 4 in a row. */
+       for (retries = 0; retries < 5; retries++) {
+               *buflen = buf2len;
+               if (serial_readline(serial, buf, buflen, calc_timeout_ms(timeout_start)) != SR_OK)
+                       return SR_ERR;
+               if (!strcmp(*buf, "OK")) { /* We got an OK! */
+                       *buf[0] = '\0';
+                       *buflen = 0;
+                       return SR_OK;
+               }
+               if (*buflen > 0) /* We got a msg! */
+                       break;
+       }
+
+       /* A data msg is in buf (possibly ERROR), need to consume "OK". */
+       buf2[0] = '\0';
+       buf2ptr = buf2;
+       for (retries = 0; retries < 5; retries++) {
+               buf2len = sizeof(buf2);
+               if (serial_readline(serial, &buf2ptr, &buf2len, calc_timeout_ms(timeout_start)) != SR_OK)
+                       return SR_ERR;
+
+               if (!strcmp(buf2ptr, "OK")) { /* We got an OK! */
+                       if (!strcmp(*buf, "ERROR")) { /* OK came after msg ERROR! */
+                               sr_spew("ERROR found!");
+                               *buf[0] = '\0';
+                               *buflen = 0;
+                               return SR_ERR;
+                       }
+                       return SR_OK;
+               }
+       }
+
+       return SR_ERR; /* Timeout! */
+}
+
+/** Scan for LPS-300 series device.
+ */
+static GSList *do_scan(lps_modelid modelid, struct sr_dev_driver *drv, GSList *options)
+{
+       struct sr_dev_inst *sdi;
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+       struct sr_channel *ch;
+       struct sr_channel_group *cg;
+       GSList *devices;
+       const char *conn, *serialcomm;
+       int cnt;
+       gchar  buf[LINELEN_MAX];
+       gchar channel[10];
+       char*  verstr;
+
+       sdi = NULL;
+       devc = NULL;
+       conn = serialcomm = NULL;
+       devices = NULL;
+
+       drvc = drv->priv;
+       drvc->instances = NULL;
+
+       sr_spew("scan() called!");
+
+       /* Process and check options. */
+       if (sr_serial_extract_options(options, &conn, &serialcomm) != SR_OK)
+               return NULL;
+       if (!serialcomm)
+               serialcomm = SERIALCOMM;
+
+       /* Init serial port. */
+       if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
+               return NULL;
+
+       if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
+               goto exit_err;
+
+       /* Query and verify model string. */
+       serial_flush(serial);
+       if (lps_cmd_reply(buf, serial, "MODEL") != SR_OK)
+               return NULL;
+
+       /* Check model string. */
+       if (strncmp(buf, "LPS-", 4)) {
+               sr_spew("Unknown model code \"%s\"!", buf);
+               return NULL;
+       }
+
+       /* Bug in device FW 1.17, model number is empty, so this can't work with this FW! */
+       if (modelid == LPS_UNKNOWN) {
+               g_strstrip(buf);
+               for (cnt = LPS_301; cnt <= LPS_305; cnt++) {
+                       if (!strcmp(buf, models[cnt].modelstr)) {
+                               modelid = cnt;
+                               break;
+                       }
+               }
+               if (modelid == LPS_UNKNOWN) {
+                       sr_err("Unable to detect model from model string '%s'!", buf);
+                       return NULL;
+               }
+       }
+
+       /* Query version */
+       verstr = NULL;
+       if (lps_cmd_reply(buf, serial, "VERSION") == SR_OK) {
+               if (strncmp(buf, "Ver-", 4)) {
+                       sr_spew("Version string %s not recognized.", buf);
+                       goto exit_err;
+               }
+
+
+               g_strstrip(buf);
+               verstr = buf + 4;
+       }
+       else  /* Bug in device FW 1.17: Quering version string fails while output is active.
+               Therefore just print an error message, but do not exit with error. */
+               sr_err("Failed to query for hardware version: %d %s", errno, strerror(errno));
+
+       sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, VENDOR_MOTECH, models[modelid].modelstr, verstr);
+       sdi->driver = drv;
+       sdi->inst_type = SR_INST_SERIAL;
+       sdi->conn = serial;
+
+       devc = g_malloc0(sizeof(struct dev_context));
+       devc->model = &models[modelid];
+       devc->limit_samples = 0;
+       devc->limit_msec = 0;
+       devc->num_samples = 0;
+       devc->elapsed_msec = g_timer_new();
+
+       sdi->priv = devc;
+
+       /* Setup channels and channel groups. */
+       for (cnt = 0; cnt < models[modelid].num_channels; cnt++) {
+               snprintf(channel, sizeof(channel), "CH%d", cnt + 1);
+               ch = sr_channel_new(cnt, SR_CHANNEL_ANALOG, TRUE, channel);
+               sdi->channels = g_slist_append(sdi->channels, ch);
+
+               devc->channel_status[cnt].info = g_slist_append(NULL, ch);
+
+               cg = g_malloc(sizeof(struct sr_channel_group));
+               snprintf(channel, sizeof(channel), "CG%d", cnt+1);
+               cg->name = g_strdup(channel);
+               cg->priv = NULL;
+               cg->channels = g_slist_append(NULL, ch);
+
+               sdi->channel_groups = g_slist_append(sdi->channel_groups, cg);
+       }
+
+       drvc->instances = g_slist_append(drvc->instances, sdi);
+       devices = g_slist_append(devices, sdi);
+
+       /* Query status */
+       if (lps_query_status(sdi) != SR_OK)
+               goto exit_err;
+
+       serial_close(serial);
+       if (!devices)
+               sr_serial_dev_inst_free(serial);
+
+       return devices;
+
+exit_err:
+       sr_info("%s: Error!", __func__);
+
+       if (serial) {
+               serial_close(serial);
+               sr_serial_dev_inst_free(serial);
+       }
+       if (devc)
+               g_free(devc);
+       if (sdi)
+               sr_dev_inst_free(sdi);
+
+       return NULL;
+}
+
+/** Scan for LPS-301 device. */
+static GSList *scan_lps301(GSList *options)
+{
+       return do_scan(LPS_301, &motech_lps_301_driver_info, options);
+}
+
+static GSList *doDevList(struct sr_dev_driver *drv)
+{
+       return ((struct drv_context *)(drv->priv))->instances;
+}
+
+static GSList *dev_list_lps301(void)
+{
+       return doDevList(&motech_lps_301_driver_info);
+}
+
+static void dev_clear_private(struct dev_context* devc)
+{
+       int ch_idx;
+
+       /* Free channel_status.info (list only, data owned by sdi). */
+       for (ch_idx = 0; ch_idx < devc->model->num_channels; ch_idx++)
+               g_slist_free(devc->channel_status[ch_idx].info);
+
+       g_timer_destroy(devc->elapsed_msec);
+}
+
+static int dev_clear_lps301(void)
+{
+       return std_dev_clear(&motech_lps_301_driver_info, (std_dev_clear_callback)dev_clear_private);
+}
+
+static int cleanup(void)
+{
+       return dev_clear_lps301();
+}
+
+static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       struct sr_channel *ch;
+       int ch_idx;
+
+       if (!sdi)
+               return SR_ERR_ARG;
+
+       devc = sdi->priv;
+
+       if (!cg) {
+               /* No channel group: global options. */
+               switch (key) {
+               case SR_CONF_LIMIT_SAMPLES:
+                       *data = g_variant_new_uint64(devc->limit_samples);
+                       break;
+               case SR_CONF_LIMIT_MSEC:
+                       *data = g_variant_new_uint64(devc->limit_msec);
+                       break;
+               case SR_CONF_OUTPUT_CHANNEL:
+                       *data = g_variant_new_string(channel_modes[devc->tracking_mode]);
+                       break;
+               default:
+                       return SR_ERR_NA;
+               }
+       } else {
+               /* We only ever have one channel per channel group in this driver. */
+               ch = cg->channels->data;
+               ch_idx = ch->index;
+               switch (key) {
+               case SR_CONF_OUTPUT_VOLTAGE:
+                       *data = g_variant_new_double(devc->channel_status[ch_idx].output_voltage_last);
+                       break;
+               case SR_CONF_OUTPUT_VOLTAGE_MAX:
+                       *data = g_variant_new_double(devc->channel_status[ch_idx].output_voltage_max);
+                       break;
+               case SR_CONF_OUTPUT_CURRENT:
+                       *data = g_variant_new_double(devc->channel_status[ch_idx].output_current_last);
+                       break;
+               case SR_CONF_OUTPUT_CURRENT_MAX:
+                       *data = g_variant_new_double(devc->channel_status[ch_idx].output_current_max);
+                       break;
+               case SR_CONF_OUTPUT_ENABLED:
+                       *data = g_variant_new_boolean(devc->channel_status[ch_idx].output_enabled);
+                       break;
+               default:
+                       return SR_ERR_NA;
+               }
+       }
+
+       return SR_OK;
+}
+
+static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       struct sr_channel *ch;
+       gdouble dval;
+       int ch_idx;
+       const char *sval;
+       gboolean bval;
+       int idx;
+       gboolean found;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       devc = sdi->priv;
+
+       /* Cannot change settings while acquisition active, would cause a mess with commands.
+        * Changing this would be possible, but tricky. */
+       if (devc->acq_running)
+               return SR_ERR_NA;
+
+       if (!cg) {
+               /* No channel group: global options. */
+               switch (key) {
+               case SR_CONF_LIMIT_MSEC:
+                       if (g_variant_get_uint64(data) == 0) {
+                               sr_err("LIMIT_MSEC can't be 0.");
+                               return SR_ERR;
+                       }
+                       devc->limit_msec = g_variant_get_uint64(data);
+                       sr_dbg("Setting time limit to %" PRIu64 "ms.",
+                               devc->limit_msec);
+                       break;
+               case SR_CONF_LIMIT_SAMPLES:
+                       devc->limit_samples = g_variant_get_uint64(data);
+                       sr_dbg("Setting sample limit to %" PRIu64 ".",
+                               devc->limit_samples);
+                       break;
+               case SR_CONF_OUTPUT_CHANNEL:
+                       sval = g_variant_get_string(data, NULL);
+                       found = FALSE;
+                       for (idx = 0; idx < (int)ARRAY_SIZE(channel_modes); idx++)
+                       {
+                               if (!strcmp(sval, channel_modes[idx])) {
+                                       found = TRUE;
+                                       if (devc->tracking_mode == idx)
+                                               break;  /* Nothing to do! */
+                                       devc->tracking_mode = idx;
+                                       if (devc->model->modelid >= LPS_304) /* No use to set anything in the smaller models. */
+                                               return lps_cmd_ok(sdi->conn, "TRACK%1d", devc->tracking_mode);
+                               }
+                               if (devc->model->modelid <= LPS_303) /* Only first setting possible for smaller models. */
+                                       break;
+                       }
+                       if (!found) {
+                               return SR_ERR_ARG;
+                       }
+                       break;
+               default:
+                       return SR_ERR_NA;
+               }
+       } else {
+               /* Channel group specified: per-channel options. */
+               /* We only ever have one channel per channel group in this driver. */
+               ch = cg->channels->data;
+               ch_idx = ch->index;
+
+               switch (key) {
+               case SR_CONF_OUTPUT_VOLTAGE_MAX:
+                       dval = g_variant_get_double(data);
+                       if (dval < 0 || dval > devc->model->channels[ch_idx].voltage[1])
+                               return SR_ERR_ARG;
+                       if (ch_idx == 2) {
+                               if (devc->model->modelid < LPS_304)
+                                       return SR_ERR_ARG;
+
+                               if (fabs(dval - 5.000) <= 0.001)
+                                       dval = 5.0;
+                               else if ((devc->model->modelid >= LPS_305) && (fabs(dval - 3.300) <= 0.001))
+                                       dval = 3.3;
+                               else return SR_ERR_ARG;
+                       }
+
+                       devc->channel_status[ch_idx].output_voltage_max = dval;
+                       if (ch_idx == 2)
+                               return lps_cmd_ok(sdi->conn, "VDD%1.0f", trunc(dval));
+                       else
+                               return lps_cmd_ok(sdi->conn, "VSET%d %05.3f", ch_idx+1, dval);
+                       break;
+               case SR_CONF_OUTPUT_CURRENT_MAX:
+                       dval = g_variant_get_double(data);
+                       if (dval < 0 || dval > devc->model->channels[ch_idx].current[1])
+                               return SR_ERR_ARG;
+                       if (ch_idx == 2) /* No current setting for CH3. */
+                               return SR_ERR_NA;
+                       devc->channel_status[ch_idx].output_current_max = dval;
+                       return lps_cmd_ok(sdi->conn, "ISET%d %05.4f", ch_idx+1, dval);
+                       break;
+               case SR_CONF_OUTPUT_ENABLED:
+                       bval = g_variant_get_boolean(data);
+                       if (bval == devc->channel_status[ch_idx].output_enabled) /* Nothing to do. */
+                               break;
+                       devc->channel_status[ch_idx].output_enabled = bval;
+                       if (ch_idx != 2) { /* Channels 1,2 can be set only together. */
+                               devc->channel_status[ch_idx^1].output_enabled = bval;
+                               return lps_cmd_ok(sdi->conn, "OUT%1d", (int)bval);
+                       } else { /* Channel 3: No command to disable output, set voltage to 0 instead. */
+                               if (bval)
+                                       return lps_cmd_ok(sdi->conn, "VDD%1.0f", devc->channel_status[ch_idx].output_voltage_max);
+                               else
+                                       return lps_cmd_ok(sdi->conn, "VDD0");
+                       }
+                       break;
+               default:
+                       return SR_ERR_NA;
+               }
+       }
+
+       return SR_OK;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       struct sr_channel *ch;
+       int ch_idx, i;
+       GVariant *gvar;
+       GVariantBuilder gvb;
+
+       (void)data;
+
+       /* Driver options, no device instance necessary. */
+       switch (key) {
+       case SR_CONF_SCAN_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                                                 hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+               return SR_OK;
+       default:
+               if (sdi == NULL)
+                       return SR_ERR_ARG;
+
+               devc = sdi->priv;
+       }
+
+       /* Device options, independant from channel groups. */
+       if (cg == NULL) {
+               switch (key) {
+               case SR_CONF_DEVICE_OPTIONS:
+                       *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                                                         hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+                       return SR_OK;
+               case SR_CONF_OUTPUT_CHANNEL:
+                       if (devc->model->modelid <= LPS_303) {
+                               /* The 1-channel models. */
+                               *data = g_variant_new_strv(channel_modes, 1);
+                       } else {
+                               /* The other models support all modes. */
+                               *data = g_variant_new_strv(channel_modes, ARRAY_SIZE(channel_modes));
+                       }
+                       return SR_OK;
+                       break;
+               default:
+                       return SR_ERR_NA;
+               }
+       }
+
+       /* Device options, depending on channel groups. */
+       ch = cg->channels->data;
+       ch_idx = ch->index;
+       switch (key) {
+       case SR_CONF_DEVICE_OPTIONS:
+               if ((ch_idx == 0) || (ch_idx == 1)) /* CH1, CH2 */
+                       *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                                 hwcaps_ch12, ARRAY_SIZE(hwcaps_ch12), sizeof(int32_t));
+               else /* Must be CH3 */
+                       *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                                 hwcaps_ch3, ARRAY_SIZE(hwcaps_ch3), sizeof(int32_t));
+               break;
+       case SR_CONF_OUTPUT_VOLTAGE_MAX:
+               g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
+               /* Min, max, step. */
+               for (i = 0; i < 3; i++) {
+                       gvar = g_variant_new_double(devc->model->channels[ch_idx].voltage[i]);
+                       g_variant_builder_add_value(&gvb, gvar);
+               }
+               *data = g_variant_builder_end(&gvb);
+               break;
+       case SR_CONF_OUTPUT_CURRENT_MAX:
+               g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
+               /* Min, max, step. */
+               for (i = 0; i < 3; i++) {
+                       gvar = g_variant_new_double(devc->model->channels[ch_idx].current[i]);
+                       g_variant_builder_add_value(&gvb, gvar);
+               }
+               *data = g_variant_builder_end(&gvb);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi,
+                                   void *cb_data)
+{
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       devc = sdi->priv;
+
+       devc->acq_running = TRUE;
+
+       serial = sdi->conn;
+       serial_source_add(sdi->session, serial, G_IO_IN, 50,
+                       motech_lps_30x_receive_data, (void *)sdi);
+       std_session_send_df_header(cb_data, LOG_PREFIX);
+
+       /* Start timer, if required. */
+       if (devc->limit_msec)
+               g_timer_start(devc->elapsed_msec);
+
+       devc->acq_req = AQ_NONE;
+       /* Do not start polling device here, the read function will do it in 50 ms. */
+
+       return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct dev_context *devc;
+
+       /* Stop timer, if required. */
+       if (sdi && (devc = sdi->priv) && devc->limit_msec)
+               g_timer_stop(devc->elapsed_msec);
+
+       return std_serial_dev_acquisition_stop(sdi, cb_data, std_serial_dev_close,
+                       sdi->conn, LOG_PREFIX);
+}
+
+SR_PRIV struct sr_dev_driver motech_lps_301_driver_info = {
+       .name = "motech-lps-301",
+       .longname = "Motech LPS-301",
+       .api_version = 1,
+       .init = init_lps301,
+       .cleanup = cleanup,
+       .scan = scan_lps301,
+       .dev_list = dev_list_lps301,
+       .dev_clear = dev_clear_lps301,
+       .config_get = config_get,
+       .config_set = config_set,
+       .config_list = config_list,
+       .dev_open = std_serial_dev_open,
+       .dev_close = std_serial_dev_close,
+       .dev_acquisition_start = dev_acquisition_start,
+       .dev_acquisition_stop = dev_acquisition_stop,
+       .priv = NULL,
+};
diff --git a/src/hardware/motech-lps-30x/protocol.c b/src/hardware/motech-lps-30x/protocol.c
new file mode 100644 (file)
index 0000000..c4afd65
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Matthias Heidbrink <m-sigrok@heidbrink.biz>
+ * Copyright (C) 2014 Bert Vermeulen <bert@biot.com> (code from atten-pps3xxx)
+ *
+ * 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
+ *  <em>Motech LPS-30x series</em> power supply driver
+ *  @internal
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include "protocol.h"
+
+/** Send data packets for current measurements. */
+static void send_data(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_analog analog;
+       int i;
+       float data[MAX_CHANNELS];
+
+       devc = sdi->priv;
+       packet.type = SR_DF_ANALOG;
+       packet.payload = &analog;
+       analog.channels = sdi->channels;
+       analog.num_samples = 1;
+
+       analog.mq = SR_MQ_VOLTAGE;
+       analog.unit = SR_UNIT_VOLT;
+       analog.mqflags = SR_MQFLAG_DC;
+       analog.data = data;
+       for (i = 0; i < devc->model->num_channels; i++)
+               analog.data[i] = devc->channel_status[i].output_voltage_last; /* Value always 3.3 or 5 for channel 3, if present! */
+       sr_session_send(sdi, &packet);
+
+       analog.mq = SR_MQ_CURRENT;
+       analog.unit = SR_UNIT_AMPERE;
+       analog.mqflags = 0;
+       analog.data = data;
+       for (i = 0; i < devc->model->num_channels; i++)
+               analog.data[i] = devc->channel_status[i].output_current_last; /* Value always 0 for channel 3, if present! */
+       sr_session_send(sdi, &packet);
+
+       devc->num_samples++;
+}
+
+/** Process a complete line (without CR/LF) in buf. */
+static void process_line(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       double dbl;
+       int auxint;
+
+       devc = sdi->priv;
+
+       switch (devc->acq_req_pending) {
+       case 0: /* Should not happen... */
+               break;
+       case 1: /* Waiting for data reply to request */
+               /* Convert numbers */
+               switch (devc->acq_req) {
+               case AQ_U1:  case AQ_U2:  case AQ_I1:  case AQ_I2:
+                       if (sr_atod(devc->buf, &dbl) != SR_OK) {
+                               sr_err("Failed to convert '%s' to double, errno=%d %s",
+                                       devc->buf, errno, strerror(errno));
+                               dbl = 0.0;
+                       }
+                       break;
+               case AQ_STATUS:
+                       if (sr_atoi(devc->buf, &auxint) != SR_OK) {
+                               sr_err("Failed to convert '%s' to int, errno=%d %s",
+                                       devc->buf, errno, strerror(errno));
+                               auxint = 0;
+                       }
+                       break;
+               default:
+                       break;
+               }
+
+               switch (devc->acq_req) {
+               case AQ_U1:
+                       devc->channel_status[0].output_voltage_last = dbl;
+                       break;
+               case AQ_I1:
+                       devc->channel_status[0].output_current_last = dbl;
+                       break;
+               case AQ_U2:
+                       devc->channel_status[1].output_voltage_last = dbl;
+                       break;
+               case AQ_I2:
+                       devc->channel_status[1].output_current_last = dbl;
+                       break;
+               case AQ_STATUS: /* Process status and generate data. */
+                       if (lps_process_status(sdi, auxint) == SR_OK) {
+                               send_data(sdi);
+                       }
+                       break;
+               default:
+                       break;
+               }
+
+               devc->acq_req_pending = 2;
+               break;
+       case 2: /* Waiting for OK after request */
+               if (strcmp(devc->buf, "OK")) {
+                       sr_err("Unexpected reply while waiting for OK: '%s'", devc->buf);
+               }
+               devc->acq_req_pending = 0;
+               break;
+       }
+
+       devc->buf[0] = '\0';
+       devc->buflen = 0;
+}
+
+
+SR_PRIV int motech_lps_30x_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 len;
+       gdouble elapsed_s;
+
+       (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. */
+               while (LINELEN_MAX - devc->buflen - 2 > 0) {
+                       len = serial_read(serial, devc->buf + devc->buflen, 1);
+                       if (len < 1)
+                               break;
+
+                       /* Eliminate whitespace at beginning of line. */
+                       if (g_ascii_isspace(devc->buf[0])) {
+                               devc->buf[0] = '\0';
+                               devc->buflen = 0;
+                               continue;
+                       }
+
+                       devc->buflen += len;
+                       devc->buf[devc->buflen] = '\0';
+
+                       /* If line complete, process msg. */
+                       if ((devc->buflen > 0) && ((devc->buf[devc->buflen-1] == '\r') || devc->buf[devc->buflen-1] == '\n')) {
+                               devc->buflen--;
+                               devc->buf[devc->buflen] = '\0';
+
+                               sr_spew("Line complete: \"%s\"", devc->buf);
+                               process_line(sdi);
+                       }
+               }
+       }
+
+       /* If number of samples or time limit reached, stop acquisition. */
+       if (devc->limit_samples && (devc->num_samples >= devc->limit_samples))
+               sdi->driver->dev_acquisition_stop(sdi, cb_data);
+
+       if (devc->limit_msec) {
+               elapsed_s = g_timer_elapsed(devc->elapsed_msec, NULL);
+               if ((elapsed_s * 1000) >= devc->limit_msec)
+                       sdi->driver->dev_acquisition_stop(sdi, cb_data);
+       }
+
+       /* Request next packet, if required. */
+       if ((sdi->status == SR_ST_ACTIVE) && (devc->acq_running)){
+               if (devc->acq_req_pending) {
+                       gint64 elapsed_us = g_get_monotonic_time() - devc->req_sent_at;
+                       if (elapsed_us > (REQ_TIMEOUT_MS * 1000)) {
+                               sr_spew("Request timeout: req=%d t=%lldus", (int)devc->acq_req, elapsed_us);
+                               devc->acq_req_pending = 0;
+                       }
+               }
+               if (devc->acq_req_pending == 0) {
+                       switch(devc->acq_req)
+                       {
+                       case AQ_NONE: /* Fall through */
+                       case AQ_STATUS:
+                               devc->acq_req = AQ_U1;
+                               lps_send_req(serial, "VOUT1");
+                               break;
+                       case AQ_U1:
+                               devc->acq_req = AQ_I1;
+                               lps_send_req(serial, "IOUT1");
+                               break;
+                       case AQ_I1:
+                               if (devc->model->num_channels == 1) {
+                                       devc->acq_req = AQ_STATUS;
+                                       lps_send_req(serial, "STATUS");
+                               } else {
+                                       devc->acq_req = AQ_U2;
+                                       lps_send_req(serial, "VOUT2");
+                               }
+                               break;
+                       case AQ_U2:
+                               devc->acq_req = AQ_I2;
+                               lps_send_req(serial, "IOUT2");
+                               break;
+                       case AQ_I2:
+                               devc->acq_req = AQ_STATUS;
+                               lps_send_req(serial, "STATUS");
+                               break;
+                       default:
+                               sr_err("Illegal devc->acq_req=%d", devc->acq_req);
+                               return SR_ERR;
+                       }
+                       devc->req_sent_at = g_get_real_time();
+                       devc->acq_req_pending = 1;
+               }
+       }
+
+       return TRUE;
+}
diff --git a/src/hardware/motech-lps-30x/protocol.h b/src/hardware/motech-lps-30x/protocol.h
new file mode 100644 (file)
index 0000000..76f646d
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Matthias Heidbrink <m-sigrok@heidbrink.biz>
+ * Copyright (C) 2014 Bert Vermeulen <bert@biot.com> (code from atten-pps3xxx)
+ *
+ * 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
+ *  <em>Motech LPS-30x series</em> power supply driver
+ *  @internal
+ */
+
+
+#ifndef LIBSIGROK_HARDWARE_MOTECH_LPS_30X_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_MOTECH_LPS_30X_PROTOCOL_H
+
+#include <stdint.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+
+SR_PRIV int lps_process_status(struct sr_dev_inst* sdi, int stat);
+SR_PRIV int lps_send_req(struct sr_serial_dev_inst *serial, const char* fmt, ...);
+
+#define LOG_PREFIX "motech-lps-30x"
+
+#define LINELEN_MAX 50 /**< Max. line length for requests */
+
+#define REQ_TIMEOUT_MS 250 /**< Timeout [ms] for single request. */
+
+#define MAX_CHANNELS 3
+
+typedef enum {
+       LPS_UNKNOWN = 0,/**< Unknown model (used during detection process) */
+       LPS_301,        /**< Motech/Amrel LPS-301, 1 output */
+       LPS_302,        /**< Motech/Amrel LPS-302, 1 output */
+       LPS_303,        /**< Motech/Amrel LPS-303, 1 output */
+       LPS_304,        /**< Motech/Amrel LPS-304, 3 outputs */
+       LPS_305,        /**< Motech/Amrel LPS-305, 3 outputs */
+} lps_modelid;
+
+/** Channel specification */
+struct channel_spec {
+       /* Min, max, step. */
+       gdouble voltage[3];
+       gdouble current[3];
+};
+
+/** Model properties specification */
+struct lps_modelspec {
+       lps_modelid modelid;
+       const char* modelstr;
+       uint8_t num_channels;
+       struct channel_spec channels[3];
+};
+
+/** Used to implement a little state machine to query all required values in a row. */
+typedef enum {
+       AQ_NONE,
+       AQ_U1,
+       AQ_I1,
+       AQ_I2,
+       AQ_U2,
+       AQ_STATUS,
+} acquisition_req;
+
+/** Status of a single channel. */
+struct channel_status {
+       /* Channel information (struct channel_info*). data (struct) owned by sdi, just a reference to address a single channel. */
+       GSList* info;
+       /* Received from device. */
+       gdouble output_voltage_last;
+       gdouble output_current_last;
+       gboolean output_enabled;        /**< Also used when set. */
+       gboolean cc_mode;               /**< Constant current mode. If false, constant voltage mode. */
+       /* Set by frontend. */
+       gdouble output_voltage_max;
+       gdouble output_current_max;
+};
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+       /* Model-specific information */
+       struct lps_modelspec* model;
+
+       /* Acquisition status */
+       gboolean acq_running;           /**< Aquisition is running. */
+       uint64_t limit_samples;         /**< Target number of samples */
+       uint64_t limit_msec;            /**< Target sampling time */
+       acquisition_req acq_req;        /**< Current request. */
+       uint8_t acq_req_pending;        /**< Request pending. 0=none, 1=reply, 2=OK */
+
+       /* Operational state */
+       struct channel_status channel_status[MAX_CHANNELS];
+       guint8 tracking_mode;           /**< 0=off, 1=Tracking from CH1, 2=Tracking from CH2. */
+
+       /* Temporary state across callbacks */
+       int64_t req_sent_at;    /**< Request sent. */
+       uint64_t num_samples;   /**< Current #samples for limit_samples */
+       GTimer *elapsed_msec;   /**< Used for sampling with limit_msec  */
+       gchar buf[LINELEN_MAX]; /**< Buffer for read callback */
+       int buflen;             /**< Data len in buf */
+};
+
+SR_PRIV int motech_lps_30x_receive_data(int fd, int revents, void *cb_data);
+
+#endif
diff --git a/src/hardware/norma-dmm/api.c b/src/hardware/norma-dmm/api.c
new file mode 100644 (file)
index 0000000..798b60e
--- /dev/null
@@ -0,0 +1,375 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Matthias Heidbrink <m-sigrok@heidbrink.biz>
+ *
+ * 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
+ *  Norma DM9x0/Siemens B102x DMMs driver.
+ *  @internal
+ */
+
+#include "protocol.h"
+
+static const int32_t hwopts[] = {
+       SR_CONF_CONN,
+       SR_CONF_SERIALCOMM,
+};
+
+static const int32_t hwcaps[] = {
+       SR_CONF_MULTIMETER,
+       SR_CONF_LIMIT_SAMPLES,
+       SR_CONF_LIMIT_MSEC,
+       SR_CONF_CONTINUOUS,
+};
+
+#define BUF_MAX 50
+
+#define SERIALCOMM "4800/8n1/dtr=1/rts=0/flow=1"
+
+SR_PRIV struct sr_dev_driver norma_dmm_driver_info;
+SR_PRIV struct sr_dev_driver siemens_b102x_driver_info;
+
+static const char* get_brandstr(struct sr_dev_driver* drv)
+{
+       if (drv == &norma_dmm_driver_info)
+               return "Norma";
+       else
+               return "Siemens";
+}
+
+static const char* get_typestr(int type, struct sr_dev_driver* drv)
+{
+       static const char* nameref[5][2] = {
+               {"DM910", "B1024"},
+               {"DM920", "B1025"},
+               {"DM930", "B1026"},
+               {"DM940", "B1027"},
+               {"DM950", "B1028"}};
+
+       if ((type < 1) || (type > 5))
+               return "Unknown type!";
+
+       return nameref[type-1][(drv == &siemens_b102x_driver_info)];
+}
+
+static int init_norma_dmm(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, &norma_dmm_driver_info, LOG_PREFIX);
+}
+
+static int init_siemens_b102x(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, &siemens_b102x_driver_info, LOG_PREFIX);
+}
+
+static GSList *do_scan(struct sr_dev_driver* drv, GSList *options)
+{
+       struct sr_dev_inst *sdi;
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       struct sr_config *src;
+       struct sr_channel *ch;
+       struct sr_serial_dev_inst *serial;
+       GSList *l, *devices;
+       int len, cnt;
+       const char *conn, *serialcomm;
+       char *buf;
+       char req[10];
+       int auxtype;
+
+       devices = NULL;
+       drvc = drv->priv;
+       drvc->instances = NULL;
+       conn = serialcomm = NULL;
+
+       for (l = options; l; l = l->next) {
+               src = l->data;
+               switch (src->key) {
+               case SR_CONF_CONN:
+                       conn = g_variant_get_string(src->data, NULL);
+                       break;
+               case SR_CONF_SERIALCOMM:
+                       serialcomm = g_variant_get_string(src->data, NULL);
+                       break;
+               }
+       }
+       if (!conn)
+               return NULL;
+       if (!serialcomm)
+               serialcomm = SERIALCOMM;
+
+       if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
+               return NULL;
+
+       if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
+               return NULL;
+
+       serial_flush(serial);
+
+       if (!(buf = g_try_malloc(BUF_MAX))) {
+               sr_err("Serial buffer malloc failed.");
+               return NULL;
+       }
+
+       snprintf(req, sizeof(req), "%s\r\n",
+                nmadmm_requests[NMADMM_REQ_IDN].req_str);
+       g_usleep(150 * 1000); /* Wait a little to allow serial port to settle. */
+       for (cnt = 0; cnt < 7; cnt++) {
+               if (serial_write(serial, req, strlen(req)) == -1) {
+                       sr_err("Unable to send identification request: %d %s.",
+                              errno, strerror(errno));
+                       return NULL;
+               }
+               len = BUF_MAX;
+               serial_readline(serial, &buf, &len, NMADMM_TIMEOUT_MS);
+               if (!len)
+                       continue;
+               buf[BUF_MAX - 1] = '\0';
+
+               /* Match ID string, e.g. "1834 065 V1.06,IF V1.02" (DM950) */
+               if (g_regex_match_simple("^1834 [^,]*,IF V*", (char *)buf, 0, 0)) {
+                       auxtype = xgittoint(buf[7]);
+                       sr_spew("%s %s DMM %s detected!", get_brandstr(drv), get_typestr(auxtype, drv), buf + 9);
+
+                       if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE,
+                                               get_brandstr(drv), get_typestr(auxtype, drv), buf + 9)))
+                               return NULL;
+                       if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+                               sr_err("Device context malloc failed.");
+                               return NULL;
+                       }
+                       devc->type = auxtype;
+                       devc->version = g_strdup(&buf[9]);
+                       devc->elapsed_msec = g_timer_new();
+
+                       sdi->conn = serial;
+                       sdi->priv = devc;
+                       sdi->driver = drv;
+                       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE,
+                               "P1")))
+                               return NULL;
+                       sdi->channels = g_slist_append(sdi->channels, ch);
+                       drvc->instances = g_slist_append(drvc->instances, sdi);
+                       devices = g_slist_append(devices, sdi);
+                       break;
+               }
+
+               /*
+                * The interface of the DM9x0 contains a cap that needs to
+                * charge for up to 10s before the interface works, if not
+                * powered externally. Therefore wait a little to improve
+                * chances.
+                */
+               if (cnt == 3) {
+                       sr_info("Waiting 5s to allow interface to settle.");
+                       g_usleep(5 * 1000 * 1000);
+               }
+       }
+
+       g_free(buf);
+
+       serial_close(serial);
+       if (!devices)
+               sr_serial_dev_inst_free(serial);
+
+       return devices;
+}
+
+static GSList *scan_norma_dmm(GSList *options)
+{
+       return do_scan(&norma_dmm_driver_info, options);
+}
+
+static GSList *scan_siemens_b102x(GSList *options)
+{
+       return do_scan(&siemens_b102x_driver_info, options);
+}
+
+static GSList *dev_list_norma_dmm(void)
+{
+       return ((struct drv_context *)(norma_dmm_driver_info.priv))->instances;
+}
+
+static GSList *dev_list_siemens_b102x(void)
+{
+       return ((struct drv_context *)(siemens_b102x_driver_info.priv))->instances;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+
+       std_serial_dev_close(sdi);
+
+       /* Free dynamically allocated resources. */
+       if ((devc = sdi->priv) && devc->version) {
+               g_free(devc->version);
+               devc->version = NULL;
+               g_timer_destroy(devc->elapsed_msec);
+       }
+
+       return SR_OK;
+}
+
+static int cleanup_norma_dmm(void)
+{
+       return std_dev_clear(&norma_dmm_driver_info, NULL);
+}
+
+static int cleanup_siemens_b102x(void)
+{
+       return std_dev_clear(&siemens_b102x_driver_info, NULL);
+}
+
+static int config_set(int 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;
+
+       if (!(devc = sdi->priv)) {
+               sr_err("sdi->priv was NULL.");
+               return SR_ERR_BUG;
+       }
+
+       switch (key) {
+       case SR_CONF_LIMIT_MSEC:
+               if (g_variant_get_uint64(data) == 0) {
+                       sr_err("LIMIT_MSEC can't be 0.");
+                       return SR_ERR;
+               }
+               devc->limit_msec = g_variant_get_uint64(data);
+               sr_dbg("Setting time limit to %" PRIu64 "ms.",
+                      devc->limit_msec);
+               break;
+       case SR_CONF_LIMIT_SAMPLES:
+               devc->limit_samples = g_variant_get_uint64(data);
+               sr_dbg("Setting sample limit to %" PRIu64 ".",
+                      devc->limit_samples);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_list(int 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_INT32,
+                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+               break;
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi,
+                                   void *cb_data)
+{
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+
+       if (!sdi || !cb_data || !(devc = sdi->priv))
+               return SR_ERR_BUG;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       devc->cb_data = cb_data;
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(cb_data, LOG_PREFIX);
+
+       /* Start timer, if required. */
+       if (devc->limit_msec)
+               g_timer_start(devc->elapsed_msec);
+
+       /* Poll every 100ms, or whenever some data comes in. */
+       serial = sdi->conn;
+       serial_source_add(sdi->session, serial, G_IO_IN, 100,
+                       norma_dmm_receive_data, (void *)sdi);
+
+       return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct dev_context *devc;
+
+       /* Stop timer, if required. */
+       if (sdi && (devc = sdi->priv) && devc->limit_msec)
+               g_timer_stop(devc->elapsed_msec);
+
+       return std_serial_dev_acquisition_stop(sdi, cb_data, dev_close,
+                       sdi->conn, LOG_PREFIX);
+}
+
+SR_PRIV struct sr_dev_driver norma_dmm_driver_info = {
+       .name = "norma-dmm",
+       .longname = "Norma DM9x0 DMMs",
+       .api_version = 1,
+       .init = init_norma_dmm,
+       .cleanup = cleanup_norma_dmm,
+       .scan = scan_norma_dmm,
+       .dev_list = dev_list_norma_dmm,
+       .dev_clear = NULL,
+       .config_get = NULL,
+       .config_set = config_set,
+       .config_list = config_list,
+       .dev_open = std_serial_dev_open,
+       .dev_close = dev_close,
+       .dev_acquisition_start = dev_acquisition_start,
+       .dev_acquisition_stop = dev_acquisition_stop,
+       .priv = NULL,
+};
+
+
+SR_PRIV struct sr_dev_driver siemens_b102x_driver_info = {
+       .name = "siemens-b102x",
+       .longname = "Siemens B102x DMMs",
+       .api_version = 1,
+       .init = init_siemens_b102x,
+       .cleanup = cleanup_siemens_b102x,
+       .scan = scan_siemens_b102x,
+       .dev_list = dev_list_siemens_b102x,
+       .dev_clear = NULL,
+       .config_get = NULL,
+       .config_set = config_set,
+       .config_list = config_list,
+       .dev_open = std_serial_dev_open,
+       .dev_close = dev_close,
+       .dev_acquisition_start = dev_acquisition_start,
+       .dev_acquisition_stop = dev_acquisition_stop,
+       .priv = NULL,
+};
diff --git a/src/hardware/norma-dmm/protocol.c b/src/hardware/norma-dmm/protocol.c
new file mode 100644 (file)
index 0000000..717ef15
--- /dev/null
@@ -0,0 +1,442 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Matthias Heidbrink <m-sigrok@heidbrink.biz>
+ *
+ * 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
+ *  Norma DM9x0/Siemens B102x DMMs driver.
+ *  @internal
+ */
+
+#include "protocol.h"
+
+SR_PRIV const struct nmadmm_req nmadmm_requests[] = {
+       { NMADMM_REQ_IDN, "IDN?" },
+       { NMADMM_REQ_IDN, "STATUS?" },
+       { 0, NULL },
+};
+
+static int nma_send_req(const struct sr_dev_inst *sdi, int req, char *params)
+{
+       struct sr_serial_dev_inst *serial;
+       struct dev_context *devc;
+       char buf[NMADMM_BUFSIZE];
+       int len;
+
+       if (!sdi || !(serial = sdi->conn) || !(devc = sdi->priv))
+               return SR_ERR_BUG;
+
+       len = snprintf(buf, sizeof(buf), "%s%s\r\n",
+               nmadmm_requests[req].req_str, params ? params : "");
+
+       sr_spew("Sending request: '%s'.", buf);
+
+       devc->last_req = req;
+       devc->last_req_pending = TRUE;
+
+       if (serial_write(serial, buf, len) == -1) {
+               sr_err("Unable to send request: %d %s.",
+                       errno, strerror(errno));
+               devc->last_req_pending = FALSE;
+               return SR_ERR;
+       }
+
+       devc->req_sent_at = g_get_monotonic_time();
+
+       return SR_OK;
+}
+
+/**
+ * Convert hexadecimal digit to int.
+ *
+ * @param[in] xgit Hexadecimal digit to convert.
+ * @return Int value of xgit (0 on invalid xgit).
+ */
+SR_PRIV int xgittoint(char xgit)
+{
+       if ((xgit >= '0') && (xgit <= '9'))
+               return xgit - '0';
+       xgit = tolower(xgit);
+       if ((xgit >= 'a') && (xgit <= 'f'))
+               return xgit - 'a';
+       return 0;
+}
+
+/**
+ * Process received line. It consists of 20 hex digits + \\r\\n,
+ * e.g. '08100400018100400000'.
+ */
+static void nma_process_line(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       int pos, flags;
+       int vt, range;  /* Measurement value type, range in device format */
+       int mmode, devstat;     /* Measuring mode, device status */
+       float value;    /* Measured value */
+       float scale;    /* Scaling factor depending on range and function */
+       struct sr_datafeed_analog analog;
+       struct sr_datafeed_packet packet;
+
+       devc = sdi->priv;
+
+       devc->buf[20] = '\0';
+
+       sr_spew("Received line '%s'.", devc->buf);
+
+       /* Check line. */
+       if (strlen((const char *)devc->buf) != 20) {
+               sr_err("line: Invalid status '%s', must be 20 hex digits.",
+                      devc->buf);
+               devc->buflen = 0;
+               return;
+       }
+
+       for (pos = 0; pos < 20; pos++) {
+               if (!isxdigit(devc->buf[pos])) {
+                       sr_err("line: Expected hex digit in '%s' at pos %d!",
+                               devc->buf, pos);
+                       devc->buflen = 0;
+                       return;
+               }
+       }
+
+       /* Start decoding. */
+       value = 0.0;
+       scale = 1.0;
+       memset(&analog, 0, sizeof(analog));
+
+       /*
+        * The numbers are hex digits, starting from 0.
+        * 0: Keyboard status, currently not interesting.
+        * 1: Central switch status, currently not interesting.
+        * 2: Type of measured value.
+        */
+       vt = xgittoint(devc->buf[2]);
+       switch (vt) {
+       case 0:
+               analog.mq = SR_MQ_VOLTAGE;
+               break;
+       case 1:
+               analog.mq = SR_MQ_CURRENT;      /* 2A */
+               break;
+       case 2:
+               analog.mq = SR_MQ_RESISTANCE;
+               break;
+       case 3:
+               analog.mq = SR_MQ_CAPACITANCE;
+               break;
+       case 4:
+               analog.mq = SR_MQ_TEMPERATURE;
+               break;
+       case 5:
+               analog.mq = SR_MQ_FREQUENCY;
+               break;
+       case 6:
+               analog.mq = SR_MQ_CURRENT;      /* 10A */
+               break;
+       case 7:
+               analog.mq = SR_MQ_GAIN;         /* TODO: Scale factor */
+               break;
+       case 8:
+               analog.mq = SR_MQ_GAIN;         /* Percentage */
+               scale /= 100.0;
+               break;
+       case 9:
+               analog.mq = SR_MQ_GAIN;         /* dB */
+               scale /= 100.0;
+               break;
+       default:
+               sr_err("Unknown value type: 0x%02x.", vt);
+               break;
+       }
+
+       /* 3: Measurement range for measured value */
+       range = xgittoint(devc->buf[3]);
+       switch (vt) {
+       case 0: /* V */
+               scale *= pow(10.0, range - 5);
+               break;
+       case 1: /* A */
+               scale *= pow(10.0, range - 7);
+               break;
+       case 2: /* Î© */
+               scale *= pow(10.0, range - 2);
+               break;
+       case 3: /* F */
+               scale *= pow(10.0, range - 12);
+               break;
+       case 4: /* Â°C */
+               scale *= pow(10.0, range - 1);
+               break;
+       case 5: /* Hz */
+               scale *= pow(10.0, range - 2);
+               break;
+       // No default, other value types have fixed display format.
+       }
+
+       /* 5: Sign and 1st digit */
+       flags = xgittoint(devc->buf[5]);
+       value = (flags & 0x03);
+       if (flags & 0x04)
+               scale *= -1;
+
+       /* 6-9: 2nd-4th digit */
+       for (pos = 6; pos < 10; pos++)
+               value = value * 10 + xgittoint(devc->buf[pos]);
+       value *= scale;
+
+       /* 10: Display counter */
+       mmode = xgittoint(devc->buf[10]);
+       switch (mmode) {
+       case 0: /* Frequency */
+               analog.unit = SR_UNIT_HERTZ;
+               break;
+       case 1: /* V TRMS, only type 5 */
+               analog.unit = SR_UNIT_VOLT;
+               analog.mqflags |= (SR_MQFLAG_AC | SR_MQFLAG_DC | SR_MQFLAG_RMS);
+               break;
+       case 2: /* V AC */
+               analog.unit = SR_UNIT_VOLT;
+               analog.mqflags |= SR_MQFLAG_AC;
+               if (devc->type >= 3)
+                       analog.mqflags |= SR_MQFLAG_RMS;
+               break;
+       case 3: /* V DC */
+               analog.unit = SR_UNIT_VOLT;
+               analog.mqflags |= SR_MQFLAG_DC;
+               break;
+       case 4: /* Ohm */
+               analog.unit = SR_UNIT_OHM;
+               break;
+       case 5: /* Continuity */
+               analog.unit = SR_UNIT_BOOLEAN;
+               analog.mq = SR_MQ_CONTINUITY;
+               /* TODO: Continuity handling is a bit odd in libsigrok. */
+               break;
+       case 6: /* Degree Celsius */
+               analog.unit = SR_UNIT_CELSIUS;
+               break;
+       case 7: /* Capacity */
+               analog.unit = SR_UNIT_FARAD;
+               break;
+       case 8: /* Current DC */
+               analog.unit = SR_UNIT_AMPERE;
+               analog.mqflags |= SR_MQFLAG_DC;
+               break;
+       case 9: /* Current AC */
+               analog.unit = SR_UNIT_AMPERE;
+               analog.mqflags |= SR_MQFLAG_AC;
+               if (devc->type >= 3)
+                       analog.mqflags |= SR_MQFLAG_RMS;
+               break;
+       case 0xa: /* Current TRMS, only type 5 */
+               analog.unit = SR_UNIT_AMPERE;
+               analog.mqflags |= (SR_MQFLAG_AC | SR_MQFLAG_DC | SR_MQFLAG_RMS);
+               break;
+       case 0xb: /* Diode */
+               analog.unit = SR_UNIT_VOLT;
+               analog.mqflags |= (SR_MQFLAG_DIODE | SR_MQFLAG_DC);
+               break;
+       default:
+               sr_err("Unknown mmode: 0x%02x.", mmode);
+               break;
+       }
+
+       /* 11: Device status */
+       devstat = xgittoint(devc->buf[11]);
+
+       switch (devstat) {
+       case 1: /* Normal measurement */
+               break;
+       case 2: /* Input loop (limit, reference values) */
+               break;
+       case 3: /* TRANS/SENS */
+               break;
+       case 4: /* Error */
+               sr_err("Device error. Fuse?"); /* TODO: Really abort? */
+               devc->buflen = 0;
+               return; /* Cannot continue. */
+       default:
+               sr_err("Unknown device status: 0x%02x", devstat);
+               break;
+       }
+
+       /* 12-19: Flags and display symbols */
+       /* 12, 13 */
+       flags = (xgittoint(devc->buf[12]) << 8) | xgittoint(devc->buf[13]);
+       /* 0x80: PRINT TODO: Stop polling when discovered? */
+       /* 0x40: EXTR */
+       if (analog.mq == SR_MQ_CONTINUITY) {
+               if (flags & 0x20)
+                       value = 1.0; /* Beep */
+               else
+                       value = 0.0;
+       }
+       /* 0x10: AVG */
+       /* 0x08: Diode */
+       if (flags & 0x04) /* REL */
+               analog.mqflags |= SR_MQFLAG_RELATIVE;
+       /* 0x02: SHIFT  */
+       if (flags & 0x01) /* % */
+               analog.unit = SR_UNIT_PERCENTAGE;
+
+       /* 14, 15 */
+       flags = (xgittoint(devc->buf[14]) << 8) | xgittoint(devc->buf[15]);
+       if (!(flags & 0x80))    /* MAN: Manual range */
+               analog.mqflags |= SR_MQFLAG_AUTORANGE;
+       if (flags & 0x40) /* LOBATT1: Low battery, measurement still within specs */
+               devc->lowbatt = 1;
+       /* 0x20: PEAK */
+       /* 0x10: COUNT */
+       if (flags & 0x08)       /* HOLD */
+               analog.mqflags |= SR_MQFLAG_HOLD;
+       /* 0x04: LIMIT  */
+       if (flags & 0x02)       /* MAX */
+               analog.mqflags |= SR_MQFLAG_MAX;
+       if (flags & 0x01)       /* MIN */
+               analog.mqflags |= SR_MQFLAG_MIN;
+
+       /* 16, 17 */
+       flags = (xgittoint(devc->buf[16]) << 8) | xgittoint(devc->buf[17]);
+       /* 0xe0: undefined */
+       if (flags & 0x10) { /* LOBATT2: Low battery, measurement inaccurate */
+               devc->lowbatt = 2;
+               sr_warn("Low battery, measurement quality degraded!");
+       }
+       /* 0x08: SCALED */
+       /* 0x04: RATE (=lower resolution, allows higher rata rate up to 10/s. */
+       /* 0x02: Current clamp */
+       if (flags & 0x01) { /* dB */
+               /*
+                * TODO: The Norma has an adjustable dB reference value. If
+                * changed from default, this is not correct.
+                */
+               if (analog.unit == SR_UNIT_VOLT)
+                       analog.unit = SR_UNIT_DECIBEL_VOLT;
+               else
+                       analog.unit = SR_UNIT_UNITLESS;
+       }
+
+       /* 18, 19 */
+       /* flags = (xgittoint(devc->buf[18]) << 8) | xgittoint(devc->buf[19]); */
+       /* 0x80: Undefined. */
+       /* 0x40: Remote mode, keyboard locked */
+       /* 0x38: Undefined. */
+       /* 0x04: MIN > MAX */
+       /* 0x02: Measured value < Min */
+       /* 0x01: Measured value > Max */
+
+       /* 4: Flags. Evaluating this after setting value! */
+       flags = xgittoint(devc->buf[4]);
+       if (flags & 0x04) /* Invalid value */
+           value = NAN;
+       else if (flags & 0x01) /* Overload */
+           value =  INFINITY;
+       if (flags & 0x02) { /* Duplicate value, has been sent before. */
+           sr_spew("Duplicate value, dismissing!");
+           devc->buflen = 0;
+           return;
+       }
+
+       sr_spew("range=%d/scale=%f/value=%f", range,
+               (double)scale, (double)value);
+
+       /* Finish and send packet. */
+       analog.channels = sdi->channels;
+       analog.num_samples = 1;
+       analog.data = &value;
+
+       memset(&packet, 0, sizeof(packet));
+       packet.type = SR_DF_ANALOG;
+       packet.payload = &analog;
+       sr_session_send(devc->cb_data, &packet);
+
+       /* Finish processing. */
+       devc->num_samples++;
+       devc->buflen = 0;
+}
+
+SR_PRIV int norma_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 len;
+       gboolean terminating;
+       gdouble elapsed_s;
+
+       (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. */
+               while (NMADMM_BUFSIZE - devc->buflen - 1 > 0) {
+                       len = serial_read(serial, devc->buf + devc->buflen, 1);
+                       if (len < 1)
+                               break;
+                       devc->buflen += len;
+                       *(devc->buf + devc->buflen) = '\0';
+                       if (*(devc->buf + devc->buflen - 1) == '\n') {
+                               /*
+                                * TODO: According to specs, should be \r, but
+                                * then we'd have to get rid of the \n.
+                                */
+                               devc->last_req_pending = FALSE;
+                               nma_process_line(sdi);
+                               break;
+                       }
+               }
+       }
+
+       /* If number of samples or time limit reached, stop acquisition. */
+       terminating = FALSE;
+       if (devc->limit_samples && (devc->num_samples >= devc->limit_samples)) {
+               sdi->driver->dev_acquisition_stop(sdi, cb_data);
+               terminating = TRUE;
+       }
+
+       if (devc->limit_msec) {
+               elapsed_s = g_timer_elapsed(devc->elapsed_msec, NULL);
+               if ((elapsed_s * 1000) >= devc->limit_msec) {
+                       sdi->driver->dev_acquisition_stop(sdi, cb_data);
+                       terminating = TRUE;
+               }
+       }
+
+       /* Request next package. */
+       if (!terminating) {
+               if (devc->last_req_pending) {
+                       gint64 elapsed_us = g_get_monotonic_time() - devc->req_sent_at;
+                       if (elapsed_us > NMADMM_TIMEOUT_MS * 1000) {/* Timeout! */
+                               sr_spew("Request timeout!");
+                               devc->last_req_pending = FALSE;
+                       }
+               }
+               if (!devc->last_req_pending) {
+                       if (nma_send_req(sdi, NMADMM_REQ_STATUS, NULL) != SR_OK)
+                               return FALSE;
+               }
+       }
+
+       return TRUE;
+}
diff --git a/src/hardware/norma-dmm/protocol.h b/src/hardware/norma-dmm/protocol.h
new file mode 100644 (file)
index 0000000..951734e
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Matthias Heidbrink <m-sigrok@heidbrink.biz>
+ *
+ * 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_NORMA_DMM_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_NORMA_DMM_PROTOCOL_H
+
+#include <stdint.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <math.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+/** @file
+ *  Norma DM9x0/Siemens B102x DMMs driver.
+ *  @internal
+ */
+
+#define LOG_PREFIX "norma-dmm"
+
+#define NMADMM_BUFSIZE  256
+
+#define NMADMM_TIMEOUT_MS 2000 /**< Request timeout. */
+
+/** Norma DMM request types (used ones only, the DMMs support about 50). */
+enum {
+       NMADMM_REQ_IDN = 0,     /**< Request identity */
+       NMADMM_REQ_STATUS,      /**< Request device status (value + ...) */
+};
+
+/** Defines requests used to communicate with device. */
+struct nmadmm_req {
+       int req_type;           /**< Request type. */
+       const char *req_str;    /**< Request string. */
+};
+
+/** Strings for requests. */
+extern const struct nmadmm_req nmadmm_requests[];
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+       /* Model-specific information */
+       char *version;          /**< Version string */
+       int type;               /**< DM9x0, e.g. 5 = DM950 */
+
+       /* Acquisition settings */
+       uint64_t limit_samples; /**< Target number of samples */
+       uint64_t limit_msec;    /**< Target sampling time */
+
+       /* Opaque pointer passed in by frontend. */
+       void *cb_data;
+
+       /* Operational state */
+       int last_req;                   /**< Last request. */
+       int64_t req_sent_at;            /**< Request sent. */
+       gboolean last_req_pending;      /**< Last request not answered yet. */
+       int lowbatt;                    /**< Low battery. 1=low, 2=critical. */
+
+       /* Temporary state across callbacks */
+       uint64_t num_samples;           /**< Current #samples. */
+       GTimer *elapsed_msec;           /**< Used for limit_msec */
+       uint8_t buf[NMADMM_BUFSIZE];    /**< Buffer for read callback */
+       int buflen;                     /**< Data len in buf */
+};
+
+SR_PRIV int norma_dmm_receive_data(int fd, int revents, void *cb_data);
+SR_PRIV int xgittoint(char xgit);
+
+#endif
diff --git a/src/hardware/openbench-logic-sniffer/api.c b/src/hardware/openbench-logic-sniffer/api.c
new file mode 100644 (file)
index 0000000..cd9d817
--- /dev/null
@@ -0,0 +1,600 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert@biot.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 "protocol.h"
+#include <libserialport.h>
+
+#define SERIALCOMM "115200/8n1"
+
+static const int32_t hwopts[] = {
+       SR_CONF_CONN,
+       SR_CONF_SERIALCOMM,
+};
+
+static const int32_t hwcaps[] = {
+       SR_CONF_LOGIC_ANALYZER,
+       SR_CONF_SAMPLERATE,
+       SR_CONF_TRIGGER_MATCH,
+       SR_CONF_CAPTURE_RATIO,
+       SR_CONF_LIMIT_SAMPLES,
+       SR_CONF_EXTERNAL_CLOCK,
+       SR_CONF_PATTERN_MODE,
+       SR_CONF_SWAP,
+       SR_CONF_RLE,
+};
+
+static const int32_t trigger_matches[] = {
+       SR_TRIGGER_ZERO,
+       SR_TRIGGER_ONE,
+};
+
+#define STR_PATTERN_NONE     "None"
+#define STR_PATTERN_EXTERNAL "External"
+#define STR_PATTERN_INTERNAL "Internal"
+
+/* Supported methods of test pattern outputs */
+enum {
+       /**
+        * Capture pins 31:16 (unbuffered wing) output a test pattern
+        * that can captured on pins 0:15.
+        */
+       PATTERN_EXTERNAL,
+
+       /** Route test pattern internally to capture buffer. */
+       PATTERN_INTERNAL,
+};
+
+static const char *patterns[] = {
+       STR_PATTERN_NONE,
+       STR_PATTERN_EXTERNAL,
+       STR_PATTERN_INTERNAL,
+};
+
+/* Channels are numbered 0-31 (on the PCB silkscreen). */
+SR_PRIV const char *ols_channel_names[NUM_CHANNELS + 1] = {
+       "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12",
+       "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23",
+       "24", "25", "26", "27", "28", "29", "30", "31",
+       NULL,
+};
+
+/* Default supported samplerates, can be overridden by device metadata. */
+static const uint64_t samplerates[] = {
+       SR_HZ(10),
+       SR_MHZ(200),
+       SR_HZ(1),
+};
+
+SR_PRIV struct sr_dev_driver ols_driver_info;
+static struct sr_dev_driver *di = &ols_driver_info;
+
+static int init(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+       struct sr_config *src;
+       struct sr_dev_inst *sdi;
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       struct sr_channel *ch;
+       struct sr_serial_dev_inst *serial;
+       GPollFD probefd;
+       GSList *l, *devices;
+       int ret, i;
+       const char *conn, *serialcomm;
+       char buf[8];
+
+       drvc = di->priv;
+
+       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 == NULL)
+               serialcomm = SERIALCOMM;
+
+       if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
+               return NULL;
+
+       /* The discovery procedure is like this: first send the Reset
+        * command (0x00) 5 times, since the device could be anywhere
+        * in a 5-byte command. Then send the ID command (0x02).
+        * If the device responds with 4 bytes ("OLS1" or "SLA1"), we
+        * have a match.
+        */
+       sr_info("Probing %s.", conn);
+       if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
+               return NULL;
+
+       ret = SR_OK;
+       for (i = 0; i < 5; i++) {
+               if ((ret = send_shortcommand(serial, CMD_RESET)) != SR_OK) {
+                       sr_err("Port %s is not writable.", conn);
+                       break;
+               }
+       }
+       if (ret != SR_OK) {
+               serial_close(serial);
+               sr_err("Could not use port %s. Quitting.", conn);
+               return NULL;
+       }
+       send_shortcommand(serial, CMD_ID);
+
+       /* Wait 10ms for a response. */
+       g_usleep(10000);
+
+       sp_get_port_handle(serial->data, &probefd.fd);
+       probefd.events = G_IO_IN;
+       g_poll(&probefd, 1, 1);
+
+       if (probefd.revents != G_IO_IN)
+               return NULL;
+       if (serial_read_blocking(serial, buf, 4) != 4)
+               return NULL;
+       if (strncmp(buf, "1SLO", 4) && strncmp(buf, "1ALS", 4))
+               return NULL;
+
+       /* Definitely using the OLS protocol, check if it supports
+        * the metadata command.
+        */
+       send_shortcommand(serial, CMD_METADATA);
+       if (g_poll(&probefd, 1, 10) > 0) {
+               /* Got metadata. */
+               sdi = get_metadata(serial);
+               sdi->index = 0;
+               devc = sdi->priv;
+       } else {
+               /* Not an OLS -- some other board that uses the sump protocol. */
+               sr_info("Device does not support metadata.");
+               sdi = sr_dev_inst_new(0, SR_ST_INACTIVE,
+                               "Sump", "Logic Analyzer", "v1.0");
+               sdi->driver = di;
+               for (i = 0; i < 32; i++) {
+                       if (!(ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE,
+                                       ols_channel_names[i])))
+                               return 0;
+                       sdi->channels = g_slist_append(sdi->channels, ch);
+               }
+               devc = ols_dev_new();
+               sdi->priv = devc;
+       }
+       /* Configure samplerate and divider. */
+       if (ols_set_samplerate(sdi, DEFAULT_SAMPLERATE) != SR_OK)
+               sr_dbg("Failed to set default samplerate (%"PRIu64").",
+                               DEFAULT_SAMPLERATE);
+       sdi->inst_type = SR_INST_SERIAL;
+       sdi->conn = serial;
+
+       drvc->instances = g_slist_append(drvc->instances, sdi);
+       devices = g_slist_append(devices, sdi);
+
+       serial_close(serial);
+
+       return devices;
+}
+
+static GSList *dev_list(void)
+{
+       return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int cleanup(void)
+{
+       return std_dev_clear(di, NULL);
+}
+
+static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+
+       (void)cg;
+
+       if (!sdi)
+               return SR_ERR_ARG;
+
+       devc = sdi->priv;
+       switch (id) {
+       case SR_CONF_SAMPLERATE:
+               *data = g_variant_new_uint64(devc->cur_samplerate);
+               break;
+       case SR_CONF_CAPTURE_RATIO:
+               *data = g_variant_new_uint64(devc->capture_ratio);
+               break;
+       case SR_CONF_LIMIT_SAMPLES:
+               *data = g_variant_new_uint64(devc->limit_samples);
+               break;
+       case SR_CONF_PATTERN_MODE:
+               if (devc->flag_reg & FLAG_EXTERNAL_TEST_MODE)
+                       *data = g_variant_new_string(STR_PATTERN_EXTERNAL);
+               else if (devc->flag_reg & FLAG_INTERNAL_TEST_MODE)
+                       *data = g_variant_new_string(STR_PATTERN_INTERNAL);
+               else
+                       *data = g_variant_new_string(STR_PATTERN_NONE);
+               break;
+       case SR_CONF_RLE:
+               *data = g_variant_new_boolean(devc->flag_reg & FLAG_RLE ? TRUE : FALSE);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       uint16_t flag;
+       uint64_t tmp_u64;
+       int ret;
+       const char *stropt;
+
+       (void)cg;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       devc = sdi->priv;
+
+       switch (id) {
+       case SR_CONF_SAMPLERATE:
+               tmp_u64 = g_variant_get_uint64(data);
+               if (tmp_u64 < samplerates[0] || tmp_u64 > samplerates[1])
+                       return SR_ERR_SAMPLERATE;
+               ret = ols_set_samplerate(sdi, g_variant_get_uint64(data));
+               break;
+       case SR_CONF_LIMIT_SAMPLES:
+               tmp_u64 = g_variant_get_uint64(data);
+               if (tmp_u64 < MIN_NUM_SAMPLES)
+                       return SR_ERR;
+               devc->limit_samples = tmp_u64;
+               ret = SR_OK;
+               break;
+       case SR_CONF_CAPTURE_RATIO:
+               devc->capture_ratio = g_variant_get_uint64(data);
+               if (devc->capture_ratio < 0 || devc->capture_ratio > 100) {
+                       devc->capture_ratio = 0;
+                       ret = SR_ERR;
+               } else
+                       ret = SR_OK;
+               break;
+       case SR_CONF_EXTERNAL_CLOCK:
+               if (g_variant_get_boolean(data)) {
+                       sr_info("Enabling external clock.");
+                       devc->flag_reg |= FLAG_CLOCK_EXTERNAL;
+               } else {
+                       sr_info("Disabled external clock.");
+                       devc->flag_reg &= ~FLAG_CLOCK_EXTERNAL;
+               }
+               ret = SR_OK;
+               break;
+       case SR_CONF_PATTERN_MODE:
+               stropt = g_variant_get_string(data, NULL);
+               ret = SR_OK;
+               flag = 0xffff;
+               if (!strcmp(stropt, STR_PATTERN_NONE)) {
+                       sr_info("Disabling test modes.");
+                       flag = 0x0000;
+               }else if (!strcmp(stropt, STR_PATTERN_INTERNAL)) {
+                       sr_info("Enabling internal test mode.");
+                       flag = FLAG_INTERNAL_TEST_MODE;
+               } else if (!strcmp(stropt, STR_PATTERN_EXTERNAL)) {
+                       sr_info("Enabling external test mode.");
+                       flag = FLAG_EXTERNAL_TEST_MODE;
+               } else {
+                       ret = SR_ERR;
+               }
+               if (flag != 0xffff) {
+                       devc->flag_reg &= ~(FLAG_INTERNAL_TEST_MODE | FLAG_EXTERNAL_TEST_MODE);
+                       devc->flag_reg |= flag;
+               }
+               break;
+       case SR_CONF_SWAP:
+               if (g_variant_get_boolean(data)) {
+                       sr_info("Enabling channel swapping.");
+                       devc->flag_reg |= FLAG_SWAP_CHANNELS;
+               } else {
+                       sr_info("Disabling channel swapping.");
+                       devc->flag_reg &= ~FLAG_SWAP_CHANNELS;
+               }
+               ret = SR_OK;
+               break;
+
+       case SR_CONF_RLE:
+               if (g_variant_get_boolean(data)) {
+                       sr_info("Enabling RLE.");
+                       devc->flag_reg |= FLAG_RLE;
+               } else {
+                       sr_info("Disabling RLE.");
+                       devc->flag_reg &= ~FLAG_RLE;
+               }
+               ret = SR_OK;
+               break;
+       default:
+               ret = SR_ERR_NA;
+       }
+
+       return ret;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       GVariant *gvar, *grange[2];
+       GVariantBuilder gvb;
+       int num_ols_changrp, i;
+
+       (void)cg;
+
+       switch (key) {
+       case SR_CONF_SCAN_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+               break;
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+               break;
+       case SR_CONF_SAMPLERATE:
+               g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
+               gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), samplerates,
+                               ARRAY_SIZE(samplerates), sizeof(uint64_t));
+               g_variant_builder_add(&gvb, "{sv}", "samplerate-steps", gvar);
+               *data = g_variant_builder_end(&gvb);
+               break;
+       case SR_CONF_TRIGGER_MATCH:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               trigger_matches, ARRAY_SIZE(trigger_matches),
+                               sizeof(int32_t));
+               break;
+       case SR_CONF_PATTERN_MODE:
+               *data = g_variant_new_strv(patterns, ARRAY_SIZE(patterns));
+               break;
+       case SR_CONF_LIMIT_SAMPLES:
+               if (!sdi)
+                       return SR_ERR_ARG;
+               devc = sdi->priv;
+               if (devc->flag_reg & FLAG_RLE)
+                       return SR_ERR_NA;
+               if (devc->max_samples == 0)
+                       /* Device didn't specify sample memory size in metadata. */
+                       return SR_ERR_NA;
+               /*
+                * Channel groups are turned off if no channels in that group are
+                * enabled, making more room for samples for the enabled group.
+               */
+               ols_channel_mask(sdi);
+               num_ols_changrp = 0;
+               for (i = 0; i < 4; i++) {
+                       if (devc->channel_mask & (0xff << (i * 8)))
+                               num_ols_changrp++;
+               }
+               grange[0] = g_variant_new_uint64(MIN_NUM_SAMPLES);
+               if (num_ols_changrp)
+                       grange[1] = g_variant_new_uint64(devc->max_samples / num_ols_changrp);
+               else
+                       grange[1] = g_variant_new_uint64(MIN_NUM_SAMPLES);
+               *data = g_variant_new_tuple(grange, 2);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int set_trigger(const struct sr_dev_inst *sdi, int stage)
+{
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+       uint8_t cmd, arg[4];
+
+       devc = sdi->priv;
+       serial = sdi->conn;
+
+       cmd = CMD_SET_TRIGGER_MASK + stage * 4;
+       arg[0] = devc->trigger_mask[stage] & 0xff;
+       arg[1] = (devc->trigger_mask[stage] >> 8) & 0xff;
+       arg[2] = (devc->trigger_mask[stage] >> 16) & 0xff;
+       arg[3] = (devc->trigger_mask[stage] >> 24) & 0xff;
+       if (send_longcommand(serial, cmd, arg) != SR_OK)
+               return SR_ERR;
+
+       cmd = CMD_SET_TRIGGER_VALUE + stage * 4;
+       arg[0] = devc->trigger_value[stage] & 0xff;
+       arg[1] = (devc->trigger_value[stage] >> 8) & 0xff;
+       arg[2] = (devc->trigger_value[stage] >> 16) & 0xff;
+       arg[3] = (devc->trigger_value[stage] >> 24) & 0xff;
+       if (send_longcommand(serial, cmd, arg) != SR_OK)
+               return SR_ERR;
+
+       cmd = CMD_SET_TRIGGER_CONFIG + stage * 4;
+       arg[0] = arg[1] = arg[3] = 0x00;
+       arg[2] = stage;
+       if (stage == devc->num_stages)
+               /* Last stage, fire when this one matches. */
+               arg[3] |= TRIGGER_START;
+       if (send_longcommand(serial, cmd, arg) != SR_OK)
+               return SR_ERR;
+
+       return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi,
+               void *cb_data)
+{
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+       uint16_t samplecount, readcount, delaycount;
+       uint8_t ols_changrp_mask, arg[4];
+       int num_ols_changrp;
+       int ret, i;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       devc = sdi->priv;
+       serial = sdi->conn;
+
+       ols_channel_mask(sdi);
+
+       num_ols_changrp = 0;
+       ols_changrp_mask = 0;
+       for (i = 0; i < 4; i++) {
+               if (devc->channel_mask & (0xff << (i * 8))) {
+                       ols_changrp_mask |= (1 << i);
+                       num_ols_changrp++;
+               }
+       }
+
+       /*
+        * Limit readcount to prevent reading past the end of the hardware
+        * buffer.
+        */
+       samplecount = MIN(devc->max_samples / num_ols_changrp, devc->limit_samples);
+       readcount = samplecount / 4;
+
+       /* Rather read too many samples than too few. */
+       if (samplecount % 4 != 0)
+               readcount++;
+
+       /* Basic triggers. */
+       if (ols_convert_trigger(sdi) != SR_OK) {
+               sr_err("Failed to configure channels.");
+               return SR_ERR;
+       }
+       if (devc->num_stages > 0) {
+               delaycount = readcount * (1 - devc->capture_ratio / 100.0);
+               devc->trigger_at = (readcount - delaycount) * 4 - devc->num_stages;
+               for (i = 0; i <= devc->num_stages; i++) {
+                       sr_dbg("Setting OLS stage %d trigger.", i);
+                       if ((ret = set_trigger(sdi, i)) != SR_OK)
+                               return ret;
+               }
+       } else {
+               /* No triggers configured, force trigger on first stage. */
+               sr_dbg("Forcing trigger at stage 0.");
+               if ((ret = set_trigger(sdi, 0)) != SR_OK)
+                       return ret;
+               delaycount = readcount;
+       }
+
+       /* Samplerate. */
+       sr_dbg("Setting samplerate to %" PRIu64 "Hz (divider %u)",
+                       devc->cur_samplerate, devc->cur_samplerate_divider);
+       arg[0] = devc->cur_samplerate_divider & 0xff;
+       arg[1] = (devc->cur_samplerate_divider & 0xff00) >> 8;
+       arg[2] = (devc->cur_samplerate_divider & 0xff0000) >> 16;
+       arg[3] = 0x00;
+       if (send_longcommand(serial, CMD_SET_DIVIDER, arg) != SR_OK)
+               return SR_ERR;
+
+       /* Send sample limit and pre/post-trigger capture ratio. */
+       sr_dbg("Setting sample limit %d, trigger point at %d",
+                       (readcount - 1) * 4, (delaycount - 1) * 4);
+       arg[0] = ((readcount - 1) & 0xff);
+       arg[1] = ((readcount - 1) & 0xff00) >> 8;
+       arg[2] = ((delaycount - 1) & 0xff);
+       arg[3] = ((delaycount - 1) & 0xff00) >> 8;
+       if (send_longcommand(serial, CMD_CAPTURE_SIZE, arg) != SR_OK)
+               return SR_ERR;
+
+       /* Flag register. */
+       sr_dbg("Setting intpat %s, extpat %s, RLE %s, noise_filter %s, demux %s",
+                       devc->flag_reg & FLAG_INTERNAL_TEST_MODE ? "on": "off",
+                       devc->flag_reg & FLAG_EXTERNAL_TEST_MODE ? "on": "off",
+                       devc->flag_reg & FLAG_RLE ? "on" : "off",
+                       devc->flag_reg & FLAG_FILTER ? "on": "off",
+                       devc->flag_reg & FLAG_DEMUX ? "on" : "off");
+       /*
+        * Enable/disable OLS channel groups in the flag register according
+        * to the channel mask. 1 means "disable channel".
+        */
+       devc->flag_reg |= ~(ols_changrp_mask << 2) & 0x3c;
+       arg[0] = devc->flag_reg & 0xff;
+       arg[1] = devc->flag_reg >> 8;
+       arg[2] = arg[3] = 0x00;
+       if (send_longcommand(serial, CMD_SET_FLAGS, arg) != SR_OK)
+               return SR_ERR;
+
+       /* Start acquisition on the device. */
+       if (send_shortcommand(serial, CMD_RUN) != SR_OK)
+               return SR_ERR;
+
+       /* Reset all operational states. */
+       devc->rle_count = devc->num_transfers = 0;
+       devc->num_samples = devc->num_bytes = 0;
+       devc->cnt_bytes = devc->cnt_samples = devc->cnt_samples_rle = 0;
+       memset(devc->sample, 0, 4);
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(cb_data, LOG_PREFIX);
+
+       serial_source_add(sdi->session, serial, G_IO_IN, -1,
+                       ols_receive_data, cb_data);
+
+       return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       (void)cb_data;
+
+       abort_acquisition(sdi);
+
+       return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver ols_driver_info = {
+       .name = "ols",
+       .longname = "Openbench Logic Sniffer",
+       .api_version = 1,
+       .init = init,
+       .cleanup = cleanup,
+       .scan = scan,
+       .dev_list = dev_list,
+       .dev_clear = NULL,
+       .config_get = config_get,
+       .config_set = config_set,
+       .config_list = config_list,
+       .dev_open = std_serial_dev_open,
+       .dev_close = std_serial_dev_close,
+       .dev_acquisition_start = dev_acquisition_start,
+       .dev_acquisition_stop = dev_acquisition_stop,
+       .priv = NULL,
+};
diff --git a/src/hardware/openbench-logic-sniffer/protocol.c b/src/hardware/openbench-logic-sniffer/protocol.c
new file mode 100644 (file)
index 0000000..1c94b7f
--- /dev/null
@@ -0,0 +1,513 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert@biot.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 "protocol.h"
+#include <libserialport.h>
+
+extern SR_PRIV struct sr_dev_driver ols_driver_info;
+static struct sr_dev_driver *di = &ols_driver_info;
+
+SR_PRIV int send_shortcommand(struct sr_serial_dev_inst *serial,
+               uint8_t command)
+{
+       char buf[1];
+
+       sr_dbg("Sending cmd 0x%.2x.", command);
+       buf[0] = command;
+       if (serial_write_blocking(serial, buf, 1) != 1)
+               return SR_ERR;
+
+       return SR_OK;
+}
+
+SR_PRIV int send_longcommand(struct sr_serial_dev_inst *serial,
+               uint8_t command, uint8_t *data)
+{
+       char buf[5];
+
+       sr_dbg("Sending cmd 0x%.2x data 0x%.2x%.2x%.2x%.2x.", command,
+                       data[0], data[1], data[2], data[3]);
+       buf[0] = command;
+       buf[1] = data[0];
+       buf[2] = data[1];
+       buf[3] = data[2];
+       buf[4] = data[3];
+       if (serial_write_blocking(serial, buf, 5) != 5)
+               return SR_ERR;
+
+       return SR_OK;
+}
+
+/* Configures the channel mask based on which channels are enabled. */
+SR_PRIV void ols_channel_mask(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_channel *channel;
+       const GSList *l;
+
+       devc = sdi->priv;
+
+       devc->channel_mask = 0;
+       for (l = sdi->channels; l; l = l->next) {
+               channel = l->data;
+               if (channel->enabled)
+                       devc->channel_mask |= 1 << channel->index;
+       }
+}
+
+SR_PRIV int ols_convert_trigger(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_trigger *trigger;
+       struct sr_trigger_stage *stage;
+       struct sr_trigger_match *match;
+       const GSList *l, *m;
+       int i;
+
+       devc = sdi->priv;
+
+       devc->num_stages = 0;
+       for (i = 0; i < NUM_TRIGGER_STAGES; i++) {
+               devc->trigger_mask[i] = 0;
+               devc->trigger_value[i] = 0;
+       }
+
+       if (!(trigger = sr_session_trigger_get(sdi->session)))
+               return SR_OK;
+
+       devc->num_stages = g_slist_length(trigger->stages);
+       if (devc->num_stages > NUM_TRIGGER_STAGES) {
+               sr_err("This device only supports %d trigger stages.",
+                               NUM_TRIGGER_STAGES);
+               return SR_ERR;
+       }
+
+       for (l = trigger->stages; l; l = l->next) {
+               stage = l->data;
+               for (m = stage->matches; m; m = m->next) {
+                       match = m->data;
+                       if (!match->channel->enabled)
+                               /* Ignore disabled channels with a trigger. */
+                               continue;
+                       devc->trigger_mask[stage->stage] |= 1 << match->channel->index;
+                       if (match->match == SR_TRIGGER_ONE)
+                               devc->trigger_value[stage->stage] |= 1 << match->channel->index;
+               }
+       }
+
+       return SR_OK;
+}
+
+SR_PRIV struct dev_context *ols_dev_new(void)
+{
+       struct dev_context *devc;
+
+       if (!(devc = g_try_malloc(sizeof(struct dev_context)))) {
+               sr_err("Device context malloc failed.");
+               return NULL;
+       }
+
+       /* Device-specific settings */
+       devc->max_samples = devc->max_samplerate = devc->protocol_version = 0;
+
+       /* Acquisition settings */
+       devc->limit_samples = devc->capture_ratio = 0;
+       devc->trigger_at = -1;
+       devc->channel_mask = 0xffffffff;
+       devc->flag_reg = 0;
+
+       return devc;
+}
+
+SR_PRIV struct sr_dev_inst *get_metadata(struct sr_serial_dev_inst *serial)
+{
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       struct sr_channel *ch;
+       uint32_t tmp_int, ui;
+       uint8_t key, type, token;
+       GString *tmp_str, *devname, *version;
+       guchar tmp_c;
+
+       sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, NULL, NULL, NULL);
+       sdi->driver = di;
+       devc = ols_dev_new();
+       sdi->priv = devc;
+
+       devname = g_string_new("");
+       version = g_string_new("");
+
+       key = 0xff;
+       while (key) {
+               if (serial_read_blocking(serial, &key, 1) != 1)
+                       break;
+               if (key == 0x00) {
+                       sr_dbg("Got metadata key 0x00, metadata ends.");
+                       break;
+               }
+               type = key >> 5;
+               token = key & 0x1f;
+               switch (type) {
+               case 0:
+                       /* NULL-terminated string */
+                       tmp_str = g_string_new("");
+                       while (serial_read_blocking(serial, &tmp_c, 1) == 1 && tmp_c != '\0')
+                               g_string_append_c(tmp_str, tmp_c);
+                       sr_dbg("Got metadata key 0x%.2x value '%s'.",
+                              key, tmp_str->str);
+                       switch (token) {
+                       case 0x01:
+                               /* Device name */
+                               devname = g_string_append(devname, tmp_str->str);
+                               break;
+                       case 0x02:
+                               /* FPGA firmware version */
+                               if (version->len)
+                                       g_string_append(version, ", ");
+                               g_string_append(version, "FPGA version ");
+                               g_string_append(version, tmp_str->str);
+                               break;
+                       case 0x03:
+                               /* Ancillary version */
+                               if (version->len)
+                                       g_string_append(version, ", ");
+                               g_string_append(version, "Ancillary version ");
+                               g_string_append(version, tmp_str->str);
+                               break;
+                       default:
+                               sr_info("ols: unknown token 0x%.2x: '%s'",
+                                       token, tmp_str->str);
+                               break;
+                       }
+                       g_string_free(tmp_str, TRUE);
+                       break;
+               case 1:
+                       /* 32-bit unsigned integer */
+                       if (serial_read_blocking(serial, &tmp_int, 4) != 4)
+                               break;
+                       tmp_int = RB32(&tmp_int);
+                       sr_dbg("Got metadata key 0x%.2x value 0x%.8x.",
+                              key, tmp_int);
+                       switch (token) {
+                       case 0x00:
+                               /* Number of usable channels */
+                               for (ui = 0; ui < tmp_int; ui++) {
+                                       if (!(ch = sr_channel_new(ui, SR_CHANNEL_LOGIC, TRUE,
+                                                       ols_channel_names[ui])))
+                                               return 0;
+                                       sdi->channels = g_slist_append(sdi->channels, ch);
+                               }
+                               break;
+                       case 0x01:
+                               /* Amount of sample memory available (bytes) */
+                               devc->max_samples = tmp_int;
+                               break;
+                       case 0x02:
+                               /* Amount of dynamic memory available (bytes) */
+                               /* what is this for? */
+                               break;
+                       case 0x03:
+                               /* Maximum sample rate (hz) */
+                               devc->max_samplerate = tmp_int;
+                               break;
+                       case 0x04:
+                               /* protocol version */
+                               devc->protocol_version = tmp_int;
+                               break;
+                       default:
+                               sr_info("Unknown token 0x%.2x: 0x%.8x.",
+                                       token, tmp_int);
+                               break;
+                       }
+                       break;
+               case 2:
+                       /* 8-bit unsigned integer */
+                       if (serial_read_blocking(serial, &tmp_c, 1) != 1)
+                               break;
+                       sr_dbg("Got metadata key 0x%.2x value 0x%.2x.",
+                              key, tmp_c);
+                       switch (token) {
+                       case 0x00:
+                               /* Number of usable channels */
+                               for (ui = 0; ui < tmp_c; ui++) {
+                                       if (!(ch = sr_channel_new(ui, SR_CHANNEL_LOGIC, TRUE,
+                                                       ols_channel_names[ui])))
+                                               return 0;
+                                       sdi->channels = g_slist_append(sdi->channels, ch);
+                               }
+                               break;
+                       case 0x01:
+                               /* protocol version */
+                               devc->protocol_version = tmp_c;
+                               break;
+                       default:
+                               sr_info("Unknown token 0x%.2x: 0x%.2x.",
+                                       token, tmp_c);
+                               break;
+                       }
+                       break;
+               default:
+                       /* unknown type */
+                       break;
+               }
+       }
+
+       sdi->model = devname->str;
+       sdi->version = version->str;
+       g_string_free(devname, FALSE);
+       g_string_free(version, FALSE);
+
+       return sdi;
+}
+
+SR_PRIV int ols_set_samplerate(const struct sr_dev_inst *sdi,
+               const uint64_t samplerate)
+{
+       struct dev_context *devc;
+
+       devc = sdi->priv;
+       if (devc->max_samplerate && samplerate > devc->max_samplerate)
+               return SR_ERR_SAMPLERATE;
+
+       if (samplerate > CLOCK_RATE) {
+               sr_info("Enabling demux mode.");
+               devc->flag_reg |= FLAG_DEMUX;
+               devc->flag_reg &= ~FLAG_FILTER;
+               devc->max_channels = NUM_CHANNELS / 2;
+               devc->cur_samplerate_divider = (CLOCK_RATE * 2 / samplerate) - 1;
+       } else {
+               sr_info("Disabling demux mode.");
+               devc->flag_reg &= ~FLAG_DEMUX;
+               devc->flag_reg |= FLAG_FILTER;
+               devc->max_channels = NUM_CHANNELS;
+               devc->cur_samplerate_divider = (CLOCK_RATE / samplerate) - 1;
+       }
+
+       /* Calculate actual samplerate used and complain if it is different
+        * from the requested.
+        */
+       devc->cur_samplerate = CLOCK_RATE / (devc->cur_samplerate_divider + 1);
+       if (devc->flag_reg & FLAG_DEMUX)
+               devc->cur_samplerate *= 2;
+       if (devc->cur_samplerate != samplerate)
+               sr_info("Can't match samplerate %" PRIu64 ", using %"
+                      PRIu64 ".", samplerate, devc->cur_samplerate);
+
+       return SR_OK;
+}
+
+SR_PRIV void abort_acquisition(const struct sr_dev_inst *sdi)
+{
+       struct sr_datafeed_packet packet;
+       struct sr_serial_dev_inst *serial;
+
+       serial = sdi->conn;
+       serial_source_remove(sdi->session, serial);
+
+       /* Terminate session */
+       packet.type = SR_DF_END;
+       sr_session_send(sdi, &packet);
+}
+
+SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data)
+{
+       struct dev_context *devc;
+       struct sr_dev_inst *sdi;
+       struct sr_serial_dev_inst *serial;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_logic logic;
+       uint32_t sample;
+       int num_ols_changrp, offset, j;
+       unsigned int i;
+       unsigned char byte;
+
+       (void)fd;
+
+       sdi = cb_data;
+       serial = sdi->conn;
+       devc = sdi->priv;
+
+       if (devc->num_transfers++ == 0) {
+               /*
+                * First time round, means the device started sending data,
+                * and will not stop until done. If it stops sending for
+                * longer than it takes to send a byte, that means it's
+                * finished. We'll double that to 30ms to be sure...
+                */
+               serial_source_remove(sdi->session, serial);
+               serial_source_add(sdi->session, serial, G_IO_IN, 30,
+                               ols_receive_data, cb_data);
+               devc->raw_sample_buf = g_try_malloc(devc->limit_samples * 4);
+               if (!devc->raw_sample_buf) {
+                       sr_err("Sample buffer malloc failed.");
+                       return FALSE;
+               }
+               /* fill with 1010... for debugging */
+               memset(devc->raw_sample_buf, 0x82, devc->limit_samples * 4);
+       }
+
+       num_ols_changrp = 0;
+       for (i = NUM_CHANNELS; i > 0x02; i /= 2) {
+               if ((devc->flag_reg & i) == 0) {
+                       num_ols_changrp++;
+               }
+       }
+
+       if (revents == G_IO_IN && devc->num_samples < devc->limit_samples) {
+               if (serial_read_nonblocking(serial, &byte, 1) != 1)
+                       return FALSE;
+               devc->cnt_bytes++;
+
+               /* Ignore it if we've read enough. */
+               if (devc->num_samples >= devc->limit_samples)
+                       return TRUE;
+
+               devc->sample[devc->num_bytes++] = byte;
+               sr_spew("Received byte 0x%.2x.", byte);
+               if (devc->num_bytes == num_ols_changrp) {
+                       devc->cnt_samples++;
+                       devc->cnt_samples_rle++;
+                       /*
+                        * Got a full sample. Convert from the OLS's little-endian
+                        * sample to the local format.
+                        */
+                       sample = devc->sample[0] | (devc->sample[1] << 8) \
+                                       | (devc->sample[2] << 16) | (devc->sample[3] << 24);
+                       sr_dbg("Received sample 0x%.*x.", devc->num_bytes * 2, sample);
+                       if (devc->flag_reg & FLAG_RLE) {
+                               /*
+                                * In RLE mode the high bit of the sample is the
+                                * "count" flag, meaning this sample is the number
+                                * of times the previous sample occurred.
+                                */
+                               if (devc->sample[devc->num_bytes - 1] & 0x80) {
+                                       /* Clear the high bit. */
+                                       sample &= ~(0x80 << (devc->num_bytes - 1) * 8);
+                                       devc->rle_count = sample;
+                                       devc->cnt_samples_rle += devc->rle_count;
+                                       sr_dbg("RLE count: %u.", devc->rle_count);
+                                       devc->num_bytes = 0;
+                                       return TRUE;
+                               }
+                       }
+                       devc->num_samples += devc->rle_count + 1;
+                       if (devc->num_samples > devc->limit_samples) {
+                               /* Save us from overrunning the buffer. */
+                               devc->rle_count -= devc->num_samples - devc->limit_samples;
+                               devc->num_samples = devc->limit_samples;
+                       }
+
+                       if (num_ols_changrp < 4) {
+                               /*
+                                * Some channel groups may have been turned
+                                * off, to speed up transfer between the
+                                * hardware and the PC. Expand that here before
+                                * submitting it over the session bus --
+                                * whatever is listening on the bus will be
+                                * expecting a full 32-bit sample, based on
+                                * the number of channels.
+                                */
+                               j = 0;
+                               memset(devc->tmp_sample, 0, 4);
+                               for (i = 0; i < 4; i++) {
+                                       if (((devc->flag_reg >> 2) & (1 << i)) == 0) {
+                                               /*
+                                                * This channel group was
+                                                * enabled, copy from received
+                                                * sample.
+                                                */
+                                               devc->tmp_sample[i] = devc->sample[j++];
+                                       } else if (devc->flag_reg & FLAG_DEMUX && (i > 2)) {
+                                               /* group 2 & 3 get added to 0 & 1 */
+                                               devc->tmp_sample[i - 2] = devc->sample[j++];
+                                       }
+                               }
+                               memcpy(devc->sample, devc->tmp_sample, 4);
+                               sr_spew("Expanded sample: 0x%.8x.", sample);
+                       }
+
+                       /*
+                        * the OLS sends its sample buffer backwards.
+                        * store it in reverse order here, so we can dump
+                        * this on the session bus later.
+                        */
+                       offset = (devc->limit_samples - devc->num_samples) * 4;
+                       for (i = 0; i <= devc->rle_count; i++) {
+                               memcpy(devc->raw_sample_buf + offset + (i * 4),
+                                      devc->sample, 4);
+                       }
+                       memset(devc->sample, 0, 4);
+                       devc->num_bytes = 0;
+                       devc->rle_count = 0;
+               }
+       } else {
+               /*
+                * This is the main loop telling us a timeout was reached, or
+                * we've acquired all the samples we asked for -- we're done.
+                * Send the (properly-ordered) buffer to the frontend.
+                */
+               sr_dbg("Received %d bytes, %d samples, %d decompressed samples.",
+                               devc->cnt_bytes, devc->cnt_samples,
+                               devc->cnt_samples_rle);
+               if (devc->trigger_at != -1) {
+                       /*
+                        * A trigger was set up, so we need to tell the frontend
+                        * about it.
+                        */
+                       if (devc->trigger_at > 0) {
+                               /* There are pre-trigger samples, send those first. */
+                               packet.type = SR_DF_LOGIC;
+                               packet.payload = &logic;
+                               logic.length = devc->trigger_at * 4;
+                               logic.unitsize = 4;
+                               logic.data = devc->raw_sample_buf +
+                                       (devc->limit_samples - devc->num_samples) * 4;
+                               sr_session_send(cb_data, &packet);
+                       }
+
+                       /* Send the trigger. */
+                       packet.type = SR_DF_TRIGGER;
+                       sr_session_send(cb_data, &packet);
+
+                       /* Send post-trigger samples. */
+                       packet.type = SR_DF_LOGIC;
+                       packet.payload = &logic;
+                       logic.length = (devc->num_samples * 4) - (devc->trigger_at * 4);
+                       logic.unitsize = 4;
+                       logic.data = devc->raw_sample_buf + devc->trigger_at * 4 +
+                               (devc->limit_samples - devc->num_samples) * 4;
+                       sr_session_send(cb_data, &packet);
+               } else {
+                       /* no trigger was used */
+                       packet.type = SR_DF_LOGIC;
+                       packet.payload = &logic;
+                       logic.length = devc->num_samples * 4;
+                       logic.unitsize = 4;
+                       logic.data = devc->raw_sample_buf +
+                               (devc->limit_samples - devc->num_samples) * 4;
+                       sr_session_send(cb_data, &packet);
+               }
+               g_free(devc->raw_sample_buf);
+
+               serial_flush(serial);
+               abort_acquisition(sdi);
+       }
+
+       return TRUE;
+}
diff --git a/src/hardware/openbench-logic-sniffer/protocol.h b/src/hardware/openbench-logic-sniffer/protocol.h
new file mode 100644 (file)
index 0000000..c0f101d
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert@biot.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_OPENBENCH_LOGIC_SNIFFER_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_OPENBENCH_LOGIC_SNIFFER_PROTOCOL_H
+
+#include <stdint.h>
+#include <string.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "ols"
+
+#define NUM_CHANNELS             32
+#define NUM_TRIGGER_STAGES     4
+#define SERIAL_SPEED           B115200
+#define CLOCK_RATE             SR_MHZ(100)
+#define MIN_NUM_SAMPLES        4
+#define DEFAULT_SAMPLERATE     SR_KHZ(200)
+
+/* Command opcodes */
+#define CMD_RESET                  0x00
+#define CMD_RUN                    0x01
+#define CMD_TESTMODE               0x03
+#define CMD_ID                     0x02
+#define CMD_METADATA               0x04
+#define CMD_SET_FLAGS              0x82
+#define CMD_SET_DIVIDER            0x80
+#define CMD_CAPTURE_SIZE           0x81
+#define CMD_SET_TRIGGER_MASK       0xc0
+#define CMD_SET_TRIGGER_VALUE      0xc1
+#define CMD_SET_TRIGGER_CONFIG     0xc2
+
+/* Trigger config */
+#define TRIGGER_START              (1 << 3)
+
+/* Bitmasks for CMD_FLAGS */
+/* 12-13 unused, 14-15 RLE mode (we hardcode mode 0). */
+#define FLAG_INTERNAL_TEST_MODE    (1 << 11)
+#define FLAG_EXTERNAL_TEST_MODE    (1 << 10)
+#define FLAG_SWAP_CHANNELS           (1 << 9)
+#define FLAG_RLE                   (1 << 8)
+#define FLAG_SLOPE_FALLING         (1 << 7)
+#define FLAG_CLOCK_EXTERNAL        (1 << 6)
+#define FLAG_CHANNELGROUP_4        (1 << 5)
+#define FLAG_CHANNELGROUP_3        (1 << 4)
+#define FLAG_CHANNELGROUP_2        (1 << 3)
+#define FLAG_CHANNELGROUP_1        (1 << 2)
+#define FLAG_FILTER                (1 << 1)
+#define FLAG_DEMUX                 (1 << 0)
+
+/* Private, per-device-instance driver context. */
+struct dev_context {
+       /* Fixed device settings */
+       int max_channels;
+       uint32_t max_samples;
+       uint32_t max_samplerate;
+       uint32_t protocol_version;
+
+       /* Acquisition settings */
+       uint64_t cur_samplerate;
+       uint32_t cur_samplerate_divider;
+       uint64_t limit_samples;
+       int capture_ratio;
+       int trigger_at;
+       uint32_t channel_mask;
+       uint32_t trigger_mask[NUM_TRIGGER_STAGES];
+       uint32_t trigger_value[NUM_TRIGGER_STAGES];
+       int num_stages;
+       uint16_t flag_reg;
+
+       /* Operational states */
+       unsigned int num_transfers;
+       unsigned int num_samples;
+       int num_bytes;
+       int cnt_bytes;
+       int cnt_samples;
+       int cnt_samples_rle;
+
+       /* Temporary variables */
+       unsigned int rle_count;
+       unsigned char sample[4];
+       unsigned char tmp_sample[4];
+       unsigned char *raw_sample_buf;
+};
+
+
+SR_PRIV extern const char *ols_channel_names[NUM_CHANNELS + 1];
+
+SR_PRIV int send_shortcommand(struct sr_serial_dev_inst *serial,
+               uint8_t command);
+SR_PRIV int send_longcommand(struct sr_serial_dev_inst *serial,
+               uint8_t command, uint8_t *data);
+SR_PRIV void ols_channel_mask(const struct sr_dev_inst *sdi);
+SR_PRIV int ols_convert_trigger(const struct sr_dev_inst *sdi);
+SR_PRIV struct dev_context *ols_dev_new(void);
+SR_PRIV struct sr_dev_inst *get_metadata(struct sr_serial_dev_inst *serial);
+SR_PRIV int ols_set_samplerate(const struct sr_dev_inst *sdi,
+               uint64_t samplerate);
+SR_PRIV void abort_acquisition(const struct sr_dev_inst *sdi);
+SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data);
+
+#endif
diff --git a/src/hardware/rigol-ds/api.c b/src/hardware/rigol-ds/api.c
new file mode 100644 (file)
index 0000000..872531f
--- /dev/null
@@ -0,0 +1,1040 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Martin Ling <martin-git@earth.li>
+ * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
+ * Copyright (C) 2013 Mathias Grimmberger <mgri@zaphod.sax.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 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 <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "protocol.h"
+
+static const int32_t hwopts[] = {
+       SR_CONF_CONN,
+       SR_CONF_SERIALCOMM
+};
+
+static const int32_t hwcaps[] = {
+       SR_CONF_OSCILLOSCOPE,
+       SR_CONF_TIMEBASE,
+       SR_CONF_TRIGGER_SOURCE,
+       SR_CONF_TRIGGER_SLOPE,
+       SR_CONF_HORIZ_TRIGGERPOS,
+       SR_CONF_NUM_TIMEBASE,
+       SR_CONF_LIMIT_FRAMES,
+       SR_CONF_SAMPLERATE,
+};
+
+static const int32_t analog_hwcaps[] = {
+       SR_CONF_NUM_VDIV,
+       SR_CONF_VDIV,
+       SR_CONF_COUPLING,
+       SR_CONF_DATA_SOURCE,
+};
+
+static const uint64_t timebases[][2] = {
+       /* nanoseconds */
+       { 1, 1000000000 },
+       { 2, 1000000000 },
+       { 5, 1000000000 },
+       { 10, 1000000000 },
+       { 20, 1000000000 },
+       { 50, 1000000000 },
+       { 100, 1000000000 },
+       { 500, 1000000000 },
+       /* microseconds */
+       { 1, 1000000 },
+       { 2, 1000000 },
+       { 5, 1000000 },
+       { 10, 1000000 },
+       { 20, 1000000 },
+       { 50, 1000000 },
+       { 100, 1000000 },
+       { 200, 1000000 },
+       { 500, 1000000 },
+       /* milliseconds */
+       { 1, 1000 },
+       { 2, 1000 },
+       { 5, 1000 },
+       { 10, 1000 },
+       { 20, 1000 },
+       { 50, 1000 },
+       { 100, 1000 },
+       { 200, 1000 },
+       { 500, 1000 },
+       /* seconds */
+       { 1, 1 },
+       { 2, 1 },
+       { 5, 1 },
+       { 10, 1 },
+       { 20, 1 },
+       { 50, 1 },
+       { 100, 1 },
+       { 200, 1 },
+       { 500, 1 },
+       { 1000, 1 },
+};
+
+static const uint64_t vdivs[][2] = {
+       /* microvolts */
+       { 500, 1000000 },
+       /* millivolts */
+       { 1, 1000 },
+       { 2, 1000 },
+       { 5, 1000 },
+       { 10, 1000 },
+       { 20, 1000 },
+       { 50, 1000 },
+       { 100, 1000 },
+       { 200, 1000 },
+       { 500, 1000 },
+       /* volts */
+       { 1, 1 },
+       { 2, 1 },
+       { 5, 1 },
+       { 10, 1 },
+};
+
+#define NUM_TIMEBASE  ARRAY_SIZE(timebases)
+#define NUM_VDIV      ARRAY_SIZE(vdivs)
+
+static const char *trigger_sources[] = {
+       "CH1",
+       "CH2",
+       "CH3",
+       "CH4",
+       "EXT",
+       "AC Line",
+       "D0",
+       "D1",
+       "D2",
+       "D3",
+       "D4",
+       "D5",
+       "D6",
+       "D7",
+       "D8",
+       "D9",
+       "D10",
+       "D11",
+       "D12",
+       "D13",
+       "D14",
+       "D15",
+};
+
+static const char *trigger_slopes[] = {
+       "r",
+       "f",
+};
+
+static const char *coupling[] = {
+       "AC",
+       "DC",
+       "GND",
+};
+
+/* Do not change the order of entries */
+static const char *data_sources[] = {
+       "Live",
+       "Memory",
+       "Segmented",
+};
+
+enum vendor {
+       RIGOL,
+       AGILENT,
+};
+
+enum series {
+       VS5000,
+       DS1000,
+       DS2000,
+       DS2000A,
+       DSO1000,
+};
+
+/* short name, full name */
+static const struct rigol_ds_vendor supported_vendors[] = {
+       [RIGOL] = {"Rigol", "Rigol Technologies"},
+       [AGILENT] = {"Agilent", "Rigol Technologies"},
+};
+
+#define VENDOR(x) &supported_vendors[x]
+/* vendor, series, protocol, max timebase, min vdiv, number of horizontal divs,
+ * live waveform samples, memory buffer samples */
+static const struct rigol_ds_series supported_series[] = {
+       [VS5000] = {VENDOR(RIGOL), "VS5000", PROTOCOL_V1, FORMAT_RAW,
+               {50, 1}, {2, 1000}, 14, 2048, 0},
+       [DS1000] = {VENDOR(RIGOL), "DS1000", PROTOCOL_V2, FORMAT_IEEE488_2,
+               {50, 1}, {2, 1000}, 12, 600, 1048576},
+       [DS2000] = {VENDOR(RIGOL), "DS2000", PROTOCOL_V3, FORMAT_IEEE488_2,
+               {500, 1}, {2, 1000}, 14, 1400, 14000},
+       [DS2000A] = {VENDOR(RIGOL), "DS2000A", PROTOCOL_V3, FORMAT_IEEE488_2,
+               {1000, 1}, {500, 1000000}, 14, 1400, 14000},
+       [DSO1000] = {VENDOR(AGILENT), "DSO1000", PROTOCOL_V3, FORMAT_IEEE488_2,
+               {50, 1}, {2, 1000}, 12, 600, 20480},
+};
+
+#define SERIES(x) &supported_series[x]
+/* series, model, min timebase, analog channels, digital */
+static const struct rigol_ds_model supported_models[] = {
+       {SERIES(VS5000), "VS5022", {20, 1000000000}, 2, false},
+       {SERIES(VS5000), "VS5042", {10, 1000000000}, 2, false},
+       {SERIES(VS5000), "VS5062", {5, 1000000000}, 2, false},
+       {SERIES(VS5000), "VS5102", {2, 1000000000}, 2, false},
+       {SERIES(VS5000), "VS5202", {2, 1000000000}, 2, false},
+       {SERIES(VS5000), "VS5022D", {20, 1000000000}, 2, true},
+       {SERIES(VS5000), "VS5042D", {10, 1000000000}, 2, true},
+       {SERIES(VS5000), "VS5062D", {5, 1000000000}, 2, true},
+       {SERIES(VS5000), "VS5102D", {2, 1000000000}, 2, true},
+       {SERIES(VS5000), "VS5202D", {2, 1000000000}, 2, true},
+       {SERIES(DS1000), "DS1052E", {5, 1000000000}, 2, false},
+       {SERIES(DS1000), "DS1102E", {2, 1000000000}, 2, false},
+       {SERIES(DS1000), "DS1152E", {2, 1000000000}, 2, false},
+       {SERIES(DS1000), "DS1052D", {5, 1000000000}, 2, true},
+       {SERIES(DS1000), "DS1102D", {2, 1000000000}, 2, true},
+       {SERIES(DS1000), "DS1152D", {2, 1000000000}, 2, true},
+       {SERIES(DS2000), "DS2072", {5, 1000000000}, 2, false},
+       {SERIES(DS2000), "DS2102", {5, 1000000000}, 2, false},
+       {SERIES(DS2000), "DS2202", {2, 1000000000}, 2, false},
+       {SERIES(DS2000), "DS2302", {1, 1000000000}, 2, false},
+       {SERIES(DS2000A), "DS2072A", {5, 1000000000}, 2, false},
+       {SERIES(DS2000A), "DS2102A", {5, 1000000000}, 2, false},
+       {SERIES(DS2000A), "DS2202A", {2, 1000000000}, 2, false},
+       {SERIES(DS2000A), "DS2302A", {1, 1000000000}, 2, false},
+       {SERIES(DSO1000), "DSO1002A", {5, 1000000000}, 2, false},
+       {SERIES(DSO1000), "DSO1004A", {5, 1000000000}, 4, false},
+       {SERIES(DSO1000), "DSO1012A", {2, 1000000000}, 2, false},
+       {SERIES(DSO1000), "DSO1014A", {2, 1000000000}, 4, false},
+       {SERIES(DSO1000), "DSO1022A", {2, 1000000000}, 2, false},
+       {SERIES(DSO1000), "DSO1024A", {2, 1000000000}, 4, false},
+};
+
+SR_PRIV struct sr_dev_driver rigol_ds_driver_info;
+static struct sr_dev_driver *di = &rigol_ds_driver_info;
+
+static void clear_helper(void *priv)
+{
+       struct dev_context *devc;
+
+       devc = priv;
+       g_free(devc->data);
+       g_free(devc->buffer);
+       g_free(devc->coupling[0]);
+       g_free(devc->coupling[1]);
+       g_free(devc->trigger_source);
+       g_free(devc->trigger_slope);
+       g_slist_free(devc->analog_groups[0].channels);
+       g_slist_free(devc->analog_groups[1].channels);
+       g_slist_free(devc->digital_group.channels);
+}
+
+static int dev_clear(void)
+{
+       return std_dev_clear(di, clear_helper);
+}
+
+static int init(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static struct sr_dev_inst *probe_device(struct sr_scpi_dev_inst *scpi)
+{
+       struct dev_context *devc;
+       struct sr_dev_inst *sdi;
+       struct sr_scpi_hw_info *hw_info;
+       struct sr_channel *ch;
+       long n[3];
+       unsigned int i;
+       const struct rigol_ds_model *model = NULL;
+       gchar *channel_name, **version;
+
+       if (sr_scpi_get_hw_id(scpi, &hw_info) != SR_OK) {
+               sr_info("Couldn't get IDN response, retrying.");
+               sr_scpi_close(scpi);
+               sr_scpi_open(scpi);
+               if (sr_scpi_get_hw_id(scpi, &hw_info) != SR_OK) {
+                       sr_info("Couldn't get IDN response.");
+                       return NULL;
+               }
+       }
+
+       for (i = 0; i < ARRAY_SIZE(supported_models); i++) {
+               if (!strcasecmp(hw_info->manufacturer,
+                                       supported_models[i].series->vendor->full_name) &&
+                               !strcmp(hw_info->model, supported_models[i].name)) {
+                       model = &supported_models[i];
+                       break;
+               }
+       }
+
+       if (!model || !(sdi = sr_dev_inst_new(0, SR_ST_ACTIVE,
+                                             model->series->vendor->name,
+                                                 model->name,
+                                                 hw_info->firmware_version))) {
+               sr_scpi_hw_info_free(hw_info);
+               return NULL;
+       }
+
+       sdi->conn = scpi;
+
+       sdi->driver = di;
+       sdi->inst_type = SR_INST_SCPI;
+
+       if (!(devc = g_try_malloc0(sizeof(struct dev_context))))
+               return NULL;
+
+       devc->limit_frames = 0;
+       devc->model = model;
+       devc->format = model->series->format;
+
+       /* DS1000 models with firmware before 0.2.4 used the old data format. */
+       if (model->series == SERIES(DS1000)) {
+               version = g_strsplit(hw_info->firmware_version, ".", 0);
+               do {
+                       if (!version[0] || !version[1] || !version[2])
+                               break;
+                       if (version[0][0] == 0 || version[1][0] == 0 || version[2][0] == 0)
+                               break;
+                       for (i = 0; i < 3; i++) {
+                               if (sr_atol(version[i], &n[i]) != SR_OK)
+                                       break;
+                       }
+                       if (i != 3)
+                               break;
+                       if (n[0] != 0 || n[1] > 2)
+                               break;
+                       if (n[1] == 2 && n[2] > 3)
+                               break;
+                       sr_dbg("Found DS1000 firmware < 0.2.4, using raw data format.");
+                       devc->format = FORMAT_RAW;
+               } while(0);
+               g_strfreev(version);
+       }
+
+       sr_scpi_hw_info_free(hw_info);
+
+       for (i = 0; i < model->analog_channels; i++) {
+               if (!(channel_name = g_strdup_printf("CH%d", i + 1)))
+                       return NULL;
+               ch = sr_channel_new(i, SR_CHANNEL_ANALOG, TRUE, channel_name);
+               sdi->channels = g_slist_append(sdi->channels, ch);
+               devc->analog_groups[i].name = channel_name;
+               devc->analog_groups[i].channels = g_slist_append(NULL, ch);
+               sdi->channel_groups = g_slist_append(sdi->channel_groups,
+                               &devc->analog_groups[i]);
+       }
+
+       if (devc->model->has_digital) {
+               for (i = 0; i < 16; i++) {
+                       if (!(channel_name = g_strdup_printf("D%d", i)))
+                               return NULL;
+                       ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE, channel_name);
+                       g_free(channel_name);
+                       if (!ch)
+                               return NULL;
+                       sdi->channels = g_slist_append(sdi->channels, ch);
+                       devc->digital_group.channels = g_slist_append(
+                                       devc->digital_group.channels, ch);
+               }
+               devc->digital_group.name = "LA";
+               sdi->channel_groups = g_slist_append(sdi->channel_groups,
+                               &devc->digital_group);
+       }
+
+       for (i = 0; i < NUM_TIMEBASE; i++) {
+               if (!memcmp(&devc->model->min_timebase, &timebases[i], sizeof(uint64_t[2])))
+                       devc->timebases = &timebases[i];
+               if (!memcmp(&devc->model->series->max_timebase, &timebases[i], sizeof(uint64_t[2])))
+                       devc->num_timebases = &timebases[i] - devc->timebases + 1;
+       }
+
+       for (i = 0; i < NUM_VDIV; i++)
+               if (!memcmp(&devc->model->series->min_vdiv, &vdivs[i], sizeof(uint64_t[2])))
+                       devc->vdivs = &vdivs[i];
+
+       if (!(devc->buffer = g_try_malloc(ACQ_BUFFER_SIZE)))
+               return NULL;
+       if (!(devc->data = g_try_malloc(ACQ_BUFFER_SIZE * sizeof(float))))
+               return NULL;
+
+       devc->data_source = DATA_SOURCE_LIVE;
+
+       sdi->priv = devc;
+
+       return sdi;
+}
+
+static GSList *scan(GSList *options)
+{
+       return sr_scpi_scan(di->priv, options, probe_device);
+}
+
+static GSList *dev_list(void)
+{
+       return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+       struct sr_scpi_dev_inst *scpi = sdi->conn;
+
+       if (sr_scpi_open(scpi) < 0)
+               return SR_ERR;
+
+       if (rigol_ds_get_dev_cfg(sdi) != SR_OK)
+               return SR_ERR;
+
+       sdi->status = SR_ST_ACTIVE;
+
+       return SR_OK;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+       struct sr_scpi_dev_inst *scpi;
+       struct dev_context *devc;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       scpi = sdi->conn;
+       devc = sdi->priv;
+
+       if (devc->model->series->protocol == PROTOCOL_V2)
+               rigol_ds_config_set(sdi, ":KEY:LOCK DISABLE");
+
+       if (scpi) {
+               if (sr_scpi_close(scpi) < 0)
+                       return SR_ERR;
+               sdi->status = SR_ST_INACTIVE;
+       }
+
+       return SR_OK;
+}
+
+static int cleanup(void)
+{
+       return dev_clear();
+}
+
+static int analog_frame_size(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc = sdi->priv;
+       struct sr_channel *ch;
+       int analog_channels = 0;
+       GSList *l;
+
+       for (l = sdi->channels; l; l = l->next) {
+               ch = l->data;
+               if (ch->type == SR_CHANNEL_ANALOG && ch->enabled)
+                       analog_channels++;
+       }
+
+       if (analog_channels == 0)
+               return 0;
+
+       switch (devc->data_source) {
+       case DATA_SOURCE_LIVE:
+               return devc->model->series->live_samples;
+       case DATA_SOURCE_MEMORY:
+               return devc->model->series->buffer_samples / analog_channels;
+       default:
+               return 0;
+       }
+}
+
+static int digital_frame_size(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc = sdi->priv;
+
+       switch (devc->data_source) {
+       case DATA_SOURCE_LIVE:
+               return devc->model->series->live_samples * 2;
+       case DATA_SOURCE_MEMORY:
+               return devc->model->series->buffer_samples * 2;
+       default:
+               return 0;
+       }
+}
+
+static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       struct sr_channel *ch;
+       const char *tmp_str;
+       uint64_t samplerate;
+       int analog_channel = -1;
+       float smallest_diff = 0.0000000001;
+       int idx = -1;
+       unsigned i;
+
+       if (!sdi || !(devc = sdi->priv))
+               return SR_ERR_ARG;
+
+       /* If a channel group is specified, it must be a valid one. */
+       if (cg && !g_slist_find(sdi->channel_groups, cg)) {
+               sr_err("Invalid channel group specified.");
+               return SR_ERR;
+       }
+
+       if (cg) {
+               ch = g_slist_nth_data(cg->channels, 0);
+               if (!ch)
+                       return SR_ERR;
+               if (ch->type == SR_CHANNEL_ANALOG) {
+                       if (ch->name[2] < '1' || ch->name[2] > '4')
+                               return SR_ERR;
+                       analog_channel = ch->name[2] - '1';
+               }
+       }
+
+       switch (id) {
+       case SR_CONF_NUM_TIMEBASE:
+               *data = g_variant_new_int32(devc->model->series->num_horizontal_divs);
+               break;
+       case SR_CONF_NUM_VDIV:
+               *data = g_variant_new_int32(NUM_VDIV);
+       case SR_CONF_DATA_SOURCE:
+               if (devc->data_source == DATA_SOURCE_LIVE)
+                       *data = g_variant_new_string("Live");
+               else if (devc->data_source == DATA_SOURCE_MEMORY)
+                       *data = g_variant_new_string("Memory");
+               else
+                       *data = g_variant_new_string("Segmented");
+               break;
+       case SR_CONF_SAMPLERATE:
+               if (devc->data_source == DATA_SOURCE_LIVE) {
+                       samplerate = analog_frame_size(sdi) /
+                               (devc->timebase * devc->model->series->num_horizontal_divs);
+                       *data = g_variant_new_uint64(samplerate);
+               } else {
+                       return SR_ERR_NA;
+               }
+               break;
+       case SR_CONF_TRIGGER_SOURCE:
+               if (!strcmp(devc->trigger_source, "ACL"))
+                       tmp_str = "AC Line";
+               else if (!strcmp(devc->trigger_source, "CHAN1"))
+                       tmp_str = "CH1";
+               else if (!strcmp(devc->trigger_source, "CHAN2"))
+                       tmp_str = "CH2";
+               else if (!strcmp(devc->trigger_source, "CHAN3"))
+                       tmp_str = "CH3";
+               else if (!strcmp(devc->trigger_source, "CHAN4"))
+                       tmp_str = "CH4";
+               else
+                       tmp_str = devc->trigger_source;
+               *data = g_variant_new_string(tmp_str);
+               break;
+       case SR_CONF_TRIGGER_SLOPE:
+               if (!strcmp(devc->trigger_slope, "POS"))
+                       tmp_str = "r";
+               else if (!strcmp(devc->trigger_slope, "NEG"))
+                       tmp_str = "f";
+               else
+                       return SR_ERR_NA;
+               *data = g_variant_new_string(tmp_str);
+               break;
+       case SR_CONF_TIMEBASE:
+               for (i = 0; i < devc->num_timebases; i++) {
+                       float tb = (float)devc->timebases[i][0] / devc->timebases[i][1];
+                       float diff = fabs(devc->timebase - tb);
+                       if (diff < smallest_diff) {
+                               smallest_diff = diff;
+                               idx = i;
+                       }
+               }
+               if (idx < 0)
+                       return SR_ERR_NA;
+               *data = g_variant_new("(tt)", devc->timebases[idx][0],
+                                             devc->timebases[idx][1]);
+               break;
+       case SR_CONF_VDIV:
+               if (analog_channel < 0)
+                       return SR_ERR_NA;
+               for (i = 0; i < ARRAY_SIZE(vdivs); i++) {
+                       float vdiv = (float)vdivs[i][0] / vdivs[i][1];
+                       float diff = fabs(devc->vdiv[analog_channel] - vdiv);
+                       if (diff < smallest_diff) {
+                               smallest_diff = diff;
+                               idx = i;
+                       }
+               }
+               if (idx < 0)
+                       return SR_ERR_NA;
+               *data = g_variant_new("(tt)", vdivs[idx][0], vdivs[idx][1]);
+               break;
+       case SR_CONF_COUPLING:
+               if (analog_channel < 0)
+                       return SR_ERR_NA;
+               *data = g_variant_new_string(devc->coupling[analog_channel]);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       uint64_t p, q;
+       double t_dbl;
+       unsigned int i, j;
+       int ret;
+       const char *tmp_str;
+       char buffer[16];
+
+       if (!(devc = sdi->priv))
+               return SR_ERR_ARG;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       /* If a channel group is specified, it must be a valid one. */
+       if (cg && !g_slist_find(sdi->channel_groups, cg)) {
+               sr_err("Invalid channel group specified.");
+               return SR_ERR;
+       }
+
+       ret = SR_OK;
+       switch (id) {
+       case SR_CONF_LIMIT_FRAMES:
+               devc->limit_frames = g_variant_get_uint64(data);
+               break;
+       case SR_CONF_TRIGGER_SLOPE:
+               tmp_str = g_variant_get_string(data, NULL);
+
+               if (!tmp_str || !(tmp_str[0] == 'f' || tmp_str[0] == 'r'))
+                       return SR_ERR_ARG;
+
+               g_free(devc->trigger_slope);
+               devc->trigger_slope = g_strdup((tmp_str[0] == 'r') ? "POS" : "NEG");
+               ret = rigol_ds_config_set(sdi, ":TRIG:EDGE:SLOP %s", devc->trigger_slope);
+               break;
+       case SR_CONF_HORIZ_TRIGGERPOS:
+               t_dbl = g_variant_get_double(data);
+               if (t_dbl < 0.0 || t_dbl > 1.0)
+                       return SR_ERR;
+               devc->horiz_triggerpos = t_dbl;
+               /* We have the trigger offset as a percentage of the frame, but
+                * need to express this in seconds. */
+               t_dbl = -(devc->horiz_triggerpos - 0.5) * devc->timebase * devc->num_timebases;
+               g_ascii_formatd(buffer, sizeof(buffer), "%.6f", t_dbl);
+               ret = rigol_ds_config_set(sdi, ":TIM:OFFS %s", buffer);
+               break;
+       case SR_CONF_TIMEBASE:
+               g_variant_get(data, "(tt)", &p, &q);
+               for (i = 0; i < devc->num_timebases; i++) {
+                       if (devc->timebases[i][0] == p && devc->timebases[i][1] == q) {
+                               devc->timebase = (float)p / q;
+                               g_ascii_formatd(buffer, sizeof(buffer), "%.9f",
+                                               devc->timebase);
+                               ret = rigol_ds_config_set(sdi, ":TIM:SCAL %s", buffer);
+                               break;
+                       }
+               }
+               if (i == devc->num_timebases)
+                       ret = SR_ERR_ARG;
+               break;
+       case SR_CONF_TRIGGER_SOURCE:
+               tmp_str = g_variant_get_string(data, NULL);
+               for (i = 0; i < ARRAY_SIZE(trigger_sources); i++) {
+                       if (!strcmp(trigger_sources[i], tmp_str)) {
+                               g_free(devc->trigger_source);
+                               devc->trigger_source = g_strdup(trigger_sources[i]);
+                               if (!strcmp(devc->trigger_source, "AC Line"))
+                                       tmp_str = "ACL";
+                               else if (!strcmp(devc->trigger_source, "CH1"))
+                                       tmp_str = "CHAN1";
+                               else if (!strcmp(devc->trigger_source, "CH2"))
+                                       tmp_str = "CHAN2";
+                               else if (!strcmp(devc->trigger_source, "CH3"))
+                                       tmp_str = "CHAN3";
+                               else if (!strcmp(devc->trigger_source, "CH4"))
+                                       tmp_str = "CHAN4";
+                               else
+                                       tmp_str = (char *)devc->trigger_source;
+                               ret = rigol_ds_config_set(sdi, ":TRIG:EDGE:SOUR %s", tmp_str);
+                               break;
+                       }
+               }
+               if (i == ARRAY_SIZE(trigger_sources))
+                       ret = SR_ERR_ARG;
+               break;
+       case SR_CONF_VDIV:
+               if (!cg) {
+                       sr_err("No channel group specified.");
+                       return SR_ERR_CHANNEL_GROUP;
+               }
+               g_variant_get(data, "(tt)", &p, &q);
+               for (i = 0; i < 2; i++) {
+                       if (cg == &devc->analog_groups[i]) {
+                               for (j = 0; j < ARRAY_SIZE(vdivs); j++) {
+                                       if (vdivs[j][0] != p || vdivs[j][1] != q)
+                                               continue;
+                                       devc->vdiv[i] = (float)p / q;
+                                       g_ascii_formatd(buffer, sizeof(buffer), "%.3f",
+                                                       devc->vdiv[i]);
+                                       return rigol_ds_config_set(sdi, ":CHAN%d:SCAL %s", i + 1,
+                                                       buffer);
+                               }
+                               return SR_ERR_ARG;
+                       }
+               }
+               return SR_ERR_NA;
+       case SR_CONF_COUPLING:
+               if (!cg) {
+                       sr_err("No channel group specified.");
+                       return SR_ERR_CHANNEL_GROUP;
+               }
+               tmp_str = g_variant_get_string(data, NULL);
+               for (i = 0; i < 2; i++) {
+                       if (cg == &devc->analog_groups[i]) {
+                               for (j = 0; j < ARRAY_SIZE(coupling); j++) {
+                                       if (!strcmp(tmp_str, coupling[j])) {
+                                               g_free(devc->coupling[i]);
+                                               devc->coupling[i] = g_strdup(coupling[j]);
+                                               return rigol_ds_config_set(sdi, ":CHAN%d:COUP %s", i + 1,
+                                                               devc->coupling[i]);
+                                       }
+                               }
+                               return SR_ERR_ARG;
+                       }
+               }
+               return SR_ERR_NA;
+       case SR_CONF_DATA_SOURCE:
+               tmp_str = g_variant_get_string(data, NULL);
+               if (!strcmp(tmp_str, "Live"))
+                       devc->data_source = DATA_SOURCE_LIVE;
+               else if (devc->model->series->protocol >= PROTOCOL_V2
+                       && !strcmp(tmp_str, "Memory"))
+                       devc->data_source = DATA_SOURCE_MEMORY;
+               else if (devc->model->series->protocol >= PROTOCOL_V3
+                        && !strcmp(tmp_str, "Segmented"))
+                       devc->data_source = DATA_SOURCE_SEGMENTED;
+               else
+                       return SR_ERR;
+               break;
+       default:
+               ret = SR_ERR_NA;
+               break;
+       }
+
+       return ret;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       GVariant *tuple, *rational[2];
+       GVariantBuilder gvb;
+       unsigned int i;
+       struct dev_context *devc = NULL;
+
+       if (sdi)
+               devc = sdi->priv;
+
+       if (key == SR_CONF_SCAN_OPTIONS) {
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+               return SR_OK;
+       } else if (key == SR_CONF_DEVICE_OPTIONS && cg == NULL) {
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                       hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+               return SR_OK;
+       }
+
+       /* Every other option requires a valid device instance. */
+       if (!sdi || !(devc = sdi->priv))
+               return SR_ERR_ARG;
+
+       /* If a channel group is specified, it must be a valid one. */
+       if (cg) {
+               if (cg != &devc->analog_groups[0]
+                               && cg != &devc->analog_groups[1]) {
+                       sr_err("Invalid channel group specified.");
+                       return SR_ERR;
+               }
+       }
+
+       switch (key) {
+       case SR_CONF_DEVICE_OPTIONS:
+               if (!cg) {
+                       sr_err("No channel group specified.");
+                       return SR_ERR_CHANNEL_GROUP;
+               }
+               if (cg == &devc->digital_group) {
+                       *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               NULL, 0, sizeof(int32_t));
+                       return SR_OK;
+               } else {
+                       for (i = 0; i < 2; i++) {
+                               if (cg == &devc->analog_groups[i]) {
+                                       *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                                               analog_hwcaps, ARRAY_SIZE(analog_hwcaps), sizeof(int32_t));
+                                       return SR_OK;
+                               }
+                       }
+                       return SR_ERR_NA;
+               }
+               break;
+       case SR_CONF_COUPLING:
+               if (!cg) {
+                       sr_err("No channel group specified.");
+                       return SR_ERR_CHANNEL_GROUP;
+               }
+               *data = g_variant_new_strv(coupling, ARRAY_SIZE(coupling));
+               break;
+       case SR_CONF_VDIV:
+               if (!devc)
+                       /* Can't know this until we have the exact model. */
+                       return SR_ERR_ARG;
+               if (!cg) {
+                       sr_err("No channel group specified.");
+                       return SR_ERR_CHANNEL_GROUP;
+               }
+               g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
+               for (i = 0; i < NUM_VDIV; i++) {
+                       rational[0] = g_variant_new_uint64(devc->vdivs[i][0]);
+                       rational[1] = g_variant_new_uint64(devc->vdivs[i][1]);
+                       tuple = g_variant_new_tuple(rational, 2);
+                       g_variant_builder_add_value(&gvb, tuple);
+               }
+               *data = g_variant_builder_end(&gvb);
+               break;
+       case SR_CONF_TIMEBASE:
+               if (!devc)
+                       /* Can't know this until we have the exact model. */
+                       return SR_ERR_ARG;
+               if (devc->num_timebases <= 0)
+                       return SR_ERR_NA;
+               g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
+               for (i = 0; i < devc->num_timebases; i++) {
+                       rational[0] = g_variant_new_uint64(devc->timebases[i][0]);
+                       rational[1] = g_variant_new_uint64(devc->timebases[i][1]);
+                       tuple = g_variant_new_tuple(rational, 2);
+                       g_variant_builder_add_value(&gvb, tuple);
+               }
+               *data = g_variant_builder_end(&gvb);
+               break;
+       case SR_CONF_TRIGGER_SOURCE:
+               if (!devc)
+                       /* Can't know this until we have the exact model. */
+                       return SR_ERR_ARG;
+               *data = g_variant_new_strv(trigger_sources,
+                               devc->model->has_digital ? ARRAY_SIZE(trigger_sources) : 4);
+               break;
+       case SR_CONF_TRIGGER_SLOPE:
+               *data = g_variant_new_strv(trigger_slopes, ARRAY_SIZE(trigger_slopes));
+               break;
+       case SR_CONF_DATA_SOURCE:
+               if (!devc)
+                       /* Can't know this until we have the exact model. */
+                       return SR_ERR_ARG;
+               switch (devc->model->series->protocol) {
+               case PROTOCOL_V1:
+                       *data = g_variant_new_strv(data_sources, ARRAY_SIZE(data_sources) - 2);
+                       break;
+               case PROTOCOL_V2:
+                       *data = g_variant_new_strv(data_sources, ARRAY_SIZE(data_sources) - 1);
+                       break;
+               default:
+                       *data = g_variant_new_strv(data_sources, ARRAY_SIZE(data_sources));
+                       break;
+               }
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct sr_scpi_dev_inst *scpi;
+       struct dev_context *devc;
+       struct sr_channel *ch;
+       struct sr_datafeed_packet packet;
+       GSList *l;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       scpi = sdi->conn;
+       devc = sdi->priv;
+
+       devc->num_frames = 0;
+
+       for (l = sdi->channels; l; l = l->next) {
+               ch = l->data;
+               sr_dbg("handling channel %s", ch->name);
+               if (ch->type == SR_CHANNEL_ANALOG) {
+                       if (ch->enabled)
+                               devc->enabled_analog_channels = g_slist_append(
+                                               devc->enabled_analog_channels, ch);
+                       if (ch->enabled != devc->analog_channels[ch->index]) {
+                               /* Enabled channel is currently disabled, or vice versa. */
+                               if (rigol_ds_config_set(sdi, ":CHAN%d:DISP %s", ch->index + 1,
+                                               ch->enabled ? "ON" : "OFF") != SR_OK)
+                                       return SR_ERR;
+                               devc->analog_channels[ch->index] = ch->enabled;
+                       }
+               } else if (ch->type == SR_CHANNEL_LOGIC) {
+                       if (ch->enabled) {
+                               devc->enabled_digital_channels = g_slist_append(
+                                               devc->enabled_digital_channels, ch);
+                               /* Turn on LA module if currently off. */
+                               if (!devc->la_enabled) {
+                                       if (rigol_ds_config_set(sdi, ":LA:DISP ON") != SR_OK)
+                                               return SR_ERR;
+                                       devc->la_enabled = TRUE;
+                               }
+                       }
+                       if (ch->enabled != devc->digital_channels[ch->index]) {
+                               /* Enabled channel is currently disabled, or vice versa. */
+                               if (rigol_ds_config_set(sdi, ":DIG%d:TURN %s", ch->index,
+                                               ch->enabled ? "ON" : "OFF") != SR_OK)
+                                       return SR_ERR;
+                               devc->digital_channels[ch->index] = ch->enabled;
+                       }
+               }
+       }
+
+       if (!devc->enabled_analog_channels && !devc->enabled_digital_channels)
+               return SR_ERR;
+
+       /* Turn off LA module if on and no digital channels selected. */
+       if (devc->la_enabled && !devc->enabled_digital_channels)
+               if (rigol_ds_config_set(sdi, ":LA:DISP OFF") != SR_OK)
+                       return SR_ERR;
+
+       /* Set memory mode. */
+       if (devc->data_source == DATA_SOURCE_SEGMENTED) {
+               sr_err("Data source 'Segmented' not yet supported");
+               return SR_ERR;
+       }
+
+       devc->analog_frame_size = analog_frame_size(sdi);
+       devc->digital_frame_size = digital_frame_size(sdi);
+
+       switch (devc->model->series->protocol) {
+       case PROTOCOL_V2:
+               if (rigol_ds_config_set(sdi, ":ACQ:MEMD LONG") != SR_OK)
+                       return SR_ERR;
+               break;
+       case PROTOCOL_V3:
+               /* Apparently for the DS2000 the memory
+                * depth can only be set in Running state -
+                * this matches the behaviour of the UI. */
+               if (rigol_ds_config_set(sdi, ":RUN") != SR_OK)
+                       return SR_ERR;
+               if (rigol_ds_config_set(sdi, ":ACQ:MDEP %d",
+                                       devc->analog_frame_size) != SR_OK)
+                       return SR_ERR;
+               if (rigol_ds_config_set(sdi, ":STOP") != SR_OK)
+                       return SR_ERR;
+               break;
+       default:
+               break;
+       }
+
+       if (devc->data_source == DATA_SOURCE_LIVE)
+               if (rigol_ds_config_set(sdi, ":RUN") != SR_OK)
+                       return SR_ERR;
+
+       sr_scpi_source_add(sdi->session, scpi, G_IO_IN, 50,
+                       rigol_ds_receive, (void *)sdi);
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(cb_data, LOG_PREFIX);
+
+       if (devc->enabled_analog_channels)
+               devc->channel_entry = devc->enabled_analog_channels;
+       else
+               devc->channel_entry = devc->enabled_digital_channels;
+
+       if (rigol_ds_capture_start(sdi) != SR_OK)
+               return SR_ERR;
+
+       /* Start of first frame. */
+       packet.type = SR_DF_FRAME_BEGIN;
+       sr_session_send(cb_data, &packet);
+
+       return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct dev_context *devc;
+       struct sr_scpi_dev_inst *scpi;
+       struct sr_datafeed_packet packet;
+
+       (void)cb_data;
+
+       devc = sdi->priv;
+
+       if (sdi->status != SR_ST_ACTIVE) {
+               sr_err("Device inactive, can't stop acquisition.");
+               return SR_ERR;
+       }
+
+       /* End of last frame. */
+       packet.type = SR_DF_END;
+       sr_session_send(sdi, &packet);
+
+       g_slist_free(devc->enabled_analog_channels);
+       g_slist_free(devc->enabled_digital_channels);
+       devc->enabled_analog_channels = NULL;
+       devc->enabled_digital_channels = NULL;
+       scpi = sdi->conn;
+       sr_scpi_source_remove(sdi->session, scpi);
+
+       return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver rigol_ds_driver_info = {
+       .name = "rigol-ds",
+       .longname = "Rigol DS",
+       .api_version = 1,
+       .init = init,
+       .cleanup = cleanup,
+       .scan = scan,
+       .dev_list = dev_list,
+       .dev_clear = dev_clear,
+       .config_get = config_get,
+       .config_set = config_set,
+       .config_list = config_list,
+       .dev_open = dev_open,
+       .dev_close = dev_close,
+       .dev_acquisition_start = dev_acquisition_start,
+       .dev_acquisition_stop = dev_acquisition_stop,
+       .priv = NULL,
+};
diff --git a/src/hardware/rigol-ds/protocol.c b/src/hardware/rigol-ds/protocol.c
new file mode 100644 (file)
index 0000000..97cb353
--- /dev/null
@@ -0,0 +1,812 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Martin Ling <martin-git@earth.li>
+ * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
+ * Copyright (C) 2013 Mathias Grimmberger <mgri@zaphod.sax.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 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 <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <math.h>
+#include <ctype.h>
+#include <time.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "protocol.h"
+
+/*
+ * This is a unified protocol driver for the DS1000 and DS2000 series.
+ *
+ * DS1000 support tested with a Rigol DS1102D.
+ *
+ * DS2000 support tested with a Rigol DS2072 using firmware version 01.01.00.02.
+ *
+ * The Rigol DS2000 series scopes try to adhere to the IEEE 488.2 (I think)
+ * standard. If you want to read it - it costs real money...
+ *
+ * Every response from the scope has a linefeed appended because the
+ * standard says so. In principle this could be ignored because sending the
+ * next command clears the output queue of the scope. This driver tries to
+ * avoid doing that because it may cause an error being generated inside the
+ * scope and who knows what bugs the firmware has WRT this.
+ *
+ * Waveform data is transferred in a format called "arbitrary block program
+ * data" specified in IEEE 488.2. See Agilents programming manuals for their
+ * 2000/3000 series scopes for a nice description.
+ *
+ * Each data block from the scope has a header, e.g. "#900000001400".
+ * The '#' marks the start of a block.
+ * Next is one ASCII decimal digit between 1 and 9, this gives the number of
+ * ASCII decimal digits following.
+ * Last are the ASCII decimal digits giving the number of bytes (not
+ * samples!) in the block.
+ *
+ * After this header as many data bytes as indicated follow.
+ *
+ * Each data block has a trailing linefeed too.
+ */
+
+static int parse_int(const char *str, int *ret)
+{
+       char *e;
+       long tmp;
+
+       errno = 0;
+       tmp = strtol(str, &e, 10);
+       if (e == str || *e != '\0') {
+               sr_dbg("Failed to parse integer: '%s'", str);
+               return SR_ERR;
+       }
+       if (errno) {
+               sr_dbg("Failed to parse integer: '%s', numerical overflow", str);
+               return SR_ERR;
+       }
+       if (tmp > INT_MAX || tmp < INT_MIN) {
+               sr_dbg("Failed to parse integer: '%s', value to large/small", str);
+               return SR_ERR;
+       }
+
+       *ret = (int)tmp;
+       return SR_OK;
+}
+
+/* Set the next event to wait for in rigol_ds_receive */
+static void rigol_ds_set_wait_event(struct dev_context *devc, enum wait_events event)
+{
+       if (event == WAIT_STOP)
+               devc->wait_status = 2;
+       else
+               devc->wait_status = 1;
+       devc->wait_event = event;
+}
+
+/*
+ * Waiting for a event will return a timeout after 2 to 3 seconds in order
+ * to not block the application.
+ */
+static int rigol_ds_event_wait(const struct sr_dev_inst *sdi, char status1, char status2)
+{
+       char *buf;
+       struct dev_context *devc;
+       time_t start;
+
+       if (!(devc = sdi->priv))
+               return SR_ERR;
+
+       start = time(NULL);
+
+       /*
+        * Trigger status may return:
+        * "TD" or "T'D" - triggered
+        * "AUTO"        - autotriggered
+        * "RUN"         - running
+        * "WAIT"        - waiting for trigger
+        * "STOP"        - stopped
+        */
+
+       if (devc->wait_status == 1) {
+               do {
+                       if (time(NULL) - start >= 3) {
+                               sr_dbg("Timeout waiting for trigger");
+                               return SR_ERR_TIMEOUT;
+                       }
+
+                       if (sr_scpi_get_string(sdi->conn, ":TRIG:STAT?", &buf) != SR_OK)
+                               return SR_ERR;
+               } while (buf[0] == status1 || buf[0] == status2);
+
+               devc->wait_status = 2;
+       }
+       if (devc->wait_status == 2) {
+               do {
+                       if (time(NULL) - start >= 3) {
+                               sr_dbg("Timeout waiting for trigger");
+                               return SR_ERR_TIMEOUT;
+                       }
+
+                       if (sr_scpi_get_string(sdi->conn, ":TRIG:STAT?", &buf) != SR_OK)
+                               return SR_ERR;
+               } while (buf[0] != status1 && buf[0] != status2);
+
+               rigol_ds_set_wait_event(devc, WAIT_NONE);
+       }
+
+       return SR_OK;
+}
+
+/*
+ * For live capture we need to wait for a new trigger event to ensure that
+ * sample data is not returned twice.
+ *
+ * Unfortunately this will never really work because for sufficiently fast
+ * timebases and trigger rates it just can't catch the status changes.
+ *
+ * What would be needed is a trigger event register with autoreset like the
+ * Agilents have. The Rigols don't seem to have anything like this.
+ *
+ * The workaround is to only wait for the trigger when the timebase is slow
+ * enough. Of course this means that for faster timebases sample data can be
+ * returned multiple times, this effect is mitigated somewhat by sleeping
+ * for about one sweep time in that case.
+ */
+static int rigol_ds_trigger_wait(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       long s;
+
+       if (!(devc = sdi->priv))
+               return SR_ERR;
+
+       /* 
+        * If timebase < 50 msecs/DIV just sleep about one sweep time except
+        * for really fast sweeps.
+        */
+       if (devc->timebase < 0.0499) {
+               if (devc->timebase > 0.99e-6) {
+                       /*
+                        * Timebase * num hor. divs * 85(%) * 1e6(usecs) / 100
+                        * -> 85 percent of sweep time
+                        */
+                       s = (devc->timebase * devc->model->series->num_horizontal_divs
+                            * 85e6) / 100L;
+                       sr_spew("Sleeping for %ld usecs instead of trigger-wait", s);
+                       g_usleep(s);
+               }
+               rigol_ds_set_wait_event(devc, WAIT_NONE);
+               return SR_OK;
+       } else {
+               return rigol_ds_event_wait(sdi, 'T', 'A');
+       }
+}
+
+/* Wait for scope to got to "Stop" in single shot mode */
+static int rigol_ds_stop_wait(const struct sr_dev_inst *sdi)
+{
+       return rigol_ds_event_wait(sdi, 'S', 'S');
+}
+
+/* Check that a single shot acquisition actually succeeded on the DS2000 */
+static int rigol_ds_check_stop(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_channel *ch;
+       int tmp;
+
+       if (!(devc = sdi->priv))
+               return SR_ERR;
+
+       ch = devc->channel_entry->data;
+
+       if (devc->model->series->protocol <= PROTOCOL_V2)
+               return SR_OK;
+
+       if (rigol_ds_config_set(sdi, ":WAV:SOUR CHAN%d",
+                         ch->index + 1) != SR_OK)
+               return SR_ERR;
+       /* Check that the number of samples will be accepted */
+       if (rigol_ds_config_set(sdi, ":WAV:POIN %d", devc->analog_frame_size) != SR_OK)
+               return SR_ERR;
+       if (sr_scpi_get_int(sdi->conn, "*ESR?", &tmp) != SR_OK)
+               return SR_ERR;
+       /*
+        * If we get an "Execution error" the scope went from "Single" to
+        * "Stop" without actually triggering. There is no waveform
+        * displayed and trying to download one will fail - the scope thinks
+        * it has 1400 samples (like display memory) and the driver thinks
+        * it has a different number of samples.
+        *
+        * In that case just try to capture something again. Might still
+        * fail in interesting ways.
+        *
+        * Ain't firmware fun?
+        */
+       if (tmp & 0x10) {
+               sr_warn("Single shot acquisition failed, retrying...");
+               /* Sleep a bit, otherwise the single shot will often fail */
+               g_usleep(500000);
+               rigol_ds_config_set(sdi, ":SING");
+               rigol_ds_set_wait_event(devc, WAIT_STOP);
+               return SR_ERR;
+       }
+
+       return SR_OK;
+}
+
+/* Wait for enough data becoming available in scope output buffer */
+static int rigol_ds_block_wait(const struct sr_dev_inst *sdi)
+{
+       char *buf;
+       struct dev_context *devc;
+       time_t start;
+       int len;
+
+       if (!(devc = sdi->priv))
+               return SR_ERR;
+
+       if (devc->model->series->protocol >= PROTOCOL_V3) {
+
+               start = time(NULL);
+
+               do {
+                       if (time(NULL) - start >= 3) {
+                               sr_dbg("Timeout waiting for data block");
+                               return SR_ERR_TIMEOUT;
+                       }
+
+                       /*
+                        * The scope copies data really slowly from sample
+                        * memory to its output buffer, so try not to bother
+                        * it too much with SCPI requests but don't wait too
+                        * long for short sample frame sizes.
+                        */
+                       g_usleep(devc->analog_frame_size < 15000 ? 100000 : 1000000);
+
+                       /* "READ,nnnn" (still working) or "IDLE,nnnn" (finished) */
+                       if (sr_scpi_get_string(sdi->conn, ":WAV:STAT?", &buf) != SR_OK)
+                               return SR_ERR;
+
+                       if (parse_int(buf + 5, &len) != SR_OK)
+                               return SR_ERR;
+               } while (buf[0] == 'R' && len < 1000000);
+       }
+
+       rigol_ds_set_wait_event(devc, WAIT_NONE);
+
+       return SR_OK;
+}
+
+/* Send a configuration setting. */
+SR_PRIV int rigol_ds_config_set(const struct sr_dev_inst *sdi, const char *format, ...)
+{
+       struct dev_context *devc = sdi->priv;
+       va_list args;
+       int ret;
+
+       va_start(args, format);
+       ret = sr_scpi_send_variadic(sdi->conn, format, args);
+       va_end(args);
+
+       if (ret != SR_OK)
+               return SR_ERR;
+
+       if (devc->model->series->protocol == PROTOCOL_V2) {
+               /* The DS1000 series needs this stupid delay, *OPC? doesn't work. */
+               sr_spew("delay %dms", 100);
+               g_usleep(100000);
+               return SR_OK;
+       } else {
+               return sr_scpi_get_opc(sdi->conn);
+       }
+}
+
+/* Start capturing a new frameset */
+SR_PRIV int rigol_ds_capture_start(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       gchar *trig_mode;
+
+       if (!(devc = sdi->priv))
+               return SR_ERR;
+
+       sr_dbg("Starting data capture for frameset %lu of %lu",
+              devc->num_frames + 1, devc->limit_frames);
+
+       switch (devc->model->series->protocol) {
+       case PROTOCOL_V1:
+               rigol_ds_set_wait_event(devc, WAIT_TRIGGER);
+               break;
+       case PROTOCOL_V2:
+               if (devc->data_source == DATA_SOURCE_LIVE) {
+                       if (rigol_ds_config_set(sdi, ":WAV:POIN:MODE NORMAL") != SR_OK)
+                               return SR_ERR;
+                       rigol_ds_set_wait_event(devc, WAIT_TRIGGER);
+               } else {
+                       if (rigol_ds_config_set(sdi, ":STOP") != SR_OK)
+                               return SR_ERR;
+                       if (rigol_ds_config_set(sdi, ":WAV:POIN:MODE RAW") != SR_OK)
+                               return SR_ERR;
+                       if (sr_scpi_get_string(sdi->conn, ":TRIG:MODE?", &trig_mode) != SR_OK)
+                               return SR_ERR;
+                       if (rigol_ds_config_set(sdi, ":TRIG:%s:SWE SING", trig_mode) != SR_OK)
+                               return SR_ERR;
+                       if (rigol_ds_config_set(sdi, ":RUN") != SR_OK)
+                               return SR_ERR;
+                       rigol_ds_set_wait_event(devc, WAIT_STOP);
+               }
+               break;
+       case PROTOCOL_V3:
+               if (rigol_ds_config_set(sdi, ":WAV:FORM BYTE") != SR_OK)
+                       return SR_ERR;
+               if (devc->data_source == DATA_SOURCE_LIVE) {
+                       if (rigol_ds_config_set(sdi, ":WAV:MODE NORM") != SR_OK)
+                               return SR_ERR;
+                       rigol_ds_set_wait_event(devc, WAIT_TRIGGER);
+               } else {
+                       if (rigol_ds_config_set(sdi, ":WAV:MODE RAW") != SR_OK)
+                               return SR_ERR;
+                       if (rigol_ds_config_set(sdi, ":SING") != SR_OK)
+                               return SR_ERR;
+                       rigol_ds_set_wait_event(devc, WAIT_STOP);
+               }
+               break;
+       }
+
+       return SR_OK;
+}
+
+/* Start reading data from the current channel */
+SR_PRIV int rigol_ds_channel_start(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_channel *ch;
+
+       if (!(devc = sdi->priv))
+               return SR_ERR;
+
+       ch = devc->channel_entry->data;
+
+       sr_dbg("Starting reading data from channel %d", ch->index + 1);
+
+       if (devc->model->series->protocol <= PROTOCOL_V2) {
+               if (ch->type == SR_CHANNEL_LOGIC) {
+                       if (sr_scpi_send(sdi->conn, ":WAV:DATA? DIG") != SR_OK)
+                               return SR_ERR;
+               } else {
+                       if (sr_scpi_send(sdi->conn, ":WAV:DATA? CHAN%d",
+                                       ch->index + 1) != SR_OK)
+                               return SR_ERR;
+               }
+               rigol_ds_set_wait_event(devc, WAIT_NONE);
+       } else {
+               if (rigol_ds_config_set(sdi, ":WAV:SOUR CHAN%d",
+                                 ch->index + 1) != SR_OK)
+                       return SR_ERR;
+               if (devc->data_source != DATA_SOURCE_LIVE) {
+                       if (rigol_ds_config_set(sdi, ":WAV:RES") != SR_OK)
+                               return SR_ERR;
+                       if (rigol_ds_config_set(sdi, ":WAV:BEG") != SR_OK)
+                               return SR_ERR;
+               }
+       }
+
+       rigol_ds_set_wait_event(devc, WAIT_BLOCK);
+
+       devc->num_channel_bytes = 0;
+       devc->num_header_bytes = 0;
+       devc->num_block_bytes = 0;
+
+       return SR_OK;
+}
+
+/* Read the header of a data block */
+static int rigol_ds_read_header(struct sr_dev_inst *sdi)
+{
+       struct sr_scpi_dev_inst *scpi = sdi->conn;
+       struct dev_context *devc = sdi->priv;
+       char *buf = (char *) devc->buffer;
+       size_t header_length;
+       int ret;
+
+       /* Try to read the hashsign and length digit. */
+       if (devc->num_header_bytes < 2) {
+               ret = sr_scpi_read_data(scpi, buf + devc->num_header_bytes,
+                               2 - devc->num_header_bytes);
+               if (ret < 0) {
+                       sr_err("Read error while reading data header.");
+                       return SR_ERR;
+               }
+               devc->num_header_bytes += ret;
+       }
+
+       if (devc->num_header_bytes < 2)
+               return 0;
+
+       if (buf[0] != '#' || !isdigit(buf[1]) || buf[1] == '0') {
+               sr_err("Received invalid data block header '%c%c'.", buf[0], buf[1]);
+               return SR_ERR;
+       }
+
+       header_length = 2 + buf[1] - '0';
+
+       /* Try to read the length. */
+       if (devc->num_header_bytes < header_length) {
+               ret = sr_scpi_read_data(scpi, buf + devc->num_header_bytes,
+                               header_length - devc->num_header_bytes);
+               if (ret < 0) {
+                       sr_err("Read error while reading data header.");
+                       return SR_ERR;
+               }
+               devc->num_header_bytes += ret;
+       }
+
+       if (devc->num_header_bytes < header_length)
+               return 0;
+
+       /* Read the data length. */
+       buf[header_length] = '\0';
+
+       if (parse_int(buf + 2, &ret) != SR_OK) {
+               sr_err("Received invalid data block length '%s'.", buf + 2);
+               return -1;
+       }
+
+       sr_dbg("Received data block header: '%s' -> block length %d", buf, ret);
+
+       return ret;
+}
+
+SR_PRIV int rigol_ds_receive(int fd, int revents, void *cb_data)
+{
+       struct sr_dev_inst *sdi;
+       struct sr_scpi_dev_inst *scpi;
+       struct dev_context *devc;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_analog analog;
+       struct sr_datafeed_logic logic;
+       double vdiv, offset;
+       int len, i, vref;
+       struct sr_channel *ch;
+       gsize expected_data_bytes;
+
+       (void)fd;
+
+       if (!(sdi = cb_data))
+               return TRUE;
+
+       if (!(devc = sdi->priv))
+               return TRUE;
+
+       scpi = sdi->conn;
+
+       if (revents == G_IO_IN || revents == 0) {
+               switch(devc->wait_event) {
+               case WAIT_NONE:
+                       break;
+               case WAIT_TRIGGER:
+                       if (rigol_ds_trigger_wait(sdi) != SR_OK)
+                               return TRUE;
+                       if (rigol_ds_channel_start(sdi) != SR_OK)
+                               return TRUE;
+                       return TRUE;
+               case WAIT_BLOCK:
+                       if (rigol_ds_block_wait(sdi) != SR_OK)
+                               return TRUE;
+                       break;
+               case WAIT_STOP:
+                       if (rigol_ds_stop_wait(sdi) != SR_OK)
+                               return TRUE;
+                       if (rigol_ds_check_stop(sdi) != SR_OK)
+                               return TRUE;
+                       if (rigol_ds_channel_start(sdi) != SR_OK)
+                               return TRUE;
+                       return TRUE;
+               default:
+                       sr_err("BUG: Unknown event target encountered");
+               }
+
+               ch = devc->channel_entry->data;
+
+               expected_data_bytes = ch->type == SR_CHANNEL_ANALOG ?
+                               devc->analog_frame_size : devc->digital_frame_size;
+
+               if (devc->num_block_bytes == 0) {
+                       if (devc->model->series->protocol >= PROTOCOL_V3)
+                               if (sr_scpi_send(sdi->conn, ":WAV:DATA?") != SR_OK)
+                                       return TRUE;
+
+                       if (sr_scpi_read_begin(scpi) != SR_OK)
+                               return TRUE;
+
+                       if (devc->format == FORMAT_IEEE488_2) {
+                               sr_dbg("New block header expected");
+                               len = rigol_ds_read_header(sdi);
+                               if (len == 0)
+                                       /* Still reading the header. */
+                                       return TRUE;
+                               if (len == -1) {
+                                       sr_err("Read error, aborting capture.");
+                                       packet.type = SR_DF_FRAME_END;
+                                       sr_session_send(cb_data, &packet);
+                                       sdi->driver->dev_acquisition_stop(sdi, cb_data);
+                                       return TRUE;
+                               }
+                               /* At slow timebases in live capture the DS2072
+                                * sometimes returns "short" data blocks, with
+                                * apparently no way to get the rest of the data.
+                                * Discard these, the complete data block will
+                                * appear eventually.
+                                */
+                               if (devc->data_source == DATA_SOURCE_LIVE
+                                               && (unsigned)len < expected_data_bytes) {
+                                       sr_dbg("Discarding short data block");
+                                       sr_scpi_read_data(scpi, (char *)devc->buffer, len + 1);
+                                       return TRUE;
+                               }
+                               devc->num_block_bytes = len;
+                       } else {
+                               devc->num_block_bytes = expected_data_bytes;
+                       }
+                       devc->num_block_read = 0;
+               }
+
+               len = devc->num_block_bytes - devc->num_block_read;
+               if (len > ACQ_BUFFER_SIZE)
+                       len = ACQ_BUFFER_SIZE;
+               sr_dbg("Requesting read of %d bytes", len);
+
+               len = sr_scpi_read_data(scpi, (char *)devc->buffer, len);
+
+               if (len == -1) {
+                       sr_err("Read error, aborting capture.");
+                       packet.type = SR_DF_FRAME_END;
+                       sr_session_send(cb_data, &packet);
+                       sdi->driver->dev_acquisition_stop(sdi, cb_data);
+                       return TRUE;
+               }
+
+               sr_dbg("Received %d bytes.", len);
+
+               devc->num_block_read += len;
+
+               if (ch->type == SR_CHANNEL_ANALOG) {
+                       vref = devc->vert_reference[ch->index];
+                       vdiv = devc->vdiv[ch->index] / 25.6;
+                       offset = devc->vert_offset[ch->index];
+                       if (devc->model->series->protocol >= PROTOCOL_V3)
+                               for (i = 0; i < len; i++)
+                                       devc->data[i] = ((int)devc->buffer[i] - vref) * vdiv - offset;
+                       else
+                               for (i = 0; i < len; i++)
+                                       devc->data[i] = (128 - devc->buffer[i]) * vdiv - offset;
+                       analog.channels = g_slist_append(NULL, ch);
+                       analog.num_samples = len;
+                       analog.data = devc->data;
+                       analog.mq = SR_MQ_VOLTAGE;
+                       analog.unit = SR_UNIT_VOLT;
+                       analog.mqflags = 0;
+                       packet.type = SR_DF_ANALOG;
+                       packet.payload = &analog;
+                       sr_session_send(cb_data, &packet);
+                       g_slist_free(analog.channels);
+               } else {
+                       logic.length = len;
+                       logic.unitsize = 2;
+                       logic.data = devc->buffer;
+                       packet.type = SR_DF_LOGIC;
+                       packet.payload = &logic;
+                       sr_session_send(cb_data, &packet);
+               }
+
+               if (devc->num_block_read == devc->num_block_bytes) {
+                       sr_dbg("Block has been completed");
+                       if (devc->model->series->protocol >= PROTOCOL_V3) {
+                               /* Discard the terminating linefeed */
+                               sr_scpi_read_data(scpi, (char *)devc->buffer, 1);
+                       }
+                       if (devc->format == FORMAT_IEEE488_2) {
+                               /* Prepare for possible next block */
+                               devc->num_header_bytes = 0;
+                               devc->num_block_bytes = 0;
+                               if (devc->data_source != DATA_SOURCE_LIVE)
+                                       rigol_ds_set_wait_event(devc, WAIT_BLOCK);
+                       }
+                       if (!sr_scpi_read_complete(scpi)) {
+                               sr_err("Read should have been completed");
+                               packet.type = SR_DF_FRAME_END;
+                               sr_session_send(cb_data, &packet);
+                               sdi->driver->dev_acquisition_stop(sdi, cb_data);
+                               return TRUE;
+                       }
+                       devc->num_block_read = 0;
+               } else {
+                       sr_dbg("%d of %d block bytes read", devc->num_block_read, devc->num_block_bytes);
+               }
+
+               devc->num_channel_bytes += len;
+
+               if (devc->num_channel_bytes < expected_data_bytes)
+                       /* Don't have the full data for this channel yet, re-run. */
+                       return TRUE;
+
+               /* End of data for this channel. */
+               if (devc->model->series->protocol >= PROTOCOL_V3) {
+                       /* Signal end of data download to scope */
+                       if (devc->data_source != DATA_SOURCE_LIVE)
+                               /*
+                                * This causes a query error, without it switching
+                                * to the next channel causes an error. Fun with
+                                * firmware...
+                                */
+                               rigol_ds_config_set(sdi, ":WAV:END");
+               }
+
+               if (ch->type == SR_CHANNEL_ANALOG
+                               && devc->channel_entry->next != NULL) {
+                       /* We got the frame for this analog channel, but
+                        * there's another analog channel. */
+                       devc->channel_entry = devc->channel_entry->next;
+                       rigol_ds_channel_start(sdi);
+               } else {
+                       /* Done with all analog channels in this frame. */
+                       if (devc->enabled_digital_channels
+                                       && devc->channel_entry != devc->enabled_digital_channels) {
+                               /* Now we need to get the digital data. */
+                               devc->channel_entry = devc->enabled_digital_channels;
+                               rigol_ds_channel_start(sdi);
+                       } else {
+                               /* Done with this frame. */
+                               packet.type = SR_DF_FRAME_END;
+                               sr_session_send(cb_data, &packet);
+
+                               if (++devc->num_frames == devc->limit_frames) {
+                                       /* Last frame, stop capture. */
+                                       sdi->driver->dev_acquisition_stop(sdi, cb_data);
+                               } else {
+                                       /* Get the next frame, starting with the first analog channel. */
+                                       if (devc->enabled_analog_channels)
+                                               devc->channel_entry = devc->enabled_analog_channels;
+                                       else
+                                               devc->channel_entry = devc->enabled_digital_channels;
+
+                                       rigol_ds_capture_start(sdi);
+
+                                       /* Start of next frame. */
+                                       packet.type = SR_DF_FRAME_BEGIN;
+                                       sr_session_send(cb_data, &packet);
+                               }
+                       }
+               }
+       }
+
+       return TRUE;
+}
+
+SR_PRIV int rigol_ds_get_dev_cfg(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       char *t_s, *cmd;
+       unsigned int i;
+       int res;
+
+       devc = sdi->priv;
+
+       /* Analog channel state. */
+       for (i = 0; i < devc->model->analog_channels; i++) {
+               cmd = g_strdup_printf(":CHAN%d:DISP?", i + 1);
+               res = sr_scpi_get_string(sdi->conn, cmd, &t_s);
+               g_free(cmd);
+               if (res != SR_OK)
+                       return SR_ERR;
+               devc->analog_channels[i] = !strcmp(t_s, "ON") || !strcmp(t_s, "1");
+       }
+       sr_dbg("Current analog channel state:");
+       for (i = 0; i < devc->model->analog_channels; i++)
+               sr_dbg("CH%d %s", i + 1, devc->analog_channels[i] ? "on" : "off");
+
+       /* Digital channel state. */
+       if (devc->model->has_digital) {
+               if (sr_scpi_get_string(sdi->conn, ":LA:DISP?", &t_s) != SR_OK)
+                       return SR_ERR;
+               devc->la_enabled = !strcmp(t_s, "ON") ? TRUE : FALSE;
+               sr_dbg("Logic analyzer %s, current digital channel state:",
+                               devc->la_enabled ? "enabled" : "disabled");
+               for (i = 0; i < 16; i++) {
+                       cmd = g_strdup_printf(":DIG%d:TURN?", i);
+                       res = sr_scpi_get_string(sdi->conn, cmd, &t_s);
+                       g_free(cmd);
+                       if (res != SR_OK)
+                               return SR_ERR;
+                       devc->digital_channels[i] = !strcmp(t_s, "ON") ? TRUE : FALSE;
+                       g_free(t_s);
+                       sr_dbg("D%d: %s", i, devc->digital_channels[i] ? "on" : "off");
+               }
+       }
+
+       /* Timebase. */
+       if (sr_scpi_get_float(sdi->conn, ":TIM:SCAL?", &devc->timebase) != SR_OK)
+               return SR_ERR;
+       sr_dbg("Current timebase %g", devc->timebase);
+
+       /* Vertical gain. */
+       for (i = 0; i < devc->model->analog_channels; i++) {
+               cmd = g_strdup_printf(":CHAN%d:SCAL?", i + 1);
+               res = sr_scpi_get_float(sdi->conn, cmd, &devc->vdiv[i]);
+               g_free(cmd);
+               if (res != SR_OK)
+                       return SR_ERR;
+       }
+       sr_dbg("Current vertical gain:");
+       for (i = 0; i < devc->model->analog_channels; i++)
+               sr_dbg("CH%d %g", i + 1, devc->vdiv[i]);
+
+       sr_dbg("Current vertical reference:");
+       if (devc->model->series->protocol >= PROTOCOL_V3) {
+               /* Vertical reference - not certain if this is the place to read it. */
+               for (i = 0; i < devc->model->analog_channels; i++) {
+                       if (rigol_ds_config_set(sdi, ":WAV:SOUR CHAN%d", i + 1) != SR_OK)
+                               return SR_ERR;
+                       if (sr_scpi_get_int(sdi->conn, ":WAV:YREF?", &devc->vert_reference[i]) != SR_OK)
+                               return SR_ERR;
+                       sr_dbg("CH%d %d", i + 1, devc->vert_reference[i]);
+               }
+       }
+
+       /* Vertical offset. */
+       for (i = 0; i < devc->model->analog_channels; i++) {
+               cmd = g_strdup_printf(":CHAN%d:OFFS?", i + 1);
+               res = sr_scpi_get_float(sdi->conn, cmd, &devc->vert_offset[i]);
+               g_free(cmd);
+               if (res != SR_OK)
+                       return SR_ERR;
+       }
+       sr_dbg("Current vertical offset:");
+       for (i = 0; i < devc->model->analog_channels; i++)
+               sr_dbg("CH%d %g", i + 1, devc->vert_offset[i]);
+
+       /* Coupling. */
+       for (i = 0; i < devc->model->analog_channels; i++) {
+               cmd = g_strdup_printf(":CHAN%d:COUP?", i + 1);
+               res = sr_scpi_get_string(sdi->conn, cmd, &devc->coupling[i]);
+               g_free(cmd);
+               if (res != SR_OK)
+                       return SR_ERR;
+       }
+       sr_dbg("Current coupling:");
+       for (i = 0; i < devc->model->analog_channels; i++)
+               sr_dbg("CH%d %s", i + 1, devc->coupling[i]);
+
+       /* Trigger source. */
+       if (sr_scpi_get_string(sdi->conn, ":TRIG:EDGE:SOUR?", &devc->trigger_source) != SR_OK)
+               return SR_ERR;
+       sr_dbg("Current trigger source %s", devc->trigger_source);
+
+       /* Horizontal trigger position. */
+       if (sr_scpi_get_float(sdi->conn, ":TIM:OFFS?", &devc->horiz_triggerpos) != SR_OK)
+               return SR_ERR;
+       sr_dbg("Current horizontal trigger position %g", devc->horiz_triggerpos);
+
+       /* Trigger slope. */
+       if (sr_scpi_get_string(sdi->conn, ":TRIG:EDGE:SLOP?", &devc->trigger_slope) != SR_OK)
+               return SR_ERR;
+       sr_dbg("Current trigger slope %s", devc->trigger_slope);
+
+       return SR_OK;
+}
diff --git a/src/hardware/rigol-ds/protocol.h b/src/hardware/rigol-ds/protocol.h
new file mode 100644 (file)
index 0000000..0117628
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Martin Ling <martin-git@earth.li>
+ * Copyright (C) 2013 Bert Vermeulen <bert@biot.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_RIGOL_DS_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_RIGOL_DS_PROTOCOL_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "rigol-ds"
+
+/* Size of acquisition buffers */
+#define ACQ_BUFFER_SIZE 32768
+
+#define MAX_ANALOG_CHANNELS 4
+#define MAX_DIGITAL_CHANNELS 16
+
+enum protocol_version {
+       PROTOCOL_V1, /* VS5000 */
+       PROTOCOL_V2, /* DS1000 */
+       PROTOCOL_V3, /* DS2000, DSO1000 */
+};
+
+enum data_format {
+       /* Used by DS1000 versions up to 2.02, and VS5000 series */
+       FORMAT_RAW,
+       /* Used by DS1000 versions from 2.04 onwards and all later series */
+       FORMAT_IEEE488_2,
+};
+
+enum data_source {
+       DATA_SOURCE_LIVE,
+       DATA_SOURCE_MEMORY,
+       DATA_SOURCE_SEGMENTED,
+};
+
+struct rigol_ds_vendor {
+       const char *name;
+       const char *full_name;
+};
+
+struct rigol_ds_series {
+       const struct rigol_ds_vendor *vendor;
+       const char *name;
+       enum protocol_version protocol;
+       enum data_format format;
+       uint64_t max_timebase[2];
+       uint64_t min_vdiv[2];
+       int num_horizontal_divs;
+       int live_samples;
+       int buffer_samples;
+};
+
+struct rigol_ds_model {
+       const struct rigol_ds_series *series;
+       const char *name;
+       uint64_t min_timebase[2];
+       unsigned int analog_channels;
+       bool has_digital;
+};
+
+enum wait_events {
+       WAIT_NONE,    /* Don't wait */
+       WAIT_TRIGGER, /* Wait for trigger (only live capture) */
+       WAIT_BLOCK,   /* Wait for block data (only when reading sample mem) */
+       WAIT_STOP,    /* Wait for scope stopping (only single shots) */
+};
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+       /* Device model */
+       const struct rigol_ds_model *model;
+       enum data_format format;
+
+       /* Device properties */
+       const uint64_t (*timebases)[2];
+       uint64_t num_timebases;
+       const uint64_t (*vdivs)[2];
+       uint64_t num_vdivs;
+
+       /* Channel groups */
+       struct sr_channel_group analog_groups[MAX_ANALOG_CHANNELS];
+       struct sr_channel_group digital_group;
+
+       /* Acquisition settings */
+       GSList *enabled_analog_channels;
+       GSList *enabled_digital_channels;
+       uint64_t limit_frames;
+       void *cb_data;
+       enum data_source data_source;
+       uint64_t analog_frame_size;
+       uint64_t digital_frame_size;
+
+       /* Device settings */
+       gboolean analog_channels[MAX_ANALOG_CHANNELS];
+       gboolean digital_channels[MAX_DIGITAL_CHANNELS];
+       gboolean la_enabled;
+       float timebase;
+       float vdiv[MAX_ANALOG_CHANNELS];
+       int vert_reference[MAX_ANALOG_CHANNELS];
+       float vert_offset[MAX_ANALOG_CHANNELS];
+       char *trigger_source;
+       float horiz_triggerpos;
+       char *trigger_slope;
+       char *coupling[MAX_ANALOG_CHANNELS];
+
+       /* Operational state */
+
+       /* Number of frames received in total. */
+       uint64_t num_frames;
+       /* GSList entry for the current channel. */
+       GSList *channel_entry;
+       /* Number of bytes received for current channel. */
+       uint64_t num_channel_bytes;
+       /* Number of bytes of block header read */
+       uint64_t num_header_bytes;
+       /* Number of bytes in current data block, if 0 block header expected */
+       uint64_t num_block_bytes;
+       /* Number of data block bytes already read */
+       uint64_t num_block_read;
+       /* What to wait for in *_receive */
+       enum wait_events wait_event;
+       /* Trigger/block copying/stop waiting status */
+       int wait_status;
+       /* Acq buffers used for reading from the scope and sending data to app */
+       unsigned char *buffer;
+       float *data;
+};
+
+SR_PRIV int rigol_ds_config_set(const struct sr_dev_inst *sdi, const char *format, ...);
+SR_PRIV int rigol_ds_capture_start(const struct sr_dev_inst *sdi);
+SR_PRIV int rigol_ds_channel_start(const struct sr_dev_inst *sdi);
+SR_PRIV int rigol_ds_receive(int fd, int revents, void *cb_data);
+SR_PRIV int rigol_ds_get_dev_cfg(const struct sr_dev_inst *sdi);
+
+#endif
diff --git a/src/hardware/saleae-logic16/api.c b/src/hardware/saleae-logic16/api.c
new file mode 100644 (file)
index 0000000..6bd539c
--- /dev/null
@@ -0,0 +1,837 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Marcus Comstedt <marcus@mc.pp.se>
+ * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
+ * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <libusb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "protocol.h"
+
+#define LOGIC16_VID            0x21a9
+#define LOGIC16_PID            0x1001
+
+#define USB_INTERFACE          0
+#define USB_CONFIGURATION      1
+#define FX2_FIRMWARE           FIRMWARE_DIR "/saleae-logic16-fx2.fw"
+
+#define MAX_RENUM_DELAY_MS     3000
+#define NUM_SIMUL_TRANSFERS    32
+
+SR_PRIV struct sr_dev_driver saleae_logic16_driver_info;
+static struct sr_dev_driver *di = &saleae_logic16_driver_info;
+
+static const int32_t hwopts[] = {
+       SR_CONF_CONN,
+};
+
+static const int32_t hwcaps[] = {
+       SR_CONF_LOGIC_ANALYZER,
+       SR_CONF_SAMPLERATE,
+       SR_CONF_VOLTAGE_THRESHOLD,
+       SR_CONF_TRIGGER_MATCH,
+
+       /* These are really implemented in the driver, not the hardware. */
+       SR_CONF_LIMIT_SAMPLES,
+       SR_CONF_CONTINUOUS,
+};
+
+static const int32_t soft_trigger_matches[] = {
+       SR_TRIGGER_ZERO,
+       SR_TRIGGER_ONE,
+       SR_TRIGGER_RISING,
+       SR_TRIGGER_FALLING,
+       SR_TRIGGER_EDGE,
+};
+
+static const char *channel_names[] = {
+       "0", "1", "2", "3", "4", "5", "6", "7", "8",
+       "9", "10", "11", "12", "13", "14", "15",
+       NULL,
+};
+
+static const struct {
+       enum voltage_range range;
+       gdouble low;
+       gdouble high;
+} volt_thresholds[] = {
+       { VOLTAGE_RANGE_18_33_V, 0.7, 1.4 },
+       { VOLTAGE_RANGE_5_V,     1.4, 3.6 },
+};
+
+static const uint64_t samplerates[] = {
+       SR_KHZ(500),
+       SR_MHZ(1),
+       SR_MHZ(2),
+       SR_MHZ(4),
+       SR_MHZ(5),
+       SR_MHZ(8),
+       SR_MHZ(10),
+       SR_KHZ(12500),
+       SR_MHZ(16),
+       SR_MHZ(25),
+       SR_MHZ(32),
+       SR_MHZ(40),
+       SR_MHZ(80),
+       SR_MHZ(100),
+};
+
+static int init(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static gboolean check_conf_profile(libusb_device *dev)
+{
+       struct libusb_device_descriptor des;
+       struct libusb_device_handle *hdl;
+       gboolean ret;
+       unsigned char strdesc[64];
+
+       hdl = NULL;
+       ret = FALSE;
+       while (!ret) {
+               /* Assume the FW has not been loaded, unless proven wrong. */
+               if (libusb_get_device_descriptor(dev, &des) != 0)
+                       break;
+
+               if (libusb_open(dev, &hdl) != 0)
+                       break;
+
+               if (libusb_get_string_descriptor_ascii(hdl,
+                   des.iManufacturer, strdesc, sizeof(strdesc)) < 0)
+                       break;
+               if (strcmp((const char *)strdesc, "Saleae LLC"))
+                       break;
+
+               if (libusb_get_string_descriptor_ascii(hdl,
+                   des.iProduct, strdesc, sizeof(strdesc)) < 0)
+                       break;
+               if (strcmp((const char *)strdesc, "Logic S/16"))
+                       break;
+
+               /* If we made it here, it must be a configured Logic16. */
+               ret = TRUE;
+       }
+       if (hdl)
+               libusb_close(hdl);
+
+       return ret;
+}
+
+static GSList *scan(GSList *options)
+{
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       struct sr_dev_inst *sdi;
+       struct sr_usb_dev_inst *usb;
+       struct sr_channel *ch;
+       struct sr_config *src;
+       GSList *l, *devices, *conn_devices;
+       struct libusb_device_descriptor des;
+       libusb_device **devlist;
+       int devcnt, ret, i, j;
+       const char *conn;
+
+       drvc = di->priv;
+
+       conn = NULL;
+       for (l = options; l; l = l->next) {
+               src = l->data;
+               switch (src->key) {
+               case SR_CONF_CONN:
+                       conn = g_variant_get_string(src->data, NULL);
+                       break;
+               }
+       }
+       if (conn)
+               conn_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn);
+       else
+               conn_devices = NULL;
+
+       /* Find all Logic16 devices and upload firmware to them. */
+       devices = NULL;
+       libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
+       for (i = 0; devlist[i]; i++) {
+               if (conn) {
+                       usb = NULL;
+                       for (l = conn_devices; l; l = l->next) {
+                               usb = l->data;
+                               if (usb->bus == libusb_get_bus_number(devlist[i])
+                                   && usb->address == libusb_get_device_address(devlist[i]))
+                                       break;
+                       }
+                       if (!l)
+                               /* This device matched none of the ones that
+                                * matched the conn specification. */
+                               continue;
+               }
+
+               if ((ret = libusb_get_device_descriptor(devlist[i], &des)) != 0) {
+                       sr_warn("Failed to get device descriptor: %s.",
+                               libusb_error_name(ret));
+                       continue;
+               }
+
+               if (des.idVendor != LOGIC16_VID || des.idProduct != LOGIC16_PID)
+                       continue;
+
+               devcnt = g_slist_length(drvc->instances);
+               sdi = sr_dev_inst_new(devcnt, SR_ST_INITIALIZING,
+                                     "Saleae", "Logic16", NULL);
+               if (!sdi)
+                       return NULL;
+               sdi->driver = di;
+
+               for (j = 0; channel_names[j]; j++) {
+                       if (!(ch = sr_channel_new(j, SR_CHANNEL_LOGIC, TRUE,
+                                                  channel_names[j])))
+                               return NULL;
+                       sdi->channels = g_slist_append(sdi->channels, ch);
+               }
+
+               if (!(devc = g_try_malloc0(sizeof(struct dev_context))))
+                       return NULL;
+               devc->selected_voltage_range = VOLTAGE_RANGE_18_33_V;
+               sdi->priv = devc;
+               drvc->instances = g_slist_append(drvc->instances, sdi);
+               devices = g_slist_append(devices, sdi);
+
+               if (check_conf_profile(devlist[i])) {
+                       /* Already has the firmware, so fix the new address. */
+                       sr_dbg("Found a Logic16 device.");
+                       sdi->status = SR_ST_INACTIVE;
+                       sdi->inst_type = SR_INST_USB;
+                       sdi->conn = sr_usb_dev_inst_new(
+                               libusb_get_bus_number(devlist[i]),
+                               libusb_get_device_address(devlist[i]), NULL);
+               } else {
+                       if (ezusb_upload_firmware(devlist[i], USB_CONFIGURATION,
+                                                 FX2_FIRMWARE) == SR_OK)
+                               /* Store when this device's FW was updated. */
+                               devc->fw_updated = g_get_monotonic_time();
+                       else
+                               sr_err("Firmware upload failed for "
+                                      "device %d.", devcnt);
+                       sdi->inst_type = SR_INST_USB;
+                       sdi->conn = sr_usb_dev_inst_new(
+                               libusb_get_bus_number(devlist[i]), 0xff, NULL);
+               }
+       }
+       libusb_free_device_list(devlist, 1);
+       g_slist_free_full(conn_devices, (GDestroyNotify)sr_usb_dev_inst_free);
+
+       return devices;
+}
+
+static GSList *dev_list(void)
+{
+       return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int logic16_dev_open(struct sr_dev_inst *sdi)
+{
+       libusb_device **devlist;
+       struct sr_usb_dev_inst *usb;
+       struct libusb_device_descriptor des;
+       struct drv_context *drvc;
+       int ret, skip, i, device_count;
+
+       drvc = di->priv;
+       usb = sdi->conn;
+
+       if (sdi->status == SR_ST_ACTIVE)
+               /* Device is already in use. */
+               return SR_ERR;
+
+       skip = 0;
+       device_count = libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
+       if (device_count < 0) {
+               sr_err("Failed to get device list: %s.",
+                      libusb_error_name(device_count));
+               return SR_ERR;
+       }
+
+       for (i = 0; i < device_count; i++) {
+               if ((ret = libusb_get_device_descriptor(devlist[i], &des))) {
+                       sr_err("Failed to get device descriptor: %s.",
+                              libusb_error_name(ret));
+                       continue;
+               }
+
+               if (des.idVendor != LOGIC16_VID || des.idProduct != LOGIC16_PID)
+                       continue;
+
+               if (sdi->status == SR_ST_INITIALIZING) {
+                       if (skip != sdi->index) {
+                               /* Skip devices of this type that aren't the one we want. */
+                               skip += 1;
+                               continue;
+                       }
+               } else if (sdi->status == SR_ST_INACTIVE) {
+                       /*
+                        * This device is fully enumerated, so we need to find
+                        * this device by vendor, product, bus and address.
+                        */
+                       if (libusb_get_bus_number(devlist[i]) != usb->bus
+                           || libusb_get_device_address(devlist[i]) != usb->address)
+                               /* This is not the one. */
+                               continue;
+               }
+
+               if (!(ret = libusb_open(devlist[i], &usb->devhdl))) {
+                       if (usb->address == 0xff)
+                               /*
+                                * First time we touch this device after FW
+                                * upload, so we don't know the address yet.
+                                */
+                               usb->address = libusb_get_device_address(devlist[i]);
+               } else {
+                       sr_err("Failed to open device: %s.",
+                              libusb_error_name(ret));
+                       break;
+               }
+
+               ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE);
+               if (ret == LIBUSB_ERROR_BUSY) {
+                       sr_err("Unable to claim USB interface. Another "
+                              "program or driver has already claimed it.");
+                       break;
+               } else if (ret == LIBUSB_ERROR_NO_DEVICE) {
+                       sr_err("Device has been disconnected.");
+                       break;
+               } else if (ret != 0) {
+                       sr_err("Unable to claim interface: %s.",
+                              libusb_error_name(ret));
+                       break;
+               }
+
+               if ((ret = logic16_init_device(sdi)) != SR_OK) {
+                       sr_err("Failed to init device.");
+                       break;
+               }
+
+               sdi->status = SR_ST_ACTIVE;
+               sr_info("Opened device %d on %d.%d, interface %d.",
+                       sdi->index, usb->bus, usb->address, USB_INTERFACE);
+
+               break;
+       }
+       libusb_free_device_list(devlist, 1);
+
+       if (sdi->status != SR_ST_ACTIVE) {
+               if (usb->devhdl) {
+                       libusb_release_interface(usb->devhdl, USB_INTERFACE);
+                       libusb_close(usb->devhdl);
+                       usb->devhdl = NULL;
+               }
+               return SR_ERR;
+       }
+
+       return SR_OK;
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       int ret;
+       int64_t timediff_us, timediff_ms;
+
+       devc = sdi->priv;
+
+       /*
+        * If the firmware was recently uploaded, wait up to MAX_RENUM_DELAY_MS
+        * milliseconds for the FX2 to renumerate.
+        */
+       ret = SR_ERR;
+       if (devc->fw_updated > 0) {
+               sr_info("Waiting for device to reset.");
+               /* Takes >= 300ms for the FX2 to be gone from the USB bus. */
+               g_usleep(300 * 1000);
+               timediff_ms = 0;
+               while (timediff_ms < MAX_RENUM_DELAY_MS) {
+                       if ((ret = logic16_dev_open(sdi)) == SR_OK)
+                               break;
+                       g_usleep(100 * 1000);
+
+                       timediff_us = g_get_monotonic_time() - devc->fw_updated;
+                       timediff_ms = timediff_us / 1000;
+                       sr_spew("Waited %" PRIi64 "ms.", timediff_ms);
+               }
+               if (ret != SR_OK) {
+                       sr_err("Device failed to renumerate.");
+                       return SR_ERR;
+               }
+               sr_info("Device came back after %" PRIi64 "ms.", timediff_ms);
+       } else {
+               sr_info("Firmware upload was not needed.");
+               ret = logic16_dev_open(sdi);
+       }
+
+       if (ret != SR_OK) {
+               sr_err("Unable to open device.");
+               return SR_ERR;
+       }
+
+       if (devc->cur_samplerate == 0) {
+               /* Samplerate hasn't been set; default to the slowest one. */
+               devc->cur_samplerate = samplerates[0];
+       }
+
+       return SR_OK;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+       struct sr_usb_dev_inst *usb;
+
+       usb = sdi->conn;
+       if (usb->devhdl == NULL)
+               return SR_ERR;
+
+       sr_info("Closing device %d on %d.%d interface %d.",
+               sdi->index, usb->bus, usb->address, USB_INTERFACE);
+       libusb_release_interface(usb->devhdl, USB_INTERFACE);
+       libusb_close(usb->devhdl);
+       usb->devhdl = NULL;
+       sdi->status = SR_ST_INACTIVE;
+
+       return SR_OK;
+}
+
+static int cleanup(void)
+{
+       int ret;
+       struct drv_context *drvc;
+
+       if (!(drvc = di->priv))
+               /* Can get called on an unused driver, doesn't matter. */
+               return SR_OK;
+
+
+       ret = std_dev_clear(di, NULL);
+       g_free(drvc);
+       di->priv = NULL;
+
+       return ret;
+}
+
+static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       struct sr_usb_dev_inst *usb;
+       GVariant *range[2];
+       char str[128];
+       int ret;
+       unsigned int i;
+
+       (void)cg;
+
+       ret = SR_OK;
+       switch (key) {
+       case SR_CONF_CONN:
+               if (!sdi || !sdi->conn)
+                       return SR_ERR_ARG;
+               usb = sdi->conn;
+               if (usb->address == 255)
+                       /* Device still needs to re-enumerate after firmware
+                        * upload, so we don't know its (future) address. */
+                       return SR_ERR;
+               snprintf(str, 128, "%d.%d", usb->bus, usb->address);
+               *data = g_variant_new_string(str);
+               break;
+       case SR_CONF_SAMPLERATE:
+               if (!sdi)
+                       return SR_ERR;
+               devc = sdi->priv;
+               *data = g_variant_new_uint64(devc->cur_samplerate);
+               break;
+       case SR_CONF_VOLTAGE_THRESHOLD:
+               if (!sdi)
+                       return SR_ERR;
+               devc = sdi->priv;
+               ret = SR_ERR;
+               for (i = 0; i < ARRAY_SIZE(volt_thresholds); i++) {
+                       if (devc->selected_voltage_range !=
+                           volt_thresholds[i].range)
+                               continue;
+                       range[0] = g_variant_new_double(volt_thresholds[i].low);
+                       range[1] = g_variant_new_double(volt_thresholds[i].high);
+                       *data = g_variant_new_tuple(range, 2);
+                       ret = SR_OK;
+                       break;
+               }
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return ret;
+}
+
+static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       gdouble low, high;
+       int ret;
+       unsigned int i;
+
+       (void)cg;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       devc = sdi->priv;
+
+       ret = SR_OK;
+       switch (key) {
+       case SR_CONF_SAMPLERATE:
+               devc->cur_samplerate = g_variant_get_uint64(data);
+               break;
+       case SR_CONF_LIMIT_SAMPLES:
+               devc->limit_samples = g_variant_get_uint64(data);
+               break;
+       case SR_CONF_VOLTAGE_THRESHOLD:
+               g_variant_get(data, "(dd)", &low, &high);
+               ret = SR_ERR_ARG;
+               for (i = 0; i < ARRAY_SIZE(volt_thresholds); i++) {
+                       if (fabs(volt_thresholds[i].low - low) < 0.1 &&
+                           fabs(volt_thresholds[i].high - high) < 0.1) {
+                               devc->selected_voltage_range =
+                                       volt_thresholds[i].range;
+                               ret = SR_OK;
+                               break;
+                       }
+               }
+               break;
+       default:
+               ret = SR_ERR_NA;
+       }
+
+       return ret;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       GVariant *gvar, *range[2];
+       GVariantBuilder gvb;
+       int ret;
+       unsigned int i;
+
+       (void)sdi;
+       (void)cg;
+
+       ret = SR_OK;
+       switch (key) {
+       case SR_CONF_SCAN_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+               break;
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+               break;
+       case SR_CONF_SAMPLERATE:
+               g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
+               gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"),
+                       samplerates, ARRAY_SIZE(samplerates), sizeof(uint64_t));
+               g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar);
+               *data = g_variant_builder_end(&gvb);
+               break;
+       case SR_CONF_VOLTAGE_THRESHOLD:
+               g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
+               for (i = 0; i < ARRAY_SIZE(volt_thresholds); i++) {
+                       range[0] = g_variant_new_double(volt_thresholds[i].low);
+                       range[1] = g_variant_new_double(volt_thresholds[i].high);
+                       gvar = g_variant_new_tuple(range, 2);
+                       g_variant_builder_add_value(&gvb, gvar);
+               }
+               *data = g_variant_builder_end(&gvb);
+               break;
+       case SR_CONF_TRIGGER_MATCH:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               soft_trigger_matches, ARRAY_SIZE(soft_trigger_matches),
+                               sizeof(int32_t));
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return ret;
+}
+
+static void abort_acquisition(struct dev_context *devc)
+{
+       int i;
+
+       devc->sent_samples = -1;
+
+       for (i = devc->num_transfers - 1; i >= 0; i--) {
+               if (devc->transfers[i])
+                       libusb_cancel_transfer(devc->transfers[i]);
+       }
+}
+
+static unsigned int bytes_per_ms(struct dev_context *devc)
+{
+       return devc->cur_samplerate * devc->num_channels / 8000;
+}
+
+static size_t get_buffer_size(struct dev_context *devc)
+{
+       size_t s;
+
+       /*
+        * The buffer should be large enough to hold 10ms of data and
+        * a multiple of 512.
+        */
+       s = 10 * bytes_per_ms(devc);
+       return (s + 511) & ~511;
+}
+
+static unsigned int get_number_of_transfers(struct dev_context *devc)
+{
+       unsigned int n;
+
+       /* Total buffer size should be able to hold about 500ms of data. */
+       n = 500 * bytes_per_ms(devc) / get_buffer_size(devc);
+
+       if (n > NUM_SIMUL_TRANSFERS)
+               return NUM_SIMUL_TRANSFERS;
+
+       return n;
+}
+
+static unsigned int get_timeout(struct dev_context *devc)
+{
+       size_t total_size;
+       unsigned int timeout;
+
+       total_size = get_buffer_size(devc) * get_number_of_transfers(devc);
+       timeout = total_size / bytes_per_ms(devc);
+       return timeout + timeout / 4; /* Leave a headroom of 25% percent. */
+}
+
+static int configure_channels(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_channel *ch;
+       GSList *l;
+       uint16_t channel_bit;
+
+       devc = sdi->priv;
+
+       devc->cur_channels = 0;
+       devc->num_channels = 0;
+       for (l = sdi->channels; l; l = l->next) {
+               ch = (struct sr_channel *)l->data;
+               if (ch->enabled == FALSE)
+                       continue;
+
+               channel_bit = 1 << (ch->index);
+
+               devc->cur_channels |= channel_bit;
+
+#ifdef WORDS_BIGENDIAN
+               /*
+                * Output logic data should be stored in little endian format.
+                * To speed things up during conversion, do the switcharoo
+                * here instead.
+                */
+               channel_bit = 1 << (ch->index ^ 8);
+#endif
+
+               devc->channel_masks[devc->num_channels++] = channel_bit;
+       }
+
+       return SR_OK;
+}
+
+static int receive_data(int fd, int revents, void *cb_data)
+{
+       struct timeval tv;
+       struct dev_context *devc;
+       struct drv_context *drvc;
+       const struct sr_dev_inst *sdi;
+
+       (void)fd;
+       (void)revents;
+
+       sdi = cb_data;
+       drvc = di->priv;
+       devc = sdi->priv;
+
+       tv.tv_sec = tv.tv_usec = 0;
+       libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
+
+       if (devc->sent_samples == -2) {
+               logic16_abort_acquisition(sdi);
+               abort_acquisition(devc);
+       }
+
+       return TRUE;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct dev_context *devc;
+       struct drv_context *drvc;
+       struct sr_usb_dev_inst *usb;
+       struct sr_trigger *trigger;
+       struct libusb_transfer *transfer;
+       unsigned int i, timeout, num_transfers;
+       int ret;
+       unsigned char *buf;
+       size_t size, convsize;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       drvc = di->priv;
+       devc = sdi->priv;
+       usb = sdi->conn;
+
+       /* Configures devc->cur_channels. */
+       if (configure_channels(sdi) != SR_OK) {
+               sr_err("Failed to configure channels.");
+               return SR_ERR;
+       }
+
+       devc->cb_data = cb_data;
+       devc->sent_samples = 0;
+       devc->empty_transfer_count = 0;
+       devc->cur_channel = 0;
+       memset(devc->channel_data, 0, sizeof(devc->channel_data));
+
+       if ((trigger = sr_session_trigger_get(sdi->session))) {
+               devc->stl = soft_trigger_logic_new(sdi, trigger);
+               devc->trigger_fired = FALSE;
+       } else
+               devc->trigger_fired = TRUE;
+
+       timeout = get_timeout(devc);
+       num_transfers = get_number_of_transfers(devc);
+       size = get_buffer_size(devc);
+       convsize = (size / devc->num_channels + 2) * 16;
+       devc->submitted_transfers = 0;
+
+       devc->convbuffer_size = convsize;
+       if (!(devc->convbuffer = g_try_malloc(convsize))) {
+               sr_err("Conversion buffer malloc failed.");
+               return SR_ERR_MALLOC;
+       }
+
+       devc->transfers = g_try_malloc0(sizeof(*devc->transfers) * num_transfers);
+       if (!devc->transfers) {
+               sr_err("USB transfers malloc failed.");
+               g_free(devc->convbuffer);
+               return SR_ERR_MALLOC;
+       }
+
+       if ((ret = logic16_setup_acquisition(sdi, devc->cur_samplerate,
+                                            devc->cur_channels)) != SR_OK) {
+               g_free(devc->transfers);
+               g_free(devc->convbuffer);
+               return ret;
+       }
+
+       devc->num_transfers = num_transfers;
+       for (i = 0; i < num_transfers; i++) {
+               if (!(buf = g_try_malloc(size))) {
+                       sr_err("USB transfer buffer malloc failed.");
+                       if (devc->submitted_transfers)
+                               abort_acquisition(devc);
+                       else {
+                               g_free(devc->transfers);
+                               g_free(devc->convbuffer);
+                       }
+                       return SR_ERR_MALLOC;
+               }
+               transfer = libusb_alloc_transfer(0);
+               libusb_fill_bulk_transfer(transfer, usb->devhdl,
+                               2 | LIBUSB_ENDPOINT_IN, buf, size,
+                               logic16_receive_transfer, (void *)sdi, timeout);
+               if ((ret = libusb_submit_transfer(transfer)) != 0) {
+                       sr_err("Failed to submit transfer: %s.",
+                              libusb_error_name(ret));
+                       libusb_free_transfer(transfer);
+                       g_free(buf);
+                       abort_acquisition(devc);
+                       return SR_ERR;
+               }
+               devc->transfers[i] = transfer;
+               devc->submitted_transfers++;
+       }
+
+       devc->ctx = drvc->sr_ctx;
+
+       usb_source_add(sdi->session, devc->ctx, timeout, receive_data, (void *)sdi);
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(cb_data, LOG_PREFIX);
+
+       if ((ret = logic16_start_acquisition(sdi)) != SR_OK) {
+               abort_acquisition(devc);
+               return ret;
+       }
+
+       return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       int ret;
+
+       (void)cb_data;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       ret = logic16_abort_acquisition(sdi);
+
+       abort_acquisition(sdi->priv);
+
+       return ret;
+}
+
+SR_PRIV struct sr_dev_driver saleae_logic16_driver_info = {
+       .name = "saleae-logic16",
+       .longname = "Saleae Logic16",
+       .api_version = 1,
+       .init = init,
+       .cleanup = cleanup,
+       .scan = scan,
+       .dev_list = 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,
+       .priv = NULL,
+};
diff --git a/src/hardware/saleae-logic16/protocol.c b/src/hardware/saleae-logic16/protocol.c
new file mode 100644 (file)
index 0000000..7858334
--- /dev/null
@@ -0,0 +1,790 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Marcus Comstedt <marcus@mc.pp.se>
+ * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
+ * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "protocol.h"
+
+#include <stdint.h>
+#include <string.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <stdio.h>
+#include <errno.h>
+#include <math.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define FPGA_FIRMWARE_18       FIRMWARE_DIR"/saleae-logic16-fpga-18.bitstream"
+#define FPGA_FIRMWARE_33       FIRMWARE_DIR"/saleae-logic16-fpga-33.bitstream"
+
+#define MAX_SAMPLE_RATE                SR_MHZ(100)
+#define MAX_4CH_SAMPLE_RATE    SR_MHZ(50)
+#define MAX_7CH_SAMPLE_RATE    SR_MHZ(40)
+#define MAX_8CH_SAMPLE_RATE    SR_MHZ(32)
+#define MAX_10CH_SAMPLE_RATE   SR_MHZ(25)
+#define MAX_13CH_SAMPLE_RATE   SR_MHZ(16)
+
+#define BASE_CLOCK_0_FREQ      SR_MHZ(100)
+#define BASE_CLOCK_1_FREQ      SR_MHZ(160)
+
+#define COMMAND_START_ACQUISITION      1
+#define COMMAND_ABORT_ACQUISITION_ASYNC        2
+#define COMMAND_WRITE_EEPROM           6
+#define COMMAND_READ_EEPROM            7
+#define COMMAND_WRITE_LED_TABLE                0x7a
+#define COMMAND_SET_LED_MODE           0x7b
+#define COMMAND_RETURN_TO_BOOTLOADER   0x7c
+#define COMMAND_ABORT_ACQUISITION_SYNC 0x7d
+#define COMMAND_FPGA_UPLOAD_INIT       0x7e
+#define COMMAND_FPGA_UPLOAD_SEND_DATA  0x7f
+#define COMMAND_FPGA_WRITE_REGISTER    0x80
+#define COMMAND_FPGA_READ_REGISTER     0x81
+#define COMMAND_GET_REVID              0x82
+
+#define WRITE_EEPROM_COOKIE1           0x42
+#define WRITE_EEPROM_COOKIE2           0x55
+#define READ_EEPROM_COOKIE1            0x33
+#define READ_EEPROM_COOKIE2            0x81
+#define ABORT_ACQUISITION_SYNC_PATTERN 0x55
+
+#define MAX_EMPTY_TRANSFERS            64
+
+static void encrypt(uint8_t *dest, const uint8_t *src, uint8_t cnt)
+{
+       uint8_t state1 = 0x9b, state2 = 0x54;
+       uint8_t t, v;
+       int i;
+
+       for (i = 0; i < cnt; i++) {
+               v = src[i];
+               t = (((v ^ state2 ^ 0x2b) - 0x05) ^ 0x35) - 0x39;
+               t = (((t ^ state1 ^ 0x5a) - 0xb0) ^ 0x38) - 0x45;
+               dest[i] = state2 = t;
+               state1 = v;
+       }
+}
+
+static void decrypt(uint8_t *dest, const uint8_t *src, uint8_t cnt)
+{
+       uint8_t state1 = 0x9b, state2 = 0x54;
+       uint8_t t, v;
+       int i;
+
+       for (i = 0; i < cnt; i++) {
+               v = src[i];
+               t = (((v + 0x45) ^ 0x38) + 0xb0) ^ 0x5a ^ state1;
+               t = (((t + 0x39) ^ 0x35) + 0x05) ^ 0x2b ^ state2;
+               dest[i] = state1 = t;
+               state2 = v;
+       }
+}
+
+static int do_ep1_command(const struct sr_dev_inst *sdi,
+                         const uint8_t *command, uint8_t cmd_len,
+                         uint8_t *reply, uint8_t reply_len)
+{
+       uint8_t buf[64];
+       struct sr_usb_dev_inst *usb;
+       int ret, xfer;
+
+       usb = sdi->conn;
+
+       if (cmd_len < 1 || cmd_len > 64 || reply_len > 64 ||
+           command == NULL || (reply_len > 0 && reply == NULL))
+               return SR_ERR_ARG;
+
+       encrypt(buf, command, cmd_len);
+
+       ret = libusb_bulk_transfer(usb->devhdl, 1, buf, cmd_len, &xfer, 1000);
+       if (ret != 0) {
+               sr_dbg("Failed to send EP1 command 0x%02x: %s.",
+                      command[0], libusb_error_name(ret));
+               return SR_ERR;
+       }
+       if (xfer != cmd_len) {
+               sr_dbg("Failed to send EP1 command 0x%02x: incorrect length "
+                      "%d != %d.", xfer, cmd_len);
+               return SR_ERR;
+       }
+
+       if (reply_len == 0)
+               return SR_OK;
+
+       ret = libusb_bulk_transfer(usb->devhdl, 0x80 | 1, buf, reply_len,
+                                  &xfer, 1000);
+       if (ret != 0) {
+               sr_dbg("Failed to receive reply to EP1 command 0x%02x: %s.",
+                      command[0], libusb_error_name(ret));
+               return SR_ERR;
+       }
+       if (xfer != reply_len) {
+               sr_dbg("Failed to receive reply to EP1 command 0x%02x: "
+                      "incorrect length %d != %d.", xfer, reply_len);
+               return SR_ERR;
+       }
+
+       decrypt(reply, buf, reply_len);
+
+       return SR_OK;
+}
+
+static int read_eeprom(const struct sr_dev_inst *sdi,
+                      uint8_t address, uint8_t length, uint8_t *buf)
+{
+       uint8_t command[5] = {
+               COMMAND_READ_EEPROM,
+               READ_EEPROM_COOKIE1,
+               READ_EEPROM_COOKIE2,
+               address,
+               length,
+       };
+
+       return do_ep1_command(sdi, command, 5, buf, length);
+}
+
+static int upload_led_table(const struct sr_dev_inst *sdi,
+                           const uint8_t *table, uint8_t offset, uint8_t cnt)
+{
+       uint8_t chunk, command[64];
+       int ret;
+
+       if (cnt < 1 || cnt + offset > 64 || table == NULL)
+               return SR_ERR_ARG;
+
+       while (cnt > 0) {
+               chunk = (cnt > 32 ? 32 : cnt);
+
+               command[0] = COMMAND_WRITE_LED_TABLE;
+               command[1] = offset;
+               command[2] = chunk;
+               memcpy(command + 3, table, chunk);
+
+               ret = do_ep1_command(sdi, command, 3 + chunk, NULL, 0);
+               if (ret != SR_OK)
+                       return ret;
+
+               table += chunk;
+               offset += chunk;
+               cnt -= chunk;
+       }
+
+       return SR_OK;
+}
+
+static int set_led_mode(const struct sr_dev_inst *sdi,
+                       uint8_t animate, uint16_t t2reload, uint8_t div,
+                       uint8_t repeat)
+{
+       uint8_t command[6] = {
+               COMMAND_SET_LED_MODE,
+               animate,
+               t2reload & 0xff,
+               t2reload >> 8,
+               div,
+               repeat,
+       };
+
+       return do_ep1_command(sdi, command, 6, NULL, 0);
+}
+
+static int read_fpga_register(const struct sr_dev_inst *sdi,
+                             uint8_t address, uint8_t *value)
+{
+       uint8_t command[3] = {
+               COMMAND_FPGA_READ_REGISTER,
+               1,
+               address,
+       };
+
+       return do_ep1_command(sdi, command, 3, value, 1);
+}
+
+static int write_fpga_registers(const struct sr_dev_inst *sdi,
+                               uint8_t (*regs)[2], uint8_t cnt)
+{
+       uint8_t command[64];
+       int i;
+
+       if (cnt < 1 || cnt > 31)
+               return SR_ERR_ARG;
+
+       command[0] = COMMAND_FPGA_WRITE_REGISTER;
+       command[1] = cnt;
+       for (i = 0; i < cnt; i++) {
+               command[2 + 2 * i] = regs[i][0];
+               command[3 + 2 * i] = regs[i][1];
+       }
+
+       return do_ep1_command(sdi, command, 2 * (cnt + 1), NULL, 0);
+}
+
+static int write_fpga_register(const struct sr_dev_inst *sdi,
+                              uint8_t address, uint8_t value)
+{
+       uint8_t regs[2] = { address, value };
+
+       return write_fpga_registers(sdi, &regs, 1);
+}
+
+static uint8_t map_eeprom_data(uint8_t v)
+{
+       return (((v ^ 0x80) + 0x44) ^ 0xd5) + 0x69;
+}
+
+static int prime_fpga(const struct sr_dev_inst *sdi)
+{
+       uint8_t eeprom_data[16];
+       uint8_t old_reg_10, version;
+       uint8_t regs[8][2] = {
+               {10, 0x00},
+               {10, 0x40},
+               {12, 0},
+               {10, 0xc0},
+               {10, 0x40},
+               {6, 0},
+               {7, 1},
+               {7, 0}
+       };
+       int i, ret;
+
+       if ((ret = read_eeprom(sdi, 16, 16, eeprom_data)) != SR_OK)
+               return ret;
+
+       if ((ret = read_fpga_register(sdi, 10, &old_reg_10)) != SR_OK)
+               return ret;
+
+       regs[0][1] = (old_reg_10 &= 0x7f);
+       regs[1][1] |= old_reg_10;
+       regs[3][1] |= old_reg_10;
+       regs[4][1] |= old_reg_10;
+
+       for (i = 0; i < 16; i++) {
+               regs[2][1] = eeprom_data[i];
+               regs[5][1] = map_eeprom_data(eeprom_data[i]);
+               if (i)
+                       ret = write_fpga_registers(sdi, &regs[2], 6);
+               else
+                       ret = write_fpga_registers(sdi, &regs[0], 8);
+               if (ret != SR_OK)
+                       return ret;
+       }
+
+       if ((ret = write_fpga_register(sdi, 10, old_reg_10)) != SR_OK)
+               return ret;
+
+       if ((ret = read_fpga_register(sdi, 0, &version)) != SR_OK)
+               return ret;
+
+       if (version != 0x10) {
+               sr_err("Invalid FPGA bitstream version: 0x%02x != 0x10.", version);
+               return SR_ERR;
+       }
+
+       return SR_OK;
+}
+
+static void make_heartbeat(uint8_t *table, int len)
+{
+       int i, j;
+
+       memset(table, 0, len);
+       len >>= 3;
+       for (i = 0; i < 2; i++)
+               for (j = 0; j < len; j++)
+                       *table++ = sin(j * M_PI / len) * 255;
+}
+
+static int configure_led(const struct sr_dev_inst *sdi)
+{
+       uint8_t table[64];
+       int ret;
+
+       make_heartbeat(table, 64);
+       if ((ret = upload_led_table(sdi, table, 0, 64)) != SR_OK)
+               return ret;
+
+       return set_led_mode(sdi, 1, 6250, 0, 1);
+}
+
+static int upload_fpga_bitstream(const struct sr_dev_inst *sdi,
+                                enum voltage_range vrange)
+{
+       struct dev_context *devc;
+       int offset, chunksize, ret;
+       const char *filename;
+       uint8_t len, buf[256 * 62], command[64];
+       FILE *fw;
+
+       devc = sdi->priv;
+
+       if (devc->cur_voltage_range == vrange)
+               return SR_OK;
+
+       switch (vrange) {
+       case VOLTAGE_RANGE_18_33_V:
+               filename = FPGA_FIRMWARE_18;
+               break;
+       case VOLTAGE_RANGE_5_V:
+               filename = FPGA_FIRMWARE_33;
+               break;
+       default:
+               sr_err("Unsupported voltage range.");
+               return SR_ERR;
+       }
+
+       sr_info("Uploading FPGA bitstream at %s.", filename);
+       if ((fw = g_fopen(filename, "rb")) == NULL) {
+               sr_err("Unable to open bitstream file %s for reading: %s.",
+                      filename, strerror(errno));
+               return SR_ERR;
+       }
+
+       buf[0] = COMMAND_FPGA_UPLOAD_INIT;
+       if ((ret = do_ep1_command(sdi, buf, 1, NULL, 0)) != SR_OK) {
+               fclose(fw);
+               return ret;
+       }
+
+       while (1) {
+               chunksize = fread(buf, 1, sizeof(buf), fw);
+               if (chunksize == 0)
+                       break;
+
+               for (offset = 0; offset < chunksize; offset += 62) {
+                       len = (offset + 62 > chunksize ?
+                               chunksize - offset : 62);
+                       command[0] = COMMAND_FPGA_UPLOAD_SEND_DATA;
+                       command[1] = len;
+                       memcpy(command + 2, buf + offset, len);
+                       ret = do_ep1_command(sdi, command, len + 2, NULL, 0);
+                       if (ret != SR_OK) {
+                               fclose(fw);
+                               return ret;
+                       }
+               }
+
+               sr_info("Uploaded %d bytes.", chunksize);
+       }
+       fclose(fw);
+       sr_info("FPGA bitstream upload done.");
+
+       if ((ret = prime_fpga(sdi)) != SR_OK)
+               return ret;
+
+       if ((ret = configure_led(sdi)) != SR_OK)
+               return ret;
+
+       devc->cur_voltage_range = vrange;
+       return SR_OK;
+}
+
+static int abort_acquisition_sync(const struct sr_dev_inst *sdi)
+{
+       static const uint8_t command[2] = {
+               COMMAND_ABORT_ACQUISITION_SYNC,
+               ABORT_ACQUISITION_SYNC_PATTERN,
+       };
+       uint8_t reply, expected_reply;
+       int ret;
+
+       if ((ret = do_ep1_command(sdi, command, 2, &reply, 1)) != SR_OK)
+               return ret;
+
+       expected_reply = ~command[1];
+       if (reply != expected_reply) {
+               sr_err("Invalid response for abort acquisition command: "
+                      "0x%02x != 0x%02x.", reply, expected_reply);
+               return SR_ERR;
+       }
+
+       return SR_OK;
+}
+
+SR_PRIV int logic16_setup_acquisition(const struct sr_dev_inst *sdi,
+                            uint64_t samplerate, uint16_t channels)
+{
+       uint8_t clock_select, reg1, reg10;
+       uint64_t div;
+       int i, ret, nchan = 0;
+       struct dev_context *devc;
+
+       devc = sdi->priv;
+
+       if (samplerate == 0 || samplerate > MAX_SAMPLE_RATE) {
+               sr_err("Unable to sample at %" PRIu64 "Hz.", samplerate);
+               return SR_ERR;
+       }
+
+       if (BASE_CLOCK_0_FREQ % samplerate == 0 &&
+           (div = BASE_CLOCK_0_FREQ / samplerate) <= 256) {
+               clock_select = 0;
+       } else if (BASE_CLOCK_1_FREQ % samplerate == 0 &&
+                  (div = BASE_CLOCK_1_FREQ / samplerate) <= 256) {
+               clock_select = 1;
+       } else {
+               sr_err("Unable to sample at %" PRIu64 "Hz.", samplerate);
+               return SR_ERR;
+       }
+
+       for (i = 0; i < 16; i++)
+               if (channels & (1U << i))
+                       nchan++;
+
+       if ((nchan >= 13 && samplerate > MAX_13CH_SAMPLE_RATE) ||
+           (nchan >= 10 && samplerate > MAX_10CH_SAMPLE_RATE) ||
+           (nchan >= 8  && samplerate > MAX_8CH_SAMPLE_RATE) ||
+           (nchan >= 7  && samplerate > MAX_7CH_SAMPLE_RATE) ||
+           (nchan >= 4  && samplerate > MAX_4CH_SAMPLE_RATE)) {
+               sr_err("Unable to sample at %" PRIu64 "Hz "
+                      "with this many channels.", samplerate);
+               return SR_ERR;
+       }
+
+       ret = upload_fpga_bitstream(sdi, devc->selected_voltage_range);
+       if (ret != SR_OK)
+               return ret;
+
+       if ((ret = read_fpga_register(sdi, 1, &reg1)) != SR_OK)
+               return ret;
+
+       if (reg1 != 0x08) {
+               sr_dbg("Invalid state at acquisition setup: 0x%02x != 0x08.", reg1);
+               return SR_ERR;
+       }
+
+       if ((ret = write_fpga_register(sdi, 1, 0x40)) != SR_OK)
+               return ret;
+
+       if ((ret = write_fpga_register(sdi, 10, clock_select)) != SR_OK)
+               return ret;
+
+       if ((ret = write_fpga_register(sdi, 4, (uint8_t)(div - 1))) != SR_OK)
+               return ret;
+
+       if ((ret = write_fpga_register(sdi, 2, (uint8_t)(channels & 0xff))) != SR_OK)
+               return ret;
+
+       if ((ret = write_fpga_register(sdi, 3, (uint8_t)(channels >> 8))) != SR_OK)
+               return ret;
+
+       if ((ret = write_fpga_register(sdi, 1, 0x42)) != SR_OK)
+               return ret;
+
+       if ((ret = write_fpga_register(sdi, 1, 0x40)) != SR_OK)
+               return ret;
+
+       if ((ret = read_fpga_register(sdi, 1, &reg1)) != SR_OK)
+               return ret;
+
+       if (reg1 != 0x48) {
+               sr_dbg("Invalid state at acquisition setup: 0x%02x != 0x48.", reg1);
+               return SR_ERR;
+       }
+
+       if ((ret = read_fpga_register(sdi, 10, &reg10)) != SR_OK)
+               return ret;
+
+       if (reg10 != clock_select) {
+               sr_dbg("Invalid state at acquisition setup: 0x%02x != 0x%02x.",
+                      reg10, clock_select);
+               return SR_ERR;
+       }
+
+       return SR_OK;
+}
+
+SR_PRIV int logic16_start_acquisition(const struct sr_dev_inst *sdi)
+{
+       static const uint8_t command[1] = {
+               COMMAND_START_ACQUISITION,
+       };
+       int ret;
+
+       if ((ret = do_ep1_command(sdi, command, 1, NULL, 0)) != SR_OK)
+               return ret;
+
+       return write_fpga_register(sdi, 1, 0x41);
+}
+
+SR_PRIV int logic16_abort_acquisition(const struct sr_dev_inst *sdi)
+{
+       static const uint8_t command[1] = {
+               COMMAND_ABORT_ACQUISITION_ASYNC,
+       };
+       int ret;
+       uint8_t reg1, reg8, reg9;
+
+       if ((ret = do_ep1_command(sdi, command, 1, NULL, 0)) != SR_OK)
+               return ret;
+
+       if ((ret = write_fpga_register(sdi, 1, 0x00)) != SR_OK)
+               return ret;
+
+       if ((ret = read_fpga_register(sdi, 1, &reg1)) != SR_OK)
+               return ret;
+
+       if (reg1 != 0x08) {
+               sr_dbg("Invalid state at acquisition stop: 0x%02x != 0x08.", reg1);
+               return SR_ERR;
+       }
+
+       if ((ret = read_fpga_register(sdi, 8, &reg8)) != SR_OK)
+               return ret;
+
+       if ((ret = read_fpga_register(sdi, 9, &reg9)) != SR_OK)
+               return ret;
+
+       return SR_OK;
+}
+
+SR_PRIV int logic16_init_device(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       int ret;
+
+       devc = sdi->priv;
+
+       devc->cur_voltage_range = VOLTAGE_RANGE_UNKNOWN;
+
+       if ((ret = abort_acquisition_sync(sdi)) != SR_OK)
+               return ret;
+
+       if ((ret = read_eeprom(sdi, 8, 8, devc->eeprom_data)) != SR_OK)
+               return ret;
+
+       ret = upload_fpga_bitstream(sdi, devc->selected_voltage_range);
+       if (ret != SR_OK)
+               return ret;
+
+       return SR_OK;
+}
+
+static void finish_acquisition(struct sr_dev_inst *sdi)
+{
+       struct sr_datafeed_packet packet;
+       struct dev_context *devc;
+
+       devc = sdi->priv;
+
+       /* Terminate session. */
+       packet.type = SR_DF_END;
+       sr_session_send(devc->cb_data, &packet);
+
+       /* Remove fds from polling. */
+       usb_source_remove(sdi->session, devc->ctx);
+
+       devc->num_transfers = 0;
+       g_free(devc->transfers);
+       g_free(devc->convbuffer);
+       if (devc->stl) {
+               soft_trigger_logic_free(devc->stl);
+               devc->stl = NULL;
+       }
+}
+
+static void free_transfer(struct libusb_transfer *transfer)
+{
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       unsigned int i;
+
+       sdi = transfer->user_data;
+       devc = sdi->priv;
+
+       g_free(transfer->buffer);
+       transfer->buffer = NULL;
+       libusb_free_transfer(transfer);
+
+       for (i = 0; i < devc->num_transfers; i++) {
+               if (devc->transfers[i] == transfer) {
+                       devc->transfers[i] = NULL;
+                       break;
+               }
+       }
+
+       devc->submitted_transfers--;
+       if (devc->submitted_transfers == 0)
+               finish_acquisition(sdi);
+}
+
+static void resubmit_transfer(struct libusb_transfer *transfer)
+{
+       int ret;
+
+       if ((ret = libusb_submit_transfer(transfer)) == LIBUSB_SUCCESS)
+               return;
+
+       free_transfer(transfer);
+       /* TODO: Stop session? */
+
+       sr_err("%s: %s", __func__, libusb_error_name(ret));
+}
+
+static size_t convert_sample_data(struct dev_context *devc,
+               uint8_t *dest, size_t destcnt, const uint8_t *src, size_t srccnt)
+{
+       uint16_t *channel_data;
+       int i, cur_channel;
+       size_t ret = 0;
+       uint16_t sample, channel_mask;
+
+       srccnt /= 2;
+
+       channel_data = devc->channel_data;
+       cur_channel = devc->cur_channel;
+
+       while (srccnt--) {
+               sample = src[0] | (src[1] << 8);
+               src += 2;
+
+               channel_mask = devc->channel_masks[cur_channel];
+
+               for (i = 15; i >= 0; --i, sample >>= 1)
+                       if (sample & 1)
+                               channel_data[i] |= channel_mask;
+
+               if (++cur_channel == devc->num_channels) {
+                       cur_channel = 0;
+                       if (destcnt < 16 * 2) {
+                               sr_err("Conversion buffer too small!");
+                               break;
+                       }
+                       memcpy(dest, channel_data, 16 * 2);
+                       memset(channel_data, 0, 16 * 2);
+                       dest += 16 * 2;
+                       ret += 16;
+                       destcnt -= 16 * 2;
+               }
+       }
+
+       devc->cur_channel = cur_channel;
+
+       return ret;
+}
+
+SR_PRIV void logic16_receive_transfer(struct libusb_transfer *transfer)
+{
+       gboolean packet_has_error = FALSE;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_logic logic;
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       size_t new_samples, num_samples;
+       int trigger_offset;
+
+       sdi = transfer->user_data;
+       devc = sdi->priv;
+
+       /*
+        * If acquisition has already ended, just free any queued up
+        * transfer that come in.
+        */
+       if (devc->sent_samples < 0) {
+               free_transfer(transfer);
+               return;
+       }
+
+       sr_info("receive_transfer(): status %d received %d bytes.",
+               transfer->status, transfer->actual_length);
+
+       switch (transfer->status) {
+       case LIBUSB_TRANSFER_NO_DEVICE:
+               devc->sent_samples = -2;
+               free_transfer(transfer);
+               return;
+       case LIBUSB_TRANSFER_COMPLETED:
+       case LIBUSB_TRANSFER_TIMED_OUT: /* We may have received some data though. */
+               break;
+       default:
+               packet_has_error = TRUE;
+               break;
+       }
+
+       if (transfer->actual_length & 1) {
+               sr_err("Got an odd number of bytes from the device. "
+                      "This should not happen.");
+               /* Bail out right away. */
+               packet_has_error = TRUE;
+               devc->empty_transfer_count = MAX_EMPTY_TRANSFERS;
+       }
+
+       if (transfer->actual_length == 0 || packet_has_error) {
+               devc->empty_transfer_count++;
+               if (devc->empty_transfer_count > MAX_EMPTY_TRANSFERS) {
+                       /*
+                        * The FX2 gave up. End the acquisition, the frontend
+                        * will work out that the samplecount is short.
+                        */
+                       devc->sent_samples = -2;
+                       free_transfer(transfer);
+               } else {
+                       resubmit_transfer(transfer);
+               }
+               return;
+       } else {
+               devc->empty_transfer_count = 0;
+       }
+
+       new_samples = convert_sample_data(devc, devc->convbuffer,
+                       devc->convbuffer_size, transfer->buffer, transfer->actual_length);
+
+       if (new_samples > 0) {
+               if (devc->trigger_fired) {
+                       /* Send the incoming transfer to the session bus. */
+                       packet.type = SR_DF_LOGIC;
+                       packet.payload = &logic;
+                       if (devc->limit_samples &&
+                                       new_samples > devc->limit_samples - devc->sent_samples)
+                               new_samples = devc->limit_samples - devc->sent_samples;
+                       logic.length = new_samples * 2;
+                       logic.unitsize = 2;
+                       logic.data = devc->convbuffer;
+                       sr_session_send(devc->cb_data, &packet);
+                       devc->sent_samples += new_samples;
+               } else {
+                       trigger_offset = soft_trigger_logic_check(devc->stl,
+                                       devc->convbuffer, new_samples * 2);
+                       if (trigger_offset > -1) {
+                               packet.type = SR_DF_LOGIC;
+                               packet.payload = &logic;
+                               num_samples = new_samples - trigger_offset;
+                               if (devc->limit_samples &&
+                                               num_samples > devc->limit_samples - devc->sent_samples)
+                                       num_samples = devc->limit_samples - devc->sent_samples;
+                               logic.length = num_samples * 2;
+                               logic.unitsize = 2;
+                               logic.data = devc->convbuffer + trigger_offset * 2;
+                               sr_session_send(devc->cb_data, &packet);
+                               devc->sent_samples += num_samples;
+
+                               devc->trigger_fired = TRUE;
+                       }
+               }
+
+               if (devc->limit_samples &&
+                               (uint64_t)devc->sent_samples >= devc->limit_samples) {
+                       devc->sent_samples = -2;
+                       free_transfer(transfer);
+                       return;
+               }
+       }
+
+       resubmit_transfer(transfer);
+}
diff --git a/src/hardware/saleae-logic16/protocol.h b/src/hardware/saleae-logic16/protocol.h
new file mode 100644 (file)
index 0000000..8a1ded8
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Marcus Comstedt <marcus@mc.pp.se>
+ * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
+ * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_SALEAE_LOGIC16_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_SALEAE_LOGIC16_PROTOCOL_H
+
+#include <stdint.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "saleae-logic16"
+
+enum voltage_range {
+       VOLTAGE_RANGE_UNKNOWN,
+       VOLTAGE_RANGE_18_33_V,  /* 1.8V and 3.3V logic */
+       VOLTAGE_RANGE_5_V,      /* 5V logic */
+};
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+       /*
+        * Since we can't keep track of a Logic16 device after upgrading
+        * the firmware (it renumerates into a different device address
+        * after the upgrade) this is like a global lock. No device will open
+        * until a proper delay after the last device was upgraded.
+        */
+       int64_t fw_updated;
+
+       /** The currently configured samplerate of the device. */
+       uint64_t cur_samplerate;
+
+       /** Maximum number of samples to capture, if nonzero. */
+       uint64_t limit_samples;
+
+       /** The currently configured input voltage of the device. */
+       enum voltage_range cur_voltage_range;
+
+       /** The input voltage selected by the user. */
+       enum voltage_range selected_voltage_range;
+
+       /** Channels to use. */
+       uint16_t cur_channels;
+
+       /* EEPROM data from address 8. */
+       uint8_t eeprom_data[8];
+
+       int64_t sent_samples;
+       int submitted_transfers;
+       int empty_transfer_count;
+       int num_channels;
+       int cur_channel;
+       uint16_t channel_masks[16];
+       uint16_t channel_data[16];
+       uint8_t *convbuffer;
+       size_t convbuffer_size;
+       struct soft_trigger_logic *stl;
+       gboolean trigger_fired;
+
+       void *cb_data;
+       unsigned int num_transfers;
+       struct libusb_transfer **transfers;
+       struct sr_context *ctx;
+};
+
+SR_PRIV int logic16_setup_acquisition(const struct sr_dev_inst *sdi,
+                       uint64_t samplerate, uint16_t channels);
+SR_PRIV int logic16_start_acquisition(const struct sr_dev_inst *sdi);
+SR_PRIV int logic16_abort_acquisition(const struct sr_dev_inst *sdi);
+SR_PRIV int logic16_init_device(const struct sr_dev_inst *sdi);
+SR_PRIV void logic16_receive_transfer(struct libusb_transfer *transfer);
+
+#endif
diff --git a/src/hardware/serial-dmm/api.c b/src/hardware/serial-dmm/api.c
new file mode 100644 (file)
index 0000000..b96c7a0
--- /dev/null
@@ -0,0 +1,632 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert@biot.com>
+ * Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@gmail.com>
+ * Copyright (C) 2012 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 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 <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "protocol.h"
+
+static const int32_t hwopts[] = {
+       SR_CONF_CONN,
+       SR_CONF_SERIALCOMM,
+};
+
+static const int32_t hwcaps[] = {
+       SR_CONF_MULTIMETER,
+       SR_CONF_LIMIT_SAMPLES,
+       SR_CONF_LIMIT_MSEC,
+       SR_CONF_CONTINUOUS,
+};
+
+SR_PRIV struct sr_dev_driver bbcgm_m2110_driver_info;
+SR_PRIV struct sr_dev_driver digitek_dt4000zc_driver_info;
+SR_PRIV struct sr_dev_driver tekpower_tp4000zc_driver_info;
+SR_PRIV struct sr_dev_driver metex_me31_driver_info;
+SR_PRIV struct sr_dev_driver peaktech_3410_driver_info;
+SR_PRIV struct sr_dev_driver mastech_mas345_driver_info;
+SR_PRIV struct sr_dev_driver va_va18b_driver_info;
+SR_PRIV struct sr_dev_driver va_va40b_driver_info;
+SR_PRIV struct sr_dev_driver metex_m3640d_driver_info;
+SR_PRIV struct sr_dev_driver metex_m4650cr_driver_info;
+SR_PRIV struct sr_dev_driver peaktech_4370_driver_info;
+SR_PRIV struct sr_dev_driver pce_pce_dm32_driver_info;
+SR_PRIV struct sr_dev_driver radioshack_22_168_driver_info;
+SR_PRIV struct sr_dev_driver radioshack_22_805_driver_info;
+SR_PRIV struct sr_dev_driver radioshack_22_812_driver_info;
+SR_PRIV struct sr_dev_driver tecpel_dmm_8061_ser_driver_info;
+SR_PRIV struct sr_dev_driver voltcraft_m3650cr_driver_info;
+SR_PRIV struct sr_dev_driver voltcraft_m3650d_driver_info;
+SR_PRIV struct sr_dev_driver voltcraft_m4650cr_driver_info;
+SR_PRIV struct sr_dev_driver voltcraft_me42_driver_info;
+SR_PRIV struct sr_dev_driver voltcraft_vc820_ser_driver_info;
+SR_PRIV struct sr_dev_driver voltcraft_vc830_ser_driver_info;
+SR_PRIV struct sr_dev_driver voltcraft_vc840_ser_driver_info;
+SR_PRIV struct sr_dev_driver uni_t_ut60a_ser_driver_info;
+SR_PRIV struct sr_dev_driver uni_t_ut60e_ser_driver_info;
+SR_PRIV struct sr_dev_driver uni_t_ut60g_ser_driver_info;
+SR_PRIV struct sr_dev_driver uni_t_ut61b_ser_driver_info;
+SR_PRIV struct sr_dev_driver uni_t_ut61c_ser_driver_info;
+SR_PRIV struct sr_dev_driver uni_t_ut61d_ser_driver_info;
+SR_PRIV struct sr_dev_driver uni_t_ut61e_ser_driver_info;
+SR_PRIV struct sr_dev_driver iso_tech_idm103n_driver_info;
+SR_PRIV struct sr_dev_driver tenma_72_7745_ser_driver_info;
+SR_PRIV struct sr_dev_driver tenma_72_7750_ser_driver_info;
+
+SR_PRIV struct dmm_info dmms[] = {
+       {
+               "BBC Goertz Metrawatt", "M2110", "1200/7n2", 1200,
+               BBCGM_M2110_PACKET_SIZE, 0, 0, NULL,
+               sr_m2110_packet_valid, sr_m2110_parse,
+               NULL,
+               &bbcgm_m2110_driver_info, receive_data_BBCGM_M2110,
+       },
+       {
+               "Digitek", "DT4000ZC", "2400/8n1/dtr=1", 2400,
+               FS9721_PACKET_SIZE, 0, 0, NULL,
+               sr_fs9721_packet_valid, sr_fs9721_parse,
+               sr_fs9721_10_temp_c,
+               &digitek_dt4000zc_driver_info, receive_data_DIGITEK_DT4000ZC,
+       },
+       {
+               "TekPower", "TP4000ZC", "2400/8n1/dtr=1", 2400,
+               FS9721_PACKET_SIZE, 0, 0, NULL,
+               sr_fs9721_packet_valid, sr_fs9721_parse,
+               sr_fs9721_10_temp_c,
+               &tekpower_tp4000zc_driver_info, receive_data_TEKPOWER_TP4000ZC,
+       },
+       {
+               "Metex", "ME-31", "600/7n2/rts=0/dtr=1", 600,
+               METEX14_PACKET_SIZE, 0, 0, sr_metex14_packet_request,
+               sr_metex14_packet_valid, sr_metex14_parse,
+               NULL,
+               &metex_me31_driver_info, receive_data_METEX_ME31,
+       },
+       {
+               "Peaktech", "3410", "600/7n2/rts=0/dtr=1", 600,
+               METEX14_PACKET_SIZE, 0, 0, sr_metex14_packet_request,
+               sr_metex14_packet_valid, sr_metex14_parse,
+               NULL,
+               &peaktech_3410_driver_info, receive_data_PEAKTECH_3410,
+       },
+       {
+               "MASTECH", "MAS345", "600/7n2/rts=0/dtr=1", 600,
+               METEX14_PACKET_SIZE, 0, 0, sr_metex14_packet_request,
+               sr_metex14_packet_valid, sr_metex14_parse,
+               NULL,
+               &mastech_mas345_driver_info, receive_data_MASTECH_MAS345,
+       },
+       {
+               "V&A", "VA18B", "2400/8n1", 2400,
+               FS9721_PACKET_SIZE, 0, 0, NULL,
+               sr_fs9721_packet_valid, sr_fs9721_parse,
+               sr_fs9721_01_temp_c,
+               &va_va18b_driver_info, receive_data_VA_VA18B,
+       },
+       {
+               "V&A", "VA40B", "2400/8n1", 2400,
+               FS9721_PACKET_SIZE, 0, 0, NULL,
+               sr_fs9721_packet_valid, sr_fs9721_parse,
+               sr_fs9721_max_c_min,
+               &va_va40b_driver_info, receive_data_VA_VA40B,
+       },
+       {
+               "Metex", "M-3640D", "1200/7n2/rts=0/dtr=1", 1200,
+               METEX14_PACKET_SIZE, 0, 0, sr_metex14_packet_request,
+               sr_metex14_packet_valid, sr_metex14_parse,
+               NULL,
+               &metex_m3640d_driver_info, receive_data_METEX_M3640D,
+       },
+       {
+               "Metex", "M-4650CR", "1200/7n2/rts=0/dtr=1", 1200,
+               METEX14_PACKET_SIZE, 0, 0, sr_metex14_packet_request,
+               sr_metex14_packet_valid, sr_metex14_parse,
+               NULL,
+               &metex_m4650cr_driver_info, receive_data_METEX_M4650CR,
+       },
+       {
+               "PeakTech", "4370", "1200/7n2/rts=0/dtr=1", 1200,
+               METEX14_PACKET_SIZE, 0, 0, sr_metex14_packet_request,
+               sr_metex14_packet_valid, sr_metex14_parse,
+               NULL,
+               &peaktech_4370_driver_info, receive_data_PEAKTECH_4370,
+       },
+       {
+               "PCE", "PCE-DM32", "2400/8n1", 2400,
+               FS9721_PACKET_SIZE, 0, 0, NULL,
+               sr_fs9721_packet_valid, sr_fs9721_parse,
+               sr_fs9721_01_10_temp_f_c,
+               &pce_pce_dm32_driver_info, receive_data_PCE_PCE_DM32,
+       },
+       {
+               "RadioShack", "22-168", "1200/7n2/rts=0/dtr=1", 1200,
+               METEX14_PACKET_SIZE, 0, 0, sr_metex14_packet_request,
+               sr_metex14_packet_valid, sr_metex14_parse,
+               NULL,
+               &radioshack_22_168_driver_info, receive_data_RADIOSHACK_22_168,
+       },
+       {
+               "RadioShack", "22-805", "600/7n2/rts=0/dtr=1", 600,
+               METEX14_PACKET_SIZE, 0, 0, sr_metex14_packet_request,
+               sr_metex14_packet_valid, sr_metex14_parse,
+               NULL,
+               &radioshack_22_805_driver_info, receive_data_RADIOSHACK_22_805,
+       },
+       {
+               "RadioShack", "22-812", "4800/8n1/rts=0/dtr=1", 4800,
+               RS9LCD_PACKET_SIZE, 0, 0, NULL,
+               sr_rs9lcd_packet_valid, sr_rs9lcd_parse,
+               NULL,
+               &radioshack_22_812_driver_info, receive_data_RADIOSHACK_22_812,
+       },
+       {
+               "Tecpel", "DMM-8061 (UT-D02 cable)", "2400/8n1/rts=0/dtr=1",
+               2400, FS9721_PACKET_SIZE, 0, 0, NULL,
+               sr_fs9721_packet_valid, sr_fs9721_parse,
+               sr_fs9721_00_temp_c,
+               &tecpel_dmm_8061_ser_driver_info,
+               receive_data_TECPEL_DMM_8061_SER,
+       },
+       {
+               "Voltcraft", "M-3650CR", "1200/7n2/rts=0/dtr=1", 1200,
+               METEX14_PACKET_SIZE, 150, 20, sr_metex14_packet_request,
+               sr_metex14_packet_valid, sr_metex14_parse,
+               NULL,
+               &voltcraft_m3650cr_driver_info, receive_data_VOLTCRAFT_M3650CR,
+       },
+       {
+               "Voltcraft", "M-3650D", "1200/7n2/rts=0/dtr=1", 1200,
+               METEX14_PACKET_SIZE, 0, 0, sr_metex14_packet_request,
+               sr_metex14_packet_valid, sr_metex14_parse,
+               NULL,
+               &voltcraft_m3650d_driver_info, receive_data_VOLTCRAFT_M3650D,
+       },
+       {
+               "Voltcraft", "M-4650CR", "1200/7n2/rts=0/dtr=1", 1200,
+               METEX14_PACKET_SIZE, 0, 0, sr_metex14_packet_request,
+               sr_metex14_packet_valid, sr_metex14_parse,
+               NULL,
+               &voltcraft_m4650cr_driver_info, receive_data_VOLTCRAFT_M4650CR,
+       },
+       {
+               "Voltcraft", "ME-42", "600/7n2/rts=0/dtr=1", 600,
+               METEX14_PACKET_SIZE, 250, 60, sr_metex14_packet_request,
+               sr_metex14_packet_valid, sr_metex14_parse,
+               NULL,
+               &voltcraft_me42_driver_info, receive_data_VOLTCRAFT_ME42,
+       },
+       {
+               "Voltcraft", "VC-820 (UT-D02 cable)", "2400/8n1/rts=0/dtr=1",
+               2400, FS9721_PACKET_SIZE, 0, 0, NULL,
+               sr_fs9721_packet_valid, sr_fs9721_parse,
+               NULL,
+               &voltcraft_vc820_ser_driver_info,
+               receive_data_VOLTCRAFT_VC820_SER,
+       },
+       {
+               /*
+                * Note: The VC830 doesn't set the 'volt' and 'diode' bits of
+                * the FS9922 protocol. Instead, it only sets the user-defined
+                * bit "z1" to indicate "diode mode" and "voltage".
+                */
+               "Voltcraft", "VC-830 (UT-D02 cable)", "2400/8n1/rts=0/dtr=1",
+               2400, FS9922_PACKET_SIZE, 0, 0, NULL,
+               sr_fs9922_packet_valid, sr_fs9922_parse,
+               &sr_fs9922_z1_diode,
+               &voltcraft_vc830_ser_driver_info,
+               receive_data_VOLTCRAFT_VC830_SER,
+       },
+       {
+               "Voltcraft", "VC-840 (UT-D02 cable)", "2400/8n1/rts=0/dtr=1",
+               2400, FS9721_PACKET_SIZE, 0, 0, NULL,
+               sr_fs9721_packet_valid, sr_fs9721_parse,
+               sr_fs9721_00_temp_c,
+               &voltcraft_vc840_ser_driver_info,
+               receive_data_VOLTCRAFT_VC840_SER,
+       },
+       {
+               "UNI-T", "UT60A (UT-D02 cable)", "2400/8n1/rts=0/dtr=1",
+               2400, FS9721_PACKET_SIZE, 0, 0, NULL,
+               sr_fs9721_packet_valid, sr_fs9721_parse,
+               NULL,
+               &uni_t_ut60a_ser_driver_info,
+               receive_data_UNI_T_UT60A_SER,
+       },
+       {
+               "UNI-T", "UT60E (UT-D02 cable)", "2400/8n1/rts=0/dtr=1",
+               2400, FS9721_PACKET_SIZE, 0, 0, NULL,
+               sr_fs9721_packet_valid, sr_fs9721_parse,
+               sr_fs9721_00_temp_c,
+               &uni_t_ut60e_ser_driver_info,
+               receive_data_UNI_T_UT60E_SER,
+       },
+       {
+               /* Note: ES51986 baudrate is actually 19230! */
+               "UNI-T", "UT60G (UT-D02 cable)", "19200/7o1/rts=0/dtr=1",
+               19200, ES519XX_11B_PACKET_SIZE, 0, 0, NULL,
+               sr_es519xx_19200_11b_packet_valid, sr_es519xx_19200_11b_parse,
+               NULL,
+               &uni_t_ut60g_ser_driver_info, receive_data_UNI_T_UT60G_SER,
+       },
+       {
+               "UNI-T", "UT61B (UT-D02 cable)", "2400/8n1/rts=0/dtr=1",
+               2400, FS9922_PACKET_SIZE, 0, 0, NULL,
+               sr_fs9922_packet_valid, sr_fs9922_parse, NULL,
+               &uni_t_ut61b_ser_driver_info, receive_data_UNI_T_UT61B_SER,
+       },
+       {
+               "UNI-T", "UT61C (UT-D02 cable)", "2400/8n1/rts=0/dtr=1",
+               2400, FS9922_PACKET_SIZE, 0, 0, NULL,
+               sr_fs9922_packet_valid, sr_fs9922_parse, NULL,
+               &uni_t_ut61c_ser_driver_info, receive_data_UNI_T_UT61C_SER,
+       },
+       {
+               "UNI-T", "UT61D (UT-D02 cable)", "2400/8n1/rts=0/dtr=1",
+               2400, FS9922_PACKET_SIZE, 0, 0, NULL,
+               sr_fs9922_packet_valid, sr_fs9922_parse, NULL,
+               &uni_t_ut61d_ser_driver_info, receive_data_UNI_T_UT61D_SER,
+       },
+       {
+               /* Note: ES51922 baudrate is actually 19230! */
+               "UNI-T", "UT61E (UT-D02 cable)", "19200/7o1/rts=0/dtr=1",
+               19200, ES519XX_14B_PACKET_SIZE, 0, 0, NULL,
+               sr_es519xx_19200_14b_packet_valid, sr_es519xx_19200_14b_parse,
+               NULL,
+               &uni_t_ut61e_ser_driver_info, receive_data_UNI_T_UT61E_SER,
+       },
+       {
+               "ISO-TECH", "IDM103N", "2400/7o1/rts=0/dtr=1",
+               2400, ES519XX_11B_PACKET_SIZE, 0, 0, NULL,
+               sr_es519xx_2400_11b_packet_valid, sr_es519xx_2400_11b_parse,
+               NULL,
+               &iso_tech_idm103n_driver_info, receive_data_ISO_TECH_IDM103N,
+       },
+       {
+               "Tenma", "72-7745 (UT-D02 cable)", "2400/8n1/rts=0/dtr=1",
+               2400, FS9721_PACKET_SIZE, 0, 0, NULL,
+               sr_fs9721_packet_valid, sr_fs9721_parse,
+               sr_fs9721_00_temp_c,
+               &tenma_72_7745_ser_driver_info, receive_data_TENMA_72_7745_SER,
+       },
+       {
+               /* Note: ES51986 baudrate is actually 19230! */
+               "Tenma", "72-7750 (UT-D02 cable)", "19200/7o1/rts=0/dtr=1",
+               19200, ES519XX_11B_PACKET_SIZE, 0, 0, NULL,
+               sr_es519xx_19200_11b_packet_valid, sr_es519xx_19200_11b_parse,
+               NULL,
+               &tenma_72_7750_ser_driver_info, receive_data_TENMA_72_7750_SER,
+       },
+};
+
+static int dev_clear(int dmm)
+{
+       return std_dev_clear(dmms[dmm].di, NULL);
+}
+
+static int init(struct sr_context *sr_ctx, int dmm)
+{
+       sr_dbg("Selected '%s' subdriver.", dmms[dmm].di->name);
+
+       return std_init(sr_ctx, dmms[dmm].di, LOG_PREFIX);
+}
+
+static GSList *sdmm_scan(const char *conn, const char *serialcomm, int dmm)
+{
+       struct sr_dev_inst *sdi;
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       struct sr_channel *ch;
+       struct sr_serial_dev_inst *serial;
+       GSList *devices;
+       int dropped, ret;
+       size_t len;
+       uint8_t buf[128];
+
+       if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
+               return NULL;
+
+       if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
+               return NULL;
+
+       sr_info("Probing serial port %s.", conn);
+
+       drvc = dmms[dmm].di->priv;
+       devices = NULL;
+       serial_flush(serial);
+
+       /* Request a packet if the DMM requires this. */
+       if (dmms[dmm].packet_request) {
+               if ((ret = dmms[dmm].packet_request(serial)) < 0) {
+                       sr_err("Failed to request packet: %d.", ret);
+                       return FALSE;
+               }
+       }
+
+       /*
+        * There's no way to get an ID from the multimeter. It just sends data
+        * periodically (or upon request), so the best we can do is check if
+        * the packets match the expected format.
+        */
+
+       /* Let's get a bit of data and see if we can find a packet. */
+       len = sizeof(buf);
+       ret = serial_stream_detect(serial, buf, &len, dmms[dmm].packet_size,
+                                  dmms[dmm].packet_valid, 3000,
+                                  dmms[dmm].baudrate);
+       if (ret != SR_OK)
+               goto scan_cleanup;
+
+       /*
+        * If we dropped more than two packets worth of data, something is
+        * wrong. We shouldn't quit however, since the dropped bytes might be
+        * just zeroes at the beginning of the stream. Those can occur as a
+        * combination of the nonstandard cable that ships with some devices
+        * and the serial port or USB to serial adapter.
+        */
+       dropped = len - dmms[dmm].packet_size;
+       if (dropped > 2 * dmms[dmm].packet_size)
+               sr_warn("Had to drop too much data.");
+
+       sr_info("Found device on port %s.", conn);
+
+       if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, dmms[dmm].vendor,
+                                   dmms[dmm].device, NULL)))
+               goto scan_cleanup;
+
+       if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+               sr_err("Device context malloc failed.");
+               goto scan_cleanup;
+       }
+
+       sdi->inst_type = SR_INST_SERIAL;
+       sdi->conn = serial;
+
+       sdi->priv = devc;
+       sdi->driver = dmms[dmm].di;
+       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1")))
+               goto scan_cleanup;
+       sdi->channels = g_slist_append(sdi->channels, ch);
+       drvc->instances = g_slist_append(drvc->instances, sdi);
+       devices = g_slist_append(devices, sdi);
+
+scan_cleanup:
+       serial_close(serial);
+
+       return devices;
+}
+
+static GSList *scan(GSList *options, int dmm)
+{
+       struct sr_config *src;
+       GSList *l, *devices;
+       const char *conn, *serialcomm;
+
+       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 = sdmm_scan(conn, serialcomm, dmm);
+       } else {
+               /* Try the default. */
+               devices = sdmm_scan(conn, dmms[dmm].conn, dmm);
+       }
+
+       return devices;
+}
+
+static GSList *dev_list(int dmm)
+{
+       return ((struct drv_context *)(dmms[dmm].di->priv))->instances;
+}
+
+static int cleanup(int dmm)
+{
+       return dev_clear(dmm);
+}
+
+static int config_set(int id, 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;
+
+       if (!(devc = sdi->priv)) {
+               sr_err("sdi->priv was NULL.");
+               return SR_ERR_BUG;
+       }
+
+       switch (id) {
+       case SR_CONF_LIMIT_SAMPLES:
+               devc->limit_samples = g_variant_get_uint64(data);
+               sr_dbg("Setting sample limit to %" PRIu64 ".",
+                      devc->limit_samples);
+               break;
+       case SR_CONF_LIMIT_MSEC:
+               devc->limit_msec = g_variant_get_uint64(data);
+               sr_dbg("Setting time limit to %" PRIu64 "ms.",
+                      devc->limit_msec);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_list(int 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_INT32,
+                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+               break;
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi,
+                                   void *cb_data, int dmm)
+{
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       if (!(devc = sdi->priv)) {
+               sr_err("sdi->priv was NULL.");
+               return SR_ERR_BUG;
+       }
+
+       devc->cb_data = cb_data;
+
+       /*
+        * Reset the number of samples to take. If we've already collected our
+        * quota, but we start a new session, and don't reset this, we'll just
+        * quit without acquiring any new samples.
+        */
+       devc->num_samples = 0;
+       devc->starttime = g_get_monotonic_time();
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(cb_data, LOG_PREFIX);
+
+       /* Poll every 50ms, or whenever some data comes in. */
+       serial = sdi->conn;
+       serial_source_add(sdi->session, serial, G_IO_IN, 50,
+                     dmms[dmm].receive_data, (void *)sdi);
+
+       return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       return std_serial_dev_acquisition_stop(sdi, cb_data, std_serial_dev_close,
+                       sdi->conn, LOG_PREFIX);
+}
+
+/* Driver-specific API function wrappers */
+#define HW_INIT(X) \
+static int init_##X(struct sr_context *sr_ctx) { return init(sr_ctx, X); }
+#define HW_CLEANUP(X) \
+static int cleanup_##X(void) { return cleanup(X); }
+#define HW_SCAN(X) \
+static GSList *scan_##X(GSList *options) { return scan(options, X); }
+#define HW_DEV_LIST(X) \
+static GSList *dev_list_##X(void) { return dev_list(X); }
+#define HW_DEV_CLEAR(X) \
+static int dev_clear_##X(void) { return dev_clear(X); }
+#define HW_DEV_ACQUISITION_START(X) \
+static int dev_acquisition_start_##X(const struct sr_dev_inst *sdi, \
+void *cb_data) { return dev_acquisition_start(sdi, cb_data, X); }
+
+/* Driver structs and API function wrappers */
+#define DRV(ID, ID_UPPER, NAME, LONGNAME) \
+HW_INIT(ID_UPPER) \
+HW_CLEANUP(ID_UPPER) \
+HW_SCAN(ID_UPPER) \
+HW_DEV_LIST(ID_UPPER) \
+HW_DEV_CLEAR(ID_UPPER) \
+HW_DEV_ACQUISITION_START(ID_UPPER) \
+SR_PRIV struct sr_dev_driver ID##_driver_info = { \
+       .name = NAME, \
+       .longname = LONGNAME, \
+       .api_version = 1, \
+       .init = init_##ID_UPPER, \
+       .cleanup = cleanup_##ID_UPPER, \
+       .scan = scan_##ID_UPPER, \
+       .dev_list = dev_list_##ID_UPPER, \
+       .dev_clear = dev_clear_##ID_UPPER, \
+       .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_##ID_UPPER, \
+       .dev_acquisition_stop = dev_acquisition_stop, \
+       .priv = NULL, \
+};
+
+DRV(bbcgm_m2110, BBCGM_M2110, "bbcgm-m2110", "BBC Goertz Metrawatt M2110")
+DRV(digitek_dt4000zc, DIGITEK_DT4000ZC, "digitek-dt4000zc", "Digitek DT4000ZC")
+DRV(tekpower_tp4000zc, TEKPOWER_TP4000ZC, "tekpower-tp4000zc", "TekPower TP4000ZC")
+DRV(metex_me31, METEX_ME31, "metex-me31", "Metex ME-31")
+DRV(peaktech_3410, PEAKTECH_3410, "peaktech-3410", "PeakTech 3410")
+DRV(mastech_mas345, MASTECH_MAS345, "mastech-mas345", "MASTECH MAS345")
+DRV(va_va18b, VA_VA18B, "va-va18b", "V&A VA18B")
+DRV(va_va40b, VA_VA40B, "va-va40b", "V&A VA40B")
+DRV(metex_m3640d, METEX_M3640D, "metex-m3640d", "Metex M-3640D")
+DRV(metex_m4650cr, METEX_M4650CR, "metex-m4650cr", "Metex M-4650CR")
+DRV(peaktech_4370, PEAKTECH_4370, "peaktech-4370", "PeakTech 4370")
+DRV(pce_pce_dm32, PCE_PCE_DM32, "pce-pce-dm32", "PCE PCE-DM32")
+DRV(radioshack_22_168, RADIOSHACK_22_168, "radioshack-22-168", "RadioShack 22-168")
+DRV(radioshack_22_805, RADIOSHACK_22_805, "radioshack-22-805", "RadioShack 22-805")
+DRV(radioshack_22_812, RADIOSHACK_22_812, "radioshack-22-812", "RadioShack 22-812")
+DRV(tecpel_dmm_8061_ser, TECPEL_DMM_8061_SER, "tecpel-dmm-8061-ser", "Tecpel DMM-8061 (UT-D02 cable)")
+DRV(voltcraft_m3650cr, VOLTCRAFT_M3650CR, "voltcraft-m3650cr", "Voltcraft M-3650CR")
+DRV(voltcraft_m3650d, VOLTCRAFT_M3650D, "voltcraft-m3650d", "Voltcraft M-3650D")
+DRV(voltcraft_m4650cr, VOLTCRAFT_M4650CR, "voltcraft-m4650cr", "Voltcraft M-4650CR")
+DRV(voltcraft_me42, VOLTCRAFT_ME42, "voltcraft-me42", "Voltcraft ME-42")
+DRV(voltcraft_vc820_ser, VOLTCRAFT_VC820_SER, "voltcraft-vc820-ser", "Voltcraft VC-820 (UT-D02 cable)")
+DRV(voltcraft_vc830_ser, VOLTCRAFT_VC830_SER, "voltcraft-vc830-ser", "Voltcraft VC-830 (UT-D02 cable)")
+DRV(voltcraft_vc840_ser, VOLTCRAFT_VC840_SER, "voltcraft-vc840-ser", "Voltcraft VC-840 (UT-D02 cable)")
+DRV(uni_t_ut60a_ser, UNI_T_UT60A_SER, "uni-t-ut60a-ser", "UNI-T UT60A (UT-D02 cable)")
+DRV(uni_t_ut60e_ser, UNI_T_UT60E_SER, "uni-t-ut60e-ser", "UNI-T UT60E (UT-D02 cable)")
+DRV(uni_t_ut60g_ser, UNI_T_UT60G_SER, "uni-t-ut60g-ser", "UNI-T UT60G (UT-D02 cable)")
+DRV(uni_t_ut61b_ser, UNI_T_UT61B_SER, "uni-t-ut61b-ser", "UNI-T UT61B (UT-D02 cable)")
+DRV(uni_t_ut61c_ser, UNI_T_UT61C_SER, "uni-t-ut61c-ser", "UNI-T UT61C (UT-D02 cable)")
+DRV(uni_t_ut61d_ser, UNI_T_UT61D_SER, "uni-t-ut61d-ser", "UNI-T UT61D (UT-D02 cable)")
+DRV(uni_t_ut61e_ser, UNI_T_UT61E_SER, "uni-t-ut61e-ser", "UNI-T UT61E (UT-D02 cable)")
+DRV(iso_tech_idm103n, ISO_TECH_IDM103N, "iso-tech-idm103n", "ISO-TECH IDM103N")
+DRV(tenma_72_7745_ser, TENMA_72_7745_SER, "tenma-72-7745-ser", "Tenma 72-7745 (UT-D02 cable)")
+DRV(tenma_72_7750_ser, TENMA_72_7750_SER, "tenma-72-7750-ser", "Tenma 72-7750 (UT-D02 cable)")
diff --git a/src/hardware/serial-dmm/protocol.c b/src/hardware/serial-dmm/protocol.c
new file mode 100644 (file)
index 0000000..0b2472f
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@gmail.com>
+ * Copyright (C) 2012 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 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 <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <errno.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "protocol.h"
+
+static void log_dmm_packet(const uint8_t *buf)
+{
+       sr_dbg("DMM packet: %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]);
+}
+
+static void handle_packet(const uint8_t *buf, struct sr_dev_inst *sdi,
+                         int dmm, void *info)
+{
+       float floatval;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_analog analog;
+       struct dev_context *devc;
+
+       log_dmm_packet(buf);
+       devc = sdi->priv;
+
+       memset(&analog, 0, sizeof(struct sr_datafeed_analog));
+
+       analog.channels = sdi->channels;
+       analog.num_samples = 1;
+       analog.mq = -1;
+
+       dmms[dmm].packet_parse(buf, &floatval, &analog, info);
+       analog.data = &floatval;
+
+       /* If this DMM needs additional handling, call the resp. function. */
+       if (dmms[dmm].dmm_details)
+               dmms[dmm].dmm_details(&analog, info);
+
+       if (analog.mq != -1) {
+               /* Got a measurement. */
+               packet.type = SR_DF_ANALOG;
+               packet.payload = &analog;
+               sr_session_send(devc->cb_data, &packet);
+               devc->num_samples++;
+       }
+}
+
+/** Request packet, if required. */
+SR_PRIV int req_packet(struct sr_dev_inst *sdi, int dmm)
+{
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+       int ret;
+
+       if (!dmms[dmm].packet_request)
+               return SR_OK;
+
+       devc = sdi->priv;
+       serial = sdi->conn;
+
+       if (devc->req_next_at && (devc->req_next_at > g_get_monotonic_time())) {
+               sr_spew("Not requesting new packet yet, %" PRIi64 " ms left.",
+                       ((devc->req_next_at - g_get_monotonic_time()) / 1000));
+               return SR_OK;
+       }
+
+       ret = dmms[dmm].packet_request(serial);
+       if (ret < 0) {
+               sr_err("Failed to request packet: %d.", ret);
+               return ret;
+       }
+
+       if (dmms[dmm].req_timeout_ms)
+               devc->req_next_at = g_get_monotonic_time() + (dmms[dmm].req_timeout_ms * 1000);
+
+       return SR_OK;
+}
+
+static void handle_new_data(struct sr_dev_inst *sdi, int dmm, void *info)
+{
+       struct dev_context *devc;
+       int len, i, 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(serial, devc->buf + devc->buflen, len);
+       if (len == 0)
+               return; /* No new bytes, nothing to do. */
+       if (len < 0) {
+               sr_err("Serial port read error: %d.", len);
+               return;
+       }
+       devc->buflen += len;
+
+       /* Now look for packets in that data. */
+       while ((devc->buflen - offset) >= dmms[dmm].packet_size) {
+               if (dmms[dmm].packet_valid(devc->buf + offset)) {
+                       handle_packet(devc->buf + offset, sdi, dmm, info);
+                       offset += dmms[dmm].packet_size;
+
+                       /* Request next packet, if required. */
+                       if (!dmms[dmm].packet_request)
+                               break;
+                       if (dmms[dmm].req_timeout_ms || dmms[dmm].req_delay_ms)
+                               devc->req_next_at = g_get_monotonic_time() +
+                                       dmms[dmm].req_delay_ms * 1000;
+                       req_packet(sdi, dmm);
+               } else {
+                       offset++;
+               }
+       }
+
+       /* If we have any data left, move it to the beginning of our buffer. */
+       for (i = 0; i < devc->buflen - offset; i++)
+               devc->buf[i] = devc->buf[offset + i];
+       devc->buflen -= offset;
+}
+
+static int receive_data(int fd, int revents, int dmm, void *info, void *cb_data)
+{
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       int64_t time;
+
+       (void)fd;
+
+       if (!(sdi = cb_data))
+               return TRUE;
+
+       if (!(devc = sdi->priv))
+               return TRUE;
+
+       if (revents == G_IO_IN) {
+               /* Serial data arrived. */
+               handle_new_data(sdi, dmm, info);
+       } else {
+               /* Timeout; send another packet request if DMM needs it. */
+               if (dmms[dmm].packet_request && (req_packet(sdi, dmm) < 0))
+                       return FALSE;
+       }
+
+       if (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
+               sr_info("Requested number of samples reached.");
+               sdi->driver->dev_acquisition_stop(sdi, cb_data);
+               return TRUE;
+       }
+
+       if (devc->limit_msec) {
+               time = (g_get_monotonic_time() - devc->starttime) / 1000;
+               if (time > (int64_t)devc->limit_msec) {
+                       sr_info("Requested time limit reached.");
+                       sdi->driver->dev_acquisition_stop(sdi, cb_data);
+                       return TRUE;
+               }
+       }
+
+       return TRUE;
+}
+
+#define RECEIVE_DATA(ID_UPPER, DMM_DRIVER) \
+SR_PRIV int receive_data_##ID_UPPER(int fd, int revents, void *cb_data) { \
+       struct DMM_DRIVER##_info info; \
+       return receive_data(fd, revents, ID_UPPER, &info, cb_data); }
+
+/* Driver-specific receive_data() wrappers */
+RECEIVE_DATA(BBCGM_M2110, metex14) /* metex14_info used as a dummy. */
+RECEIVE_DATA(DIGITEK_DT4000ZC, fs9721)
+RECEIVE_DATA(TEKPOWER_TP4000ZC, fs9721)
+RECEIVE_DATA(METEX_ME31, metex14)
+RECEIVE_DATA(PEAKTECH_3410, metex14)
+RECEIVE_DATA(MASTECH_MAS345, metex14)
+RECEIVE_DATA(VA_VA18B, fs9721)
+RECEIVE_DATA(VA_VA40B, fs9721)
+RECEIVE_DATA(METEX_M3640D, metex14)
+RECEIVE_DATA(METEX_M4650CR, metex14)
+RECEIVE_DATA(PEAKTECH_4370, metex14)
+RECEIVE_DATA(PCE_PCE_DM32, fs9721)
+RECEIVE_DATA(RADIOSHACK_22_168, metex14)
+RECEIVE_DATA(RADIOSHACK_22_805, metex14)
+RECEIVE_DATA(RADIOSHACK_22_812, rs9lcd)
+RECEIVE_DATA(TECPEL_DMM_8061_SER, fs9721)
+RECEIVE_DATA(VOLTCRAFT_M3650CR, metex14)
+RECEIVE_DATA(VOLTCRAFT_M3650D, metex14)
+RECEIVE_DATA(VOLTCRAFT_M4650CR, metex14)
+RECEIVE_DATA(VOLTCRAFT_ME42, metex14)
+RECEIVE_DATA(VOLTCRAFT_VC820_SER, fs9721)
+RECEIVE_DATA(VOLTCRAFT_VC830_SER, fs9922)
+RECEIVE_DATA(VOLTCRAFT_VC840_SER, fs9721)
+RECEIVE_DATA(UNI_T_UT60A_SER, fs9721)
+RECEIVE_DATA(UNI_T_UT60E_SER, fs9721)
+RECEIVE_DATA(UNI_T_UT60G_SER, es519xx)
+RECEIVE_DATA(UNI_T_UT61B_SER, fs9922)
+RECEIVE_DATA(UNI_T_UT61C_SER, fs9922)
+RECEIVE_DATA(UNI_T_UT61D_SER, fs9922)
+RECEIVE_DATA(UNI_T_UT61E_SER, es519xx)
+RECEIVE_DATA(ISO_TECH_IDM103N, es519xx)
+RECEIVE_DATA(TENMA_72_7745_SER, fs9721)
+RECEIVE_DATA(TENMA_72_7750_SER, es519xx)
diff --git a/src/hardware/serial-dmm/protocol.h b/src/hardware/serial-dmm/protocol.h
new file mode 100644 (file)
index 0000000..fb5a2a3
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * 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_SERIAL_DMM_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_SERIAL_DMM_PROTOCOL_H
+
+#define LOG_PREFIX "serial-dmm"
+
+enum {
+       BBCGM_M2110,
+       DIGITEK_DT4000ZC,
+       TEKPOWER_TP4000ZC,
+       METEX_ME31,
+       PEAKTECH_3410,
+       MASTECH_MAS345,
+       VA_VA18B,
+       VA_VA40B,
+       METEX_M3640D,
+       METEX_M4650CR,
+       PEAKTECH_4370,
+       PCE_PCE_DM32,
+       RADIOSHACK_22_168,
+       RADIOSHACK_22_805,
+       RADIOSHACK_22_812,
+       TECPEL_DMM_8061_SER,
+       VOLTCRAFT_M3650CR,
+       VOLTCRAFT_M3650D,
+       VOLTCRAFT_M4650CR,
+       VOLTCRAFT_ME42,
+       VOLTCRAFT_VC820_SER,
+       VOLTCRAFT_VC830_SER,
+       VOLTCRAFT_VC840_SER,
+       UNI_T_UT60A_SER,
+       UNI_T_UT60E_SER,
+       UNI_T_UT60G_SER,
+       UNI_T_UT61B_SER,
+       UNI_T_UT61C_SER,
+       UNI_T_UT61D_SER,
+       UNI_T_UT61E_SER,
+       ISO_TECH_IDM103N,
+       TENMA_72_7745_SER,
+       TENMA_72_7750_SER,
+};
+
+struct dmm_info {
+       /** Manufacturer/brand. */
+       char *vendor;
+       /** Model. */
+       char *device;
+       /** serialconn string. */
+       char *conn;
+       /** Baud rate. */
+       uint32_t baudrate;
+       /** Packet size in bytes. */
+       int packet_size;
+       /** Request timeout [ms] before request is considered lost and a new
+        *  one is sent. Used only if device needs polling. */
+       int64_t req_timeout_ms;
+       /** Delay between reception of packet and next request. Some DMMs
+        *  need this. Used only if device needs polling. */
+       int64_t req_delay_ms;
+       /** Packet request function. */
+       int (*packet_request)(struct sr_serial_dev_inst *);
+       /** Packet validation function. */
+       gboolean (*packet_valid)(const uint8_t *);
+       /** Packet parsing function. */
+       int (*packet_parse)(const uint8_t *, float *,
+                           struct sr_datafeed_analog *, void *);
+       /** */
+       void (*dmm_details)(struct sr_datafeed_analog *, void *);
+       /** libsigrok driver info struct. */
+       struct sr_dev_driver *di;
+       /** Data reception function. */
+       int (*receive_data)(int, int, void *);
+};
+
+extern SR_PRIV struct dmm_info dmms[];
+
+#define DMM_BUFSIZE 256
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+       /** The current sampling limit (in number of samples). */
+       uint64_t limit_samples;
+
+       /** The time limit (in milliseconds). */
+       uint64_t limit_msec;
+
+       /** Opaque pointer passed in by the frontend. */
+       void *cb_data;
+
+       /** The current number of already received samples. */
+       uint64_t num_samples;
+
+       /** The starting time of current sampling run. */
+       int64_t starttime;
+
+       uint8_t buf[DMM_BUFSIZE];
+       int bufoffset;
+       int buflen;
+
+       /** The timestamp [µs] to send the next request.
+        *  Used only if device needs polling. */
+       int64_t req_next_at;
+};
+
+SR_PRIV int req_packet(struct sr_dev_inst *sdi, int dmm);
+
+SR_PRIV int receive_data_BBCGM_M2110(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_DIGITEK_DT4000ZC(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_TEKPOWER_TP4000ZC(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_METEX_ME31(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_PEAKTECH_3410(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_MASTECH_MAS345(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_VA_VA18B(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_VA_VA40B(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_METEX_M3640D(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_METEX_M4650CR(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_PEAKTECH_4370(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_PCE_PCE_DM32(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_RADIOSHACK_22_168(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_RADIOSHACK_22_805(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_RADIOSHACK_22_812(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_TECPEL_DMM_8061_SER(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_VOLTCRAFT_M3650CR(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_VOLTCRAFT_M3650D(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_VOLTCRAFT_M4650CR(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_VOLTCRAFT_ME42(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_VOLTCRAFT_VC820_SER(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_VOLTCRAFT_VC830_SER(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_VOLTCRAFT_VC840_SER(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_UNI_T_UT60A_SER(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_UNI_T_UT60E_SER(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_UNI_T_UT60G_SER(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_UNI_T_UT61B_SER(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_UNI_T_UT61C_SER(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_UNI_T_UT61D_SER(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_UNI_T_UT61E_SER(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_ISO_TECH_IDM103N(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_TENMA_72_7745_SER(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_TENMA_72_7750_SER(int fd, int revents, void *cb_data);
+
+#endif
diff --git a/src/hardware/sysclk-lwla/api.c b/src/hardware/sysclk-lwla/api.c
new file mode 100644 (file)
index 0000000..a4346a0
--- /dev/null
@@ -0,0 +1,584 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Daniel Elstner <daniel.kitta@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 "protocol.h"
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include <glib.h>
+#include <libusb.h>
+#include <stdlib.h>
+#include <string.h>
+
+static const int32_t hwopts[] = {
+       SR_CONF_CONN,
+};
+
+static const int32_t hwcaps[] = {
+       SR_CONF_LOGIC_ANALYZER,
+       SR_CONF_SAMPLERATE,
+       SR_CONF_EXTERNAL_CLOCK,
+       SR_CONF_CLOCK_EDGE,
+       SR_CONF_TRIGGER_MATCH,
+       SR_CONF_TRIGGER_SOURCE,
+       SR_CONF_TRIGGER_SLOPE,
+       SR_CONF_LIMIT_MSEC,
+       SR_CONF_LIMIT_SAMPLES,
+};
+
+static const int32_t trigger_matches[] = {
+       SR_TRIGGER_ZERO,
+       SR_TRIGGER_ONE,
+       SR_TRIGGER_RISING,
+       SR_TRIGGER_FALLING,
+};
+
+/* The hardware supports more samplerates than these, but these are the
+ * options hardcoded into the vendor's Windows GUI.
+ */
+static const uint64_t samplerates[] = {
+       SR_MHZ(125), SR_MHZ(100),
+       SR_MHZ(50),  SR_MHZ(20),  SR_MHZ(10),
+       SR_MHZ(5),   SR_MHZ(2),   SR_MHZ(1),
+       SR_KHZ(500), SR_KHZ(200), SR_KHZ(100),
+       SR_KHZ(50),  SR_KHZ(20),  SR_KHZ(10),
+       SR_KHZ(5),   SR_KHZ(2),   SR_KHZ(1),
+       SR_HZ(500),  SR_HZ(200),  SR_HZ(100),
+};
+
+/* Names assigned to available trigger sources.  Indices must match
+ * trigger_source enum values.
+ */
+static const char *const trigger_source_names[] = { "CH", "TRG" };
+
+/* Names assigned to available trigger slope choices.  Indices must
+ * match the signal_edge enum values.
+ */
+static const char *const signal_edge_names[] = { "r", "f" };
+
+SR_PRIV struct sr_dev_driver sysclk_lwla_driver_info;
+static struct sr_dev_driver *const di = &sysclk_lwla_driver_info;
+
+static int init(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *gen_channel_list(int num_channels)
+{
+       GSList *list;
+       struct sr_channel *ch;
+       int i;
+       char name[8];
+
+       list = NULL;
+
+       for (i = num_channels; i > 0; --i) {
+               /* The LWLA series simply number channels from CH1 to CHxx. */
+               g_snprintf(name, sizeof(name), "CH%d", i);
+
+               ch = sr_channel_new(i - 1, SR_CHANNEL_LOGIC, TRUE, name);
+               list = g_slist_prepend(list, ch);
+       }
+
+       return list;
+}
+
+static struct sr_dev_inst *dev_inst_new(int device_index)
+{
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+
+       /* Allocate memory for our private driver context. */
+       devc = g_try_new0(struct dev_context, 1);
+       if (!devc) {
+               sr_err("Device context malloc failed.");
+               return NULL;
+       }
+
+       /* Register the device with libsigrok. */
+       sdi = sr_dev_inst_new(device_index, SR_ST_INACTIVE,
+                             VENDOR_NAME, MODEL_NAME, NULL);
+       if (!sdi) {
+               sr_err("Failed to instantiate device.");
+               g_free(devc);
+               return NULL;
+       }
+
+       /* Enable all channels to match the default channel configuration. */
+       devc->channel_mask = ALL_CHANNELS_MASK;
+       devc->samplerate = DEFAULT_SAMPLERATE;
+
+       sdi->priv = devc;
+       sdi->channels = gen_channel_list(NUM_CHANNELS);
+
+       return sdi;
+}
+
+static GSList *scan(GSList *options)
+{
+       GSList *usb_devices, *devices, *node;
+       struct drv_context *drvc;
+       struct sr_dev_inst *sdi;
+       struct sr_usb_dev_inst *usb;
+       struct sr_config *src;
+       const char *conn;
+       int device_index;
+
+       drvc = di->priv;
+       conn = USB_VID_PID;
+
+       for (node = options; node != NULL; node = node->next) {
+               src = node->data;
+               if (src->key == SR_CONF_CONN) {
+                       conn = g_variant_get_string(src->data, NULL);
+                       break;
+               }
+       }
+       usb_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn);
+       devices = NULL;
+       device_index = g_slist_length(drvc->instances);
+
+       for (node = usb_devices; node != NULL; node = node->next) {
+               usb = node->data;
+
+               /* Create sigrok device instance. */
+               sdi = dev_inst_new(device_index);
+               if (!sdi) {
+                       sr_usb_dev_inst_free(usb);
+                       continue;
+               }
+               sdi->driver = di;
+               sdi->inst_type = SR_INST_USB;
+               sdi->conn = usb;
+
+               /* Register device instance with driver. */
+               drvc->instances = g_slist_append(drvc->instances, sdi);
+               devices = g_slist_append(devices, sdi);
+       }
+
+       g_slist_free(usb_devices);
+
+       return devices;
+}
+
+static GSList *dev_list(void)
+{
+       struct drv_context *drvc;
+
+       drvc = di->priv;
+
+       return drvc->instances;
+}
+
+static void clear_dev_context(void *priv)
+{
+       struct dev_context *devc;
+
+       devc = priv;
+
+       sr_dbg("Device context cleared.");
+
+       lwla_free_acquisition_state(devc->acquisition);
+       g_free(devc);
+}
+
+static int dev_clear(void)
+{
+       return std_dev_clear(di, &clear_dev_context);
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+       struct drv_context *drvc;
+       struct sr_usb_dev_inst *usb;
+       int ret;
+
+       drvc = di->priv;
+
+       if (!drvc) {
+               sr_err("Driver was not initialized.");
+               return SR_ERR;
+       }
+
+       usb = sdi->conn;
+
+       ret = sr_usb_open(drvc->sr_ctx->libusb_ctx, usb);
+       if (ret != SR_OK)
+               return ret;
+
+       ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE);
+       if (ret < 0) {
+               sr_err("Failed to claim interface: %s.",
+                       libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+       sdi->status = SR_ST_INITIALIZING;
+
+       ret = lwla_init_device(sdi);
+
+       if (ret == SR_OK)
+               sdi->status = SR_ST_ACTIVE;
+
+       return ret;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+       struct sr_usb_dev_inst *usb;
+
+       if (!di->priv) {
+               sr_err("Driver was not initialized.");
+               return SR_ERR;
+       }
+
+       usb = sdi->conn;
+       if (!usb->devhdl)
+               return SR_OK;
+
+       sdi->status = SR_ST_INACTIVE;
+
+       /* Trigger download of the shutdown bitstream. */
+       if (lwla_set_clock_config(sdi) != SR_OK)
+               sr_err("Unable to shut down device.");
+
+       libusb_release_interface(usb->devhdl, USB_INTERFACE);
+       libusb_close(usb->devhdl);
+
+       usb->devhdl = NULL;
+
+       return SR_OK;
+}
+
+static int cleanup(void)
+{
+       return dev_clear();
+}
+
+static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
+                     const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       size_t idx;
+
+       (void)cg;
+
+       if (!sdi)
+               return SR_ERR_ARG;
+
+       devc = sdi->priv;
+
+       switch (key) {
+       case SR_CONF_SAMPLERATE:
+               *data = g_variant_new_uint64(devc->samplerate);
+               break;
+       case SR_CONF_LIMIT_MSEC:
+               *data = g_variant_new_uint64(devc->limit_msec);
+               break;
+       case SR_CONF_LIMIT_SAMPLES:
+               *data = g_variant_new_uint64(devc->limit_samples);
+               break;
+       case SR_CONF_EXTERNAL_CLOCK:
+               *data = g_variant_new_boolean(devc->cfg_clock_source
+                                               == CLOCK_EXT_CLK);
+               break;
+       case SR_CONF_CLOCK_EDGE:
+               idx = devc->cfg_clock_edge;
+               if (idx >= G_N_ELEMENTS(signal_edge_names))
+                       return SR_ERR_BUG;
+               *data = g_variant_new_string(signal_edge_names[idx]);
+               break;
+       case SR_CONF_TRIGGER_SOURCE:
+               idx = devc->cfg_trigger_source;
+               if (idx >= G_N_ELEMENTS(trigger_source_names))
+                       return SR_ERR_BUG;
+               *data = g_variant_new_string(trigger_source_names[idx]);
+               break;
+       case SR_CONF_TRIGGER_SLOPE:
+               idx = devc->cfg_trigger_slope;
+               if (idx >= G_N_ELEMENTS(signal_edge_names))
+                       return SR_ERR_BUG;
+               *data = g_variant_new_string(signal_edge_names[idx]);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+/* Helper for mapping a string-typed configuration value to an index
+ * within a table of possible values.
+ */
+static int lookup_index(GVariant *value, const char *const *table, int len)
+{
+       const char *entry;
+       int i;
+
+       entry = g_variant_get_string(value, NULL);
+       if (!entry)
+               return -1;
+
+       /* Linear search is fine for very small tables. */
+       for (i = 0; i < len; ++i) {
+               if (strcmp(entry, table[i]) == 0)
+                       return i;
+       }
+       return -1;
+}
+
+static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
+                     const struct sr_channel_group *cg)
+{
+       uint64_t value;
+       struct dev_context *devc;
+       int idx;
+
+       (void)cg;
+
+       devc = sdi->priv;
+       if (!devc)
+               return SR_ERR_DEV_CLOSED;
+
+       switch (key) {
+       case SR_CONF_SAMPLERATE:
+               value = g_variant_get_uint64(data);
+               if (value < samplerates[G_N_ELEMENTS(samplerates) - 1]
+                               || value > samplerates[0])
+                       return SR_ERR_SAMPLERATE;
+               devc->samplerate = value;
+               break;
+       case SR_CONF_LIMIT_MSEC:
+               value = g_variant_get_uint64(data);
+               if (value > MAX_LIMIT_MSEC)
+                       return SR_ERR_ARG;
+               devc->limit_msec = value;
+               break;
+       case SR_CONF_LIMIT_SAMPLES:
+               value = g_variant_get_uint64(data);
+               if (value > MAX_LIMIT_SAMPLES)
+                       return SR_ERR_ARG;
+               devc->limit_samples = value;
+               break;
+       case SR_CONF_EXTERNAL_CLOCK:
+               devc->cfg_clock_source = (g_variant_get_boolean(data))
+                       ? CLOCK_EXT_CLK : CLOCK_INTERNAL;
+               break;
+       case SR_CONF_CLOCK_EDGE:
+               idx = lookup_index(data, signal_edge_names,
+                                  G_N_ELEMENTS(signal_edge_names));
+               if (idx < 0)
+                       return SR_ERR_ARG;
+               devc->cfg_clock_edge = idx;
+               break;
+       case SR_CONF_TRIGGER_SOURCE:
+               idx = lookup_index(data, trigger_source_names,
+                                  G_N_ELEMENTS(trigger_source_names));
+               if (idx < 0)
+                       return SR_ERR_ARG;
+               devc->cfg_trigger_source = idx;
+               break;
+       case SR_CONF_TRIGGER_SLOPE:
+               idx = lookup_index(data, signal_edge_names,
+                                  G_N_ELEMENTS(signal_edge_names));
+               if (idx < 0)
+                       return SR_ERR_ARG;
+               devc->cfg_trigger_slope = idx;
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_channel_set(const struct sr_dev_inst *sdi,
+               struct sr_channel *ch, unsigned int changes)
+{
+       uint64_t channel_bit;
+       struct dev_context *devc;
+
+       devc = sdi->priv;
+       if (!devc)
+               return SR_ERR_DEV_CLOSED;
+
+       if (ch->index < 0 || ch->index >= NUM_CHANNELS) {
+               sr_err("Channel index %d out of range.", ch->index);
+               return SR_ERR_BUG;
+       }
+       channel_bit = (uint64_t)1 << ch->index;
+
+       if ((changes & SR_CHANNEL_SET_ENABLED) != 0) {
+               /* Enable or disable input channel for this channel. */
+               if (ch->enabled)
+                       devc->channel_mask |= channel_bit;
+               else
+                       devc->channel_mask &= ~channel_bit;
+       }
+
+       return SR_OK;
+}
+
+static int config_commit(const struct sr_dev_inst *sdi)
+{
+       if (sdi->status != SR_ST_ACTIVE) {
+               sr_err("Device not ready (status %d).", (int)sdi->status);
+               return SR_ERR;
+       }
+
+       return lwla_set_clock_config(sdi);
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+                      const struct sr_channel_group *cg)
+{
+       GVariant *gvar;
+       GVariantBuilder gvb;
+
+       (void)sdi;
+       (void)cg;
+
+       switch (key) {
+       case SR_CONF_SCAN_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwopts, G_N_ELEMENTS(hwopts), sizeof(int32_t));
+               break;
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwcaps, G_N_ELEMENTS(hwcaps), sizeof(int32_t));
+               break;
+       case SR_CONF_SAMPLERATE:
+               g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
+               gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"),
+                               samplerates, G_N_ELEMENTS(samplerates),
+                               sizeof(uint64_t));
+               g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar);
+               *data = g_variant_builder_end(&gvb);
+               break;
+       case SR_CONF_TRIGGER_MATCH:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               trigger_matches, ARRAY_SIZE(trigger_matches),
+                               sizeof(int32_t));
+               break;
+       case SR_CONF_TRIGGER_SOURCE:
+               *data = g_variant_new_strv(trigger_source_names,
+                                          G_N_ELEMENTS(trigger_source_names));
+               break;
+       case SR_CONF_TRIGGER_SLOPE:
+       case SR_CONF_CLOCK_EDGE:
+               *data = g_variant_new_strv(signal_edge_names,
+                                          G_N_ELEMENTS(signal_edge_names));
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       struct acquisition_state *acq;
+       int ret;
+
+       (void)cb_data;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       devc = sdi->priv;
+       drvc = di->priv;
+
+       if (devc->acquisition) {
+               sr_err("Acquisition still in progress?");
+               return SR_ERR;
+       }
+       acq = lwla_alloc_acquisition_state();
+       if (!acq)
+               return SR_ERR_MALLOC;
+
+       devc->stopping_in_progress = FALSE;
+       devc->transfer_error = FALSE;
+
+       sr_info("Starting acquisition.");
+
+       devc->acquisition = acq;
+       lwla_convert_trigger(sdi);
+       ret = lwla_setup_acquisition(sdi);
+       if (ret != SR_OK) {
+               sr_err("Failed to set up acquisition.");
+               devc->acquisition = NULL;
+               lwla_free_acquisition_state(acq);
+               return ret;
+       }
+
+       ret = lwla_start_acquisition(sdi);
+       if (ret != SR_OK) {
+               sr_err("Failed to start acquisition.");
+               devc->acquisition = NULL;
+               lwla_free_acquisition_state(acq);
+               return ret;
+       }
+       usb_source_add(sdi->session, drvc->sr_ctx, 100, &lwla_receive_data,
+                      (struct sr_dev_inst *)sdi);
+
+       sr_info("Waiting for data.");
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(sdi, LOG_PREFIX);
+
+       return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       (void)cb_data;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       sr_dbg("Stopping acquisition.");
+
+       sdi->status = SR_ST_STOPPING;
+
+       return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver sysclk_lwla_driver_info = {
+       .name = "sysclk-lwla",
+       .longname = "SysClk LWLA series",
+       .api_version = 1,
+       .init = init,
+       .cleanup = cleanup,
+       .scan = scan,
+       .dev_list = dev_list,
+       .dev_clear = dev_clear,
+       .config_get = config_get,
+       .config_set = config_set,
+       .config_channel_set = config_channel_set,
+       .config_commit = config_commit,
+       .config_list = config_list,
+       .dev_open = dev_open,
+       .dev_close = dev_close,
+       .dev_acquisition_start = dev_acquisition_start,
+       .dev_acquisition_stop = dev_acquisition_stop,
+       .priv = NULL,
+};
diff --git a/src/hardware/sysclk-lwla/lwla.c b/src/hardware/sysclk-lwla/lwla.c
new file mode 100644 (file)
index 0000000..dcb7af7
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Daniel Elstner <daniel.kitta@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 "lwla.h"
+#include "protocol.h"
+#include "libsigrok-internal.h"
+#include <errno.h>
+#include <glib/gstdio.h>
+
+#define BITSTREAM_MAX_SIZE     262144  /* bitstream size limit for safety */
+#define BITSTREAM_HEADER_SIZE  4       /* transfer header size in bytes */
+
+/* Load a bitstream file into memory.  Returns a newly allocated array
+ * consisting of a 32-bit length field followed by the bitstream data.
+ */
+static unsigned char *load_bitstream_file(const char *filename, int *length_p)
+{
+       GStatBuf statbuf;
+       FILE *file;
+       unsigned char *stream;
+       size_t length, count;
+
+       /* Retrieve and validate the file size. */
+       if (g_stat(filename, &statbuf) < 0) {
+               sr_err("Failed to access bitstream file: %s.",
+                      g_strerror(errno));
+               return NULL;
+       }
+       if (!S_ISREG(statbuf.st_mode)) {
+               sr_err("Bitstream is not a regular file.");
+               return NULL;
+       }
+       if (statbuf.st_size <= 0 || statbuf.st_size > BITSTREAM_MAX_SIZE) {
+               sr_err("Refusing to load bitstream of unreasonable size "
+                      "(%" PRIu64 " bytes).", (uint64_t)statbuf.st_size);
+               return NULL;
+       }
+
+       /* The message length includes the 4-byte header. */
+       length = BITSTREAM_HEADER_SIZE + statbuf.st_size;
+       stream = g_try_malloc(length);
+       if (!stream) {
+               sr_err("Failed to allocate bitstream buffer.");
+               return NULL;
+       }
+
+       file = g_fopen(filename, "rb");
+       if (!file) {
+               sr_err("Failed to open bitstream file: %s.", g_strerror(errno));
+               g_free(stream);
+               return NULL;
+       }
+
+       /* Write the message length header. */
+       *(uint32_t *)stream = GUINT32_TO_BE(length);
+
+       count = fread(stream + BITSTREAM_HEADER_SIZE,
+                     length - BITSTREAM_HEADER_SIZE, 1, file);
+       if (count != 1) {
+               sr_err("Failed to read bitstream file: %s.", g_strerror(errno));
+               fclose(file);
+               g_free(stream);
+               return NULL;
+       }
+       fclose(file);
+
+       *length_p = length;
+       return stream;
+}
+
+/* Load a Raw Binary File (.rbf) from the firmware directory and transfer
+ * it to the device.
+ */
+SR_PRIV int lwla_send_bitstream(const struct sr_usb_dev_inst *usb,
+                               const char *basename)
+{
+       char *filename;
+       unsigned char *stream;
+       int ret;
+       int length;
+       int xfer_len;
+
+       if (!usb || !basename)
+               return SR_ERR_BUG;
+
+       filename = g_build_filename(FIRMWARE_DIR, basename, NULL);
+       sr_info("Downloading FPGA bitstream at '%s'.", filename);
+
+       stream = load_bitstream_file(filename, &length);
+       g_free(filename);
+
+       if (!stream)
+               return SR_ERR;
+
+       /* Transfer the entire bitstream in one URB. */
+       ret = libusb_bulk_transfer(usb->devhdl, EP_BITSTREAM,
+                                  stream, length, &xfer_len, USB_TIMEOUT);
+       g_free(stream);
+
+       if (ret != 0) {
+               sr_err("Failed to transfer bitstream: %s.",
+                      libusb_error_name(ret));
+               return SR_ERR;
+       }
+       if (xfer_len != length) {
+               sr_err("Failed to transfer bitstream: incorrect length "
+                      "%d != %d.", xfer_len, length);
+               return SR_ERR;
+       }
+       sr_info("FPGA bitstream download of %d bytes done.", xfer_len);
+
+       /* This delay appears to be necessary for reliable operation. */
+       g_usleep(30000);
+
+       return SR_OK;
+}
+
+SR_PRIV int lwla_send_command(const struct sr_usb_dev_inst *usb,
+                             const uint16_t *command, int cmd_len)
+{
+       int ret;
+       int xfer_len;
+
+       if (!usb || !command || cmd_len <= 0)
+               return SR_ERR_BUG;
+
+       xfer_len = 0;
+       ret = libusb_bulk_transfer(usb->devhdl, EP_COMMAND,
+                                  (unsigned char *)command, cmd_len * 2,
+                                  &xfer_len, USB_TIMEOUT);
+       if (ret != 0) {
+               sr_dbg("Failed to send command %d: %s.",
+                      LWLA_TO_UINT16(command[0]), libusb_error_name(ret));
+               return SR_ERR;
+       }
+       if (xfer_len != cmd_len * 2) {
+               sr_dbg("Failed to send command %d: incorrect length %d != %d.",
+                      LWLA_TO_UINT16(command[0]), xfer_len, cmd_len * 2);
+               return SR_ERR;
+       }
+       return SR_OK;
+}
+
+SR_PRIV int lwla_receive_reply(const struct sr_usb_dev_inst *usb,
+                              uint32_t *reply, int reply_len, int expect_len)
+{
+       int ret;
+       int xfer_len;
+
+       if (!usb || !reply || reply_len <= 0)
+               return SR_ERR_BUG;
+
+       xfer_len = 0;
+       ret = libusb_bulk_transfer(usb->devhdl, EP_REPLY,
+                                  (unsigned char *)reply, reply_len * 4,
+                                  &xfer_len, USB_TIMEOUT);
+       if (ret != 0) {
+               sr_dbg("Failed to receive reply: %s.", libusb_error_name(ret));
+               return SR_ERR;
+       }
+       if (xfer_len != expect_len * 4) {
+               sr_dbg("Failed to receive reply: incorrect length %d != %d.",
+                      xfer_len, expect_len * 4);
+               return SR_ERR;
+       }
+       return SR_OK;
+}
+
+SR_PRIV int lwla_read_reg(const struct sr_usb_dev_inst *usb,
+                         uint16_t reg, uint32_t *value)
+{
+       int ret;
+       uint16_t command[2];
+       uint32_t reply[128]; /* full EP buffer to avoid overflows */
+
+       command[0] = LWLA_WORD(CMD_READ_REG);
+       command[1] = LWLA_WORD(reg);
+
+       ret = lwla_send_command(usb, command, G_N_ELEMENTS(command));
+
+       if (ret != SR_OK)
+               return ret;
+
+       ret = lwla_receive_reply(usb, reply, G_N_ELEMENTS(reply), 1);
+
+       if (ret == SR_OK)
+               *value = LWLA_TO_UINT32(reply[0]);
+
+       return ret;
+}
+
+SR_PRIV int lwla_write_reg(const struct sr_usb_dev_inst *usb,
+                          uint16_t reg, uint32_t value)
+{
+       uint16_t command[4];
+
+       command[0] = LWLA_WORD(CMD_WRITE_REG);
+       command[1] = LWLA_WORD(reg);
+       command[2] = LWLA_WORD_0(value);
+       command[3] = LWLA_WORD_1(value);
+
+       return lwla_send_command(usb, command, G_N_ELEMENTS(command));
+}
+
+SR_PRIV int lwla_write_regs(const struct sr_usb_dev_inst *usb,
+                           const struct regval_pair *regvals, int count)
+{
+       int i;
+       int ret;
+
+       ret = SR_OK;
+
+       for (i = 0; i < count; ++i) {
+               ret = lwla_write_reg(usb, regvals[i].reg, regvals[i].val);
+
+               if (ret != SR_OK)
+                       break;
+       }
+
+       return ret;
+}
diff --git a/src/hardware/sysclk-lwla/lwla.h b/src/hardware/sysclk-lwla/lwla.h
new file mode 100644 (file)
index 0000000..94db07e
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Daniel Elstner <daniel.kitta@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_SYSCLK_LWLA_LWLA_H
+#define LIBSIGROK_HARDWARE_SYSCLK_LWLA_LWLA_H
+
+#include "libsigrok.h"
+#include <stdint.h>
+#include <libusb.h>
+#include <glib.h>
+
+struct sr_usb_dev_inst;
+
+/* Rotate argument n bits to the left.
+ * This construct is an idiom recognized by GCC as bit rotation.
+ */
+#define LROTATE(a, n) (((a) << (n)) | ((a) >> (CHAR_BIT * sizeof(a) - (n))))
+
+/* Convert 16-bit little endian LWLA protocol word to machine word order. */
+#define LWLA_TO_UINT16(val) GUINT16_FROM_LE(val)
+
+/* Convert 32-bit mixed endian LWLA protocol word to machine word order. */
+#define LWLA_TO_UINT32(val) LROTATE(GUINT32_FROM_LE(val), 16)
+
+/* Convert 16-bit argument to LWLA protocol word. */
+#define LWLA_WORD(val) GUINT16_TO_LE(val)
+
+/* Extract 16-bit units in mixed endian order from 32/64-bit value. */
+#define LWLA_WORD_0(val) GUINT16_TO_LE(((val) >> 16) & 0xFFFF)
+#define LWLA_WORD_1(val) GUINT16_TO_LE((val) & 0xFFFF)
+#define LWLA_WORD_2(val) GUINT16_TO_LE(((val) >> 48) & 0xFFFF)
+#define LWLA_WORD_3(val) GUINT16_TO_LE(((val) >> 32) & 0xFFFF)
+
+/** USB device end points.
+ */
+enum {
+       EP_COMMAND   = 2,
+       EP_BITSTREAM = 4,
+       EP_REPLY     = 6 | LIBUSB_ENDPOINT_IN
+};
+
+/** LWLA protocol command ID codes.
+ */
+enum {
+       CMD_READ_REG    = 1,
+       CMD_WRITE_REG   = 2,
+       CMD_READ_MEM    = 6,
+       CMD_CAP_SETUP   = 7,
+       CMD_CAP_STATUS  = 8,
+};
+
+/** LWLA capture state flags.
+ */
+enum {
+       STATUS_CAPTURING = 1 << 1,
+       STATUS_TRIGGERED = 1 << 4,
+       STATUS_MEM_AVAIL = 1 << 5,
+       STATUS_FLAG_MASK = 0x3F
+};
+
+/** LWLA register addresses.
+ */
+enum {
+       REG_MEM_CTRL2   = 0x1074, /* capture buffer control ??? */
+       REG_MEM_FILL    = 0x1078, /* capture buffer fill level */
+       REG_MEM_CTRL4   = 0x107C, /* capture buffer control ??? */
+
+       REG_DIV_BYPASS  = 0x1094, /* bypass clock divider flag */
+
+       REG_CMD_CTRL1   = 0x10B0, /* command control ??? */
+       REG_CMD_CTRL2   = 0x10B4, /* command control ??? */
+       REG_CMD_CTRL3   = 0x10B8, /* command control ??? */
+       REG_CMD_CTRL4   = 0x10BC, /* command control ??? */
+
+       REG_FREQ_CH1    = 0x10C0, /* channel 1 live frequency */
+       REG_FREQ_CH2    = 0x10C4, /* channel 2 live frequency */
+       REG_FREQ_CH3    = 0x10C8, /* channel 3 live frequency */
+       REG_FREQ_CH4    = 0x10CC, /* channel 4 live frequency */
+};
+
+/** Register/value pair.
+ */
+struct regval_pair {
+       unsigned int reg;
+       unsigned int val;
+};
+
+SR_PRIV int lwla_send_bitstream(const struct sr_usb_dev_inst *usb,
+                               const char *basename);
+
+SR_PRIV int lwla_send_command(const struct sr_usb_dev_inst *usb,
+                             const uint16_t *command, int cmd_len);
+
+SR_PRIV int lwla_receive_reply(const struct sr_usb_dev_inst *usb,
+                              uint32_t *reply, int reply_len, int expect_len);
+
+SR_PRIV int lwla_read_reg(const struct sr_usb_dev_inst *usb,
+                         uint16_t reg, uint32_t *value);
+
+SR_PRIV int lwla_write_reg(const struct sr_usb_dev_inst *usb,
+                          uint16_t reg, uint32_t value);
+
+SR_PRIV int lwla_write_regs(const struct sr_usb_dev_inst *usb,
+                           const struct regval_pair *regvals, int count);
+
+#endif /* !LIBSIGROK_HARDWARE_SYSCLK_LWLA_LWLA_H */
diff --git a/src/hardware/sysclk-lwla/protocol.c b/src/hardware/sysclk-lwla/protocol.c
new file mode 100644 (file)
index 0000000..f1ae8b3
--- /dev/null
@@ -0,0 +1,1034 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Daniel Elstner <daniel.kitta@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 "protocol.h"
+#include <string.h>
+
+/* Bit mask for the RLE repeat-count-follows flag. */
+#define RLE_FLAG_LEN_FOLLOWS ((uint64_t)1 << 35)
+
+/* Start address of capture status memory area to read. */
+#define CAP_STAT_ADDR 5
+
+/* Number of 64-bit words read from the capture status memory. */
+#define CAP_STAT_LEN 5
+
+/* The bitstream filenames are indexed by the clock_config enumeration.
+ */
+static const char bitstream_map[][32] = {
+       "sysclk-lwla1034-off.rbf",
+       "sysclk-lwla1034-int.rbf",
+       "sysclk-lwla1034-extpos.rbf",
+       "sysclk-lwla1034-extneg.rbf",
+};
+
+/* Submit an already filled-in USB transfer.
+ */
+static int submit_transfer(struct dev_context *devc,
+                          struct libusb_transfer *xfer)
+{
+       int ret;
+
+       ret = libusb_submit_transfer(xfer);
+
+       if (ret != 0) {
+               sr_err("Submit transfer failed: %s.", libusb_error_name(ret));
+               devc->transfer_error = TRUE;
+               return SR_ERR;
+       }
+
+       return SR_OK;
+}
+
+/* Set up the LWLA in preparation for an acquisition session.
+ */
+static int capture_setup(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct acquisition_state *acq;
+       uint64_t divider_count;
+       uint64_t trigger_mask;
+       uint64_t memory_limit;
+       uint16_t command[3 + 10*4];
+
+       devc = sdi->priv;
+       acq  = devc->acquisition;
+
+       command[0] = LWLA_WORD(CMD_CAP_SETUP);
+       command[1] = LWLA_WORD(0); /* address */
+       command[2] = LWLA_WORD(10); /* length */
+
+       command[3] = LWLA_WORD_0(devc->channel_mask);
+       command[4] = LWLA_WORD_1(devc->channel_mask);
+       command[5] = LWLA_WORD_2(devc->channel_mask);
+       command[6] = LWLA_WORD_3(devc->channel_mask);
+
+       /* Set the clock divide counter maximum for samplerates of up to
+        * 100 MHz. At the highest samplerate of 125 MHz the clock divider
+        * is bypassed.
+        */
+       if (!acq->bypass_clockdiv && devc->samplerate > 0)
+               divider_count = SR_MHZ(100) / devc->samplerate - 1;
+       else
+               divider_count = 0;
+
+       command[7]  = LWLA_WORD_0(divider_count);
+       command[8]  = LWLA_WORD_1(divider_count);
+       command[9]  = LWLA_WORD_2(divider_count);
+       command[10] = LWLA_WORD_3(divider_count);
+
+       command[11] = LWLA_WORD_0(devc->trigger_values);
+       command[12] = LWLA_WORD_1(devc->trigger_values);
+       command[13] = LWLA_WORD_2(devc->trigger_values);
+       command[14] = LWLA_WORD_3(devc->trigger_values);
+
+       command[15] = LWLA_WORD_0(devc->trigger_edge_mask);
+       command[16] = LWLA_WORD_1(devc->trigger_edge_mask);
+       command[17] = LWLA_WORD_2(devc->trigger_edge_mask);
+       command[18] = LWLA_WORD_3(devc->trigger_edge_mask);
+
+       trigger_mask = devc->trigger_mask;
+       /* Set bits to select external TRG input edge. */
+       if (devc->cfg_trigger_source == TRIGGER_EXT_TRG)
+               switch (devc->cfg_trigger_slope) {
+               case EDGE_POSITIVE: trigger_mask |= (uint64_t)1 << 35; break; 
+               case EDGE_NEGATIVE: trigger_mask |= (uint64_t)1 << 34; break; 
+               }
+
+       command[19] = LWLA_WORD_0(trigger_mask);
+       command[20] = LWLA_WORD_1(trigger_mask);
+       command[21] = LWLA_WORD_2(trigger_mask);
+       command[22] = LWLA_WORD_3(trigger_mask);
+
+       /* Set the capture memory full threshold. This is slightly less
+        * than the actual maximum, most likely in order to compensate for
+        * pipeline latency.
+        */
+       memory_limit = MEMORY_DEPTH - 16;
+
+       command[23] = LWLA_WORD_0(memory_limit);
+       command[24] = LWLA_WORD_1(memory_limit);
+       command[25] = LWLA_WORD_2(memory_limit);
+       command[26] = LWLA_WORD_3(memory_limit);
+
+       /* Fill remaining 64-bit words with zeroes. */
+       memset(&command[27], 0, 16 * sizeof(uint16_t));
+
+       return lwla_send_command(sdi->conn, command, G_N_ELEMENTS(command));
+}
+
+/* Issue a register write command as an asynchronous USB transfer.
+ */
+static int issue_write_reg(const struct sr_dev_inst *sdi,
+                          unsigned int reg, unsigned int value)
+{
+       struct dev_context *devc;
+       struct acquisition_state *acq;
+
+       devc = sdi->priv;
+       acq  = devc->acquisition;
+
+       acq->xfer_buf_out[0] = LWLA_WORD(CMD_WRITE_REG);
+       acq->xfer_buf_out[1] = LWLA_WORD(reg);
+       acq->xfer_buf_out[2] = LWLA_WORD_0(value);
+       acq->xfer_buf_out[3] = LWLA_WORD_1(value);
+
+       acq->xfer_out->length = 4 * sizeof(uint16_t);
+
+       return submit_transfer(devc, acq->xfer_out);
+}
+
+/* Issue a register write command as an asynchronous USB transfer for the
+ * next register/value pair of the currently active register write sequence.
+ */
+static int issue_next_write_reg(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct regval_pair *regval;
+       int ret;
+
+       devc = sdi->priv;
+
+       if (devc->reg_write_pos >= devc->reg_write_len) {
+               sr_err("Already written all registers in sequence.");
+               return SR_ERR_BUG;
+       }
+       regval = &devc->reg_write_seq[devc->reg_write_pos];
+
+       ret = issue_write_reg(sdi, regval->reg, regval->val);
+       if (ret != SR_OK)
+               return ret;
+
+       ++devc->reg_write_pos;
+       return SR_OK;
+}
+
+/* Issue a capture status request as an asynchronous USB transfer.
+ */
+static void request_capture_status(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct acquisition_state *acq;
+
+       devc = sdi->priv;
+       acq  = devc->acquisition;
+
+       acq->xfer_buf_out[0] = LWLA_WORD(CMD_CAP_STATUS);
+       acq->xfer_buf_out[1] = LWLA_WORD(CAP_STAT_ADDR);
+       acq->xfer_buf_out[2] = LWLA_WORD(CAP_STAT_LEN);
+
+       acq->xfer_out->length = 3 * sizeof(uint16_t);
+
+       if (submit_transfer(devc, acq->xfer_out) == SR_OK)
+               devc->state = STATE_STATUS_REQUEST;
+}
+
+/* Issue a request for the capture buffer fill level as
+ * an asynchronous USB transfer.
+ */
+static void request_capture_length(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct acquisition_state *acq;
+
+       devc = sdi->priv;
+       acq  = devc->acquisition;
+
+       acq->xfer_buf_out[0] = LWLA_WORD(CMD_READ_REG);
+       acq->xfer_buf_out[1] = LWLA_WORD(REG_MEM_FILL);
+
+       acq->xfer_out->length = 2 * sizeof(uint16_t);
+
+       if (submit_transfer(devc, acq->xfer_out) == SR_OK)
+               devc->state = STATE_LENGTH_REQUEST;
+}
+
+/* Initiate the capture memory read operation:  Reset the acquisition state
+ * and start a sequence of register writes in order to set up the device for
+ * reading from the capture buffer.
+ */
+static void issue_read_start(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct acquisition_state *acq;
+       struct regval_pair *regvals;
+
+       devc = sdi->priv;
+       acq  = devc->acquisition;
+
+       /* Reset RLE state. */
+       acq->rle = RLE_STATE_DATA;
+       acq->sample  = 0;
+       acq->run_len = 0;
+
+       acq->samples_done = 0;
+
+       /* For some reason, the start address is 4 rather than 0. */
+       acq->mem_addr_done = 4;
+       acq->mem_addr_next = 4;
+       acq->mem_addr_stop = acq->mem_addr_fill;
+
+       /* Sample position in the packet output buffer. */
+       acq->out_index = 0;
+
+       regvals = devc->reg_write_seq;
+
+       regvals[0].reg = REG_DIV_BYPASS;
+       regvals[0].val = 1;
+
+       regvals[1].reg = REG_MEM_CTRL2;
+       regvals[1].val = 2;
+
+       regvals[2].reg = REG_MEM_CTRL4;
+       regvals[2].val = 4;
+
+       devc->reg_write_pos = 0;
+       devc->reg_write_len = 3;
+
+       if (issue_next_write_reg(sdi) == SR_OK)
+               devc->state = STATE_READ_PREPARE;
+}
+
+/* Issue a command as an asynchronous USB transfer which returns the device
+ * to normal state after a read operation.  Sets a new device context state
+ * on success.
+ */
+static void issue_read_end(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+
+       devc = sdi->priv;
+
+       if (issue_write_reg(sdi, REG_DIV_BYPASS, 0) == SR_OK)
+               devc->state = STATE_READ_END;
+}
+
+/* Decode an incoming reponse to a buffer fill level request and act on it
+ * as appropriate.  Note that this function changes the device context state.
+ */
+static void process_capture_length(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct acquisition_state *acq;
+
+       devc = sdi->priv;
+       acq  = devc->acquisition;
+
+       if (acq->xfer_in->actual_length != 4) {
+               sr_err("Received size %d doesn't match expected size 4.",
+                      acq->xfer_in->actual_length);
+               devc->transfer_error = TRUE;
+               return;
+       }
+       acq->mem_addr_fill = LWLA_TO_UINT32(acq->xfer_buf_in[0]);
+
+       sr_dbg("%zu words in capture buffer.", acq->mem_addr_fill);
+
+       if (acq->mem_addr_fill > 0 && sdi->status == SR_ST_ACTIVE)
+               issue_read_start(sdi);
+       else
+               issue_read_end(sdi);
+}
+
+/* Initiate a sequence of register write commands with the effect of
+ * cancelling a running capture operation.  This sets a new device state
+ * if issuing the first command succeeds.
+ */
+static void issue_stop_capture(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct regval_pair *regvals;
+
+       devc = sdi->priv;
+
+       if (devc->stopping_in_progress)
+               return;
+
+       regvals = devc->reg_write_seq;
+
+       regvals[0].reg = REG_CMD_CTRL2;
+       regvals[0].val = 10;
+
+       regvals[1].reg = REG_CMD_CTRL3;
+       regvals[1].val = 0;
+
+       regvals[2].reg = REG_CMD_CTRL4;
+       regvals[2].val = 0;
+
+       regvals[3].reg = REG_CMD_CTRL1;
+       regvals[3].val = 0;
+
+       regvals[4].reg = REG_DIV_BYPASS;
+       regvals[4].val = 0;
+
+       devc->reg_write_pos = 0;
+       devc->reg_write_len = 5;
+
+       if (issue_next_write_reg(sdi) == SR_OK) {
+               devc->stopping_in_progress = TRUE;
+               devc->state = STATE_STOP_CAPTURE;
+       }
+}
+
+/* Decode an incoming capture status reponse and act on it as appropriate.
+ * Note that this function changes the device state.
+ */
+static void process_capture_status(const struct sr_dev_inst *sdi)
+{
+       uint64_t duration;
+       struct dev_context *devc;
+       struct acquisition_state *acq;
+       unsigned int mem_fill;
+       unsigned int flags;
+
+       devc = sdi->priv;
+       acq  = devc->acquisition;
+
+       if (acq->xfer_in->actual_length != CAP_STAT_LEN * 8) {
+               sr_err("Received size %d doesn't match expected size %d.",
+                      acq->xfer_in->actual_length, CAP_STAT_LEN * 8);
+               devc->transfer_error = TRUE;
+               return;
+       }
+
+       /* TODO: Find out the actual bit width of these fields as stored
+        * in the FPGA.  These fields are definitely less than 64 bit wide
+        * internally, and the unused bits occasionally even contain garbage.
+        */
+       mem_fill = LWLA_TO_UINT32(acq->xfer_buf_in[0]);
+       duration = LWLA_TO_UINT32(acq->xfer_buf_in[4]);
+       flags    = LWLA_TO_UINT32(acq->xfer_buf_in[8]) & STATUS_FLAG_MASK;
+
+       /* The LWLA1034 runs at 125 MHz if the clock divider is bypassed.
+        * However, the time base used for the duration is apparently not
+        * adjusted for this "boost" mode.  Whereas normally the duration
+        * unit is 1 ms, it is 0.8 ms when the clock divider is bypassed.
+        * As 0.8 = 100 MHz / 125 MHz, it seems that the internal cycle
+        * counter period is the same as at the 100 MHz setting.
+        */
+       if (acq->bypass_clockdiv)
+               acq->duration_now = duration * 4 / 5;
+       else
+               acq->duration_now = duration;
+
+       sr_spew("Captured %u words, %" PRIu64 " ms, flags 0x%02X.",
+               mem_fill, acq->duration_now, flags);
+
+       if ((flags & STATUS_TRIGGERED) > (acq->capture_flags & STATUS_TRIGGERED))
+               sr_info("Capture triggered.");
+
+       acq->capture_flags = flags;
+
+       if (acq->duration_now >= acq->duration_max) {
+               sr_dbg("Time limit reached, stopping capture.");
+               issue_stop_capture(sdi);
+               return;
+       }
+       devc->state = STATE_STATUS_WAIT;
+
+       if ((acq->capture_flags & STATUS_TRIGGERED) == 0) {
+               sr_spew("Waiting for trigger.");
+       } else if ((acq->capture_flags & STATUS_MEM_AVAIL) == 0) {
+               sr_dbg("Capture memory filled.");
+               request_capture_length(sdi);
+       } else if ((acq->capture_flags & STATUS_CAPTURING) != 0) {
+               sr_spew("Sampling in progress.");
+       }
+}
+
+/* Issue a capture buffer read request as an asynchronous USB transfer.
+ * The address and size of the memory area to read are derived from the
+ * current acquisition state.
+ */
+static void request_read_mem(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct acquisition_state *acq;
+       size_t count;
+
+       devc = sdi->priv;
+       acq  = devc->acquisition;
+
+       if (acq->mem_addr_next >= acq->mem_addr_stop)
+               return;
+
+       /* Always read a multiple of 8 device words. */
+       count = (acq->mem_addr_stop - acq->mem_addr_next + 7) / 8 * 8;
+       count = MIN(count, READ_CHUNK_LEN);
+
+       acq->xfer_buf_out[0] = LWLA_WORD(CMD_READ_MEM);
+       acq->xfer_buf_out[1] = LWLA_WORD_0(acq->mem_addr_next);
+       acq->xfer_buf_out[2] = LWLA_WORD_1(acq->mem_addr_next);
+       acq->xfer_buf_out[3] = LWLA_WORD_0(count);
+       acq->xfer_buf_out[4] = LWLA_WORD_1(count);
+
+       acq->xfer_out->length = 5 * sizeof(uint16_t);
+
+       if (submit_transfer(devc, acq->xfer_out) == SR_OK) {
+               acq->mem_addr_next += count;
+               devc->state = STATE_READ_REQUEST;
+       }
+}
+
+/* Demangle and decompress incoming sample data from the capture buffer.
+ * The data chunk is taken from the acquisition state, and is expected to
+ * contain a multiple of 8 device words.
+ * All data currently in the acquisition buffer will be processed.  Packets
+ * of decoded samples are sent off to the session bus whenever the output
+ * buffer becomes full while decoding.
+ */
+static int process_sample_data(const struct sr_dev_inst *sdi)
+{
+       uint64_t sample;
+       uint64_t high_nibbles;
+       uint64_t word;
+       struct dev_context *devc;
+       struct acquisition_state *acq;
+       uint8_t *out_p;
+       uint32_t *slice;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_logic logic;
+       size_t expect_len;
+       size_t actual_len;
+       size_t out_max_samples;
+       size_t out_run_samples;
+       size_t ri;
+       size_t in_words_left;
+       size_t si;
+
+       devc = sdi->priv;
+       acq  = devc->acquisition;
+
+       if (acq->mem_addr_done >= acq->mem_addr_stop
+                       || acq->samples_done >= acq->samples_max)
+               return SR_OK;
+
+       in_words_left = MIN(acq->mem_addr_stop - acq->mem_addr_done,
+                           READ_CHUNK_LEN);
+       expect_len = LWLA1034_MEMBUF_LEN(in_words_left) * sizeof(uint32_t);
+       actual_len = acq->xfer_in->actual_length;
+
+       if (actual_len != expect_len) {
+               sr_err("Received size %zu does not match expected size %zu.",
+                      actual_len, expect_len);
+               devc->transfer_error = TRUE;
+               return SR_ERR;
+       }
+       acq->mem_addr_done += in_words_left;
+
+       /* Prepare session packet. */
+       packet.type    = SR_DF_LOGIC;
+       packet.payload = &logic;
+       logic.unitsize = UNIT_SIZE;
+       logic.data     = acq->out_packet;
+
+       slice = acq->xfer_buf_in;
+       si = 0; /* word index within slice */
+
+       for (;;) {
+               /* Calculate number of samples to write into packet. */
+               out_max_samples = MIN(acq->samples_max - acq->samples_done,
+                                     PACKET_LENGTH - acq->out_index);
+               out_run_samples = MIN(acq->run_len, out_max_samples);
+
+               /* Expand run-length samples into session packet. */
+               sample = acq->sample;
+               out_p = &acq->out_packet[acq->out_index * UNIT_SIZE];
+
+               for (ri = 0; ri < out_run_samples; ++ri) {
+                       out_p[0] =  sample        & 0xFF;
+                       out_p[1] = (sample >>  8) & 0xFF;
+                       out_p[2] = (sample >> 16) & 0xFF;
+                       out_p[3] = (sample >> 24) & 0xFF;
+                       out_p[4] = (sample >> 32) & 0xFF;
+                       out_p += UNIT_SIZE;
+               }
+               acq->run_len -= out_run_samples;
+               acq->out_index += out_run_samples;
+               acq->samples_done += out_run_samples;
+
+               /* Packet full or sample count limit reached? */
+               if (out_run_samples == out_max_samples) {
+                       logic.length = acq->out_index * UNIT_SIZE;
+                       sr_session_send(sdi, &packet);
+                       acq->out_index = 0;
+
+                       if (acq->samples_done >= acq->samples_max)
+                               return SR_OK; /* sample limit reached */
+                       if (acq->run_len > 0)
+                               continue; /* need another packet */
+               }
+
+               if (in_words_left == 0)
+                       break; /* done with current chunk */
+
+               /* Now work on the current slice. */
+               high_nibbles = LWLA_TO_UINT32(slice[8]);
+               word = LWLA_TO_UINT32(slice[si]);
+               word |= (high_nibbles << (4 * si + 4)) & ((uint64_t)0xF << 32);
+
+               if (acq->rle == RLE_STATE_DATA) {
+                       acq->sample = word & ALL_CHANNELS_MASK;
+                       acq->run_len = ((word >> NUM_CHANNELS) & 1) + 1;
+                       if (word & RLE_FLAG_LEN_FOLLOWS)
+                               acq->rle = RLE_STATE_LEN;
+               } else {
+                       acq->run_len += word << 1;
+                       acq->rle = RLE_STATE_DATA;
+               }
+
+               /* Move to next word. */
+               si = (si + 1) % 8;
+               if (si == 0)
+                       slice += 9;
+               --in_words_left;
+       }
+
+       /* Send out partially filled packet if this was the last chunk. */
+       if (acq->mem_addr_done >= acq->mem_addr_stop && acq->out_index > 0) {
+               logic.length = acq->out_index * UNIT_SIZE;
+               sr_session_send(sdi, &packet);
+               acq->out_index = 0;
+       }
+       return SR_OK;
+}
+
+/* Finish an acquisition session.  This sends the end packet to the session
+ * bus and removes the listener for asynchronous USB transfers.
+ */
+static void end_acquisition(struct sr_dev_inst *sdi)
+{
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       struct sr_datafeed_packet packet;
+
+       drvc = sdi->driver->priv;
+       devc = sdi->priv;
+
+       if (devc->state == STATE_IDLE)
+               return;
+
+       devc->state = STATE_IDLE;
+
+       /* Remove USB file descriptors from polling. */
+       usb_source_remove(sdi->session, drvc->sr_ctx);
+
+       packet.type = SR_DF_END;
+       sr_session_send(sdi, &packet);
+
+       lwla_free_acquisition_state(devc->acquisition);
+       devc->acquisition = NULL;
+
+       sdi->status = SR_ST_ACTIVE;
+}
+
+/* USB output transfer completion callback.
+ */
+static void receive_transfer_out(struct libusb_transfer *transfer)
+{
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+
+       sdi  = transfer->user_data;
+       devc = sdi->priv;
+
+       if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
+               sr_err("Transfer to device failed: %d.", transfer->status);
+               devc->transfer_error = TRUE;
+               return;
+       }
+
+       if (devc->reg_write_pos < devc->reg_write_len) {
+               issue_next_write_reg(sdi);
+       } else {
+               switch (devc->state) {
+               case STATE_START_CAPTURE:
+                       devc->state = STATE_STATUS_WAIT;
+                       break;
+               case STATE_STATUS_REQUEST:
+                       devc->state = STATE_STATUS_RESPONSE;
+                       submit_transfer(devc, devc->acquisition->xfer_in);
+                       break;
+               case STATE_STOP_CAPTURE:
+                       if (sdi->status == SR_ST_ACTIVE)
+                               request_capture_length(sdi);
+                       else
+                               end_acquisition(sdi);
+                       break;
+               case STATE_LENGTH_REQUEST:
+                       devc->state = STATE_LENGTH_RESPONSE;
+                       submit_transfer(devc, devc->acquisition->xfer_in);
+                       break;
+               case STATE_READ_PREPARE:
+                       request_read_mem(sdi);
+                       break;
+               case STATE_READ_REQUEST:
+                       devc->state = STATE_READ_RESPONSE;
+                       submit_transfer(devc, devc->acquisition->xfer_in);
+                       break;
+               case STATE_READ_END:
+                       end_acquisition(sdi);
+                       break;
+               default:
+                       sr_err("Unexpected device state %d.", devc->state);
+                       break;
+               }
+       }
+}
+
+/* USB input transfer completion callback.
+ */
+static void receive_transfer_in(struct libusb_transfer *transfer)
+{
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       struct acquisition_state *acq;
+
+       sdi  = transfer->user_data;
+       devc = sdi->priv;
+       acq  = devc->acquisition;
+
+       if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
+               sr_err("Transfer from device failed: %d.", transfer->status);
+               devc->transfer_error = TRUE;
+               return;
+       }
+
+       switch (devc->state) {
+       case STATE_STATUS_RESPONSE:
+               process_capture_status(sdi);
+               break;
+       case STATE_LENGTH_RESPONSE:
+               process_capture_length(sdi);
+               break;
+       case STATE_READ_RESPONSE:
+               if (process_sample_data(sdi) == SR_OK
+                               && acq->mem_addr_next < acq->mem_addr_stop
+                               && acq->samples_done < acq->samples_max)
+                       request_read_mem(sdi);
+               else
+                       issue_read_end(sdi);
+               break;
+       default:
+               sr_err("Unexpected device state %d.", devc->state);
+               break;
+       }
+}
+
+/* Initialize the LWLA.  This downloads a bitstream into the FPGA
+ * and executes a simple device test sequence.
+ */
+SR_PRIV int lwla_init_device(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       int ret;
+       uint32_t value;
+
+       devc = sdi->priv;
+
+       /* Force reload of bitstream */
+       devc->cur_clock_config = CONF_CLOCK_NONE;
+
+       ret = lwla_set_clock_config(sdi);
+
+       if (ret != SR_OK)
+               return ret;
+
+       ret = lwla_write_reg(sdi->conn, REG_CMD_CTRL2, 100);
+       if (ret != SR_OK)
+               return ret;
+
+       ret = lwla_read_reg(sdi->conn, REG_CMD_CTRL1, &value);
+       if (ret != SR_OK)
+               return ret;
+       sr_dbg("Received test word 0x%08X back.", value);
+       if (value != 0x12345678)
+               return SR_ERR;
+
+       ret = lwla_read_reg(sdi->conn, REG_CMD_CTRL4, &value);
+       if (ret != SR_OK)
+               return ret;
+       sr_dbg("Received test word 0x%08X back.", value);
+       if (value != 0x12345678)
+               return SR_ERR;
+
+       ret = lwla_read_reg(sdi->conn, REG_CMD_CTRL3, &value);
+       if (ret != SR_OK)
+               return ret;
+       sr_dbg("Received test word 0x%08X back.", value);
+       if (value != 0x87654321)
+               return SR_ERR;
+
+       return ret;
+}
+
+SR_PRIV int lwla_convert_trigger(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_trigger *trigger;
+       struct sr_trigger_stage *stage;
+       struct sr_trigger_match *match;
+       const GSList *l, *m;
+       uint64_t channel_index;
+
+       devc = sdi->priv;
+
+       devc->trigger_mask = 0;
+       devc->trigger_values = 0;
+       devc->trigger_edge_mask = 0;
+
+       if (!(trigger = sr_session_trigger_get(sdi->session)))
+               return SR_OK;
+
+       if (g_slist_length(trigger->stages) > 1) {
+               sr_err("This device only supports 1 trigger stage.");
+               return SR_ERR;
+       }
+
+       for (l = trigger->stages; l; l = l->next) {
+               stage = l->data;
+               for (m = stage->matches; m; m = m->next) {
+                       match = m->data;
+                       if (!match->channel->enabled)
+                               /* Ignore disabled channels with a trigger. */
+                               continue;
+                       channel_index = 1 << match->channel->index;
+                       devc->trigger_mask |= channel_index;
+                       switch (match->match) {
+                       case SR_TRIGGER_ONE:
+                               devc->trigger_values |= channel_index;
+                               break;
+                       case SR_TRIGGER_RISING:
+                               devc->trigger_values |= channel_index;
+                               /* Fall through for edge mask. */
+                       case SR_TRIGGER_FALLING:
+                               devc->trigger_edge_mask |= channel_index;
+                               break;
+                       }
+               }
+       }
+
+       return SR_OK;
+}
+
+/* Select the LWLA clock configuration.  If the clock source changed from
+ * the previous setting, this will download a new bitstream to the FPGA.
+ */
+SR_PRIV int lwla_set_clock_config(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       int ret;
+       enum clock_config choice;
+
+       devc = sdi->priv;
+
+       if (sdi->status == SR_ST_INACTIVE)
+               choice = CONF_CLOCK_NONE;
+       else if (devc->cfg_clock_source == CLOCK_INTERNAL)
+               choice = CONF_CLOCK_INT;
+       else if (devc->cfg_clock_edge == EDGE_POSITIVE)
+               choice = CONF_CLOCK_EXT_RISE;
+       else
+               choice = CONF_CLOCK_EXT_FALL;
+
+       if (choice != devc->cur_clock_config) {
+               devc->cur_clock_config = CONF_CLOCK_NONE;
+               ret = lwla_send_bitstream(sdi->conn, bitstream_map[choice]);
+               if (ret == SR_OK)
+                       devc->cur_clock_config = choice;
+               return ret;
+       }
+       return SR_OK;
+}
+
+/* Configure the LWLA in preparation for an acquisition session.
+ */
+SR_PRIV int lwla_setup_acquisition(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_usb_dev_inst *usb;
+       struct acquisition_state *acq;
+       struct regval_pair regvals[7];
+       int ret;
+
+       devc = sdi->priv;
+       usb  = sdi->conn;
+       acq  = devc->acquisition;
+
+       if (devc->limit_msec > 0) {
+               acq->duration_max = devc->limit_msec;
+               sr_info("Acquisition time limit %" PRIu64 " ms.",
+                       devc->limit_msec);
+       } else
+               acq->duration_max = MAX_LIMIT_MSEC;
+
+       if (devc->limit_samples > 0) {
+               acq->samples_max = devc->limit_samples;
+               sr_info("Acquisition sample count limit %" PRIu64 ".",
+                       devc->limit_samples);
+       } else
+               acq->samples_max = MAX_LIMIT_SAMPLES;
+
+       if (devc->cfg_clock_source == CLOCK_INTERNAL) {
+               sr_info("Internal clock, samplerate %" PRIu64 ".",
+                       devc->samplerate);
+               if (devc->samplerate == 0)
+                       return SR_ERR_BUG;
+               /* At 125 MHz, the clock divider is bypassed. */
+               acq->bypass_clockdiv = (devc->samplerate > SR_MHZ(100));
+
+               /* If only one of the limits is set, derive the other one. */
+               if (devc->limit_msec == 0 && devc->limit_samples > 0)
+                       acq->duration_max = devc->limit_samples
+                                       * 1000 / devc->samplerate + 1;
+               else if (devc->limit_samples == 0 && devc->limit_msec > 0)
+                       acq->samples_max = devc->limit_msec
+                                       * devc->samplerate / 1000;
+       } else {
+               acq->bypass_clockdiv = TRUE;
+
+               if (devc->cfg_clock_edge == EDGE_NEGATIVE)
+                       sr_info("External clock, falling edge.");
+               else
+                       sr_info("External clock, rising edge.");
+       }
+
+       regvals[0].reg = REG_MEM_CTRL2;
+       regvals[0].val = 2;
+
+       regvals[1].reg = REG_MEM_CTRL2;
+       regvals[1].val = 1;
+
+       regvals[2].reg = REG_CMD_CTRL2;
+       regvals[2].val = 10;
+
+       regvals[3].reg = REG_CMD_CTRL3;
+       regvals[3].val = 0x74;
+
+       regvals[4].reg = REG_CMD_CTRL4;
+       regvals[4].val = 0;
+
+       regvals[5].reg = REG_CMD_CTRL1;
+       regvals[5].val = 0;
+
+       regvals[6].reg = REG_DIV_BYPASS;
+       regvals[6].val = acq->bypass_clockdiv;
+
+       ret = lwla_write_regs(usb, regvals, G_N_ELEMENTS(regvals));
+       if (ret != SR_OK)
+               return ret;
+
+       return capture_setup(sdi);
+}
+
+/* Start the capture operation on the LWLA device.  Beginning with this
+ * function, all USB transfers will be asynchronous until the end of the
+ * acquisition session.
+ */
+SR_PRIV int lwla_start_acquisition(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_usb_dev_inst *usb;
+       struct acquisition_state *acq;
+       struct regval_pair *regvals;
+
+       devc = sdi->priv;
+       usb  = sdi->conn;
+       acq  = devc->acquisition;
+
+       acq->duration_now  = 0;
+       acq->mem_addr_fill = 0;
+       acq->capture_flags = 0;
+
+       libusb_fill_bulk_transfer(acq->xfer_out, usb->devhdl, EP_COMMAND,
+                                 (unsigned char *)acq->xfer_buf_out, 0,
+                                 &receive_transfer_out,
+                                 (struct sr_dev_inst *)sdi, USB_TIMEOUT);
+
+       libusb_fill_bulk_transfer(acq->xfer_in, usb->devhdl, EP_REPLY,
+                                 (unsigned char *)acq->xfer_buf_in,
+                                 sizeof acq->xfer_buf_in,
+                                 &receive_transfer_in,
+                                 (struct sr_dev_inst *)sdi, USB_TIMEOUT);
+
+       regvals = devc->reg_write_seq;
+
+       regvals[0].reg = REG_CMD_CTRL2;
+       regvals[0].val = 10;
+
+       regvals[1].reg = REG_CMD_CTRL3;
+       regvals[1].val = 1;
+
+       regvals[2].reg = REG_CMD_CTRL4;
+       regvals[2].val = 0;
+
+       regvals[3].reg = REG_CMD_CTRL1;
+       regvals[3].val = 0;
+
+       devc->reg_write_pos = 0;
+       devc->reg_write_len = 4;
+
+       devc->state = STATE_START_CAPTURE;
+
+       return issue_next_write_reg(sdi);
+}
+
+/* Allocate an acquisition state object.
+ */
+SR_PRIV struct acquisition_state *lwla_alloc_acquisition_state(void)
+{
+       struct acquisition_state *acq;
+
+       acq = g_try_new0(struct acquisition_state, 1);
+       if (!acq) {
+               sr_err("Acquisition state malloc failed.");
+               return NULL;
+       }
+
+       acq->xfer_in = libusb_alloc_transfer(0);
+       if (!acq->xfer_in) {
+               sr_err("Transfer malloc failed.");
+               g_free(acq);
+               return NULL;
+       }
+
+       acq->xfer_out = libusb_alloc_transfer(0);
+       if (!acq->xfer_out) {
+               sr_err("Transfer malloc failed.");
+               libusb_free_transfer(acq->xfer_in);
+               g_free(acq);
+               return NULL;
+       }
+
+       return acq;
+}
+
+/* Deallocate an acquisition state object.
+ */
+SR_PRIV void lwla_free_acquisition_state(struct acquisition_state *acq)
+{
+       if (acq) {
+               libusb_free_transfer(acq->xfer_out);
+               libusb_free_transfer(acq->xfer_in);
+               g_free(acq);
+       }
+}
+
+/* USB I/O source callback.
+ */
+SR_PRIV int lwla_receive_data(int fd, int revents, void *cb_data)
+{
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       struct drv_context *drvc;
+       struct timeval tv;
+       int ret;
+
+       (void)fd;
+
+       sdi  = cb_data;
+       devc = sdi->priv;
+       drvc = sdi->driver->priv;
+
+       if (!devc || !drvc)
+               return FALSE;
+
+       /* No timeout: return immediately. */
+       tv.tv_sec  = 0;
+       tv.tv_usec = 0;
+
+       ret = libusb_handle_events_timeout_completed(drvc->sr_ctx->libusb_ctx,
+                                                    &tv, NULL);
+       if (ret != 0)
+               sr_err("Event handling failed: %s.", libusb_error_name(ret));
+
+       /* If no event flags are set the timeout must have expired. */
+       if (revents == 0 && devc->state == STATE_STATUS_WAIT) {
+               if (sdi->status == SR_ST_STOPPING)
+                       issue_stop_capture(sdi);
+               else
+                       request_capture_status(sdi);
+       }
+
+       /* Check if an error occurred on a transfer. */
+       if (devc->transfer_error)
+               end_acquisition(sdi);
+
+       return TRUE;
+}
diff --git a/src/hardware/sysclk-lwla/protocol.h b/src/hardware/sysclk-lwla/protocol.h
new file mode 100644 (file)
index 0000000..1e353ad
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Daniel Elstner <daniel.kitta@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_SYSCLK_LWLA_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_SYSCLK_LWLA_PROTOCOL_H
+
+#define LOG_PREFIX "sysclk-lwla"
+
+#include "lwla.h"
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include <stdint.h>
+#include <glib.h>
+
+/* For now, only the LWLA1034 is supported.
+ */
+#define VENDOR_NAME    "SysClk"
+#define MODEL_NAME     "LWLA1034"
+
+#define USB_VID_PID    "2961.6689"
+#define USB_INTERFACE  0
+#define USB_TIMEOUT    3000 /* ms */
+
+#define NUM_CHANNELS   34
+
+/* Bit mask covering all 34 channels.
+ */
+#define ALL_CHANNELS_MASK (((uint64_t)1 << NUM_CHANNELS) - 1)
+
+/** Unit and packet size for the sigrok logic datafeed.
+ */
+#define UNIT_SIZE      ((NUM_CHANNELS + 7) / 8)
+#define PACKET_LENGTH  10000   /* units */
+
+/** Size of the acquisition buffer in device memory units.
+ */
+#define MEMORY_DEPTH   (256 * 1024)    /* 256k x 36 bit */
+
+/** Number of device memory units (36 bit) to read at a time.  Slices of 8
+ * consecutive 36-bit words are mapped to 9 32-bit words each, so the chunk
+ * length should be a multiple of 8 to ensure alignment to slice boundaries.
+ *
+ * Experimentation has shown that reading chunks larger than about 1024 bytes
+ * is unreliable.  The threshold seems to relate to the buffer size on the FX2
+ * USB chip:  The configured endpoint buffer size is 512, and with double or
+ * triple buffering enabled a multiple of 512 bytes can be kept in fly.
+ *
+ * The vendor software limits reads to 120 words (15 slices, 540 bytes) at
+ * a time.  So far, it appears safe to increase this to 224 words (28 slices,
+ * 1008 bytes), thus making the most of two 512 byte buffers.
+ */
+#define READ_CHUNK_LEN (28 * 8)
+
+/** Calculate the required buffer size in 32-bit units for reading a given
+ * number of device memory words.  Rounded to a multiple of 8 device words.
+ */
+#define LWLA1034_MEMBUF_LEN(count) (((count) + 7) / 8 * 9)
+
+/** Maximum number of 16-bit words sent at a time during acquisition.
+ * Used for allocating the libusb transfer buffer.
+ */
+#define MAX_ACQ_SEND_WORDS     8 /* 5 for memory read request plus stuffing */
+
+/** Maximum number of 32-bit words received at a time during acquisition.
+ * Round to the next multiple of the endpoint buffer size to avoid nasty
+ * transfer overflow conditions on hiccups.
+ */
+#define MAX_ACQ_RECV_LEN       ((READ_CHUNK_LEN / 8 * 9 + 127) / 128 * 128)
+
+/** Maximum length of a register write sequence.
+ */
+#define MAX_REG_WRITE_SEQ_LEN   5
+
+/** Default configured samplerate.
+ */
+#define DEFAULT_SAMPLERATE     SR_MHZ(125)
+
+/** Maximum configurable sample count limit.
+ */
+#define MAX_LIMIT_SAMPLES      (UINT64_C(1) << 48)
+
+/** Maximum configurable capture duration in milliseconds.
+ */
+#define MAX_LIMIT_MSEC         (UINT64_C(1) << 32)
+
+/** LWLA1034 FPGA clock configurations.
+ */
+enum clock_config {
+       CONF_CLOCK_NONE,
+       CONF_CLOCK_INT,
+       CONF_CLOCK_EXT_RISE,
+       CONF_CLOCK_EXT_FALL,
+};
+
+/** Available clock sources.
+ */
+enum clock_source {
+       CLOCK_INTERNAL,
+       CLOCK_EXT_CLK,
+};
+
+/** Available trigger sources.
+ */
+enum trigger_source {
+       TRIGGER_CHANNELS = 0,
+       TRIGGER_EXT_TRG,
+};
+
+/** Available edge choices for the external clock and trigger inputs.
+ */
+enum signal_edge {
+       EDGE_POSITIVE = 0,
+       EDGE_NEGATIVE,
+};
+
+/** LWLA device states.
+ */
+enum device_state {
+       STATE_IDLE = 0,
+
+       STATE_START_CAPTURE,
+
+       STATE_STATUS_WAIT,
+       STATE_STATUS_REQUEST,
+       STATE_STATUS_RESPONSE,
+
+       STATE_STOP_CAPTURE,
+
+       STATE_LENGTH_REQUEST,
+       STATE_LENGTH_RESPONSE,
+
+       STATE_READ_PREPARE,
+       STATE_READ_REQUEST,
+       STATE_READ_RESPONSE,
+       STATE_READ_END,
+};
+
+/** LWLA run-length encoding states.
+ */
+enum rle_state {
+       RLE_STATE_DATA,
+       RLE_STATE_LEN
+};
+
+/** LWLA sample acquisition and decompression state.
+ */
+struct acquisition_state {
+       uint64_t sample;
+       uint64_t run_len;
+
+       /** Maximum number of samples to process. */
+       uint64_t samples_max;
+       /** Number of samples sent to the session bus. */
+       uint64_t samples_done;
+
+       /** Maximum duration of capture, in milliseconds. */
+       uint64_t duration_max;
+       /** Running capture duration since trigger event. */
+       uint64_t duration_now;
+
+       /** Capture memory fill level. */
+       size_t mem_addr_fill;
+
+       size_t mem_addr_done;
+       size_t mem_addr_next;
+       size_t mem_addr_stop;
+
+       size_t out_index;
+
+       struct libusb_transfer *xfer_in;
+       struct libusb_transfer *xfer_out;
+
+       unsigned int capture_flags;
+
+       enum rle_state rle;
+
+       /** Whether to bypass the clock divider. */
+       gboolean bypass_clockdiv;
+
+       /* Payload data buffers for incoming and outgoing transfers. */
+       uint32_t xfer_buf_in[MAX_ACQ_RECV_LEN];
+       uint16_t xfer_buf_out[MAX_ACQ_SEND_WORDS];
+
+       /* Payload buffer for sigrok logic packets. */
+       uint8_t out_packet[PACKET_LENGTH * UNIT_SIZE];
+};
+
+/** Private, per-device-instance driver context.
+ */
+struct dev_context {
+       /** The samplerate selected by the user. */
+       uint64_t samplerate;
+
+       /** The maximimum sampling duration, in milliseconds. */
+       uint64_t limit_msec;
+
+       /** The maximimum number of samples to acquire. */
+       uint64_t limit_samples;
+
+       /** Channels to use. */
+       uint64_t channel_mask;
+
+       uint64_t trigger_mask;
+       uint64_t trigger_edge_mask;
+       uint64_t trigger_values;
+
+       struct acquisition_state *acquisition;
+
+       struct regval_pair reg_write_seq[MAX_REG_WRITE_SEQ_LEN];
+       int reg_write_pos;
+       int reg_write_len;
+
+       enum device_state state;
+
+       /** The currently active clock configuration of the device. */
+       enum clock_config cur_clock_config;
+
+       /** Clock source configuration setting. */
+       enum clock_source cfg_clock_source;
+       /** Clock edge configuration setting. */
+       enum signal_edge cfg_clock_edge;
+
+       /** Trigger source configuration setting. */
+       enum trigger_source cfg_trigger_source;
+       /** Trigger slope configuration setting. */
+       enum signal_edge cfg_trigger_slope;
+
+       /* Indicates that stopping the acquisition is currently in progress. */
+       gboolean stopping_in_progress;
+
+       /* Indicates whether a transfer failed. */
+       gboolean transfer_error;
+};
+
+SR_PRIV struct acquisition_state *lwla_alloc_acquisition_state(void);
+SR_PRIV void lwla_free_acquisition_state(struct acquisition_state *acq);
+
+SR_PRIV int lwla_init_device(const struct sr_dev_inst *sdi);
+SR_PRIV int lwla_convert_trigger(const struct sr_dev_inst *sdi);
+SR_PRIV int lwla_set_clock_config(const struct sr_dev_inst *sdi);
+SR_PRIV int lwla_setup_acquisition(const struct sr_dev_inst *sdi);
+SR_PRIV int lwla_start_acquisition(const struct sr_dev_inst *sdi);
+SR_PRIV int lwla_abort_acquisition(const struct sr_dev_inst *sdi);
+
+SR_PRIV int lwla_receive_data(int fd, int revents, void *cb_data);
+
+#endif /* !LIBSIGROK_HARDWARE_SYSCLK_LWLA_PROTOCOL_H */
diff --git a/src/hardware/teleinfo/api.c b/src/hardware/teleinfo/api.c
new file mode 100644 (file)
index 0000000..c4fd846
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 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 <stdlib.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "protocol.h"
+
+static const int32_t hwopts[] = {
+       SR_CONF_CONN,
+       SR_CONF_SERIALCOMM,
+};
+
+static const int32_t hwcaps[] = {
+       SR_CONF_ENERGYMETER,
+       SR_CONF_LIMIT_SAMPLES,
+       SR_CONF_LIMIT_MSEC,
+       SR_CONF_CONTINUOUS,
+};
+
+SR_PRIV struct sr_dev_driver teleinfo_driver_info;
+static struct sr_dev_driver *di = &teleinfo_driver_info;
+
+static int init(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+       struct sr_dev_inst *sdi;
+       struct sr_channel *ch;
+       GSList *devices = NULL, *l;
+       const char *conn = NULL, *serialcomm = NULL;
+       uint8_t buf[292];
+       size_t len;
+       struct sr_config *src;
+
+       len = sizeof(buf);
+
+       for (l = options; l; l = l->next) {
+               src = l->data;
+               switch (src->key) {
+               case SR_CONF_CONN:
+                       conn = g_variant_get_string(src->data, NULL);
+                       break;
+               case SR_CONF_SERIALCOMM:
+                       serialcomm = g_variant_get_string(src->data, NULL);
+                       break;
+               }
+       }
+       if (!conn)
+               return NULL;
+       if (!serialcomm)
+               serialcomm = "1200/7e1";
+
+       if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
+               return NULL;
+       if (serial_open(serial, SERIAL_RDONLY | SERIAL_NONBLOCK) != SR_OK)
+               return NULL;
+
+       sr_info("Probing serial port %s.", conn);
+
+       drvc = di->priv;
+       drvc->instances = NULL;
+       serial_flush(serial);
+
+       /* Let's get a bit of data and see if we can find a packet. */
+       if (serial_stream_detect(serial, buf, &len, len,
+                                teleinfo_packet_valid, 3000, 1200) != SR_OK)
+               goto scan_cleanup;
+
+       sr_info("Found device on port %s.", conn);
+
+       if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "EDF", "Teleinfo", NULL)))
+               goto scan_cleanup;
+
+       if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+               sr_err("Device context malloc failed.");
+               goto scan_cleanup;
+       }
+
+       devc->optarif = teleinfo_get_optarif(buf);
+
+       sdi->inst_type = SR_INST_SERIAL;
+       sdi->conn = serial;
+       sdi->priv = devc;
+       sdi->driver = di;
+
+       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P")))
+               goto scan_cleanup;
+       sdi->channels = g_slist_append(sdi->channels, ch);
+
+       if (devc->optarif == OPTARIF_BASE) {
+               if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "BASE")))
+                       goto scan_cleanup;
+               sdi->channels = g_slist_append(sdi->channels, ch);
+       } else if (devc->optarif == OPTARIF_HC) {
+               if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "HP")))
+                       goto scan_cleanup;
+               sdi->channels = g_slist_append(sdi->channels, ch);
+               if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "HC")))
+                       goto scan_cleanup;
+               sdi->channels = g_slist_append(sdi->channels, ch);
+       } else if (devc->optarif == OPTARIF_EJP) {
+               if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "HN")))
+                       goto scan_cleanup;
+               sdi->channels = g_slist_append(sdi->channels, ch);
+               if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "HPM")))
+                       goto scan_cleanup;
+               sdi->channels = g_slist_append(sdi->channels, ch);
+       } else if (devc->optarif == OPTARIF_BBR) {
+               if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "HPJB")))
+                       goto scan_cleanup;
+               sdi->channels = g_slist_append(sdi->channels, ch);
+               if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "HPJW")))
+                       goto scan_cleanup;
+               sdi->channels = g_slist_append(sdi->channels, ch);
+               if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "HPJR")))
+                       goto scan_cleanup;
+               sdi->channels = g_slist_append(sdi->channels, ch);
+               if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "HCJB")))
+                       goto scan_cleanup;
+               sdi->channels = g_slist_append(sdi->channels, ch);
+               if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "HCJW")))
+                       goto scan_cleanup;
+               sdi->channels = g_slist_append(sdi->channels, ch);
+               if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "HCJR")))
+                       goto scan_cleanup;
+               sdi->channels = g_slist_append(sdi->channels, ch);
+       }
+
+       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "IINST")))
+               goto scan_cleanup;
+       sdi->channels = g_slist_append(sdi->channels, ch);
+
+       if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "PAPP")))
+               goto scan_cleanup;
+       sdi->channels = g_slist_append(sdi->channels, ch);
+
+       drvc->instances = g_slist_append(drvc->instances, sdi);
+       devices = g_slist_append(devices, sdi);
+
+scan_cleanup:
+       serial_close(serial);
+
+       return devices;
+}
+
+static GSList *dev_list(void)
+{
+       return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int cleanup(void)
+{
+       return std_dev_clear(di, NULL);
+}
+
+static int config_set(int 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;
+
+       if (!(devc = sdi->priv)) {
+               sr_err("sdi->priv was NULL.");
+               return SR_ERR_BUG;
+       }
+
+       switch (key) {
+       case SR_CONF_LIMIT_SAMPLES:
+               devc->limit_samples = g_variant_get_uint64(data);
+               sr_dbg("Setting sample limit to %" PRIu64 ".", devc->limit_samples);
+               break;
+       case SR_CONF_LIMIT_MSEC:
+               devc->limit_msec = g_variant_get_uint64(data);
+               sr_dbg("Setting time limit to %" PRIu64 "ms.", devc->limit_msec);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_list(int 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_INT32,
+                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+               break;
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct sr_serial_dev_inst *serial = sdi->conn;
+       struct dev_context *devc;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       if (!(devc = sdi->priv)) {
+               sr_err("sdi->priv was NULL.");
+               return SR_ERR_BUG;
+       }
+
+       devc->session_cb_data = cb_data;
+
+       /*
+        * Reset the number of samples to take. If we've already collected our
+        * quota, but we start a new session, and don't reset this, we'll just
+        * quit without acquiring any new samples.
+        */
+       devc->num_samples = 0;
+       devc->start_time = g_get_monotonic_time();
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(cb_data, LOG_PREFIX);
+
+       /* Poll every 50ms, or whenever some data comes in. */
+       serial_source_add(sdi->session, serial, G_IO_IN, 50,
+                       teleinfo_receive_data, (void *)sdi);
+
+       return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       return std_serial_dev_acquisition_stop(sdi, cb_data,
+                       std_serial_dev_close, sdi->conn, LOG_PREFIX);
+}
+
+SR_PRIV struct sr_dev_driver teleinfo_driver_info = {
+       .name = "teleinfo",
+       .longname = "Teleinfo",
+       .api_version = 1,
+       .init = init,
+       .cleanup = cleanup,
+       .scan = scan,
+       .dev_list = 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 = dev_acquisition_stop,
+       .priv = NULL,
+};
diff --git a/src/hardware/teleinfo/protocol.c b/src/hardware/teleinfo/protocol.c
new file mode 100644 (file)
index 0000000..a610173
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 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 <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include "protocol.h"
+
+#define STX  0x02
+#define ETX  0x03
+#define EOT  0x04
+#define LF   0x0A
+#define CR   0x0D
+
+static gboolean teleinfo_control_check(char *label, char *data, char control)
+{
+       int sum = 0;
+       while (*label)
+               sum += *label++;
+       sum += ' ';
+       while (*data)
+               sum += *data++;
+       return ((sum & 0x3F) + ' ') == control;
+}
+
+static gint teleinfo_channel_compare(gconstpointer a, gconstpointer b)
+{
+       const struct sr_channel *ch = a;
+       const char *name = b;
+       return strcmp(ch->name, name);
+}
+
+static struct sr_channel *teleinfo_find_channel(struct sr_dev_inst *sdi,
+                                            const char *name)
+{
+       GSList *elem = g_slist_find_custom(sdi->channels, name,
+                                          teleinfo_channel_compare);
+       return elem ? elem->data : NULL;
+}
+
+static void teleinfo_send_value(struct sr_dev_inst *sdi, const char *channel_name,
+                                float value, int mq, int unit)
+{
+       struct dev_context *devc;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_analog analog;
+       struct sr_channel *ch;
+
+       devc = sdi->priv;
+       ch = teleinfo_find_channel(sdi, channel_name);
+
+       if (!ch || !ch->enabled)
+               return;
+
+       memset(&analog, 0, sizeof(struct sr_datafeed_analog));
+       analog.channels = g_slist_append(analog.channels, ch);
+       analog.num_samples = 1;
+       analog.mq = mq;
+       analog.unit = unit;
+       analog.data = &value;
+
+       packet.type = SR_DF_ANALOG;
+       packet.payload = &analog;
+       sr_session_send(devc->session_cb_data, &packet);
+       g_slist_free(analog.channels);
+}
+
+static void teleinfo_handle_mesurement(struct sr_dev_inst *sdi,
+                                       const char *label, const char *data,
+                                       char *optarif)
+{
+       struct dev_context *devc;
+       int v = atoi(data);
+
+       if (!sdi || !(devc = sdi->priv)) {
+               if (optarif && !strcmp(label, "OPTARIF"))
+                       strcpy(optarif, data);
+               return;
+       }
+
+       if (!strcmp(label, "ADCO")) {
+               devc->num_samples++;
+       } else if (!strcmp(label, "BASE")) {
+               teleinfo_send_value(sdi, "BASE", v, SR_MQ_POWER, SR_UNIT_WATT_HOUR);
+       } else if (!strcmp(label, "HCHP")) {
+               teleinfo_send_value(sdi, "HP"  , v, SR_MQ_POWER, SR_UNIT_WATT_HOUR);
+       } else if (!strcmp(label, "HCHC")) {
+               teleinfo_send_value(sdi, "HC"  , v, SR_MQ_POWER, SR_UNIT_WATT_HOUR);
+       } else if (!strcmp(label, "EJPHN")) {
+               teleinfo_send_value(sdi, "HN"  , v, SR_MQ_POWER, SR_UNIT_WATT_HOUR);
+       } else if (!strcmp(label, "EJPHPM")) {
+               teleinfo_send_value(sdi, "HPM" , v, SR_MQ_POWER, SR_UNIT_WATT_HOUR);
+       } else if (!strcmp(label, "BBRHPJB")) {
+               teleinfo_send_value(sdi, "HPJB", v, SR_MQ_POWER, SR_UNIT_WATT_HOUR);
+       } else if (!strcmp(label, "BBRHPJW")) {
+               teleinfo_send_value(sdi, "HPJW", v, SR_MQ_POWER, SR_UNIT_WATT_HOUR);
+       } else if (!strcmp(label, "BBRHPJR")) {
+               teleinfo_send_value(sdi, "HPJR", v, SR_MQ_POWER, SR_UNIT_WATT_HOUR);
+       } else if (!strcmp(label, "BBRHCJB")) {
+               teleinfo_send_value(sdi, "HCJB", v, SR_MQ_POWER, SR_UNIT_WATT_HOUR);
+       } else if (!strcmp(label, "BBRHCJW")) {
+               teleinfo_send_value(sdi, "HCJW", v, SR_MQ_POWER, SR_UNIT_WATT_HOUR);
+       } else if (!strcmp(label, "BBRHCJR")) {
+               teleinfo_send_value(sdi, "HCJR", v, SR_MQ_POWER, SR_UNIT_WATT_HOUR);
+       } else if (!strcmp(label, "IINST")) {
+               teleinfo_send_value(sdi, "IINST", v, SR_MQ_CURRENT, SR_UNIT_AMPERE);
+       } else if (!strcmp(label, "PAPP")) {
+               teleinfo_send_value(sdi, "PAPP", v, SR_MQ_POWER, SR_UNIT_VOLT_AMPERE);
+       }
+}
+
+static gboolean teleinfo_parse_group(struct sr_dev_inst *sdi,
+                                     const uint8_t *group, char *optarif)
+{
+       char label[9], data[13], control, cr;
+       const char *str = (const char *)group;
+       if (sscanf(str, "\x0A%8s %13s %c%c", label, data, &control, &cr) != 4
+           || cr != CR)
+               return FALSE;
+       if (!teleinfo_control_check(label, data, control))
+               return FALSE;
+       teleinfo_handle_mesurement(sdi, label, data, optarif);
+       return TRUE;
+}
+
+static const uint8_t *teleinfo_parse_data(struct sr_dev_inst *sdi,
+                                          const uint8_t *buf, int len,
+                                          char *optarif)
+{
+       const uint8_t *group_start, *group_end;
+
+       group_start = memchr(buf, LF, len);
+       if (!group_start)
+               return NULL;
+
+       group_end = memchr(group_start, CR, len - (group_start - buf));
+       if (!group_end)
+               return NULL;
+
+       teleinfo_parse_group(sdi, group_start, optarif);
+       return group_end + 1;
+}
+
+SR_PRIV int teleinfo_get_optarif(const uint8_t *buf)
+{
+       const uint8_t *ptr = buf;
+       char optarif[5] = { 0 };
+
+       while ((ptr = teleinfo_parse_data(NULL, ptr, 292-(ptr-buf), optarif)));
+       if (!strcmp(optarif, "BASE"))
+               return OPTARIF_BASE;
+       else if (!strcmp(optarif, "HC.."))
+               return OPTARIF_HC;
+       else if (!strcmp(optarif, "EJP."))
+               return OPTARIF_EJP;
+       else if (!strncmp(optarif, "BBR", 3))
+               return OPTARIF_BBR;
+       return OPTARIF_NONE;
+}
+
+SR_PRIV gboolean teleinfo_packet_valid(const uint8_t *buf)
+{
+       return !!teleinfo_get_optarif(buf);
+}
+
+SR_PRIV int teleinfo_receive_data(int fd, int revents, void *cb_data)
+{
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+       const uint8_t *ptr, *next_ptr, *end_ptr;
+       int len;
+       int64_t time;
+
+       (void)fd;
+
+       if (!(sdi = cb_data) || !(devc = sdi->priv) || revents != G_IO_IN)
+               return TRUE;
+       serial = sdi->conn;
+
+       /* Try to get as much data as the buffer can hold. */
+       len = TELEINFO_BUF_SIZE - devc->buf_len;
+       len = serial_read(serial, devc->buf + devc->buf_len, len);
+       if (len < 1) {
+               sr_err("Serial port read error: %d.", len);
+               return FALSE;
+       }
+       devc->buf_len += len;
+
+       /* Now look for packets in that data. */
+       ptr = devc->buf;
+       end_ptr = ptr + devc->buf_len;
+       while ((next_ptr = teleinfo_parse_data(sdi, ptr, end_ptr - ptr, NULL)))
+               ptr = next_ptr;
+
+       /* If we have any data left, move it to the beginning of our buffer. */
+       memmove(devc->buf, ptr, end_ptr - ptr);
+       devc->buf_len -= ptr - devc->buf;
+
+       /* If buffer is full and no valid packet was found, wipe buffer. */
+       if (devc->buf_len >= TELEINFO_BUF_SIZE) {
+               devc->buf_len = 0;
+               return FALSE;
+       }
+
+       if (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
+               sr_info("Requested number of samples reached.");
+               sdi->driver->dev_acquisition_stop(sdi, devc->session_cb_data);
+               return TRUE;
+       }
+
+       if (devc->limit_msec) {
+               time = (g_get_monotonic_time() - devc->start_time) / 1000;
+               if (time > (int64_t)devc->limit_msec) {
+                       sr_info("Requested time limit reached.");
+                       sdi->driver->dev_acquisition_stop(sdi, devc->session_cb_data);
+                       return TRUE;
+               }
+       }
+       return TRUE;
+}
diff --git a/src/hardware/teleinfo/protocol.h b/src/hardware/teleinfo/protocol.h
new file mode 100644 (file)
index 0000000..f95c50e
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Aurelien Jacobs <aurel@gnuage.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_TELEINFO_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_TELEINFO_PROTOCOL_H
+
+#include <stdint.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "teleinfo"
+
+enum optarif {
+       OPTARIF_NONE,
+       OPTARIF_BASE,
+       OPTARIF_HC,
+       OPTARIF_EJP,
+       OPTARIF_BBR,
+};
+
+#define TELEINFO_BUF_SIZE 256
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+       /* Acquisition settings */
+       uint64_t limit_samples;   /**< The sampling limit (in number of samples). */
+       uint64_t limit_msec;      /**< The time limit (in milliseconds). */
+       void *session_cb_data;    /**< Opaque pointer passed in by the frontend. */
+
+       /* Operational state */
+       enum optarif optarif;     /**< The device mode (which mesures are reported) */
+       uint64_t num_samples;     /**< The number of already received samples. */
+       int64_t start_time;       /**< The time at which sampling started. */
+
+       /* Temporary state across callbacks */
+       uint8_t buf[TELEINFO_BUF_SIZE];
+       int buf_len;
+};
+
+SR_PRIV gboolean teleinfo_packet_valid(const uint8_t *buf);
+SR_PRIV int teleinfo_receive_data(int fd, int revents, void *cb_data);
+SR_PRIV int teleinfo_get_optarif(const uint8_t *buf);
+
+#endif
diff --git a/src/hardware/testo/api.c b/src/hardware/testo/api.c
new file mode 100644 (file)
index 0000000..2b4c963
--- /dev/null
@@ -0,0 +1,535 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Bert Vermeulen <bert@biot.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 <string.h>
+#include "protocol.h"
+
+#define SERIALCOMM "115200/8n1"
+
+SR_PRIV struct sr_dev_driver testo_driver_info;
+static struct sr_dev_driver *di = &testo_driver_info;
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data);
+
+static const int32_t scanopts[] = {
+       SR_CONF_CONN,
+};
+
+static const int32_t devopts[] = {
+       SR_CONF_MULTIMETER,
+       SR_CONF_LIMIT_MSEC,
+       SR_CONF_LIMIT_SAMPLES,
+       SR_CONF_CONTINUOUS,
+};
+
+unsigned char TESTO_x35_REQUEST[] = { 0x12, 0, 0, 0, 1, 1, 0x55, 0xd1, 0xb7 };
+struct testo_model models[] = {
+       { "435", 9, TESTO_x35_REQUEST },
+};
+
+static int init(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       struct sr_config *src;
+       struct sr_dev_inst *sdi;
+       struct sr_usb_dev_inst *usb;
+       struct libusb_device_descriptor des;
+       libusb_device **devlist;
+       struct libusb_device_handle *hdl;
+       GSList *conn_devices, *devices, *l;
+       int devcnt, ret, i;
+       const char *str;
+       char manufacturer[64], product[64];
+
+       devices = NULL;
+       drvc = di->priv;
+       drvc->instances = NULL;
+
+       conn_devices = NULL;
+       for (l = options; l; l = l->next) {
+               src = l->data;
+               if (src->key != SR_CONF_CONN)
+                       continue;
+               str = g_variant_get_string(src->data, NULL);
+               conn_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, str);
+       }
+
+       libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
+       for (i = 0; devlist[i]; i++) {
+               if (conn_devices) {
+                       usb = NULL;
+                       for (l = conn_devices; l; l = l->next) {
+                               usb = l->data;
+                               if (usb->bus == libusb_get_bus_number(devlist[i])
+                                       && usb->address == libusb_get_device_address(devlist[i]))
+                                       break;
+                       }
+                       if (!l)
+                               /* This device matched none of the ones that
+                                * matched the conn specification. */
+                               continue;
+               }
+
+               if ((ret = libusb_get_device_descriptor( devlist[i], &des)) != 0) {
+                       sr_warn("Failed to get device descriptor: %s.",
+                               libusb_error_name(ret));
+                       continue;
+               }
+
+               if ((ret = libusb_open(devlist[i], &hdl)) < 0)
+                       continue;
+
+               manufacturer[0] = product[0] = '\0';
+               if (des.iManufacturer && (ret = libusb_get_string_descriptor_ascii(
+                               hdl, des.iManufacturer, (unsigned char *) manufacturer,
+                               sizeof(manufacturer))) < 0) {
+                       sr_warn("Failed to get manufacturer string descriptor: %s.",
+                               libusb_error_name(ret));
+               }
+               if (des.iProduct && (ret = libusb_get_string_descriptor_ascii(
+                               hdl, des.iProduct, (unsigned char *) product,
+                               sizeof(product))) < 0) {
+                       sr_warn("Failed to get product string descriptor: %s.",
+                               libusb_error_name(ret));
+               }
+               libusb_close(hdl);
+
+               if (strncmp(manufacturer, "testo", 5))
+                       continue;
+
+               /* Hardcode the 435 for now.*/
+               if (strcmp(product, "testo 435/635/735"))
+                       continue;
+
+               devcnt = g_slist_length(drvc->instances);
+               sdi = sr_dev_inst_new(devcnt, SR_ST_INACTIVE, "Testo",
+                               "435/635/735", NULL);
+               sdi->driver = di;
+               sdi->inst_type = SR_INST_USB;
+               sdi->conn = sr_usb_dev_inst_new(libusb_get_bus_number(devlist[i]),
+                               libusb_get_device_address(devlist[i]), NULL);
+               devc = g_malloc(sizeof(struct dev_context));
+               devc->model = &models[0];
+               devc->limit_msec = 0;
+               devc->limit_samples = 0;
+               sdi->priv = devc;
+               if (testo_probe_channels(sdi) != SR_OK)
+                       continue;
+               drvc->instances = g_slist_append(drvc->instances, sdi);
+               devices = g_slist_append(devices, sdi);
+       }
+       libusb_free_device_list(devlist, 1);
+       g_slist_free_full(conn_devices, (GDestroyNotify)sr_usb_dev_inst_free);
+
+       return devices;
+}
+
+static GSList *dev_list(void)
+{
+       return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int dev_clear(void)
+{
+       return std_dev_clear(di, NULL);
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+       struct drv_context *drvc = di->priv;
+       struct sr_usb_dev_inst *usb;
+       libusb_device **devlist;
+       int ret, i;
+
+       if (!di->priv) {
+               sr_err("Driver was not initialized.");
+               return SR_ERR;
+       }
+
+       usb = sdi->conn;
+       libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
+       for (i = 0; devlist[i]; i++) {
+               if (libusb_get_bus_number(devlist[i]) != usb->bus
+                               || libusb_get_device_address(devlist[i]) != usb->address)
+                       continue;
+               if ((ret = libusb_open(devlist[i], &usb->devhdl))) {
+                       sr_err("Failed to open device: %s.", libusb_error_name(ret));
+                       return SR_ERR;
+               }
+               break;
+       }
+       libusb_free_device_list(devlist, 1);
+       if (!devlist[i]) {
+               sr_err("Device not found.");
+               return SR_ERR;
+       }
+
+       if (libusb_has_capability(LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER)) {
+               if (libusb_kernel_driver_active(usb->devhdl, 0) == 1) {
+                       if ((ret = libusb_detach_kernel_driver(usb->devhdl, 0)) < 0) {
+                               sr_err("Failed to detach kernel driver: %s.",
+                                          libusb_error_name(ret));
+                               return SR_ERR;
+                       }
+               }
+       }
+
+       if ((ret = libusb_claim_interface(usb->devhdl, 0))) {
+               sr_err("Failed to claim interface: %s.", libusb_error_name(ret));
+               return SR_ERR;
+       }
+       sdi->status = SR_ST_ACTIVE;
+
+       return SR_OK;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+       struct sr_usb_dev_inst *usb;
+
+       if (!di->priv) {
+               sr_err("Driver was not initialized.");
+               return SR_ERR;
+       }
+
+       usb = sdi->conn;
+       if (!usb->devhdl)
+               /*  Nothing to do. */
+               return SR_OK;
+
+       libusb_release_interface(usb->devhdl, 0);
+       libusb_close(usb->devhdl);
+       usb->devhdl = NULL;
+       sdi->status = SR_ST_INACTIVE;
+
+       return SR_OK;
+}
+
+static int cleanup(void)
+{
+       int ret;
+       struct drv_context *drvc;
+
+       if (!(drvc = di->priv))
+               return SR_OK;
+
+       ret = dev_clear();
+       g_free(drvc);
+       di->priv = NULL;
+
+       return ret;
+}
+
+static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct sr_usb_dev_inst *usb;
+       char str[128];
+
+       (void)cg;
+
+       switch (key) {
+       case SR_CONF_CONN:
+               if (!sdi || !sdi->conn)
+                       return SR_ERR_ARG;
+               usb = sdi->conn;
+               snprintf(str, 128, "%d.%d", usb->bus, usb->address);
+               *data = g_variant_new_string(str);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       gint64 now;
+       int ret;
+
+       (void)cg;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       if (!di->priv) {
+               sr_err("Driver was not initialized.");
+               return SR_ERR;
+       }
+
+       devc = sdi->priv;
+       ret = SR_OK;
+       switch (key) {
+       case SR_CONF_LIMIT_MSEC:
+               devc->limit_msec = g_variant_get_uint64(data);
+               now = g_get_monotonic_time() / 1000;
+               devc->end_time = now + devc->limit_msec;
+               sr_dbg("Setting time limit to %" PRIu64 "ms.",
+                      devc->limit_msec);
+               break;
+       case SR_CONF_LIMIT_SAMPLES:
+               devc->limit_samples = g_variant_get_uint64(data);
+               sr_dbg("Setting sample limit to %" PRIu64 ".",
+                      devc->limit_samples);
+               break;
+       default:
+               ret = SR_ERR_NA;
+       }
+
+       return ret;
+}
+
+static int config_list(int 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_INT32,
+                               scanopts, ARRAY_SIZE(scanopts), sizeof(int32_t));
+               break;
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               devopts, ARRAY_SIZE(devopts), sizeof(int32_t));
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static void receive_data(struct sr_dev_inst *sdi, unsigned char *data, int len)
+{
+       struct dev_context *devc;
+       int packet_size;
+       uint16_t crc;
+
+       devc = sdi->priv;
+
+       if (devc->reply_size + len > MAX_REPLY_SIZE) {
+               /* Something went very wrong. */
+               sr_dbg("Receive buffer overrun.");
+               devc->reply_size = 0;
+               return;
+       }
+
+       memcpy(devc->reply + devc->reply_size, data, len);
+       devc->reply_size += len;
+       /* Sixth byte contains the length of the packet. */
+       if (devc->reply_size < 7)
+               return;
+
+       packet_size = 7 + devc->reply[6] * 7 + 2;
+       if (devc->reply_size < packet_size)
+               return;
+
+       if (!testo_check_packet_prefix(devc->reply, devc->reply_size))
+               return;
+
+       crc = crc16_mcrf4xx(0xffff, devc->reply, devc->reply_size - 2);
+       if (crc == RL16(&devc->reply[devc->reply_size - 2])) {
+               testo_receive_packet(sdi);
+               devc->num_samples++;
+       } else {
+               sr_dbg("Packet has invalid CRC.");
+       }
+
+       devc->reply_size = 0;
+       if (devc->limit_samples && devc->num_samples >= devc->limit_samples)
+               dev_acquisition_stop(sdi, devc->cb_data);
+       else
+               testo_request_packet(sdi);
+
+}
+
+SR_PRIV void receive_transfer(struct libusb_transfer *transfer)
+{
+       struct dev_context *devc;
+       struct sr_dev_inst *sdi;
+       int ret;
+
+       sdi = transfer->user_data;
+       devc = sdi->priv;
+       if (transfer == devc->out_transfer)
+               /* Just the command acknowledgement. */
+               return;
+
+       if (transfer->status == LIBUSB_TRANSFER_NO_DEVICE) {
+               /* USB device was unplugged. */
+               dev_acquisition_stop(sdi, devc->cb_data);
+       } else if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
+               /* First two bytes in any transfer are FTDI status bytes. */
+               if (transfer->actual_length > 2)
+                       receive_data(sdi, transfer->buffer + 2, transfer->actual_length - 2);
+       }
+       /* Anything else is either an error or a timeout, which is fine:
+        * we were just going to send another transfer request anyway. */
+
+       if (sdi->status == SR_ST_ACTIVE) {
+               if ((ret = libusb_submit_transfer(transfer) != 0)) {
+                       sr_err("Unable to resubmit transfer: %s.",
+                              libusb_error_name(ret));
+                       g_free(transfer->buffer);
+                       libusb_free_transfer(transfer);
+                       dev_acquisition_stop(sdi, devc->cb_data);
+               }
+       } else {
+               /* This was the last transfer we're going to receive, so
+                * clean up now. */
+               g_free(transfer->buffer);
+               libusb_free_transfer(transfer);
+       }
+}
+
+static int handle_events(int fd, int revents, void *cb_data)
+{
+       struct dev_context *devc;
+       struct drv_context *drvc = di->priv;
+       struct sr_datafeed_packet packet;
+       struct sr_dev_inst *sdi;
+       struct timeval tv;
+       gint64 now;
+
+       (void)fd;
+       (void)revents;
+
+       sdi = cb_data;
+       devc = sdi->priv;
+
+       if (devc->limit_msec) {
+               now = g_get_monotonic_time() / 1000;
+               if (now > devc->end_time)
+                       dev_acquisition_stop(sdi, devc->cb_data);
+       }
+
+       if (sdi->status == SR_ST_STOPPING) {
+               usb_source_remove(sdi->session, drvc->sr_ctx);
+
+               dev_close(sdi);
+
+               packet.type = SR_DF_END;
+               sr_session_send(sdi, &packet);
+       }
+
+       memset(&tv, 0, sizeof(struct timeval));
+       libusb_handle_events_timeout_completed(drvc->sr_ctx->libusb_ctx, &tv,
+                       NULL);
+
+       return TRUE;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       struct sr_usb_dev_inst *usb;
+       struct libusb_transfer *transfer;
+       int ret;
+       unsigned char *buf;
+
+       drvc = di->priv;
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       if (!di->priv) {
+               sr_err("Driver was not initialized.");
+               return SR_ERR;
+       }
+
+       devc = sdi->priv;
+       usb = sdi->conn;
+       devc->cb_data = cb_data;
+       devc->end_time = 0;
+       devc->num_samples = 0;
+       devc->reply_size = 0;
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(cb_data, LOG_PREFIX);
+
+       usb_source_add(sdi->session, drvc->sr_ctx, 100,
+                       handle_events, (void *)sdi);
+
+       if (testo_set_serial_params(usb) != SR_OK)
+               return SR_ERR;
+
+       devc->out_transfer = libusb_alloc_transfer(0);
+       if (testo_request_packet(sdi) != SR_OK)
+               return SR_ERR;
+
+       buf = g_try_malloc(MAX_REPLY_SIZE);
+       transfer = libusb_alloc_transfer(0);
+       libusb_fill_bulk_transfer(transfer, usb->devhdl, EP_IN, buf,
+                       MAX_REPLY_SIZE, receive_transfer, (void *)sdi, 100);
+       if ((ret = libusb_submit_transfer(transfer) != 0)) {
+               sr_err("Unable to submit transfer: %s.", libusb_error_name(ret));
+               libusb_free_transfer(transfer);
+               g_free(buf);
+               return SR_ERR;
+       }
+       devc->reply_size = 0;
+
+       return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       (void)cb_data;
+
+       if (!di->priv) {
+               sr_err("Driver was not initialized.");
+               return SR_ERR;
+       }
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       sdi->status = SR_ST_STOPPING;
+
+       return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver testo_driver_info = {
+       .name = "testo",
+       .longname = "Testo",
+       .api_version = 1,
+       .init = init,
+       .cleanup = cleanup,
+       .scan = scan,
+       .dev_list = dev_list,
+       .dev_clear = dev_clear,
+       .config_get = config_get,
+       .config_set = config_set,
+       .config_list = config_list,
+       .dev_open = dev_open,
+       .dev_close = dev_close,
+       .dev_acquisition_start = dev_acquisition_start,
+       .dev_acquisition_stop = dev_acquisition_stop,
+       .priv = NULL,
+};
diff --git a/src/hardware/testo/protocol.c b/src/hardware/testo/protocol.c
new file mode 100644 (file)
index 0000000..bdfaf1f
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Bert Vermeulen <bert@biot.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 <string.h>
+#include "protocol.h"
+
+SR_PRIV int testo_set_serial_params(struct sr_usb_dev_inst *usb)
+{
+       int ret;
+
+    if ((ret = libusb_control_transfer(usb->devhdl, 0x40, FTDI_SET_BAUDRATE,
+                       FTDI_BAUDRATE_115200, FTDI_INDEX, NULL, 0, 10)) < 0) {
+                       sr_err("Failed to set baudrate: %s", libusb_error_name(ret));
+                       return SR_ERR;
+       }
+
+    if ((ret = libusb_control_transfer(usb->devhdl, 0x40, FTDI_SET_PARAMS,
+                       FTDI_PARAMS_8N1, FTDI_INDEX, NULL, 0, 10)) < 0) {
+                       sr_err("Failed to set comm parameters: %s", libusb_error_name(ret));
+                       return SR_ERR;
+       }
+
+    if ((ret = libusb_control_transfer(usb->devhdl, 0x40, FTDI_SET_FLOWCTRL,
+                       FTDI_FLOW_NONE, FTDI_INDEX, NULL, 0, 10)) < 0) {
+                       sr_err("Failed to set flow control: %s", libusb_error_name(ret));
+                       return SR_ERR;
+       }
+
+    if ((ret = libusb_control_transfer(usb->devhdl, 0x40, FTDI_SET_MODEMCTRL,
+                       FTDI_MODEM_ALLHIGH, FTDI_INDEX, NULL, 0, 10)) < 0) {
+                       sr_err("Failed to set modem control: %s", libusb_error_name(ret));
+                       return SR_ERR;
+       }
+
+       return SR_OK;
+}
+
+
+/* Due to the modular nature of the Testo hardware, you can't assume
+ * which measurements the device will supply. Fetch a single result
+ * set synchronously to see which measurements it has. */
+SR_PRIV int testo_probe_channels(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_usb_dev_inst *usb;
+       struct sr_channel *ch;
+       int unit, packet_len, len, i;
+       unsigned char packet[MAX_REPLY_SIZE], buf[MAX_REPLY_SIZE];
+       char *probe_name;
+
+       devc = sdi->priv;
+       usb = sdi->conn;
+
+       sr_dbg("Probing for channels.");
+       if (sdi->driver->dev_open(sdi) != SR_OK)
+               return SR_ERR;
+       if (testo_set_serial_params(usb) != SR_OK)
+               return SR_ERR;
+
+       /* Flush anything buffered from a previous run. */
+       do {
+               libusb_bulk_transfer(usb->devhdl, EP_IN, buf, MAX_REPLY_SIZE, &len, 10);
+       } while (len > 2);
+
+       if (libusb_bulk_transfer(usb->devhdl, EP_OUT, devc->model->request,
+                       devc->model->request_size, &devc->reply_size, 10) < 0)
+               return SR_ERR;
+
+       packet_len = 0;
+       while(TRUE) {
+               if (libusb_bulk_transfer(usb->devhdl, EP_IN, buf, MAX_REPLY_SIZE,
+                               &len, 250) < 0)
+                       return SR_ERR;
+               if (len == 2)
+                       /* FTDI cruft */
+                       continue;
+               if (packet_len + len - 2 > MAX_REPLY_SIZE)
+                       return SR_ERR;
+
+               memcpy(packet + packet_len, buf + 2, len - 2);
+               packet_len += len - 2;
+               if (packet_len < 5)
+                       /* Not even enough to check prefix yet. */
+                       continue;
+
+               if (!testo_check_packet_prefix(packet, packet_len)) {
+                       /* Tail end of some previous data, drop it. */
+                       packet_len = 0;
+                       continue;
+               }
+
+               if (packet_len >= 7 + packet[6] * 7 + 2)
+                       /* Got a complete packet. */
+                       break;
+       }
+       sdi->driver->dev_close(sdi);
+
+       if (packet[6] > MAX_CHANNELS) {
+               sr_err("Device says it has %d channels!", packet[6]);
+               return SR_ERR;
+       }
+
+       for (i = 0; i < packet[6]; i++) {
+               unit = packet[7 + i * 7 + 4];
+               devc->channel_units[i] = unit;
+               switch (unit) {
+               case 1:
+                       probe_name = "Temperature";
+                       break;
+               case 3:
+                       probe_name = "Humidity";
+                       break;
+               case 5:
+                       probe_name = "Windspeed";
+                       break;
+               case 24:
+                       probe_name = "Pressure";
+                       break;
+               default:
+                       sr_dbg("Unsupported measurement unit %d", unit);
+                       return SR_ERR;
+               }
+               ch = sr_channel_new(i, SR_CHANNEL_ANALOG, TRUE, probe_name);
+               sdi->channels = g_slist_append(sdi->channels, ch);
+       }
+       devc->num_channels = packet[6];
+       sr_dbg("Found %d channel%s.", devc->num_channels,
+                       devc->num_channels > 1 ? "s" : "");
+
+       return SR_OK;
+}
+
+SR_PRIV int testo_request_packet(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_usb_dev_inst *usb;
+       int ret;
+
+       devc = sdi->priv;
+       usb = sdi->conn;
+
+       libusb_fill_bulk_transfer(devc->out_transfer, usb->devhdl, EP_OUT,
+                       devc->model->request, devc->model->request_size,
+                       receive_transfer, (void *)sdi, 100);
+       if ((ret = libusb_submit_transfer(devc->out_transfer) != 0)) {
+               sr_err("Failed to request packet: %s.", libusb_error_name(ret));
+               sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi,
+                               devc->cb_data);
+               return SR_ERR;
+       }
+       sr_dbg("Requested new packet.");
+
+       return SR_OK;
+}
+
+/* Check if the packet is well-formed. This matches packets for the
+ * Testo 175/177/400/650/950/435/635/735/445/645/945/946/545. */
+SR_PRIV gboolean testo_check_packet_prefix(unsigned char *buf, int len)
+{
+       int i;
+       unsigned char check[] = { 0x21, 0, 0, 0, 1 };
+
+       if (len < 5)
+               return FALSE;
+
+       for (i = 0; i < 5; i++) {
+               if (buf[i] != check[i]) {
+                       sr_dbg("Packet has invalid prefix.");
+                       return FALSE;
+               }
+       }
+
+       return TRUE;
+}
+
+SR_PRIV uint16_t crc16_mcrf4xx(uint16_t crc, uint8_t *data, size_t len)
+{
+       int i;
+
+       if (!data || !len)
+               return crc;
+
+       while (len--) {
+               crc ^= *data++;
+               for (i = 0; i < 8; i++) {
+                       if (crc & 1)
+                               crc = (crc >> 1) ^ 0x8408;
+                       else
+                               crc = (crc >> 1);
+               }
+       }
+
+       return crc;
+}
+
+static float binary32_le_to_float(unsigned char *buf)
+{
+       GFloatIEEE754 f;
+
+       f.v_float = 0;
+       f.mpn.sign = (buf[3] & 0x80) ? 1 : 0;
+       f.mpn.biased_exponent = (buf[3] << 1) | (buf[2] >> 7);
+       f.mpn.mantissa = buf[0] | (buf[1] << 8) | ((buf[2] & 0x7f) << 16);
+
+       return f.v_float;
+}
+
+SR_PRIV void testo_receive_packet(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_analog analog;
+       struct sr_channel *ch;
+       GString *dbg;
+       float value;
+       int i;
+       unsigned char *buf;
+
+       devc = sdi->priv;
+       sr_dbg("Got %d-byte packet.", devc->reply_size);
+
+       if (sr_log_loglevel_get() >= SR_LOG_SPEW) {
+               dbg = g_string_sized_new(128);
+               g_string_printf(dbg, "Packet:");
+               for (i = 0; i < devc->reply_size; i++)
+                       g_string_append_printf(dbg, " %.2x", devc->reply[i]);
+               sr_spew("%s", dbg->str);
+               g_string_free(dbg, TRUE);
+       }
+
+       packet.type = SR_DF_ANALOG;
+       packet.payload = &analog;
+       analog.num_samples = 1;
+       analog.mqflags = 0;
+       analog.data = &value;
+       /* Decode 7-byte values */
+       for (i = 0; i < devc->reply[6]; i++) {
+               buf = devc->reply + 7 + i * 7;
+               value = binary32_le_to_float(buf);
+               switch (buf[4]) {
+               case 1:
+                       analog.mq = SR_MQ_TEMPERATURE;
+                       analog.unit = SR_UNIT_CELSIUS;
+                       break;
+               case 3:
+                       analog.mq = SR_MQ_RELATIVE_HUMIDITY;
+                       analog.unit = SR_UNIT_HUMIDITY_293K;
+                       break;
+               case 5:
+                       analog.mq = SR_MQ_WIND_SPEED;
+                       analog.unit = SR_UNIT_METER_SECOND;
+                       break;
+               case 24:
+                       analog.mq = SR_MQ_PRESSURE;
+                       analog.unit = SR_UNIT_HECTOPASCAL;
+                       break;
+               default:
+                       sr_dbg("Unsupported measurement unit %d.", buf[4]);
+                       return;
+               }
+
+               /* Match this measurement with its channel. */
+               for (i = 0; i < devc->num_channels; i++) {
+                       if (devc->channel_units[i] == buf[4])
+                               break;
+               }
+               if (i == devc->num_channels) {
+                       /* Shouldn't happen. */
+                       sr_err("Some channel hotswapped in!");
+                       return;
+               }
+               ch = g_slist_nth_data(sdi->channels, i);
+               analog.channels = g_slist_append(NULL, ch);
+               sr_session_send(sdi, &packet);
+               g_slist_free(analog.channels);
+       }
+}
+
diff --git a/src/hardware/testo/protocol.h b/src/hardware/testo/protocol.h
new file mode 100644 (file)
index 0000000..f61fe2d
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Bert Vermeulen <bert@biot.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_TESTO_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_TESTO_PROTOCOL_H
+
+#include <stdint.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "testo"
+
+#define MAX_REPLY_SIZE       128
+#define MAX_CHANNELS         16
+
+/* FTDI commands */
+#define FTDI_SET_MODEMCTRL   0x01
+#define FTDI_SET_FLOWCTRL    0x02
+#define FTDI_SET_BAUDRATE    0x03
+#define FTDI_SET_PARAMS      0x04
+/* FTDI command values */
+#define FTDI_BAUDRATE_115200 0x001a
+#define FTDI_PARAMS_8N1      0x0008
+#define FTDI_FLOW_NONE       0x0008
+#define FTDI_MODEM_ALLHIGH   0x0303
+#define FTDI_INDEX           0x0000
+/* FTDI USB stuff */
+#define EP_IN                1 | LIBUSB_ENDPOINT_IN
+#define EP_OUT               2 | LIBUSB_ENDPOINT_OUT
+
+struct testo_model {
+       char *name;
+       int request_size;
+       unsigned char *request;
+};
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+       /* Model-specific information */
+       struct testo_model *model;
+
+       /* Acquisition settings */
+       uint64_t limit_msec;
+       uint64_t limit_samples;
+       void *cb_data;
+
+       /* Operational state */
+       gint64 end_time;
+       uint64_t num_samples;
+       uint8_t channel_units[MAX_CHANNELS];
+       int num_channels;
+
+       /* Temporary state across callbacks */
+       struct libusb_transfer *out_transfer;
+       unsigned char reply[MAX_REPLY_SIZE];
+       int reply_size;
+};
+
+SR_PRIV int testo_set_serial_params(struct sr_usb_dev_inst *usb);
+SR_PRIV int testo_probe_channels(struct sr_dev_inst *sdi);
+SR_PRIV void receive_transfer(struct libusb_transfer *transfer);
+SR_PRIV int testo_request_packet(const struct sr_dev_inst *sdi);
+SR_PRIV gboolean testo_check_packet_prefix(unsigned char *buf, int len);
+SR_PRIV uint16_t crc16_mcrf4xx(uint16_t crc, uint8_t *data, size_t len);
+SR_PRIV void testo_receive_packet(const struct sr_dev_inst *sdi);
+#endif
diff --git a/src/hardware/tondaj-sl-814/api.c b/src/hardware/tondaj-sl-814/api.c
new file mode 100644 (file)
index 0000000..7917c8d
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <fcntl.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "protocol.h"
+
+#define SERIALCOMM "9600/8e1"
+
+static const int32_t hwopts[] = {
+       SR_CONF_CONN,
+       SR_CONF_SERIALCOMM,
+};
+
+static const int32_t hwcaps[] = {
+       SR_CONF_SOUNDLEVELMETER,
+       SR_CONF_LIMIT_SAMPLES,
+       SR_CONF_CONTINUOUS,
+};
+
+SR_PRIV struct sr_dev_driver tondaj_sl_814_driver_info;
+static struct sr_dev_driver *di = &tondaj_sl_814_driver_info;
+
+static int init(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       struct sr_dev_inst *sdi;
+       struct sr_config *src;
+       struct sr_channel *ch;
+       GSList *devices, *l;
+       const char *conn, *serialcomm;
+       struct sr_serial_dev_inst *serial;
+
+       drvc = di->priv;
+       drvc->instances = NULL;
+
+       devices = NULL;
+
+       conn = serialcomm = NULL;
+       for (l = options; l; l = l->next) {
+               if (!(src = l->data)) {
+                       sr_err("Invalid option data, skipping.");
+                       continue;
+               }
+               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;
+               default:
+                       sr_err("Unknown option %d, skipping.", src->key);
+                       break;
+               }
+       }
+       if (!conn)
+               return NULL;
+       if (!serialcomm)
+               serialcomm = SERIALCOMM;
+
+       if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "Tondaj",
+                                   "SL-814", NULL))) {
+               sr_err("Failed to create device instance.");
+               return NULL;
+       }
+
+       if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+               sr_err("Device context malloc failed.");
+               return NULL;
+       }
+
+       if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
+               return NULL;
+
+       if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
+               return NULL;
+
+       sdi->inst_type = SR_INST_SERIAL;
+       sdi->conn = serial;
+
+       sdi->priv = devc;
+       sdi->driver = di;
+       ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1");
+       if (!ch) {
+               sr_err("Failed to create channel.");
+               return NULL;
+       }
+       sdi->channels = g_slist_append(sdi->channels, ch);
+       drvc->instances = g_slist_append(drvc->instances, sdi);
+       devices = g_slist_append(devices, sdi);
+
+       return devices;
+}
+
+static GSList *dev_list(void)
+{
+       return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int cleanup(void)
+{
+       return std_dev_clear(di, NULL);
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+
+       (void)cg;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       devc = sdi->priv;
+
+       switch (id) {
+       case SR_CONF_LIMIT_SAMPLES:
+               devc->limit_samples = g_variant_get_uint64(data);
+               sr_dbg("Setting sample limit to %" PRIu64 ".",
+                      devc->limit_samples);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_list(int 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_INT32,
+                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+               break;
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi,
+                                   void *cb_data)
+{
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       devc = sdi->priv;
+       devc->cb_data = cb_data;
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(cb_data, LOG_PREFIX);
+
+       /* Poll every 500ms, or whenever some data comes in. */
+       serial = sdi->conn;
+       serial_source_add(sdi->session, serial, G_IO_IN, 500,
+                     tondaj_sl_814_receive_data, (void *)sdi);
+
+       return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       return std_serial_dev_acquisition_stop(sdi, cb_data, std_serial_dev_close,
+                       sdi->conn, LOG_PREFIX);
+}
+
+SR_PRIV struct sr_dev_driver tondaj_sl_814_driver_info = {
+       .name = "tondaj-sl-814",
+       .longname = "Tondaj SL-814",
+       .api_version = 1,
+       .init = init,
+       .cleanup = cleanup,
+       .scan = scan,
+       .dev_list = 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 = dev_acquisition_stop,
+       .priv = NULL,
+};
diff --git a/src/hardware/tondaj-sl-814/protocol.c b/src/hardware/tondaj-sl-814/protocol.c
new file mode 100644 (file)
index 0000000..feeec69
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <string.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "protocol.h"
+
+/* States */
+enum {
+       SEND_INIT,
+       GET_INIT_REPLY,
+       SEND_PACKET_REQUEST,
+       GET_PACKET,
+};
+
+static void parse_packet(const uint8_t *buf, float *floatval,
+                        struct sr_datafeed_analog *analog)
+{
+       gboolean is_a, is_fast;
+       uint16_t intval;
+       uint8_t level = 0, level_bits;
+
+       /* Byte 0 [7:7]: 0 = A, 1 = C */
+       is_a = ((buf[0] & (1 << 7)) == 0);
+
+       /* Byte 0 [6:6]: Unknown/unused? */
+
+       /* Byte 0 [5:4]: Level (00 = 40, 01 = 60, 10 = 80, 11 = 100) */
+       level_bits = (buf[0] >> 4) & 0x03;
+       if (level_bits == 0)
+               level = 40;
+       else if (level_bits == 1)
+               level = 60;
+       else if (level_bits == 2)
+               level = 80;
+       else if (level_bits == 3)
+               level = 100;
+
+       /* Byte 0 [3:3]: 0 = fast, 1 = slow */
+       is_fast = ((buf[0] & (1 << 3)) == 0);
+
+       /* Byte 0 [2:0]: value[10..8] */
+       /* Byte 1 [7:0]: value[7..0] */
+       intval = (buf[0] & 0x7) << 8;
+       intval |= buf[1];
+
+       *floatval = (float)intval;
+
+       /* The value on the display always has one digit after the comma. */
+       *floatval /= 10;
+
+       analog->mq = SR_MQ_SOUND_PRESSURE_LEVEL;
+       analog->unit = SR_UNIT_DECIBEL_SPL;
+
+       if (is_a)
+               analog->mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_A;
+       else
+               analog->mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_C;
+
+       if (is_fast)
+               analog->mqflags |= SR_MQFLAG_SPL_TIME_WEIGHT_F;
+       else
+               analog->mqflags |= SR_MQFLAG_SPL_TIME_WEIGHT_S;
+
+       /* TODO: How to handle level? */
+       (void)level;
+}
+
+static void decode_packet(struct sr_dev_inst *sdi)
+{
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_analog analog;
+       struct dev_context *devc;
+       float floatval;
+
+       devc = sdi->priv;
+       memset(&analog, 0, sizeof(struct sr_datafeed_analog));
+
+       parse_packet(devc->buf, &floatval, &analog);
+
+       /* Send a sample packet with one analog value. */
+       analog.channels = sdi->channels;
+       analog.num_samples = 1;
+       analog.data = &floatval;
+       packet.type = SR_DF_ANALOG;
+       packet.payload = &analog;
+       sr_session_send(devc->cb_data, &packet);
+
+       devc->num_samples++;
+}
+
+int tondaj_sl_814_receive_data(int fd, int revents, void *cb_data)
+{
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       struct sr_serial_dev_inst *serial;
+       uint8_t buf[3];
+       int ret;
+
+       (void)fd;
+       (void)revents;
+
+       sdi = cb_data;
+       serial = sdi->conn;
+       devc = sdi->priv;
+
+       /* TODO: Parts of this code need to be improved later. */
+
+       /* State machine. */
+       if (devc->state == SEND_INIT) {
+               /* On the first run, send the "init" command. */
+               buf[0] = 0x10;
+               buf[1] = 0x04;
+               buf[2] = 0x0d;
+               sr_spew("Sending init command: %02x %02x %02x.",
+                       buf[0], buf[1], buf[2]);
+               if ((ret = serial_write(serial, buf, 3)) < 0) {
+                       sr_err("Error sending init command: %d.", ret);
+                       return FALSE;
+               }
+               devc->state = GET_INIT_REPLY;
+       } else if (devc->state == GET_INIT_REPLY) {
+               /* If we just sent the "init" command, get its reply. */
+               if ((ret = serial_read(serial, buf, 2)) < 0) {
+                       sr_err("Error reading init reply: %d.", ret);
+                       return FALSE;
+               }
+               sr_spew("Received init reply: %02x %02x.", buf[0], buf[1]);
+               /* Expected reply: 0x05 0x0d */
+               if (buf[0] != 0x05 || buf[1] != 0x0d) {
+                       sr_err("Received incorrect init reply, retrying.");
+                       devc->state = SEND_INIT;
+                       return TRUE;
+               }
+               devc->state = SEND_PACKET_REQUEST;
+       } else if (devc->state == SEND_PACKET_REQUEST) {
+               /* Request a packet (send 0x30 ZZ 0x0d). */
+               buf[0] = 0x30;
+               buf[1] = 0x00; /* ZZ */
+               buf[2] = 0x0d;
+               sr_spew("Sending data request command: %02x %02x %02x.",
+                       buf[0], buf[1], buf[2]);
+               if ((ret = serial_write(serial, buf, 3)) < 0) {
+                       sr_err("Error sending request command: %d.", ret);
+                       return FALSE;
+               }
+               devc->buflen = 0;
+               devc->state = GET_PACKET;
+       } else if (devc->state == GET_PACKET) {
+               /* Read a packet from the device. */
+               ret = serial_read(serial, devc->buf + devc->buflen,
+                                 4 - devc->buflen);
+               if (ret < 0) {
+                       sr_err("Error reading packet: %d.", ret);
+                       return TRUE;
+               }
+
+               devc->buflen += ret;
+
+               /* Didn't receive all 4 bytes, yet. */
+               if (devc->buflen != 4)
+                       return TRUE;
+
+               sr_spew("Received packet: %02x %02x %02x %02x.", devc->buf[0],
+                       devc->buf[1], devc->buf[2], devc->buf[3]);
+
+               /* Expected reply: AA BB ZZ+1 0x0d */
+               if (devc->buf[2] != 0x01 || devc->buf[3] != 0x0d) {
+                       sr_err("Received incorrect request reply, retrying.");
+                       devc->state = SEND_PACKET_REQUEST;
+                       return TRUE;
+               }
+
+               decode_packet(sdi);
+
+               devc->state = SEND_PACKET_REQUEST;
+       } else {
+               sr_err("Invalid state: %d.", devc->state);
+               return FALSE;
+       }
+
+       /* Stop acquisition if we acquired enough samples. */
+       if (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
+               sr_info("Requested number of samples reached.");
+               sdi->driver->dev_acquisition_stop(sdi, cb_data);
+       }
+
+       return TRUE;
+}
diff --git a/src/hardware/tondaj-sl-814/protocol.h b/src/hardware/tondaj-sl-814/protocol.h
new file mode 100644 (file)
index 0000000..027b66d
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#ifndef LIBSIGROK_HARDWARE_TONDAJ_SL_814_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_TONDAJ_SL_814_PROTOCOL_H
+
+#include <stdint.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "tondaj-sl-814"
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+       /** The current sampling limit (in number of samples). */
+       uint64_t limit_samples;
+
+       /** The current sampling limit (in ms). */
+       uint64_t limit_msec;
+
+       /** Opaque pointer passed in by the frontend. */
+       void *cb_data;
+
+       /** The current number of already received samples. */
+       uint64_t num_samples;
+
+       int state;
+
+       uint8_t buf[4];
+       uint8_t buflen;
+};
+
+SR_PRIV int tondaj_sl_814_receive_data(int fd, int revents, void *cb_data);
+
+#endif
diff --git a/src/hardware/uni-t-dmm/api.c b/src/hardware/uni-t-dmm/api.c
new file mode 100644 (file)
index 0000000..f98c4f5
--- /dev/null
@@ -0,0 +1,424 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012-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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "protocol.h"
+
+#define UNI_T_UT_D04_NEW "1a86.e008"
+
+static const int32_t hwopts[] = {
+       SR_CONF_CONN,
+};
+
+static const int32_t hwcaps[] = {
+       SR_CONF_MULTIMETER,
+       SR_CONF_LIMIT_SAMPLES,
+       SR_CONF_LIMIT_MSEC,
+       SR_CONF_CONTINUOUS,
+};
+
+SR_PRIV struct sr_dev_driver tecpel_dmm_8061_driver_info;
+SR_PRIV struct sr_dev_driver uni_t_ut60a_driver_info;
+SR_PRIV struct sr_dev_driver uni_t_ut60e_driver_info;
+SR_PRIV struct sr_dev_driver uni_t_ut60g_driver_info;
+SR_PRIV struct sr_dev_driver uni_t_ut61b_driver_info;
+SR_PRIV struct sr_dev_driver uni_t_ut61c_driver_info;
+SR_PRIV struct sr_dev_driver uni_t_ut61d_driver_info;
+SR_PRIV struct sr_dev_driver uni_t_ut61e_driver_info;
+SR_PRIV struct sr_dev_driver voltcraft_vc820_driver_info;
+SR_PRIV struct sr_dev_driver voltcraft_vc830_driver_info;
+SR_PRIV struct sr_dev_driver voltcraft_vc840_driver_info;
+SR_PRIV struct sr_dev_driver tenma_72_7745_driver_info;
+SR_PRIV struct sr_dev_driver tenma_72_7750_driver_info;
+
+SR_PRIV struct dmm_info udmms[] = {
+       {
+               "Tecpel", "DMM-8061", 2400,
+               FS9721_PACKET_SIZE,
+               sr_fs9721_packet_valid, sr_fs9721_parse,
+               sr_fs9721_00_temp_c,
+               &tecpel_dmm_8061_driver_info, receive_data_TECPEL_DMM_8061,
+       },
+       {
+               "UNI-T", "UT60A", 2400,
+               FS9721_PACKET_SIZE,
+               sr_fs9721_packet_valid, sr_fs9721_parse,
+               NULL,
+               &uni_t_ut60a_driver_info, receive_data_UNI_T_UT60A,
+       },
+       {
+               "UNI-T", "UT60E", 2400,
+               FS9721_PACKET_SIZE,
+               sr_fs9721_packet_valid, sr_fs9721_parse,
+               sr_fs9721_00_temp_c,
+               &uni_t_ut60e_driver_info, receive_data_UNI_T_UT60E,
+       },
+       {
+               /* The baudrate is actually 19230, see "Note 1" below. */
+               "UNI-T", "UT60G", 19200,
+               ES519XX_11B_PACKET_SIZE,
+               sr_es519xx_19200_11b_packet_valid, sr_es519xx_19200_11b_parse,
+               NULL,
+               &uni_t_ut60g_driver_info, receive_data_UNI_T_UT60G,
+       },
+       {
+               "UNI-T", "UT61B", 2400,
+               FS9922_PACKET_SIZE,
+               sr_fs9922_packet_valid, sr_fs9922_parse,
+               NULL,
+               &uni_t_ut61b_driver_info, receive_data_UNI_T_UT61B,
+       },
+       {
+               "UNI-T", "UT61C", 2400,
+               FS9922_PACKET_SIZE,
+               sr_fs9922_packet_valid, sr_fs9922_parse,
+               NULL,
+               &uni_t_ut61c_driver_info, receive_data_UNI_T_UT61C,
+       },
+       {
+               "UNI-T", "UT61D", 2400,
+               FS9922_PACKET_SIZE,
+               sr_fs9922_packet_valid, sr_fs9922_parse,
+               NULL,
+               &uni_t_ut61d_driver_info, receive_data_UNI_T_UT61D,
+       },
+       {
+               /* The baudrate is actually 19230, see "Note 1" below. */
+               "UNI-T", "UT61E", 19200,
+               ES519XX_14B_PACKET_SIZE,
+               sr_es519xx_19200_14b_packet_valid, sr_es519xx_19200_14b_parse,
+               NULL,
+               &uni_t_ut61e_driver_info, receive_data_UNI_T_UT61E,
+       },
+       {
+               "Voltcraft", "VC-820", 2400,
+               FS9721_PACKET_SIZE,
+               sr_fs9721_packet_valid, sr_fs9721_parse,
+               NULL,
+               &voltcraft_vc820_driver_info, receive_data_VOLTCRAFT_VC820,
+       },
+       {
+               /*
+                * Note: The VC830 doesn't set the 'volt' and 'diode' bits of
+                * the FS9922 protocol. Instead, it only sets the user-defined
+                * bit "z1" to indicate "diode mode" and "voltage".
+                */
+               "Voltcraft", "VC-830", 2400,
+               FS9922_PACKET_SIZE,
+               sr_fs9922_packet_valid, sr_fs9922_parse,
+               &sr_fs9922_z1_diode,
+               &voltcraft_vc830_driver_info, receive_data_VOLTCRAFT_VC830,
+       },
+       {
+               "Voltcraft", "VC-840", 2400,
+               FS9721_PACKET_SIZE,
+               sr_fs9721_packet_valid, sr_fs9721_parse,
+               sr_fs9721_00_temp_c,
+               &voltcraft_vc840_driver_info, receive_data_VOLTCRAFT_VC840,
+       },
+       {
+               "Tenma", "72-7745", 2400,
+               FS9721_PACKET_SIZE,
+               sr_fs9721_packet_valid, sr_fs9721_parse,
+               sr_fs9721_00_temp_c,
+               &tenma_72_7745_driver_info, receive_data_TENMA_72_7745,
+       },
+       {
+               /* The baudrate is actually 19230, see "Note 1" below. */
+               "Tenma", "72-7750", 19200,
+               ES519XX_11B_PACKET_SIZE,
+               sr_es519xx_19200_11b_packet_valid, sr_es519xx_19200_11b_parse,
+               NULL,
+               &tenma_72_7750_driver_info, receive_data_TENMA_72_7750,
+       },
+};
+
+/*
+ * Note 1: The actual baudrate of the Cyrustek ES519xx chip used in this DMM
+ * is 19230. However, the WCH CH9325 chip (UART to USB/HID) used in (some
+ * versions of) the UNI-T UT-D04 cable doesn't support 19230 baud. It only
+ * supports 19200, and setting an unsupported baudrate will result in the
+ * default of 2400 being used (which will not work with this DMM, of course).
+ */
+
+static int dev_clear(int dmm)
+{
+       return std_dev_clear(udmms[dmm].di, NULL);
+}
+
+static int init(struct sr_context *sr_ctx, int dmm)
+{
+       sr_dbg("Selected '%s' subdriver.", udmms[dmm].di->name);
+
+       return std_init(sr_ctx, udmms[dmm].di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options, int dmm)
+{
+       GSList *usb_devices, *devices, *l;
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       struct drv_context *drvc;
+       struct sr_usb_dev_inst *usb;
+       struct sr_config *src;
+       struct sr_channel *ch;
+       const char *conn;
+
+       drvc = udmms[dmm].di->priv;
+
+       conn = NULL;
+       for (l = options; l; l = l->next) {
+               src = l->data;
+               switch (src->key) {
+               case SR_CONF_CONN:
+                       conn = g_variant_get_string(src->data, NULL);
+                       break;
+               }
+       }
+       if (!conn)
+               return NULL;
+
+       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;
+
+               if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+                       sr_err("Device context malloc failed.");
+                       return NULL;
+               }
+
+               devc->first_run = TRUE;
+
+               if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE,
+                               udmms[dmm].vendor, udmms[dmm].device, NULL))) {
+                       sr_err("sr_dev_inst_new returned NULL.");
+                       return NULL;
+               }
+               sdi->priv = devc;
+               sdi->driver = udmms[dmm].di;
+               if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1")))
+                       return NULL;
+               sdi->channels = g_slist_append(sdi->channels, ch);
+
+               sdi->inst_type = SR_INST_USB;
+               sdi->conn = usb;
+
+               drvc->instances = g_slist_append(drvc->instances, sdi);
+               devices = g_slist_append(devices, sdi);
+       }
+
+       return devices;
+}
+
+static GSList *dev_list(int dmm)
+{
+       return ((struct drv_context *)(udmms[dmm].di->priv))->instances;
+}
+
+static int dev_open(struct sr_dev_inst *sdi, int dmm)
+{
+       struct drv_context *drvc;
+       struct sr_usb_dev_inst *usb;
+       int ret;
+
+       drvc = udmms[dmm].di->priv;
+       usb = sdi->conn;
+
+       if ((ret = sr_usb_open(drvc->sr_ctx->libusb_ctx, usb)) == SR_OK)
+               sdi->status = SR_ST_ACTIVE;
+
+       return ret;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+       /* TODO */
+
+       sdi->status = SR_ST_INACTIVE;
+
+       return SR_OK;
+}
+
+static int cleanup(int dmm)
+{
+       return dev_clear(dmm);
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+
+       (void)cg;
+
+       devc = sdi->priv;
+
+       switch (id) {
+       case SR_CONF_LIMIT_MSEC:
+               if (g_variant_get_uint64(data) == 0) {
+                       sr_err("Time limit cannot be 0.");
+                       return SR_ERR;
+               }
+               devc->limit_msec = g_variant_get_uint64(data);
+               sr_dbg("Setting time limit to %" PRIu64 "ms.",
+                      devc->limit_msec);
+               break;
+       case SR_CONF_LIMIT_SAMPLES:
+               if (g_variant_get_uint64(data) == 0) {
+                       sr_err("Sample limit cannot be 0.");
+                       return SR_ERR;
+               }
+               devc->limit_samples = g_variant_get_uint64(data);
+               sr_dbg("Setting sample limit to %" PRIu64 ".",
+                      devc->limit_samples);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_list(int 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_INT32,
+                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+               break;
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi,
+                                   void *cb_data, int dmm)
+{
+       struct dev_context *devc;
+
+       devc = sdi->priv;
+
+       devc->cb_data = cb_data;
+
+       devc->starttime = g_get_monotonic_time();
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(sdi, LOG_PREFIX);
+
+       sr_session_source_add(sdi->session, 0, 0, 10 /* poll_timeout */,
+                     udmms[dmm].receive_data, (void *)sdi);
+
+       return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct sr_datafeed_packet packet;
+
+       (void)cb_data;
+
+       sr_dbg("Stopping acquisition.");
+
+       /* Send end packet to the session bus. */
+       sr_dbg("Sending SR_DF_END.");
+       packet.type = SR_DF_END;
+       sr_session_send(sdi, &packet);
+
+       sr_session_source_remove(sdi->session, 0);
+
+       return SR_OK;
+}
+
+/* Driver-specific API function wrappers */
+#define HW_INIT(X) \
+static int init_##X(struct sr_context *sr_ctx) { return init(sr_ctx, X); }
+#define HW_CLEANUP(X) \
+static int cleanup_##X(void) { return cleanup(X); }
+#define HW_SCAN(X) \
+static GSList *scan_##X(GSList *options) { return scan(options, X); }
+#define HW_DEV_LIST(X) \
+static GSList *dev_list_##X(void) { return dev_list(X); }
+#define HW_DEV_CLEAR(X) \
+static int dev_clear_##X(void) { return dev_clear(X); }
+#define HW_DEV_ACQUISITION_START(X) \
+static int dev_acquisition_start_##X(const struct sr_dev_inst *sdi, \
+void *cb_data) { return dev_acquisition_start(sdi, cb_data, X); }
+#define HW_DEV_OPEN(X) \
+static int dev_open_##X(struct sr_dev_inst *sdi) { return dev_open(sdi, X); }
+
+/* Driver structs and API function wrappers */
+#define DRV(ID, ID_UPPER, NAME, LONGNAME) \
+HW_INIT(ID_UPPER) \
+HW_CLEANUP(ID_UPPER) \
+HW_SCAN(ID_UPPER) \
+HW_DEV_LIST(ID_UPPER) \
+HW_DEV_CLEAR(ID_UPPER) \
+HW_DEV_ACQUISITION_START(ID_UPPER) \
+HW_DEV_OPEN(ID_UPPER) \
+SR_PRIV struct sr_dev_driver ID##_driver_info = { \
+       .name = NAME, \
+       .longname = LONGNAME, \
+       .api_version = 1, \
+       .init = init_##ID_UPPER, \
+       .cleanup = cleanup_##ID_UPPER, \
+       .scan = scan_##ID_UPPER, \
+       .dev_list = dev_list_##ID_UPPER, \
+       .dev_clear = dev_clear_##ID_UPPER, \
+       .config_get = NULL, \
+       .config_set = config_set, \
+       .config_list = config_list, \
+       .dev_open = dev_open_##ID_UPPER, \
+       .dev_close = dev_close, \
+       .dev_acquisition_start = dev_acquisition_start_##ID_UPPER, \
+       .dev_acquisition_stop = dev_acquisition_stop, \
+       .priv = NULL, \
+};
+
+DRV(tecpel_dmm_8061, TECPEL_DMM_8061, "tecpel-dmm-8061", "Tecpel DMM-8061")
+DRV(uni_t_ut60a, UNI_T_UT60A, "uni-t-ut60a", "UNI-T UT60A")
+DRV(uni_t_ut60e, UNI_T_UT60E, "uni-t-ut60e", "UNI-T UT60E")
+DRV(uni_t_ut60g, UNI_T_UT60G, "uni-t-ut60g", "UNI-T UT60G")
+DRV(uni_t_ut61b, UNI_T_UT61B, "uni-t-ut61b", "UNI-T UT61B")
+DRV(uni_t_ut61c, UNI_T_UT61C, "uni-t-ut61c", "UNI-T UT61C")
+DRV(uni_t_ut61d, UNI_T_UT61D, "uni-t-ut61d", "UNI-T UT61D")
+DRV(uni_t_ut61e, UNI_T_UT61E, "uni-t-ut61e", "UNI-T UT61E")
+DRV(voltcraft_vc820, VOLTCRAFT_VC820, "voltcraft-vc820", "Voltcraft VC-820")
+DRV(voltcraft_vc830, VOLTCRAFT_VC830, "voltcraft-vc830", "Voltcraft VC-830")
+DRV(voltcraft_vc840, VOLTCRAFT_VC840, "voltcraft-vc840", "Voltcraft VC-840")
+DRV(tenma_72_7745, TENMA_72_7745, "tenma-72-7745", "Tenma 72-7745")
+DRV(tenma_72_7750, TENMA_72_7750, "tenma-72-7750", "Tenma 72-7750")
diff --git a/src/hardware/uni-t-dmm/protocol.c b/src/hardware/uni-t-dmm/protocol.c
new file mode 100644 (file)
index 0000000..ca2568e
--- /dev/null
@@ -0,0 +1,315 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012-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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <string.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "protocol.h"
+
+extern struct dmm_info udmms[];
+
+/*
+ * Driver for various UNI-T multimeters (and rebranded ones).
+ *
+ * Most UNI-T DMMs can be used with two (three) different PC interface cables:
+ *  - The UT-D04 USB/HID cable, old version with Hoitek HE2325U chip.
+ *  - The UT-D04 USB/HID cable, new version with WCH CH9325 chip.
+ *  - The UT-D02 RS232 cable.
+ *
+ * This driver is meant to support all USB/HID cables, and various DMMs that
+ * can be attached to a PC via these cables. Currently only the UT-D04 cable
+ * (new version) is supported/tested.
+ * The UT-D02 RS232 cable is handled by the 'serial-dmm' driver.
+ *
+ * The data for one DMM packet (e.g. 14 bytes if the respective DMM uses a
+ * Fortune Semiconductor FS9922-DMM4 chip) is spread across multiple
+ * 8-byte chunks.
+ *
+ * An 8-byte chunk looks like this:
+ *  - Byte 0: 0xfz, where z is the number of actual data bytes in this chunk.
+ *  - Bytes 1-7: z data bytes, the rest of the bytes should be ignored.
+ *
+ * Example:
+ *  f0 00 00 00 00 00 00 00 (no data bytes)
+ *  f2 55 77 00 00 00 00 00 (2 data bytes, 0x55 and 0x77)
+ *  f1 d1 00 00 00 00 00 00 (1 data byte, 0xd1)
+ */
+
+static void decode_packet(struct sr_dev_inst *sdi, int dmm, const uint8_t *buf,
+                         void *info)
+{
+       struct dev_context *devc;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_analog analog;
+       float floatval;
+       int ret;
+
+       devc = sdi->priv;
+       memset(&analog, 0, sizeof(struct sr_datafeed_analog));
+
+       /* Parse the protocol packet. */
+       ret = udmms[dmm].packet_parse(buf, &floatval, &analog, info);
+       if (ret != SR_OK) {
+               sr_dbg("Invalid DMM packet, ignoring.");
+               return;
+       }
+
+       /* If this DMM needs additional handling, call the resp. function. */
+       if (udmms[dmm].dmm_details)
+               udmms[dmm].dmm_details(&analog, info);
+
+       /* Send a sample packet with one analog value. */
+       analog.channels = sdi->channels;
+       analog.num_samples = 1;
+       analog.data = &floatval;
+       packet.type = SR_DF_ANALOG;
+       packet.payload = &analog;
+       sr_session_send(devc->cb_data, &packet);
+
+       /* Increase sample count. */
+       devc->num_samples++;
+}
+
+static int hid_chip_init(struct sr_dev_inst *sdi, uint16_t baudrate)
+{
+       int ret;
+       uint8_t buf[5];
+       struct sr_usb_dev_inst *usb;
+
+       usb = sdi->conn;
+       
+       /* 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;
+               }
+               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.");
+
+       /* Set data for the HID feature report (e.g. baudrate). */
+       buf[0] = baudrate & 0xff;        /* Baudrate, LSB */
+       buf[1] = (baudrate >> 8) & 0xff; /* Baudrate, MSB */
+       buf[2] = 0x00;                   /* Unknown/unused (?) */
+       buf[3] = 0x00;                   /* Unknown/unused (?) */
+       buf[4] = 0x03;                   /* Unknown, always 0x03. */
+
+       /* Send HID feature report to setup the baudrate/chip. */
+       sr_dbg("Sending initial HID feature report.");
+       sr_spew("HID init = 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x (%d baud)",
+               buf[0], buf[1], buf[2], buf[3], buf[4], baudrate);
+       ret = libusb_control_transfer(
+               usb->devhdl, /* libusb device handle */
+               LIBUSB_REQUEST_TYPE_CLASS |
+               LIBUSB_RECIPIENT_INTERFACE |
+               LIBUSB_ENDPOINT_OUT,
+               9, /* bRequest: HID set_report */
+               0x300, /* wValue: HID feature, report number 0 */
+               0, /* wIndex: interface 0 */
+               (unsigned char *)&buf, /* payload buffer */
+               5, /* wLength: 5 bytes payload */
+               1000 /* timeout (ms) */);
+
+       if (ret < 0) {
+               sr_err("HID feature report error: %s.", libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+       if (ret != 5) {
+               /* TODO: Handle better by also sending the remaining bytes. */
+               sr_err("Short packet: sent %d/5 bytes.", ret);
+               return SR_ERR;
+       }
+
+       sr_dbg("Successfully sent initial HID feature report.");
+
+       return SR_OK;
+}
+
+static void log_8byte_chunk(const uint8_t *buf)
+{
+       sr_spew("8-byte chunk: %02x %02x %02x %02x %02x %02x %02x %02x "
+               "(%d data bytes)", buf[0], buf[1], buf[2], buf[3],
+               buf[4], buf[5], buf[6], buf[7], (buf[0] & 0x0f));
+}
+
+static void log_dmm_packet(const uint8_t *buf)
+{
+       sr_dbg("DMM packet:   %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]);
+}
+
+static int get_and_handle_data(struct sr_dev_inst *sdi, int dmm, void *info)
+{
+       struct dev_context *devc;
+       uint8_t buf[CHUNK_SIZE], *pbuf;
+       int i, ret, len, num_databytes_in_chunk;
+       struct sr_usb_dev_inst *usb;
+
+       devc = sdi->priv;
+       usb = sdi->conn;
+       pbuf = devc->protocol_buf;
+
+       /* On the first run, we need to init the HID chip. */
+       if (devc->first_run) {
+               if ((ret = hid_chip_init(sdi, udmms[dmm].baudrate)) != SR_OK) {
+                       sr_err("HID chip init failed: %d.", ret);
+                       return SR_ERR;
+               }
+               memset(pbuf, 0x00, DMM_BUFSIZE);
+               devc->first_run = FALSE;
+       }
+
+       memset(&buf, 0x00, CHUNK_SIZE);
+
+       /* Get data from EP2 using an interrupt transfer. */
+       ret = libusb_interrupt_transfer(
+               usb->devhdl, /* libusb device handle */
+               LIBUSB_ENDPOINT_IN | 2, /* EP2, IN */
+               (unsigned char *)&buf, /* receive buffer */
+               CHUNK_SIZE, /* wLength */
+               &len, /* actually received byte count */
+               1000 /* timeout (ms) */);
+
+       if (ret < 0) {
+               sr_err("USB receive error: %s.", libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+       if (len != CHUNK_SIZE) {
+               sr_err("Short packet: received %d/%d bytes.", len, CHUNK_SIZE);
+               /* TODO: Print the bytes? */
+               return SR_ERR;
+       }
+
+       log_8byte_chunk((const uint8_t *)&buf);
+
+       /* If there are no data bytes just return (without error). */
+       if (buf[0] == 0xf0)
+               return SR_OK;
+
+       devc->bufoffset = 0;
+
+       /*
+        * Append the 1-7 data bytes of this chunk to pbuf.
+        *
+        * Special case:
+        * DMMs with Cyrustek ES51922 chip need serial settings of
+        * 19230/7o1. The WCH CH9325 UART to USB/HID chip used in (some
+        * versions of) the UNI-T UT-D04 cable however, will also send
+        * the parity bit to the host in the 8-byte data chunks. This bit
+        * is encoded in bit 7 of each of the 1-7 data bytes and must thus
+        * be removed in order for the actual ES51922 protocol parser to
+        * work properly.
+        */
+       num_databytes_in_chunk = buf[0] & 0x0f;
+       for (i = 0; i < num_databytes_in_chunk; i++, devc->buflen++) {
+               pbuf[devc->buflen] = buf[1 + i];
+               if (udmms[dmm].packet_parse == sr_es519xx_19200_14b_parse)
+                       pbuf[devc->buflen] &= ~(1 << 7);
+       }
+
+       /* Now look for packets in that data. */
+       while ((devc->buflen - devc->bufoffset) >= udmms[dmm].packet_size) {
+               if (udmms[dmm].packet_valid(pbuf + devc->bufoffset)) {
+                       log_dmm_packet(pbuf + devc->bufoffset);
+                       decode_packet(sdi, dmm, pbuf + devc->bufoffset, info);
+                       devc->bufoffset += udmms[dmm].packet_size;
+               } else {
+                       devc->bufoffset++;
+               }
+       }
+
+       /* Move remaining bytes to beginning of buffer. */
+       for (i = 0; i < devc->buflen - devc->bufoffset; i++)
+               pbuf[i] = pbuf[devc->bufoffset + i];
+       devc->buflen -= devc->bufoffset;
+
+       return SR_OK;
+}
+
+static int receive_data(int fd, int revents, int dmm, void *info, void *cb_data)
+{
+       int ret;
+       struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       int64_t time_ms;
+
+       (void)fd;
+       (void)revents;
+
+       sdi = cb_data;
+       devc = sdi->priv;
+
+       if ((ret = get_and_handle_data(sdi, dmm, info)) != SR_OK)
+               return FALSE;
+
+       /* Abort acquisition if we acquired enough samples. */
+       if (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
+               sr_info("Requested number of samples reached.");
+               sdi->driver->dev_acquisition_stop(sdi, cb_data);
+       }
+
+       if (devc->limit_msec) {
+               time_ms = (g_get_monotonic_time() - devc->starttime) / 1000;
+               if (time_ms > (int64_t)devc->limit_msec) {
+                       sr_info("Requested time limit reached.");
+                       sdi->driver->dev_acquisition_stop(sdi, cb_data);
+                       return TRUE;
+               }
+       }
+
+       return TRUE;
+}
+
+#define RECEIVE_DATA(ID_UPPER, DMM_DRIVER) \
+SR_PRIV int receive_data_##ID_UPPER(int fd, int revents, void *cb_data) { \
+       struct DMM_DRIVER##_info info; \
+       return receive_data(fd, revents, ID_UPPER, &info, cb_data); }
+
+/* Driver-specific receive_data() wrappers */
+RECEIVE_DATA(TECPEL_DMM_8061, fs9721)
+RECEIVE_DATA(UNI_T_UT60A, fs9721)
+RECEIVE_DATA(UNI_T_UT60E, fs9721)
+RECEIVE_DATA(UNI_T_UT60G, es519xx)
+RECEIVE_DATA(UNI_T_UT61B, fs9922)
+RECEIVE_DATA(UNI_T_UT61C, fs9922)
+RECEIVE_DATA(UNI_T_UT61D, fs9922)
+RECEIVE_DATA(UNI_T_UT61E, es519xx)
+RECEIVE_DATA(VOLTCRAFT_VC820, fs9721)
+RECEIVE_DATA(VOLTCRAFT_VC830, fs9922)
+RECEIVE_DATA(VOLTCRAFT_VC840, fs9721)
+RECEIVE_DATA(TENMA_72_7745, es519xx)
+RECEIVE_DATA(TENMA_72_7750, es519xx)
diff --git a/src/hardware/uni-t-dmm/protocol.h b/src/hardware/uni-t-dmm/protocol.h
new file mode 100644 (file)
index 0000000..08fb537
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012-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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#ifndef LIBSIGROK_HARDWARE_UNI_T_DMM_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_UNI_T_DMM_PROTOCOL_H
+
+#include <stdint.h>
+#include <glib.h>
+#include <libusb.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "uni-t-dmm"
+
+enum {
+       TECPEL_DMM_8061,
+       UNI_T_UT60A,
+       UNI_T_UT60E,
+       UNI_T_UT60G,
+       UNI_T_UT61B,
+       UNI_T_UT61C,
+       UNI_T_UT61D,
+       UNI_T_UT61E,
+       VOLTCRAFT_VC820,
+       VOLTCRAFT_VC830,
+       VOLTCRAFT_VC840,
+       TENMA_72_7745,
+       TENMA_72_7750,
+};
+
+struct dmm_info {
+       char *vendor;
+       char *device;
+       uint32_t baudrate;
+       int packet_size;
+       gboolean (*packet_valid)(const uint8_t *);
+       int (*packet_parse)(const uint8_t *, float *,
+                           struct sr_datafeed_analog *, void *);
+       void (*dmm_details)(struct sr_datafeed_analog *, void *);
+       struct sr_dev_driver *di;
+       int (*receive_data)(int, int, void *);
+};
+
+#define CHUNK_SIZE             8
+
+#define DMM_BUFSIZE            256
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+       /** The current sampling limit (in number of samples). */
+       uint64_t limit_samples;
+
+       /** The current sampling limit (in ms). */
+       uint64_t limit_msec;
+
+       /** Opaque pointer passed in by the frontend. */
+       void *cb_data;
+
+       /** The current number of already received samples. */
+       uint64_t num_samples;
+
+       int64_t starttime;
+
+       gboolean first_run;
+
+       uint8_t protocol_buf[DMM_BUFSIZE];
+       uint8_t bufoffset;
+       uint8_t buflen;
+};
+
+SR_PRIV int receive_data_TECPEL_DMM_8061(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_UNI_T_UT60A(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_UNI_T_UT60E(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_UNI_T_UT60G(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_UNI_T_UT61B(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_UNI_T_UT61C(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_UNI_T_UT61D(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_UNI_T_UT61E(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_VOLTCRAFT_VC820(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_VOLTCRAFT_VC830(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_VOLTCRAFT_VC840(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_TENMA_72_7745(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_TENMA_72_7750(int fd, int revents, void *cb_data);
+
+#endif
diff --git a/src/hardware/uni-t-ut32x/api.c b/src/hardware/uni-t-ut32x/api.c
new file mode 100644 (file)
index 0000000..81024dc
--- /dev/null
@@ -0,0 +1,385 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert@biot.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 "protocol.h"
+
+#include <string.h>
+
+static const int32_t hwcaps[] = {
+       SR_CONF_THERMOMETER,
+       SR_CONF_LIMIT_SAMPLES,
+       SR_CONF_CONTINUOUS,
+       SR_CONF_DATA_SOURCE,
+};
+
+static char *channels[] = {
+       "T1",
+       "T2",
+       "T1-T2",
+};
+
+static const char *data_sources[] = {
+       "Live",
+       "Memory",
+};
+
+SR_PRIV struct sr_dev_driver uni_t_ut32x_driver_info;
+static struct sr_dev_driver *di = &uni_t_ut32x_driver_info;
+
+
+static int init(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       struct sr_dev_inst *sdi;
+       struct sr_channel *ch;
+       struct sr_config *src;
+       GSList *usb_devices, *devices, *l;
+       int i;
+       const char *conn;
+
+       drvc = di->priv;
+       drvc->instances = NULL;
+
+       conn = NULL;
+       for (l = options; l; l = l->next) {
+               src = l->data;
+               switch (src->key) {
+               case SR_CONF_CONN:
+                       conn = g_variant_get_string(src->data, NULL);
+                       break;
+               }
+       }
+       if (!conn)
+               return NULL;
+
+       devices = NULL;
+       if ((usb_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn))) {
+               /* We have a list of sr_usb_dev_inst matching the connection
+                * string. Wrap them in sr_dev_inst and we're done. */
+               for (l = usb_devices; l; l = l->next) {
+                       if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, VENDOR,
+                                       MODEL, NULL)))
+                               return NULL;
+                       sdi->driver = di;
+                       sdi->inst_type = SR_INST_USB;
+                       sdi->conn = l->data;
+                       for (i = 0; i < 3; i++) {
+                               if (!(ch = sr_channel_new(i, SR_CHANNEL_ANALOG, TRUE,
+                                               channels[i]))) {
+                                       sr_dbg("Channel malloc failed.");
+                                       return NULL;
+                               }
+                               sdi->channels = g_slist_append(sdi->channels, ch);
+                       }
+
+                       if (!(devc = g_try_malloc(sizeof(struct dev_context)))) {
+                               sr_dbg("Device context malloc failed.");
+                               return NULL;
+                       }
+                       sdi->priv = devc;
+                       devc->limit_samples = 0;
+                       devc->data_source = DEFAULT_DATA_SOURCE;
+                       drvc->instances = g_slist_append(drvc->instances, sdi);
+                       devices = g_slist_append(devices, sdi);
+               }
+               g_slist_free(usb_devices);
+       } else
+               g_slist_free_full(usb_devices, g_free);
+
+       return devices;
+}
+
+static GSList *dev_list(void)
+{
+       return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+       struct drv_context *drvc;
+       struct sr_usb_dev_inst *usb;
+       int ret;
+
+       if (!(drvc = di->priv)) {
+               sr_err("Driver was not initialized.");
+               return SR_ERR;
+       }
+
+       usb = sdi->conn;
+
+       if (sr_usb_open(drvc->sr_ctx->libusb_ctx, usb) != SR_OK)
+               return SR_ERR;
+
+/*
+ * The libusbx 1.0.9 darwin backend is broken: it can report a kernel
+ * driver being active, but detaching it always returns an error.
+ */
+#if !defined(__APPLE__)
+       if (libusb_kernel_driver_active(usb->devhdl, USB_INTERFACE) == 1) {
+               if ((ret = libusb_detach_kernel_driver(usb->devhdl, USB_INTERFACE)) < 0) {
+                       sr_err("failed to detach kernel driver: %s",
+                                       libusb_error_name(ret));
+                       return SR_ERR;
+               }
+       }
+#endif
+
+       if ((ret = libusb_set_configuration(usb->devhdl, USB_CONFIGURATION))) {
+               sr_err("Failed to set configuration: %s.", libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+       if ((ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE))) {
+               sr_err("Failed to claim interface: %s.", libusb_error_name(ret));
+               return SR_ERR;
+       }
+       sdi->status = SR_ST_ACTIVE;
+
+       return ret;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+       struct sr_usb_dev_inst *usb;
+
+       if (!di->priv) {
+               sr_err("Driver was not initialized.");
+               return SR_ERR;
+       }
+
+       usb = sdi->conn;
+       if (!usb->devhdl)
+               /*  Nothing to do. */
+               return SR_OK;
+
+       libusb_release_interface(usb->devhdl, USB_INTERFACE);
+       libusb_close(usb->devhdl);
+       usb->devhdl = NULL;
+       sdi->status = SR_ST_INACTIVE;
+
+       return SR_OK;
+}
+
+static int cleanup(void)
+{
+       int ret;
+       struct drv_context *drvc;
+
+       if (!(drvc = di->priv))
+               /* Can get called on an unused driver, doesn't matter. */
+               return SR_OK;
+
+
+       ret = std_dev_clear(di, NULL);
+       g_free(drvc);
+       di->priv = NULL;
+
+       return ret;
+}
+
+static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+
+       (void)cg;
+
+       devc = sdi->priv;
+       switch (key) {
+       case SR_CONF_LIMIT_SAMPLES:
+               *data = g_variant_new_uint64(devc->limit_samples);
+               break;
+       case SR_CONF_DATA_SOURCE:
+               if (devc->data_source == DATA_SOURCE_LIVE)
+                       *data = g_variant_new_string("Live");
+               else
+                       *data = g_variant_new_string("Memory");
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       int ret;
+       const char *tmp_str;
+
+       (void)cg;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       if (!di->priv) {
+               sr_err("Driver was not initialized.");
+               return SR_ERR;
+       }
+
+       devc = sdi->priv;
+       ret = SR_OK;
+       switch (key) {
+       case SR_CONF_LIMIT_SAMPLES:
+               devc->limit_samples = g_variant_get_uint64(data);
+               sr_dbg("Setting sample limit to %" PRIu64 ".",
+                      devc->limit_samples);
+               break;
+       case SR_CONF_DATA_SOURCE:
+               tmp_str = g_variant_get_string(data, NULL);
+               if (!strcmp(tmp_str, "Live"))
+                       devc->data_source = DATA_SOURCE_LIVE;
+               else if (!strcmp(tmp_str, "Memory"))
+                       devc->data_source = DATA_SOURCE_MEMORY;
+               else
+                       return SR_ERR;
+               break;
+       default:
+               ret = SR_ERR_NA;
+       }
+
+       return ret;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+
+       (void)sdi;
+       (void)cg;
+
+       switch (key) {
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+               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;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi,
+                                   void *cb_data)
+{
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       struct sr_usb_dev_inst *usb;
+       int len, ret;
+       unsigned char cmd[2];
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       drvc = di->priv;
+       devc = sdi->priv;
+       usb = sdi->conn;
+
+       devc->cb_data = cb_data;
+       devc->num_samples = 0;
+       devc->packet_len = 0;
+
+       /* Configure serial port parameters on USB-UART interface
+        * chip inside the device (just baudrate 2400 actually). */
+       cmd[0] = 0x09;
+       cmd[1] = 0x60;
+       ret = libusb_control_transfer(usb->devhdl, 0x21, 0x09, 0x0300, 0x00,
+                       cmd, 2, 5);
+       if (ret != 2) {
+               sr_dbg("Failed to configure CH9325: %s", libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(cb_data, LOG_PREFIX);
+
+       if (!(devc->xfer = libusb_alloc_transfer(0)))
+               return SR_ERR;
+
+       /* Length of payload to follow. */
+       cmd[0] = 0x01;
+       if (devc->data_source == DATA_SOURCE_LIVE)
+               cmd[1] = CMD_GET_LIVE;
+       else
+               cmd[1] = CMD_GET_STORED;
+
+       ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, cmd, 2, &len, 5);
+       if (ret != 0 || len != 2) {
+               sr_dbg("Failed to start acquisition: %s", libusb_error_name(ret));
+               libusb_free_transfer(devc->xfer);
+               return SR_ERR;
+       }
+
+       libusb_fill_bulk_transfer(devc->xfer, usb->devhdl, EP_IN, devc->buf,
+                       8, uni_t_ut32x_receive_transfer, (void *)sdi, 15);
+       if (libusb_submit_transfer(devc->xfer) != 0) {
+               libusb_free_transfer(devc->xfer);
+               return SR_ERR;
+       }
+
+       usb_source_add(sdi->session, drvc->sr_ctx, 10,
+                       uni_t_ut32x_handle_events, (void *)sdi);
+
+       return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+
+       (void)cb_data;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       /* Signal USB transfer handler to clean up and stop. */
+       sdi->status = SR_ST_STOPPING;
+
+       return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver uni_t_ut32x_driver_info = {
+       .name = "uni-t-ut32x",
+       .longname = "UNI-T UT32x",
+       .api_version = 1,
+       .init = init,
+       .cleanup = cleanup,
+       .scan = scan,
+       .dev_list = 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,
+       .priv = NULL,
+};
diff --git a/src/hardware/uni-t-ut32x/protocol.c b/src/hardware/uni-t-ut32x/protocol.c
new file mode 100644 (file)
index 0000000..65cb756
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert@biot.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 "protocol.h"
+
+#include <string.h>
+#include <math.h>
+
+extern struct sr_dev_driver uni_t_ut32x_driver_info;
+static struct sr_dev_driver *di = &uni_t_ut32x_driver_info;
+
+static float parse_temperature(unsigned char *buf)
+{
+       float temp;
+       int i;
+       gboolean negative;
+
+       negative = FALSE;
+       temp = 0.0;
+       for (i = 0; i < 4; i++) {
+               if (buf[i] == 0x3a)
+                       continue;
+               if (buf[i] == 0x3b) {
+                       if (negative) {
+                               sr_dbg("Double negative sign!");
+                               return NAN;
+                       } else {
+                               negative = TRUE;
+                               continue;
+                       }
+               }
+               if (buf[i] < 0x30 || buf[i] > 0x39) {
+                       sr_dbg("Invalid digit '%.2x'!", buf[i]);
+                       return NAN;
+               }
+               temp *= 10;
+               temp += (buf[i] - 0x30);
+       }
+       temp /= 10;
+       if (negative)
+               temp = -temp;
+
+       return temp;
+}
+
+static void process_packet(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_analog analog;
+       GString *spew;
+       float temp;
+       int i;
+       gboolean is_valid;
+
+       devc = sdi->priv;
+       sr_dbg("Received full 19-byte packet.");
+       if (sr_log_loglevel_get() >= SR_LOG_SPEW) {
+               spew = g_string_sized_new(60);
+               for (i = 0; i < devc->packet_len; i++)
+                       g_string_append_printf(spew, "%.2x ", devc->packet[i]);
+               sr_spew("%s", spew->str);
+               g_string_free(spew, TRUE);
+       }
+
+       is_valid = TRUE;
+       if (devc->packet[1] == 0x3b && devc->packet[2] == 0x3b
+                       && devc->packet[3] == 0x3b && devc->packet[4] == 0x3b)
+               /* No measurement: missing channel, empty storage location, ... */
+               is_valid = FALSE;
+
+       temp = parse_temperature(devc->packet + 1);
+       if (isnan(temp))
+               is_valid = FALSE;
+
+       if (is_valid) {
+               memset(&analog, 0, sizeof(struct sr_datafeed_analog));
+               analog.mq = SR_MQ_TEMPERATURE;
+               analog.mqflags = 0;
+               switch (devc->packet[5] - 0x30) {
+               case 1:
+                       analog.unit = SR_UNIT_CELSIUS;
+                       break;
+               case 2:
+                       analog.unit = SR_UNIT_FAHRENHEIT;
+                       break;
+               case 3:
+                       analog.unit = SR_UNIT_KELVIN;
+                       break;
+               default:
+                       /* We can still pass on the measurement, whatever it is. */
+                       sr_dbg("Unknown unit 0x%.2x.", devc->packet[5]);
+               }
+               switch (devc->packet[13] - 0x30) {
+               case 0:
+                       /* Channel T1. */
+                       analog.channels = g_slist_append(NULL, g_slist_nth_data(sdi->channels, 0));
+                       break;
+               case 1:
+                       /* Channel T2. */
+                       analog.channels = g_slist_append(NULL, g_slist_nth_data(sdi->channels, 1));
+                       break;
+               case 2:
+               case 3:
+                       /* Channel T1-T2. */
+                       analog.channels = g_slist_append(NULL, g_slist_nth_data(sdi->channels, 2));
+                       analog.mqflags |= SR_MQFLAG_RELATIVE;
+                       break;
+               default:
+                       sr_err("Unknown channel 0x%.2x.", devc->packet[13]);
+                       is_valid = FALSE;
+               }
+               if (is_valid) {
+                       analog.num_samples = 1;
+                       analog.data = &temp;
+                       packet.type = SR_DF_ANALOG;
+                       packet.payload = &analog;
+                       sr_session_send(devc->cb_data, &packet);
+                       g_slist_free(analog.channels);
+               }
+       }
+
+       /* We count packets even if the temperature was invalid. This way
+        * a sample limit on "Memory" data source still works: unused
+        * memory slots come through as "----" measurements. */
+       devc->num_samples++;
+       if (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
+               sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi,
+                               devc->cb_data);
+       }
+
+}
+
+SR_PRIV void uni_t_ut32x_receive_transfer(struct libusb_transfer *transfer)
+{
+       struct dev_context *devc;
+       struct sr_dev_inst *sdi;
+       int hid_payload_len, ret;
+
+       sdi = transfer->user_data;
+       devc = sdi->priv;
+       if (transfer->actual_length == 8) {
+               /* CH9325 encodes length in low nibble of first byte, with
+                * bytes 1-7 being the (padded) payload. */
+               hid_payload_len = transfer->buffer[0] & 0x0f;
+               memcpy(devc->packet + devc->packet_len, transfer->buffer + 1,
+                               hid_payload_len);
+               devc->packet_len += hid_payload_len;
+               if (devc->packet_len >= 2
+                               && devc->packet[devc->packet_len - 2] == 0x0d
+                               && devc->packet[devc->packet_len - 1] == 0x0a) {
+                       /* Got end of packet, but do we have a complete packet? */
+                       if (devc->packet_len == 19)
+                               process_packet(sdi);
+                       /* Either way, done with it. */
+                       devc->packet_len = 0;
+               } else if (devc->packet_len > 19) {
+                       /* Guard against garbage from the device overrunning
+                        * our packet buffer. */
+                       sr_dbg("Buffer overrun!");
+                       devc->packet_len = 0;
+               }
+       }
+
+       /* Get the next transfer (unless we're shutting down). */
+       if (sdi->status != SR_ST_STOPPING) {
+               if ((ret = libusb_submit_transfer(devc->xfer)) != 0) {
+                       sr_dbg("Failed to resubmit transfer: %s", libusb_error_name(ret));
+                       sdi->status = SR_ST_STOPPING;
+                       libusb_free_transfer(devc->xfer);
+               }
+       } else
+               libusb_free_transfer(devc->xfer);
+
+}
+
+SR_PRIV int uni_t_ut32x_handle_events(int fd, int revents, void *cb_data)
+{
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       struct sr_dev_inst *sdi;
+       struct sr_datafeed_packet packet;
+       struct sr_usb_dev_inst *usb;
+       struct timeval tv;
+       int len, ret;
+       unsigned char cmd[2];
+
+       (void)fd;
+       (void)revents;
+
+       drvc = di->priv;
+
+       if (!(sdi = cb_data))
+               return TRUE;
+
+       if (!(devc = sdi->priv))
+               return TRUE;
+
+       memset(&tv, 0, sizeof(struct timeval));
+       libusb_handle_events_timeout_completed(drvc->sr_ctx->libusb_ctx, &tv,
+                       NULL);
+
+       if (sdi->status == SR_ST_STOPPING) {
+               usb_source_remove(sdi->session, drvc->sr_ctx);
+               packet.type = SR_DF_END;
+               sr_session_send(cb_data, &packet);
+
+               /* Tell the device to stop sending USB packets. */
+               usb = sdi->conn;
+               cmd[0] = 0x01;
+               cmd[1] = CMD_STOP;
+               ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, cmd, 2, &len, 5);
+               if (ret != 0 || len != 2) {
+                       /* Warning only, doesn't matter. */
+                       sr_dbg("Failed to send stop command: %s", libusb_error_name(ret));
+               }
+
+               sdi->status = SR_ST_ACTIVE;
+               return TRUE;
+       }
+
+       return TRUE;
+}
+
diff --git a/src/hardware/uni-t-ut32x/protocol.h b/src/hardware/uni-t-ut32x/protocol.h
new file mode 100644 (file)
index 0000000..8513117
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert@biot.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_UNI_T_UT32X_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_UNI_T_UT32X_PROTOCOL_H
+
+#include <stdint.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "uni-t-ut32x"
+
+#define DEFAULT_DATA_SOURCE DATA_SOURCE_LIVE
+#define USB_CONN "1a86.e008"
+#define VENDOR "UNI-T"
+#define MODEL "UT32x"
+#define USB_INTERFACE 0
+#define USB_CONFIGURATION 1
+
+#define EP_IN 0x80 | 2
+#define EP_OUT 2
+
+enum {
+    DATA_SOURCE_LIVE,
+       DATA_SOURCE_MEMORY,
+};
+
+enum {
+       CMD_GET_LIVE = 1,
+       CMD_STOP = 2,
+       CMD_GET_STORED = 7,
+};
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+       /* Acquisition settings */
+       uint64_t limit_samples;
+       gboolean data_source;
+
+       /* Operational state */
+       uint64_t num_samples;
+       unsigned char buf[8];
+       struct libusb_transfer *xfer;
+       void *cb_data;
+
+       /* Temporary state across callbacks */
+       unsigned char packet[32];
+       int packet_len;
+};
+
+SR_PRIV int uni_t_ut32x_handle_events(int fd, int revents, void *cb_data);
+SR_PRIV void uni_t_ut32x_receive_transfer(struct libusb_transfer *transfer);
+
+#endif
diff --git a/src/hardware/victor-dmm/api.c b/src/hardware/victor-dmm/api.c
new file mode 100644 (file)
index 0000000..56c53e5
--- /dev/null
@@ -0,0 +1,448 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert@biot.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 <glib.h>
+#include <libusb.h>
+#include <stdlib.h>
+#include <string.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "protocol.h"
+
+#define VICTOR_VID 0x1244
+#define VICTOR_PID 0xd237
+#define VICTOR_VENDOR "Victor"
+#define VICTOR_INTERFACE 0
+#define VICTOR_ENDPOINT LIBUSB_ENDPOINT_IN | 1
+
+SR_PRIV struct sr_dev_driver victor_dmm_driver_info;
+static struct sr_dev_driver *di = &victor_dmm_driver_info;
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data);
+
+static const int32_t hwopts[] = {
+       SR_CONF_CONN,
+};
+
+static const int32_t hwcaps[] = {
+       SR_CONF_MULTIMETER,
+       SR_CONF_LIMIT_MSEC,
+       SR_CONF_LIMIT_SAMPLES,
+       SR_CONF_CONTINUOUS,
+};
+
+static int init(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       struct sr_dev_inst *sdi;
+       struct sr_channel *ch;
+       struct libusb_device_descriptor des;
+       libusb_device **devlist;
+       GSList *devices;
+       int ret, devcnt, i;
+
+       (void)options;
+
+       drvc = di->priv;
+
+       devices = NULL;
+       libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
+       for (i = 0; devlist[i]; i++) {
+               if ((ret = libusb_get_device_descriptor(devlist[i], &des)) != 0) {
+                       sr_warn("Failed to get device descriptor: %s",
+                                       libusb_error_name(ret));
+                       continue;
+               }
+
+               if (des.idVendor != VICTOR_VID || des.idProduct != VICTOR_PID)
+                       continue;
+
+               devcnt = g_slist_length(drvc->instances);
+               if (!(sdi = sr_dev_inst_new(devcnt, SR_ST_INACTIVE,
+                               VICTOR_VENDOR, NULL, NULL)))
+                       return NULL;
+               sdi->driver = di;
+
+               if (!(devc = g_try_malloc0(sizeof(struct dev_context))))
+                       return NULL;
+               sdi->priv = devc;
+
+               if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1")))
+                       return NULL;
+               sdi->channels = g_slist_append(NULL, ch);
+
+               if (!(sdi->conn = sr_usb_dev_inst_new(libusb_get_bus_number(devlist[i]),
+                               libusb_get_device_address(devlist[i]), NULL)))
+                       return NULL;
+               sdi->inst_type = SR_INST_USB;
+
+               drvc->instances = g_slist_append(drvc->instances, sdi);
+               devices = g_slist_append(devices, sdi);
+       }
+       libusb_free_device_list(devlist, 1);
+
+       return devices;
+}
+
+static GSList *dev_list(void)
+{
+       return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+       struct drv_context *drvc = di->priv;
+       struct sr_usb_dev_inst *usb;
+       libusb_device **devlist;
+       int ret, i;
+
+       if (!di->priv) {
+               sr_err("Driver was not initialized.");
+               return SR_ERR;
+       }
+
+       usb = sdi->conn;
+
+       libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
+       for (i = 0; devlist[i]; i++) {
+               if (libusb_get_bus_number(devlist[i]) != usb->bus
+                               || libusb_get_device_address(devlist[i]) != usb->address)
+                       continue;
+               if ((ret = libusb_open(devlist[i], &usb->devhdl))) {
+                       sr_err("Failed to open device: %s.", libusb_error_name(ret));
+                       return SR_ERR;
+               }
+               break;
+       }
+       libusb_free_device_list(devlist, 1);
+       if (!devlist[i]) {
+               sr_err("Device not found.");
+               return SR_ERR;
+       }
+
+       /* The device reports as HID class, so the kernel would have
+        * claimed it. */
+       if (libusb_kernel_driver_active(usb->devhdl, 0) == 1) {
+               if ((ret = libusb_detach_kernel_driver(usb->devhdl, 0)) < 0) {
+                       sr_err("Failed to detach kernel driver: %s.",
+                              libusb_error_name(ret));
+                       return SR_ERR;
+               }
+       }
+
+       if ((ret = libusb_claim_interface(usb->devhdl,
+                       VICTOR_INTERFACE))) {
+               sr_err("Failed to claim interface: %s.", libusb_error_name(ret));
+               return SR_ERR;
+       }
+       sdi->status = SR_ST_ACTIVE;
+
+       return SR_OK;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+       struct sr_usb_dev_inst *usb;
+
+       if (!di->priv) {
+               sr_err("Driver was not initialized.");
+               return SR_ERR;
+       }
+
+       usb = sdi->conn;
+
+       if (!usb->devhdl)
+               /*  Nothing to do. */
+               return SR_OK;
+
+       libusb_release_interface(usb->devhdl, VICTOR_INTERFACE);
+       libusb_close(usb->devhdl);
+       usb->devhdl = NULL;
+       sdi->status = SR_ST_INACTIVE;
+
+       return SR_OK;
+}
+
+static int cleanup(void)
+{
+       int ret;
+       struct drv_context *drvc;
+
+       if (!(drvc = di->priv))
+               /* Can get called on an unused driver, doesn't matter. */
+               return SR_OK;
+
+
+       ret = std_dev_clear(di, NULL);
+       g_free(drvc);
+       di->priv = NULL;
+
+       return ret;
+}
+
+static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct sr_usb_dev_inst *usb;
+       char str[128];
+
+       (void)cg;
+
+       switch (id) {
+       case SR_CONF_CONN:
+               if (!sdi || !sdi->conn)
+                       return SR_ERR_ARG;
+               usb = sdi->conn;
+               snprintf(str, 128, "%d.%d", usb->bus, usb->address);
+               *data = g_variant_new_string(str);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       gint64 now;
+       int ret;
+
+       (void)cg;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       if (!di->priv) {
+               sr_err("Driver was not initialized.");
+               return SR_ERR;
+       }
+
+       devc = sdi->priv;
+       ret = SR_OK;
+       switch (id) {
+       case SR_CONF_LIMIT_MSEC:
+               devc->limit_msec = g_variant_get_uint64(data);
+               now = g_get_monotonic_time() / 1000;
+               devc->end_time = now + devc->limit_msec;
+               sr_dbg("Setting time limit to %" PRIu64 "ms.",
+                      devc->limit_msec);
+               break;
+       case SR_CONF_LIMIT_SAMPLES:
+               devc->limit_samples = g_variant_get_uint64(data);
+               sr_dbg("Setting sample limit to %" PRIu64 ".",
+                      devc->limit_samples);
+               break;
+       default:
+               ret = SR_ERR_NA;
+       }
+
+       return ret;
+}
+
+static int config_list(int 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_INT32,
+                               hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+               break;
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static void receive_transfer(struct libusb_transfer *transfer)
+{
+       struct dev_context *devc;
+       struct sr_dev_inst *sdi;
+       int ret;
+
+       sdi = transfer->user_data;
+       devc = sdi->priv;
+       if (transfer->status == LIBUSB_TRANSFER_NO_DEVICE) {
+               /* USB device was unplugged. */
+               dev_acquisition_stop(sdi, sdi);
+       } else if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
+               sr_dbg("Got %d-byte packet.", transfer->actual_length);
+               if (transfer->actual_length == DMM_DATA_SIZE) {
+                       victor_dmm_receive_data(sdi, transfer->buffer);
+                       if (devc->limit_samples) {
+                               if (devc->num_samples >= devc->limit_samples)
+                                       dev_acquisition_stop(sdi, sdi);
+                       }
+               }
+       }
+       /* Anything else is either an error or a timeout, which is fine:
+        * we were just going to send another transfer request anyway. */
+
+       if (sdi->status == SR_ST_ACTIVE) {
+               /* Send the same request again. */
+               if ((ret = libusb_submit_transfer(transfer) != 0)) {
+                       sr_err("Unable to resubmit transfer: %s.",
+                              libusb_error_name(ret));
+                       g_free(transfer->buffer);
+                       libusb_free_transfer(transfer);
+                       dev_acquisition_stop(sdi, sdi);
+               }
+       } else {
+               /* This was the last transfer we're going to receive, so
+                * clean up now. */
+               g_free(transfer->buffer);
+               libusb_free_transfer(transfer);
+       }
+}
+
+static int handle_events(int fd, int revents, void *cb_data)
+{
+       struct dev_context *devc;
+       struct drv_context *drvc = di->priv;
+       struct sr_datafeed_packet packet;
+       struct sr_dev_inst *sdi;
+       struct timeval tv;
+       gint64 now;
+
+       (void)fd;
+       (void)revents;
+
+       sdi = cb_data;
+       devc = sdi->priv;
+
+       if (devc->limit_msec) {
+               now = g_get_monotonic_time() / 1000;
+               if (now > devc->end_time)
+                       dev_acquisition_stop(sdi, sdi);
+       }
+
+       if (sdi->status == SR_ST_STOPPING) {
+               usb_source_remove(sdi->session, drvc->sr_ctx);
+
+               dev_close(sdi);
+
+               packet.type = SR_DF_END;
+               sr_session_send(cb_data, &packet);
+       }
+
+       memset(&tv, 0, sizeof(struct timeval));
+       libusb_handle_events_timeout_completed(drvc->sr_ctx->libusb_ctx, &tv,
+                                              NULL);
+
+       return TRUE;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct dev_context *devc;
+       struct drv_context *drvc = di->priv;
+       struct sr_usb_dev_inst *usb;
+       struct libusb_transfer *transfer;
+       int ret;
+       unsigned char *buf;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       if (!di->priv) {
+               sr_err("Driver was not initialized.");
+               return SR_ERR;
+       }
+
+       devc = sdi->priv;
+       usb = sdi->conn;
+       devc->cb_data = cb_data;
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(cb_data, LOG_PREFIX);
+
+       usb_source_add(sdi->session, drvc->sr_ctx, 100,
+                       handle_events, (void *)sdi);
+
+       buf = g_try_malloc(DMM_DATA_SIZE);
+       transfer = libusb_alloc_transfer(0);
+       /* Each transfer request gets 100ms to arrive before it's restarted.
+        * The device only sends 1 transfer/second no matter how many
+        * times you ask, but we want to keep step with the USB events
+        * handling above. */
+       libusb_fill_interrupt_transfer(transfer, usb->devhdl,
+                       VICTOR_ENDPOINT, buf, DMM_DATA_SIZE, receive_transfer,
+                       cb_data, 100);
+       if ((ret = libusb_submit_transfer(transfer) != 0)) {
+               sr_err("Unable to submit transfer: %s.", libusb_error_name(ret));
+               libusb_free_transfer(transfer);
+               g_free(buf);
+               return SR_ERR;
+       }
+
+       return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       (void)cb_data;
+
+       if (!di->priv) {
+               sr_err("Driver was not initialized.");
+               return SR_ERR;
+       }
+
+       if (sdi->status != SR_ST_ACTIVE) {
+               sr_err("Device not active, can't stop acquisition.");
+               return SR_ERR;
+       }
+
+       sdi->status = SR_ST_STOPPING;
+
+       return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver victor_dmm_driver_info = {
+       .name = "victor-dmm",
+       .longname = "Victor DMMs",
+       .api_version = 1,
+       .init = init,
+       .cleanup = cleanup,
+       .scan = scan,
+       .dev_list = 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,
+       .priv = NULL,
+};
diff --git a/src/hardware/victor-dmm/protocol.c b/src/hardware/victor-dmm/protocol.c
new file mode 100644 (file)
index 0000000..6af5141
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert@biot.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 <glib.h>
+#include <string.h>
+#include <math.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "protocol.h"
+
+/* Reverse the high nibble into the low nibble */
+static uint8_t decode_digit(uint8_t in)
+{
+       uint8_t out, i;
+
+       out = 0;
+       in >>= 4;
+       for (i = 0x08; i; i >>= 1) {
+               out >>= 1;
+               if (in & i)
+                       out |= 0x08;
+       }
+
+       return out;
+}
+
+static void decode_buf(struct sr_dev_inst *sdi, unsigned char *data)
+{
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_analog analog;
+       struct dev_context *devc;
+       long factor, ivalue;
+       uint8_t digits[4];
+       gboolean is_duty, is_continuity, is_diode, is_ac, is_dc, is_auto;
+       gboolean is_hold, is_max, is_min, is_relative, minus;
+       float fvalue;
+
+       devc = sdi->priv;
+
+       digits[0] = decode_digit(data[12]);
+       digits[1] = decode_digit(data[11]);
+       digits[2] = decode_digit(data[10]);
+       digits[3] = decode_digit(data[9]);
+
+       if (digits[0] == 0x0f && digits[1] == 0x00 && digits[2] == 0x0a &&
+                       digits[3] == 0x0f)
+               /* The "over limit" (OL) display comes through like this */
+               ivalue = -1;
+       else if (digits[0] > 9 || digits[1] > 9 || digits[2] > 9 || digits[3] > 9)
+               /* An invalid digit in any position denotes no value. */
+               ivalue = -2;
+       else {
+               ivalue = digits[0] * 1000;
+               ivalue += digits[1] * 100;
+               ivalue += digits[2] * 10;
+               ivalue += digits[3];
+       }
+
+       /* Decimal point position */
+       factor = 0;
+       switch (data[7] >> 4) {
+       case 0x00:
+               factor = 0;
+               break;
+       case 0x02:
+               factor = 1;
+               break;
+       case 0x04:
+               factor = 2;
+               break;
+       case 0x08:
+               factor = 3;
+               break;
+       default:
+               sr_err("Unknown decimal point byte: 0x%.2x.", data[7]);
+               break;
+       }
+
+       /* Minus flag */
+       minus = data[2] & 0x01;
+
+       /* Mode detail symbols on the right side of the digits */
+       is_duty = is_continuity = is_diode = FALSE;
+       switch (data[4]) {
+       case 0x00:
+               /* None. */
+               break;
+       case 0x01:
+               /* Micro */
+               factor += 6;
+               break;
+       case 0x02:
+               /* Milli */
+               factor += 3;
+               break;
+       case 0x04:
+               /* Kilo */
+               ivalue *= 1000;
+               break;
+       case 0x08:
+               /* Mega */
+               ivalue *= 1000000;
+               break;
+       case 0x10:
+               /* Continuity shows up as Ohm + this bit */
+               is_continuity = TRUE;
+               break;
+       case 0x20:
+               /* Diode tester is Volt + this bit */
+               is_diode = TRUE;
+               break;
+       case 0x40:
+               is_duty = TRUE;
+               break;
+       case 0x80:
+               /* Never seen */
+               sr_dbg("Unknown mode right detail: 0x%.2x.", data[4]);
+               break;
+       default:
+               sr_dbg("Unknown/invalid mode right detail: 0x%.2x.", data[4]);
+               break;
+       }
+
+       /* Scale flags on the right, continued */
+       is_max = is_min = FALSE;
+       if (data[5] & 0x04)
+               is_max = TRUE;
+       if (data[5] & 0x08)
+               is_min = TRUE;
+       if (data[5] & 0x40)
+               /* Nano */
+               factor += 9;
+
+       /* Mode detail symbols on the left side of the digits */
+       is_auto = is_dc = is_ac = is_hold = is_relative = FALSE;
+       if (data[6] & 0x04)
+               is_auto = TRUE;
+       if (data[6] & 0x08)
+               is_dc = TRUE;
+       if (data[6] & 0x10)
+               is_ac = TRUE;
+       if (data[6] & 0x20)
+               is_relative = TRUE;
+       if (data[6] & 0x40)
+               is_hold = TRUE;
+
+       fvalue = (float)ivalue / pow(10, factor);
+       if (minus)
+               fvalue = -fvalue;
+
+       memset(&analog, 0, sizeof(struct sr_datafeed_analog));
+
+       /* Measurement mode */
+       analog.mq = -1;
+       switch (data[3]) {
+       case 0x00:
+               if (is_duty) {
+                       analog.mq = SR_MQ_DUTY_CYCLE;
+                       analog.unit = SR_UNIT_PERCENTAGE;
+               } else
+                       sr_dbg("Unknown measurement mode: %.2x.", data[3]);
+               break;
+       case 0x01:
+               if (is_diode) {
+                       analog.mq = SR_MQ_VOLTAGE;
+                       analog.unit = SR_UNIT_VOLT;
+                       analog.mqflags |= SR_MQFLAG_DIODE;
+                       if (ivalue < 0)
+                               fvalue = NAN;
+               } else {
+                       if (ivalue < 0)
+                               break;
+                       analog.mq = SR_MQ_VOLTAGE;
+                       analog.unit = SR_UNIT_VOLT;
+                       if (is_ac)
+                               analog.mqflags |= SR_MQFLAG_AC;
+                       if (is_dc)
+                               analog.mqflags |= SR_MQFLAG_DC;
+               }
+               break;
+       case 0x02:
+               analog.mq = SR_MQ_CURRENT;
+               analog.unit = SR_UNIT_AMPERE;
+               if (is_ac)
+                       analog.mqflags |= SR_MQFLAG_AC;
+               if (is_dc)
+                       analog.mqflags |= SR_MQFLAG_DC;
+               break;
+       case 0x04:
+               if (is_continuity) {
+                       analog.mq = SR_MQ_CONTINUITY;
+                       analog.unit = SR_UNIT_BOOLEAN;
+                       fvalue = ivalue < 0 ? 0.0 : 1.0;
+               } else {
+                       analog.mq = SR_MQ_RESISTANCE;
+                       analog.unit = SR_UNIT_OHM;
+                       if (ivalue < 0)
+                               fvalue = INFINITY;
+               }
+               break;
+       case 0x08:
+               /* Never seen */
+               sr_dbg("Unknown measurement mode: 0x%.2x.", data[3]);
+               break;
+       case 0x10:
+               analog.mq = SR_MQ_FREQUENCY;
+               analog.unit = SR_UNIT_HERTZ;
+               break;
+       case 0x20:
+               analog.mq = SR_MQ_CAPACITANCE;
+               analog.unit = SR_UNIT_FARAD;
+               break;
+       case 0x40:
+               analog.mq = SR_MQ_TEMPERATURE;
+               analog.unit = SR_UNIT_CELSIUS;
+               break;
+       case 0x80:
+               analog.mq = SR_MQ_TEMPERATURE;
+               analog.unit = SR_UNIT_FAHRENHEIT;
+               break;
+       default:
+               sr_dbg("Unknown/invalid measurement mode: 0x%.2x.", data[3]);
+               break;
+       }
+       if (analog.mq == -1)
+               return;
+
+       if (is_auto)
+               analog.mqflags |= SR_MQFLAG_AUTORANGE;
+       if (is_hold)
+               analog.mqflags |= SR_MQFLAG_HOLD;
+       if (is_max)
+               analog.mqflags |= SR_MQFLAG_MAX;
+       if (is_min)
+               analog.mqflags |= SR_MQFLAG_MIN;
+       if (is_relative)
+               analog.mqflags |= SR_MQFLAG_RELATIVE;
+
+       analog.channels = sdi->channels;
+       analog.num_samples = 1;
+       analog.data = &fvalue;
+       packet.type = SR_DF_ANALOG;
+       packet.payload = &analog;
+       sr_session_send(devc->cb_data, &packet);
+
+       devc->num_samples++;
+}
+
+SR_PRIV int victor_dmm_receive_data(struct sr_dev_inst *sdi, unsigned char *buf)
+{
+       GString *dbg;
+       int i;
+       unsigned char data[DMM_DATA_SIZE];
+       unsigned char obfuscation[DMM_DATA_SIZE] = "jodenxunickxia";
+       unsigned char shuffle[DMM_DATA_SIZE] = {
+               6, 13, 5, 11, 2, 7, 9, 8, 3, 10, 12, 0, 4, 1
+       };
+
+       for (i = 0; i < DMM_DATA_SIZE && buf[i] == 0; i++);
+       if (i == DMM_DATA_SIZE) {
+               /* This DMM outputs all zeroes from time to time, just ignore it. */
+               sr_dbg("Received all zeroes.");
+               return SR_OK;
+       }
+
+       /* Deobfuscate and reorder data. */
+       for (i = 0; i < DMM_DATA_SIZE; i++)
+               data[shuffle[i]] = (buf[i] - obfuscation[i]) & 0xff;
+
+       if (sr_log_loglevel_get() >= SR_LOG_SPEW) {
+               dbg = g_string_sized_new(128);
+               g_string_printf(dbg, "Deobfuscated.");
+               for (i = 0; i < DMM_DATA_SIZE; i++)
+                       g_string_append_printf(dbg, " %.2x", data[i]);
+               sr_spew("%s", dbg->str);
+               g_string_free(dbg, TRUE);
+       }
+
+       decode_buf(sdi, data);
+
+       return SR_OK;
+}
diff --git a/src/hardware/victor-dmm/protocol.h b/src/hardware/victor-dmm/protocol.h
new file mode 100644 (file)
index 0000000..8f12680
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert@biot.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_VICTOR_DMM_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_VICTOR_DMM_PROTOCOL_H
+
+#include <stdint.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "victor-dmm"
+
+#define DMM_DATA_SIZE 14
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+       /** The current sampling limit (in number of samples). */
+       uint64_t limit_samples;
+
+       /** The current sampling limit (in ms). */
+       uint64_t limit_msec;
+
+       /** Opaque pointer passed in by the frontend. */
+       void *cb_data;
+
+       /** The current number of already received samples. */
+       uint64_t num_samples;
+       gint64 end_time;
+};
+
+SR_PRIV int victor_dmm_receive_data(struct sr_dev_inst *sdi, unsigned char *buf);
+
+#endif
diff --git a/src/hardware/zeroplus-logic-cube/analyzer.c b/src/hardware/zeroplus-logic-cube/analyzer.c
new file mode 100644 (file)
index 0000000..c404a66
--- /dev/null
@@ -0,0 +1,677 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010 Sven Peter <sven@fail0verflow.com>
+ * Copyright (C) 2010 Haxx Enterprises <bushing@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ *  THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <assert.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "analyzer.h"
+#include "gl_usb.h"
+#include "protocol.h"
+
+enum {
+       HARD_DATA_CHECK_SUM             = 0x00,
+       PASS_WORD,
+
+       DEV_ID0                         = 0x10,
+       DEV_ID1,
+
+       START_STATUS                    = 0x20,
+       DEV_STATUS                      = 0x21,
+       FREQUENCY_REG0                  = 0x30,
+       FREQUENCY_REG1,
+       FREQUENCY_REG2,
+       FREQUENCY_REG3,
+       FREQUENCY_REG4,
+       MEMORY_LENGTH,
+       CLOCK_SOURCE,
+
+       TRIGGER_STATUS0                 = 0x40,
+       TRIGGER_STATUS1,
+       TRIGGER_STATUS2,
+       TRIGGER_STATUS3,
+       TRIGGER_STATUS4,
+       TRIGGER_STATUS5,
+       TRIGGER_STATUS6,
+       TRIGGER_STATUS7,
+       TRIGGER_STATUS8,
+
+       TRIGGER_COUNT0                  = 0x50,
+       TRIGGER_COUNT1,
+
+       TRIGGER_LEVEL0                  = 0x55,
+       TRIGGER_LEVEL1,
+       TRIGGER_LEVEL2,
+       TRIGGER_LEVEL3,
+
+       RAMSIZE_TRIGGERBAR_ADDRESS0     = 0x60,
+       RAMSIZE_TRIGGERBAR_ADDRESS1,
+       RAMSIZE_TRIGGERBAR_ADDRESS2,
+       TRIGGERBAR_ADDRESS0,
+       TRIGGERBAR_ADDRESS1,
+       TRIGGERBAR_ADDRESS2,
+       DONT_CARE_TRIGGERBAR,
+
+       FILTER_ENABLE                   = 0x70,
+       FILTER_STATUS,
+
+       ENABLE_DELAY_TIME0              = 0x7a,
+       ENABLE_DELAY_TIME1,
+
+       ENABLE_INSERT_DATA0             = 0x80,
+       ENABLE_INSERT_DATA1,
+       ENABLE_INSERT_DATA2,
+       ENABLE_INSERT_DATA3,
+       COMPRESSION_TYPE0,
+       COMPRESSION_TYPE1,
+
+       TRIGGER_ADDRESS0                = 0x90,
+       TRIGGER_ADDRESS1,
+       TRIGGER_ADDRESS2,
+
+       NOW_ADDRESS0                    = 0x96,
+       NOW_ADDRESS1,
+       NOW_ADDRESS2,
+
+       STOP_ADDRESS0                   = 0x9b,
+       STOP_ADDRESS1,
+       STOP_ADDRESS2,
+
+       READ_RAM_STATUS                 = 0xa0,
+};
+
+static int g_trigger_status[9] = { 0 };
+static int g_trigger_count = 1;
+static int g_filter_status[8] = { 0 };
+static int g_filter_enable = 0;
+
+static int g_freq_value = 1;
+static int g_freq_scale = FREQ_SCALE_MHZ;
+static int g_memory_size = MEMORY_SIZE_8K;
+static int g_ramsize_triggerbar_addr = 2 * 1024;
+static int g_triggerbar_addr = 0;
+static int g_compression = COMPRESSION_NONE;
+static int g_thresh = 0x31; /* 1.5V */
+
+/* Maybe unk specifies an "endpoint" or "register" of sorts. */
+static int analyzer_write_status(libusb_device_handle *devh, unsigned char unk,
+                                unsigned char flags)
+{
+       assert(unk <= 3);
+       return gl_reg_write(devh, START_STATUS, unk << 6 | flags);
+}
+
+#if 0
+static int __analyzer_set_freq(libusb_device_handle *devh, int freq, int scale)
+{
+       int reg0 = 0, divisor = 0, reg2 = 0;
+
+       switch (scale) {
+       case FREQ_SCALE_MHZ: /* MHz */
+               if (freq >= 100 && freq <= 200) {
+                       reg0 = freq * 0.1;
+                       divisor = 1;
+                       reg2 = 0;
+                       break;
+               }
+               if (freq >= 50 && freq < 100) {
+                       reg0 = freq * 0.2;
+                       divisor = 2;
+                       reg2 = 0;
+                       break;
+               }
+               if (freq >= 10 && freq < 50) {
+                       if (freq == 25) {
+                               reg0 = 25;
+                               divisor = 5;
+                               reg2 = 1;
+                               break;
+                       } else {
+                               reg0 = freq * 0.5;
+                               divisor = 5;
+                               reg2 = 1;
+                               break;
+                       }
+               }
+               if (freq >= 2 && freq < 10) {
+                       divisor = 5;
+                       reg0 = freq * 2;
+                       reg2 = 2;
+                       break;
+               }
+               if (freq == 1) {
+                       divisor = 5;
+                       reg2 = 16;
+                       reg0 = 5;
+                       break;
+               }
+               divisor = 5;
+               reg0 = 5;
+               reg2 = 64;
+               break;
+       case FREQ_SCALE_HZ: /* Hz */
+               if (freq >= 500 && freq < 1000) {
+                       reg0 = freq * 0.01;
+                       divisor = 10;
+                       reg2 = 64;
+                       break;
+               }
+               if (freq >= 300 && freq < 500) {
+                       reg0 = freq * 0.005 * 8;
+                       divisor = 5;
+                       reg2 = 67;
+                       break;
+               }
+               if (freq >= 100 && freq < 300) {
+                       reg0 = freq * 0.005 * 16;
+                       divisor = 5;
+                       reg2 = 68;
+                       break;
+               }
+               divisor = 5;
+               reg0 = 5;
+               reg2 = 64;
+               break;
+       case FREQ_SCALE_KHZ: /* kHz */
+               if (freq >= 500 && freq < 1000) {
+                       reg0 = freq * 0.01;
+                       divisor = 5;
+                       reg2 = 17;
+                       break;
+               }
+               if (freq >= 100 && freq < 500) {
+                       reg0 = freq * 0.05;
+                       divisor = 5;
+                       reg2 = 32;
+                       break;
+               }
+               if (freq >= 50 && freq < 100) {
+                       reg0 = freq * 0.1;
+                       divisor = 5;
+                       reg2 = 33;
+                       break;
+               }
+               if (freq >= 10 && freq < 50) {
+                       if (freq == 25) {
+                               reg0 = 25;
+                               divisor = 5;
+                               reg2 = 49;
+                               break;
+                       }
+                       reg0 = freq * 0.5;
+                       divisor = 5;
+                       reg2 = 48;
+                       break;
+               }
+               if (freq >= 2 && freq < 10) {
+                       divisor = 5;
+                       reg0 = freq * 2;
+                       reg2 = 50;
+                       break;
+               }
+               divisor = 5;
+               reg0 = 5;
+               reg2 = 64;
+               break;
+       default:
+               divisor = 5;
+               reg0 = 5;
+               reg2 = 64;
+               break;
+       }
+
+       sr_dbg("Setting samplerate regs (freq=%d, scale=%d): "
+              "reg0: %d, reg1: %d, reg2: %d, reg3: %d.",
+              freq, scale, divisor, reg0, 0x02, reg2);
+
+       if (gl_reg_write(devh, FREQUENCY_REG0, divisor) < 0)
+               return -1; /* Divisor maybe? */
+
+       if (gl_reg_write(devh, FREQUENCY_REG1, reg0) < 0)
+               return -1; /* 10 / 0.2 */
+
+       if (gl_reg_write(devh, FREQUENCY_REG2, 0x02) < 0)
+               return -1; /* Always 2 */
+
+       if (gl_reg_write(devh, FREQUENCY_REG4, reg2) < 0)
+               return -1;
+
+       return 0;
+}
+#endif
+
+/*
+ * It seems that ...
+ *     FREQUENCT_REG0 - division factor (?)
+ *     FREQUENCT_REG1 - multiplication factor (?)
+ *     FREQUENCT_REG4 - clock selection (?)
+ *
+ *     clock selection
+ *     0  10MHz  16   1MHz  32 100kHz  48  10kHz  64   1kHz
+ *     1   5MHz  17 500kHz  33  50kHz  49   5kHz  65  500Hz
+ *     2 2.5MHz   .          .         50 2.5kHz  66  250Hz
+ *     .          .          .          .         67  125Hz
+ *     .          .          .          .         68 62.5Hz
+ */
+static int __analyzer_set_freq(libusb_device_handle *devh, int freq, int scale)
+{
+       struct freq_factor {
+               int freq;
+               int scale;
+               int sel;
+               int div;
+               int mul;
+       };
+
+       static const struct freq_factor f[] = {
+               { 200, FREQ_SCALE_MHZ,  0,  1, 20 },
+               { 150, FREQ_SCALE_MHZ,  0,  1, 15 },
+               { 100, FREQ_SCALE_MHZ,  0,  1, 10 },
+               {  80, FREQ_SCALE_MHZ,  0,  2, 16 },
+               {  50, FREQ_SCALE_MHZ,  0,  2, 10 },
+               {  25, FREQ_SCALE_MHZ,  1,  5, 25 },
+               {  10, FREQ_SCALE_MHZ,  1,  5, 10 },
+               {   1, FREQ_SCALE_MHZ, 16,  5,  5 },
+               { 800, FREQ_SCALE_KHZ, 17,  5,  8 },
+               { 400, FREQ_SCALE_KHZ, 32,  5, 20 },
+               { 200, FREQ_SCALE_KHZ, 32,  5, 10 },
+               { 100, FREQ_SCALE_KHZ, 32,  5,  5 },
+               {  50, FREQ_SCALE_KHZ, 33,  5,  5 },
+               {  25, FREQ_SCALE_KHZ, 49,  5, 25 },
+               {   5, FREQ_SCALE_KHZ, 50,  5, 10 },
+               {   1, FREQ_SCALE_KHZ, 64,  5,  5 },
+               { 500, FREQ_SCALE_HZ,  64, 10,  5 },
+               { 100, FREQ_SCALE_HZ,  68,  5,  8 },
+               {   0, 0,              0,   0,  0 }
+       };
+
+       int i;
+
+       for (i = 0; f[i].freq; i++) {
+               if (scale == f[i].scale && freq == f[i].freq)
+                       break;
+       }
+       if (!f[i].freq)
+               return -1;
+
+       sr_dbg("Setting samplerate regs (freq=%d, scale=%d): "
+              "reg0: %d, reg1: %d, reg2: %d, reg3: %d.",
+              freq, scale, f[i].div, f[i].mul, 0x02, f[i].sel);
+
+       if (gl_reg_write(devh, FREQUENCY_REG0, f[i].div) < 0)
+               return -1;
+
+       if (gl_reg_write(devh, FREQUENCY_REG1, f[i].mul) < 0)
+               return -1;
+
+       if (gl_reg_write(devh, FREQUENCY_REG2, 0x02) < 0)
+               return -1;
+
+       if (gl_reg_write(devh, FREQUENCY_REG4, f[i].sel) < 0)
+               return -1;
+
+       return 0;
+}
+
+static void __analyzer_set_ramsize_trigger_address(libusb_device_handle *devh,
+                                                  unsigned int address)
+{
+       gl_reg_write(devh, RAMSIZE_TRIGGERBAR_ADDRESS0, (address >> 0) & 0xFF);
+       gl_reg_write(devh, RAMSIZE_TRIGGERBAR_ADDRESS1, (address >> 8) & 0xFF);
+       gl_reg_write(devh, RAMSIZE_TRIGGERBAR_ADDRESS2, (address >> 16) & 0xFF);
+}
+
+static void __analyzer_set_triggerbar_address(libusb_device_handle *devh,
+                                             unsigned int address)
+{
+       gl_reg_write(devh, TRIGGERBAR_ADDRESS0, (address >> 0) & 0xFF);
+       gl_reg_write(devh, TRIGGERBAR_ADDRESS1, (address >> 8) & 0xFF);
+       gl_reg_write(devh, TRIGGERBAR_ADDRESS2, (address >> 16) & 0xFF);
+}
+
+static void __analyzer_set_compression(libusb_device_handle *devh,
+                                      unsigned int type)
+{
+       gl_reg_write(devh, COMPRESSION_TYPE0, (type >> 0) & 0xFF);
+       gl_reg_write(devh, COMPRESSION_TYPE1, (type >> 8) & 0xFF);
+}
+
+static void __analyzer_set_trigger_count(libusb_device_handle *devh,
+                                        unsigned int count)
+{
+       gl_reg_write(devh, TRIGGER_COUNT0, (count >> 0) & 0xFF);
+       gl_reg_write(devh, TRIGGER_COUNT1, (count >> 8) & 0xFF);
+}
+
+static void analyzer_write_enable_insert_data(libusb_device_handle *devh)
+{
+       gl_reg_write(devh, ENABLE_INSERT_DATA0, 0x12);
+       gl_reg_write(devh, ENABLE_INSERT_DATA1, 0x34);
+       gl_reg_write(devh, ENABLE_INSERT_DATA2, 0x56);
+       gl_reg_write(devh, ENABLE_INSERT_DATA3, 0x78);
+}
+
+static void analyzer_set_filter(libusb_device_handle *devh)
+{
+       int i;
+       gl_reg_write(devh, FILTER_ENABLE, g_filter_enable);
+       for (i = 0; i < 8; i++)
+               gl_reg_write(devh, FILTER_STATUS + i, g_filter_status[i]);
+}
+
+SR_PRIV void analyzer_reset(libusb_device_handle *devh)
+{
+       analyzer_write_status(devh, 3, STATUS_FLAG_NONE);       // reset device
+       analyzer_write_status(devh, 3, STATUS_FLAG_RESET);      // reset device
+}
+
+SR_PRIV void analyzer_initialize(libusb_device_handle *devh)
+{
+       analyzer_write_status(devh, 1, STATUS_FLAG_NONE);
+       analyzer_write_status(devh, 1, STATUS_FLAG_INIT);
+       analyzer_write_status(devh, 1, STATUS_FLAG_NONE);
+}
+
+SR_PRIV void analyzer_wait(libusb_device_handle *devh, int set, int unset)
+{
+       int status;
+
+       while (1) {
+               status = gl_reg_read(devh, DEV_STATUS);
+               if ((!set || (status & set)) && ((status & unset) == 0))
+                       return;
+       }
+}
+
+SR_PRIV void analyzer_read_start(libusb_device_handle *devh)
+{
+       analyzer_write_status(devh, 3, STATUS_FLAG_20 | STATUS_FLAG_READ);
+
+       /* Prep for bulk reads */
+       gl_reg_read_buf(devh, READ_RAM_STATUS, NULL, 0);
+}
+
+SR_PRIV int analyzer_read_data(libusb_device_handle *devh, void *buffer,
+                      unsigned int size)
+{
+       return gl_read_bulk(devh, buffer, size);
+}
+
+SR_PRIV void analyzer_read_stop(libusb_device_handle *devh)
+{
+       analyzer_write_status(devh, 3, STATUS_FLAG_20);
+       analyzer_write_status(devh, 3, STATUS_FLAG_NONE);
+}
+
+SR_PRIV void analyzer_start(libusb_device_handle *devh)
+{
+       analyzer_write_status(devh, 1, STATUS_FLAG_NONE);
+       analyzer_write_status(devh, 1, STATUS_FLAG_INIT);
+       analyzer_write_status(devh, 1, STATUS_FLAG_NONE);
+       analyzer_write_status(devh, 1, STATUS_FLAG_GO);
+}
+
+SR_PRIV void analyzer_configure(libusb_device_handle *devh)
+{
+       int i;
+
+       /* Write_Start_Status */
+       analyzer_write_status(devh, 1, STATUS_FLAG_RESET);
+       analyzer_write_status(devh, 1, STATUS_FLAG_NONE);
+
+       /* Start_Config_Outside_Device ? */
+       analyzer_write_status(devh, 1, STATUS_FLAG_INIT);
+       analyzer_write_status(devh, 1, STATUS_FLAG_NONE);
+
+       /* SetData_To_Frequence_Reg */
+       __analyzer_set_freq(devh, g_freq_value, g_freq_scale);
+
+       /* SetMemory_Length */
+       gl_reg_write(devh, MEMORY_LENGTH, g_memory_size);
+
+       /* Sele_Inside_Outside_Clock */
+       gl_reg_write(devh, CLOCK_SOURCE, 0x03);
+
+       /* Set_Trigger_Status */
+       for (i = 0; i < 9; i++)
+               gl_reg_write(devh, TRIGGER_STATUS0 + i, g_trigger_status[i]);
+
+       __analyzer_set_trigger_count(devh, g_trigger_count);
+
+       /* Set_Trigger_Level */
+       gl_reg_write(devh, TRIGGER_LEVEL0, g_thresh);
+       gl_reg_write(devh, TRIGGER_LEVEL1, g_thresh);
+       gl_reg_write(devh, TRIGGER_LEVEL2, g_thresh);
+       gl_reg_write(devh, TRIGGER_LEVEL3, g_thresh);
+
+       /* Size of actual memory >> 2 */
+       __analyzer_set_ramsize_trigger_address(devh, g_ramsize_triggerbar_addr);
+       __analyzer_set_triggerbar_address(devh, g_triggerbar_addr);
+
+       /* Set_Dont_Care_TriggerBar */
+       gl_reg_write(devh, DONT_CARE_TRIGGERBAR, 0x01);
+
+       /* Enable_Status */
+       analyzer_set_filter(devh);
+
+       /* Set_Enable_Delay_Time */
+       gl_reg_write(devh, 0x7a, 0x00);
+       gl_reg_write(devh, 0x7b, 0x00);
+       analyzer_write_enable_insert_data(devh);
+       __analyzer_set_compression(devh, g_compression);
+}
+
+SR_PRIV int analyzer_add_triggers(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_trigger *trigger;
+       struct sr_trigger_stage *stage;
+       struct sr_trigger_match *match;
+       GSList *l, *m;
+       int channel;
+
+       devc = sdi->priv;
+
+       if (!(trigger = sr_session_trigger_get(sdi->session)))
+               return SR_OK;
+
+       for (l = trigger->stages; l; l = l->next) {
+               stage = l->data;
+               for (m = stage->matches; m; m = m->next) {
+                       match = m->data;
+                       devc->trigger = 1;
+                       if (!match->channel->enabled)
+                               /* Ignore disabled channels with a trigger. */
+                               continue;
+                       channel = match->channel->index;
+                       switch (match->match) {
+                       case SR_TRIGGER_ZERO:
+                               g_trigger_status[channel / 4] |= 2 << (channel % 4 * 2);
+                       case SR_TRIGGER_ONE:
+                               g_trigger_status[channel / 4] |= 1 << (channel % 4 * 2);
+                               break;
+                       default:
+                               sr_err("Unsupported match %d", match->match);
+                               return SR_ERR;
+                       }
+               }
+       }
+
+       return SR_OK;
+}
+
+SR_PRIV void analyzer_add_filter(int channel, int type)
+{
+       int i;
+
+       if (type != FILTER_HIGH && type != FILTER_LOW)
+               return;
+       if ((channel & 0xf) >= 8)
+               return;
+
+       if (channel & CHANNEL_A)
+               i = 0;
+       else if (channel & CHANNEL_B)
+               i = 2;
+       else if (channel & CHANNEL_C)
+               i = 4;
+       else if (channel & CHANNEL_D)
+               i = 6;
+       else
+               return;
+
+       if ((channel & 0xf) >= 4) {
+               i++;
+               channel -= 4;
+       }
+
+       g_filter_status[i] |=
+           1 << ((2 * channel) + (type == FILTER_LOW ? 1 : 0));
+
+       g_filter_enable = 1;
+}
+
+SR_PRIV void analyzer_set_trigger_count(int count)
+{
+       g_trigger_count = count;
+}
+
+SR_PRIV void analyzer_set_freq(int freq, int scale)
+{
+       g_freq_value = freq;
+       g_freq_scale = scale;
+}
+
+SR_PRIV void analyzer_set_memory_size(unsigned int size)
+{
+       g_memory_size = size;
+}
+
+SR_PRIV void analyzer_set_ramsize_trigger_address(unsigned int address)
+{
+       g_ramsize_triggerbar_addr = address;
+}
+
+SR_PRIV unsigned int analyzer_get_ramsize_trigger_address(void)
+{
+       return g_ramsize_triggerbar_addr;
+}
+
+SR_PRIV void analyzer_set_triggerbar_address(unsigned int address)
+{
+       g_triggerbar_addr = address;
+}
+
+SR_PRIV unsigned int analyzer_get_triggerbar_address(void)
+{
+       return g_triggerbar_addr;
+}
+
+SR_PRIV unsigned int analyzer_read_status(libusb_device_handle *devh)
+{
+       return gl_reg_read(devh, DEV_STATUS);
+}
+
+SR_PRIV unsigned int analyzer_read_id(libusb_device_handle *devh)
+{
+       return gl_reg_read(devh, DEV_ID1) << 8 | gl_reg_read(devh, DEV_ID0);
+}
+
+SR_PRIV unsigned int analyzer_get_stop_address(libusb_device_handle *devh)
+{
+       return gl_reg_read(devh, STOP_ADDRESS2) << 16 | gl_reg_read(devh,
+                       STOP_ADDRESS1) << 8 | gl_reg_read(devh, STOP_ADDRESS0);
+}
+
+SR_PRIV unsigned int analyzer_get_now_address(libusb_device_handle *devh)
+{
+       return gl_reg_read(devh, NOW_ADDRESS2) << 16 | gl_reg_read(devh,
+                       NOW_ADDRESS1) << 8 | gl_reg_read(devh, NOW_ADDRESS0);
+}
+
+SR_PRIV unsigned int analyzer_get_trigger_address(libusb_device_handle *devh)
+{
+       return gl_reg_read(devh, TRIGGER_ADDRESS2) << 16 | gl_reg_read(devh,
+               TRIGGER_ADDRESS1) << 8 | gl_reg_read(devh, TRIGGER_ADDRESS0);
+}
+
+SR_PRIV void analyzer_set_compression(unsigned int type)
+{
+       g_compression = type;
+}
+
+SR_PRIV void analyzer_set_voltage_threshold(int thresh)
+{
+       g_thresh = thresh;
+}
+
+SR_PRIV void analyzer_wait_button(libusb_device_handle *devh)
+{
+       analyzer_wait(devh, STATUS_BUTTON_PRESSED, 0);
+}
+
+SR_PRIV void analyzer_wait_data(libusb_device_handle *devh)
+{
+       analyzer_wait(devh, 0, STATUS_BUSY);
+}
+
+SR_PRIV int analyzer_decompress(void *input, unsigned int input_len,
+                               void *output, unsigned int output_len)
+{
+       unsigned char *in = input;
+       unsigned char *out = output;
+       unsigned int A, B, C, count;
+       unsigned int written = 0;
+
+       while (input_len > 0) {
+               A = *in++;
+               B = *in++;
+               C = *in++;
+               count = (*in++) + 1;
+
+               if (count > output_len)
+                       count = output_len;
+               output_len -= count;
+               written += count;
+
+               while (count--) {
+                       *out++ = A;
+                       *out++ = B;
+                       *out++ = C;
+                       *out++ = 0; /* Channel D */
+               }
+
+               input_len -= 4;
+               if (output_len == 0)
+                       break;
+       }
+
+       return written;
+}
diff --git a/src/hardware/zeroplus-logic-cube/analyzer.h b/src/hardware/zeroplus-logic-cube/analyzer.h
new file mode 100644 (file)
index 0000000..9f87259
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010 Sven Peter <sven@fail0verflow.com>
+ * Copyright (C) 2010 Haxx Enterprises <bushing@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ *  THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_ZEROPLUS_LOGIC_CUBE_ANALYZER_H
+#define LIBSIGROK_HARDWARE_ZEROPLUS_LOGIC_CUBE_ANALYZER_H
+
+#include <libusb.h>
+#include "libsigrok.h"
+
+#define STATUS_FLAG_NONE       0x00
+#define STATUS_FLAG_RESET      0x01
+#define STATUS_FLAG_INIT       0x02
+#define STATUS_FLAG_GO         0x04
+#define STATUS_FLAG_PAUSE      0x08
+#define STATUS_FLAG_READ       0x10
+#define STATUS_FLAG_20         0x20
+
+/* In bytes */
+#define MEMORY_SIZE_8K         0x00
+#define MEMORY_SIZE_64K                0x01
+#define MEMORY_SIZE_128K       0x02
+#define MEMORY_SIZE_256K       0x03
+#define MEMORY_SIZE_512K       0x04
+#define MEMORY_SIZE_1M         0x05
+#define MEMORY_SIZE_2M         0x06
+#define MEMORY_SIZE_4M         0x07
+#define MEMORY_SIZE_8M         0x08
+
+#define STATUS_BUSY            0x01    /* WTF / ??? */
+#define STATUS_READY           0x02
+#define STATUS_BUTTON_PRESSED  0x04
+
+#define CHANNEL_A              0x1000
+#define CHANNEL_B              0x2000
+#define CHANNEL_C              0x3000
+#define CHANNEL_D              0x4000
+
+#define FREQ_SCALE_HZ          0
+#define FREQ_SCALE_KHZ         1
+#define FREQ_SCALE_MHZ         2
+
+#define FILTER_HIGH            0
+#define FILTER_LOW             1
+
+#define COMPRESSION_NONE       0x0001
+#define COMPRESSION_ENABLE     0x8001
+#define COMPRESSION_DOUBLE     0x8002
+
+SR_PRIV void analyzer_set_freq(int freq, int scale);
+SR_PRIV void analyzer_set_ramsize_trigger_address(unsigned int address);
+SR_PRIV void analyzer_set_triggerbar_address(unsigned int address);
+SR_PRIV unsigned int  analyzer_get_ramsize_trigger_address(void );
+SR_PRIV unsigned int analyzer_get_triggerbar_address(void);
+SR_PRIV void analyzer_set_compression(unsigned int type);
+SR_PRIV void analyzer_set_memory_size(unsigned int size);
+SR_PRIV int analyzer_add_triggers(const struct sr_dev_inst *sdi);
+SR_PRIV void analyzer_set_trigger_count(int count);
+SR_PRIV void analyzer_add_filter(int channel, int type);
+SR_PRIV void analyzer_set_voltage_threshold(int thresh);
+
+SR_PRIV unsigned int analyzer_read_status(libusb_device_handle *devh);
+SR_PRIV unsigned int analyzer_read_id(libusb_device_handle *devh);
+SR_PRIV unsigned int analyzer_get_stop_address(libusb_device_handle *devh);
+SR_PRIV unsigned int analyzer_get_now_address(libusb_device_handle *devh);
+SR_PRIV unsigned int analyzer_get_trigger_address(libusb_device_handle *devh);
+SR_PRIV int analyzer_decompress(void *input, unsigned int input_len,
+                               void *output, unsigned int output_len);
+
+SR_PRIV void analyzer_reset(libusb_device_handle *devh);
+SR_PRIV void analyzer_initialize(libusb_device_handle *devh);
+SR_PRIV void analyzer_wait(libusb_device_handle *devh, int set, int unset);
+SR_PRIV void analyzer_read_start(libusb_device_handle *devh);
+SR_PRIV int analyzer_read_data(libusb_device_handle *devh, void *buffer,
+                              unsigned int size);
+SR_PRIV void analyzer_read_stop(libusb_device_handle *devh);
+SR_PRIV void analyzer_start(libusb_device_handle *devh);
+SR_PRIV void analyzer_configure(libusb_device_handle *devh);
+
+SR_PRIV void analyzer_wait_button(libusb_device_handle *devh);
+SR_PRIV void analyzer_wait_data(libusb_device_handle *devh);
+
+#endif
diff --git a/src/hardware/zeroplus-logic-cube/api.c b/src/hardware/zeroplus-logic-cube/api.c
new file mode 100644 (file)
index 0000000..a49f074
--- /dev/null
@@ -0,0 +1,752 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.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 "protocol.h"
+
+#define VENDOR_NAME                    "ZEROPLUS"
+#define USB_INTERFACE                  0
+#define USB_CONFIGURATION              1
+#define NUM_TRIGGER_STAGES             4
+#define PACKET_SIZE                    2048    /* ?? */
+
+//#define ZP_EXPERIMENTAL
+
+struct zp_model {
+       uint16_t vid;
+       uint16_t pid;
+       char *model_name;
+       unsigned int channels;
+       unsigned int sample_depth;      /* In Ksamples/channel */
+       unsigned int max_sampling_freq;
+};
+
+/*
+ * Note -- 16032, 16064 and 16128 *usually* -- but not always -- have the
+ * same 128K sample depth.
+ */
+static const struct zp_model zeroplus_models[] = {
+       {0x0c12, 0x7002, "LAP-16128U",    16, 128,  200},
+       {0x0c12, 0x7009, "LAP-C(16064)",  16, 64,   100},
+       {0x0c12, 0x700a, "LAP-C(16128)",  16, 128,  200},
+       {0x0c12, 0x700b, "LAP-C(32128)",  32, 128,  200},
+       {0x0c12, 0x700c, "LAP-C(321000)", 32, 1024, 200},
+       {0x0c12, 0x700d, "LAP-C(322000)", 32, 2048, 200},
+       {0x0c12, 0x700e, "LAP-C(16032)",  16, 32,   100},
+       {0x0c12, 0x7016, "LAP-C(162000)", 16, 2048, 200},
+       { 0, 0, 0, 0, 0, 0 }
+};
+
+static const int32_t hwcaps[] = {
+       SR_CONF_LOGIC_ANALYZER,
+       SR_CONF_SAMPLERATE,
+       SR_CONF_TRIGGER_MATCH,
+       SR_CONF_CAPTURE_RATIO,
+       SR_CONF_VOLTAGE_THRESHOLD,
+       SR_CONF_LIMIT_SAMPLES,
+};
+
+static const int32_t trigger_matches[] = {
+       SR_TRIGGER_ZERO,
+       SR_TRIGGER_ONE,
+};
+
+/*
+ * ZEROPLUS LAP-C (16032) numbers the 16 channels A0-A7 and B0-B7.
+ * We currently ignore other untested/unsupported devices here.
+ */
+static const char *channel_names[] = {
+       "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
+       "B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7",
+       "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7",
+       "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
+       NULL,
+};
+
+SR_PRIV struct sr_dev_driver zeroplus_logic_cube_driver_info;
+static struct sr_dev_driver *di = &zeroplus_logic_cube_driver_info;
+
+/*
+ * The hardware supports more samplerates than these, but these are the
+ * options hardcoded into the vendor's Windows GUI.
+ */
+
+static const uint64_t samplerates_100[] = {
+       SR_HZ(100),
+       SR_HZ(500),
+       SR_KHZ(1),
+       SR_KHZ(5),
+       SR_KHZ(25),
+       SR_KHZ(50),
+       SR_KHZ(100),
+       SR_KHZ(200),
+       SR_KHZ(400),
+       SR_KHZ(800),
+       SR_MHZ(1),
+       SR_MHZ(10),
+       SR_MHZ(25),
+       SR_MHZ(50),
+       SR_MHZ(80),
+       SR_MHZ(100),
+};
+
+const uint64_t samplerates_200[] = {
+       SR_HZ(100),
+       SR_HZ(500),
+       SR_KHZ(1),
+       SR_KHZ(5),
+       SR_KHZ(25),
+       SR_KHZ(50),
+       SR_KHZ(100),
+       SR_KHZ(200),
+       SR_KHZ(400),
+       SR_KHZ(800),
+       SR_MHZ(1),
+       SR_MHZ(10),
+       SR_MHZ(25),
+       SR_MHZ(50),
+       SR_MHZ(80),
+       SR_MHZ(100),
+       SR_MHZ(150),
+       SR_MHZ(200),
+};
+
+static int dev_close(struct sr_dev_inst *sdi);
+
+SR_PRIV int zp_set_samplerate(struct dev_context *devc, uint64_t samplerate)
+{
+       int i;
+
+       for (i = 0; ARRAY_SIZE(samplerates_200); i++)
+               if (samplerate == samplerates_200[i])
+                       break;
+
+       if (i == ARRAY_SIZE(samplerates_200) || samplerate > devc->max_samplerate) {
+               sr_err("Unsupported samplerate: %" PRIu64 "Hz.", samplerate);
+               return SR_ERR_ARG;
+       }
+
+       sr_info("Setting samplerate to %" PRIu64 "Hz.", samplerate);
+
+       if (samplerate >= SR_MHZ(1))
+               analyzer_set_freq(samplerate / SR_MHZ(1), FREQ_SCALE_MHZ);
+       else if (samplerate >= SR_KHZ(1))
+               analyzer_set_freq(samplerate / SR_KHZ(1), FREQ_SCALE_KHZ);
+       else
+               analyzer_set_freq(samplerate, FREQ_SCALE_HZ);
+
+       devc->cur_samplerate = samplerate;
+
+       return SR_OK;
+}
+
+static int init(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+       struct sr_dev_inst *sdi;
+       struct sr_channel *ch;
+       struct drv_context *drvc;
+       struct dev_context *devc;
+       const struct zp_model *prof;
+       struct libusb_device_descriptor des;
+       libusb_device **devlist;
+       GSList *devices;
+       int ret, devcnt, i, j;
+
+       (void)options;
+
+       drvc = di->priv;
+
+       devices = NULL;
+
+       /* Find all ZEROPLUS analyzers and add them to device list. */
+       devcnt = 0;
+       libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist); /* TODO: Errors. */
+
+       for (i = 0; devlist[i]; i++) {
+               ret = libusb_get_device_descriptor(devlist[i], &des);
+               if (ret != 0) {
+                       sr_err("Failed to get device descriptor: %s.",
+                              libusb_error_name(ret));
+                       continue;
+               }
+
+               prof = NULL;
+               for (j = 0; j < zeroplus_models[j].vid; j++) {
+                       if (des.idVendor == zeroplus_models[j].vid &&
+                               des.idProduct == zeroplus_models[j].pid) {
+                               prof = &zeroplus_models[j];
+                       }
+               }
+               /* Skip if the device was not found. */
+               if (!prof)
+                       continue;
+               sr_info("Found ZEROPLUS %s.", prof->model_name);
+
+               /* Register the device with libsigrok. */
+               if (!(sdi = sr_dev_inst_new(devcnt, SR_ST_INACTIVE,
+                               VENDOR_NAME, prof->model_name, NULL))) {
+                       sr_err("%s: sr_dev_inst_new failed", __func__);
+                       return NULL;
+               }
+               sdi->driver = di;
+
+               /* Allocate memory for our private driver context. */
+               if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+                       sr_err("Device context malloc failed.");
+                       return NULL;
+               }
+
+               sdi->priv = devc;
+               devc->prof = prof;
+               devc->num_channels = prof->channels;
+#ifdef ZP_EXPERIMENTAL
+               devc->max_sample_depth = 128 * 1024;
+               devc->max_samplerate = 200;
+#else
+               devc->max_sample_depth = prof->sample_depth * 1024;
+               devc->max_samplerate = prof->max_sampling_freq;
+#endif
+               devc->max_samplerate *= SR_MHZ(1);
+               devc->memory_size = MEMORY_SIZE_8K;
+               // memset(devc->trigger_buffer, 0, NUM_TRIGGER_STAGES);
+
+               /* Fill in channellist according to this device's profile. */
+               for (j = 0; j < devc->num_channels; j++) {
+                       if (!(ch = sr_channel_new(j, SR_CHANNEL_LOGIC, TRUE,
+                                       channel_names[j])))
+                               return NULL;
+                       sdi->channels = g_slist_append(sdi->channels, ch);
+               }
+
+               devices = g_slist_append(devices, sdi);
+               drvc->instances = g_slist_append(drvc->instances, sdi);
+               sdi->inst_type = SR_INST_USB;
+               sdi->conn = sr_usb_dev_inst_new(
+                       libusb_get_bus_number(devlist[i]),
+                       libusb_get_device_address(devlist[i]), NULL);
+               devcnt++;
+
+       }
+       libusb_free_device_list(devlist, 1);
+
+       return devices;
+}
+
+static GSList *dev_list(void)
+{
+       return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct drv_context *drvc;
+       struct sr_usb_dev_inst *usb;
+       libusb_device **devlist, *dev;
+       struct libusb_device_descriptor des;
+       int device_count, ret, i;
+
+       drvc = di->priv;
+       usb = sdi->conn;
+
+       if (!(devc = sdi->priv)) {
+               sr_err("%s: sdi->priv was NULL", __func__);
+               return SR_ERR_ARG;
+       }
+
+       device_count = libusb_get_device_list(drvc->sr_ctx->libusb_ctx,
+                                             &devlist);
+       if (device_count < 0) {
+               sr_err("Failed to retrieve device list.");
+               return SR_ERR;
+       }
+
+       dev = NULL;
+       for (i = 0; i < device_count; i++) {
+               if ((ret = libusb_get_device_descriptor(devlist[i], &des))) {
+                       sr_err("Failed to get device descriptor: %s.",
+                              libusb_error_name(ret));
+                       continue;
+               }
+               if (libusb_get_bus_number(devlist[i]) == usb->bus
+                   && libusb_get_device_address(devlist[i]) == usb->address) {
+                       dev = devlist[i];
+                       break;
+               }
+       }
+       if (!dev) {
+               sr_err("Device on bus %d address %d disappeared!",
+                      usb->bus, usb->address);
+               return SR_ERR;
+       }
+
+       if (!(ret = libusb_open(dev, &(usb->devhdl)))) {
+               sdi->status = SR_ST_ACTIVE;
+               sr_info("Opened device %d on %d.%d interface %d.",
+                       sdi->index, usb->bus, usb->address, USB_INTERFACE);
+       } else {
+               sr_err("Failed to open device: %s.", libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+       ret = libusb_set_configuration(usb->devhdl, USB_CONFIGURATION);
+       if (ret < 0) {
+               sr_err("Unable to set USB configuration %d: %s.",
+                      USB_CONFIGURATION, libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+       ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE);
+       if (ret != 0) {
+               sr_err("Unable to claim interface: %s.",
+                      libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+       /* Set default configuration after power on. */
+       if (analyzer_read_status(usb->devhdl) == 0)
+               analyzer_configure(usb->devhdl);
+
+       analyzer_reset(usb->devhdl);
+       analyzer_initialize(usb->devhdl);
+
+       //analyzer_set_memory_size(MEMORY_SIZE_512K);
+       // analyzer_set_freq(g_freq, g_freq_scale);
+       analyzer_set_trigger_count(1);
+       // analyzer_set_ramsize_trigger_address((((100 - g_pre_trigger)
+       // * get_memory_size(g_memory_size)) / 100) >> 2);
+
+#if 0
+       if (g_double_mode == 1)
+               analyzer_set_compression(COMPRESSION_DOUBLE);
+       else if (g_compression == 1)
+               analyzer_set_compression(COMPRESSION_ENABLE);
+       else
+#endif
+       analyzer_set_compression(COMPRESSION_NONE);
+
+       if (devc->cur_samplerate == 0) {
+               /* Samplerate hasn't been set. Default to 1MHz. */
+               analyzer_set_freq(1, FREQ_SCALE_MHZ);
+               devc->cur_samplerate = SR_MHZ(1);
+       }
+
+       if (devc->cur_threshold == 0)
+               set_voltage_threshold(devc, 1.5);
+
+       return SR_OK;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+       struct sr_usb_dev_inst *usb;
+
+       usb = sdi->conn;
+
+       if (!usb->devhdl)
+               return SR_ERR;
+
+       sr_info("Closing device %d on %d.%d interface %d.", sdi->index,
+               usb->bus, usb->address, USB_INTERFACE);
+       libusb_release_interface(usb->devhdl, USB_INTERFACE);
+       libusb_reset_device(usb->devhdl);
+       libusb_close(usb->devhdl);
+       usb->devhdl = NULL;
+       sdi->status = SR_ST_INACTIVE;
+
+       return SR_OK;
+}
+
+static int cleanup(void)
+{
+       return std_dev_clear(di, NULL);
+}
+
+static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+
+       (void)cg;
+
+       switch (id) {
+       case SR_CONF_SAMPLERATE:
+               if (sdi) {
+                       devc = sdi->priv;
+                       *data = g_variant_new_uint64(devc->cur_samplerate);
+                       sr_spew("Returning samplerate: %" PRIu64 "Hz.",
+                               devc->cur_samplerate);
+               } else
+                       return SR_ERR_ARG;
+               break;
+       case SR_CONF_CAPTURE_RATIO:
+               if (sdi) {
+                       devc = sdi->priv;
+                       *data = g_variant_new_uint64(devc->capture_ratio);
+               } else
+                       return SR_ERR_ARG;
+               break;
+       case SR_CONF_VOLTAGE_THRESHOLD:
+               if (sdi) {
+                       GVariant *range[2];
+                       devc = sdi->priv;
+                       range[0] = g_variant_new_double(devc->cur_threshold);
+                       range[1] = g_variant_new_double(devc->cur_threshold);
+                       *data = g_variant_new_tuple(range, 2);
+               } else
+                       return SR_ERR_ARG;
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       gdouble low, high;
+
+       (void)cg;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       if (!(devc = sdi->priv)) {
+               sr_err("%s: sdi->priv was NULL", __func__);
+               return SR_ERR_ARG;
+       }
+
+       switch (id) {
+       case SR_CONF_SAMPLERATE:
+               return zp_set_samplerate(devc, g_variant_get_uint64(data));
+       case SR_CONF_LIMIT_SAMPLES:
+               return set_limit_samples(devc, g_variant_get_uint64(data));
+       case SR_CONF_CAPTURE_RATIO:
+               return set_capture_ratio(devc, g_variant_get_uint64(data));
+       case SR_CONF_VOLTAGE_THRESHOLD:
+               g_variant_get(data, "(dd)", &low, &high);
+               return set_voltage_threshold(devc, (low + high) / 2.0);
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct dev_context *devc;
+       GVariant *gvar, *grange[2];
+       GVariantBuilder gvb;
+       double v;
+       GVariant *range[2];
+
+       (void)cg;
+
+       switch (key) {
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+               break;
+       case SR_CONF_SAMPLERATE:
+               devc = sdi->priv;
+               g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
+               if (devc->prof->max_sampling_freq == 100) {
+                       gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"),
+                                       samplerates_100, ARRAY_SIZE(samplerates_100),
+                                       sizeof(uint64_t));
+               } else if (devc->prof->max_sampling_freq == 200) {
+                       gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"),
+                                       samplerates_200, ARRAY_SIZE(samplerates_200),
+                                       sizeof(uint64_t));
+               } else {
+                       sr_err("Internal error: Unknown max. samplerate: %d.",
+                              devc->prof->max_sampling_freq);
+                       return SR_ERR_ARG;
+               }
+               g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar);
+               *data = g_variant_builder_end(&gvb);
+               break;
+       case SR_CONF_TRIGGER_MATCH:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               trigger_matches, ARRAY_SIZE(trigger_matches),
+                               sizeof(int32_t));
+               break;
+       case SR_CONF_VOLTAGE_THRESHOLD:
+               g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
+               for (v = -6.0; v <= 6.0; v += 0.1) {
+                       range[0] = g_variant_new_double(v);
+                       range[1] = g_variant_new_double(v);
+                       gvar = g_variant_new_tuple(range, 2);
+                       g_variant_builder_add_value(&gvb, gvar);
+               }
+               *data = g_variant_builder_end(&gvb);
+               break;
+       case SR_CONF_LIMIT_SAMPLES:
+               if (!sdi)
+                       return SR_ERR_ARG;
+               devc = sdi->priv;
+               grange[0] = g_variant_new_uint64(0);
+               grange[1] = g_variant_new_uint64(devc->max_sample_depth);
+               *data = g_variant_new_tuple(grange, 2);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi,
+               void *cb_data)
+{
+       struct dev_context *devc;
+       struct sr_usb_dev_inst *usb;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_logic logic;
+       unsigned int samples_read;
+       int res;
+       unsigned int packet_num, n;
+       unsigned char *buf;
+       unsigned int status;
+       unsigned int stop_address;
+       unsigned int now_address;
+       unsigned int trigger_address;
+       unsigned int trigger_offset;
+       unsigned int triggerbar;
+       unsigned int ramsize_trigger;
+       unsigned int memory_size;
+       unsigned int valid_samples;
+       unsigned int discard;
+       int trigger_now;
+
+       if (sdi->status != SR_ST_ACTIVE)
+               return SR_ERR_DEV_CLOSED;
+
+       if (!(devc = sdi->priv)) {
+               sr_err("%s: sdi->priv was NULL", __func__);
+               return SR_ERR_ARG;
+       }
+
+       if (analyzer_add_triggers(sdi) != SR_OK) {
+               sr_err("Failed to configure triggers.");
+               return SR_ERR;
+       }
+
+       usb = sdi->conn;
+
+       set_triggerbar(devc);
+
+       /* Push configured settings to device. */
+       analyzer_configure(usb->devhdl);
+
+       analyzer_start(usb->devhdl);
+       sr_info("Waiting for data.");
+       analyzer_wait_data(usb->devhdl);
+
+       status = analyzer_read_status(usb->devhdl);
+       stop_address = analyzer_get_stop_address(usb->devhdl);
+       now_address = analyzer_get_now_address(usb->devhdl);
+       trigger_address = analyzer_get_trigger_address(usb->devhdl);
+
+       triggerbar = analyzer_get_triggerbar_address();
+       ramsize_trigger = analyzer_get_ramsize_trigger_address();
+
+       n = get_memory_size(devc->memory_size);
+       memory_size = n / 4;
+
+       sr_info("Status = 0x%x.", status);
+       sr_info("Stop address       = 0x%x.", stop_address);
+       sr_info("Now address        = 0x%x.", now_address);
+       sr_info("Trigger address    = 0x%x.", trigger_address);
+       sr_info("Triggerbar address = 0x%x.", triggerbar);
+       sr_info("Ramsize trigger    = 0x%x.", ramsize_trigger);
+       sr_info("Memory size        = 0x%x.", memory_size);
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(cb_data, LOG_PREFIX);
+
+       /* Check for empty capture */
+       if ((status & STATUS_READY) && !stop_address) {
+               packet.type = SR_DF_END;
+               sr_session_send(cb_data, &packet);
+               return SR_OK;
+       }
+
+       if (!(buf = g_try_malloc(PACKET_SIZE))) {
+               sr_err("Packet buffer malloc failed.");
+               return SR_ERR_MALLOC;
+       }
+
+       /* Check if the trigger is in the samples we are throwing away */
+       trigger_now = now_address == trigger_address ||
+               ((now_address + 1) % memory_size) == trigger_address;
+
+       /*
+        * STATUS_READY doesn't clear until now_address advances past
+        * addr 0, but for our logic, clear it in that case
+        */
+       if (!now_address)
+               status &= ~STATUS_READY;
+
+       analyzer_read_start(usb->devhdl);
+
+       /* Calculate how much data to discard */
+       discard = 0;
+       if (status & STATUS_READY) {
+               /*
+                * We haven't wrapped around, we need to throw away data from
+                * our current position to the end of the buffer.
+                * Additionally, the first two samples captured are always
+                * bogus.
+                */
+               discard += memory_size - now_address + 2;
+               now_address = 2;
+       }
+
+       /* If we have more samples than we need, discard them */
+       valid_samples = (stop_address - now_address) % memory_size;
+       if (valid_samples > ramsize_trigger + triggerbar) {
+               discard += valid_samples - (ramsize_trigger + triggerbar);
+               now_address += valid_samples - (ramsize_trigger + triggerbar);
+       }
+
+       sr_info("Need to discard %d samples.", discard);
+
+       /* Calculate how far in the trigger is */
+       if (trigger_now)
+               trigger_offset = 0;
+       else
+               trigger_offset = (trigger_address - now_address) % memory_size;
+
+       /* Recalculate the number of samples available */
+       valid_samples = (stop_address - now_address) % memory_size;
+
+       /* Send the incoming transfer to the session bus. */
+       samples_read = 0;
+       for (packet_num = 0; packet_num < n / PACKET_SIZE; packet_num++) {
+               unsigned int len;
+               unsigned int buf_offset;
+
+               res = analyzer_read_data(usb->devhdl, buf, PACKET_SIZE);
+               sr_info("Tried to read %d bytes, actually read %d bytes.",
+                       PACKET_SIZE, res);
+
+               if (discard >= PACKET_SIZE / 4) {
+                       discard -= PACKET_SIZE / 4;
+                       continue;
+               }
+
+               len = PACKET_SIZE - discard * 4;
+               buf_offset = discard * 4;
+               discard = 0;
+
+               /* Check if we've read all the samples */
+               if (samples_read + len / 4 >= valid_samples)
+                       len = (valid_samples - samples_read) * 4;
+               if (!len)
+                       break;
+
+               if (samples_read < trigger_offset &&
+                   samples_read + len / 4 > trigger_offset) {
+                       /* Send out samples remaining before trigger */
+                       packet.type = SR_DF_LOGIC;
+                       packet.payload = &logic;
+                       logic.length = (trigger_offset - samples_read) * 4;
+                       logic.unitsize = 4;
+                       logic.data = buf + buf_offset;
+                       sr_session_send(cb_data, &packet);
+                       len -= logic.length;
+                       samples_read += logic.length / 4;
+                       buf_offset += logic.length;
+               }
+
+               if (samples_read == trigger_offset) {
+                       /* Send out trigger */
+                       packet.type = SR_DF_TRIGGER;
+                       packet.payload = NULL;
+                       sr_session_send(cb_data, &packet);
+               }
+
+               /* Send out data (or data after trigger) */
+               packet.type = SR_DF_LOGIC;
+               packet.payload = &logic;
+               logic.length = len;
+               logic.unitsize = 4;
+               logic.data = buf + buf_offset;
+               sr_session_send(cb_data, &packet);
+               samples_read += len / 4;
+       }
+       analyzer_read_stop(usb->devhdl);
+       g_free(buf);
+
+       packet.type = SR_DF_END;
+       sr_session_send(cb_data, &packet);
+
+       return SR_OK;
+}
+
+/* TODO: This stops acquisition on ALL devices, ignoring dev_index. */
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct dev_context *devc;
+       struct sr_usb_dev_inst *usb;
+       struct sr_datafeed_packet packet;
+
+       packet.type = SR_DF_END;
+       sr_session_send(cb_data, &packet);
+
+       if (!(devc = sdi->priv)) {
+               sr_err("%s: sdi->priv was NULL", __func__);
+               return SR_ERR_BUG;
+       }
+
+       usb = sdi->conn;
+       analyzer_reset(usb->devhdl);
+       /* TODO: Need to cancel and free any queued up transfers. */
+
+       return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver zeroplus_logic_cube_driver_info = {
+       .name = "zeroplus-logic-cube",
+       .longname = "ZEROPLUS Logic Cube LAP-C series",
+       .api_version = 1,
+       .init = init,
+       .cleanup = cleanup,
+       .scan = scan,
+       .dev_list = 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,
+       .priv = NULL,
+};
diff --git a/src/hardware/zeroplus-logic-cube/gl_usb.c b/src/hardware/zeroplus-logic-cube/gl_usb.c
new file mode 100644 (file)
index 0000000..2099328
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010 Sven Peter <sven@fail0verflow.com>
+ * Copyright (C) 2010 Haxx Enterprises <bushing@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ *  THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <libusb.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "gl_usb.h"
+#include "protocol.h"
+
+#define CTRL_IN                (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN | \
+                        LIBUSB_RECIPIENT_INTERFACE)
+#define CTRL_OUT       (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT | \
+                        LIBUSB_RECIPIENT_INTERFACE)
+#define EP1_BULK_IN    (LIBUSB_ENDPOINT_IN | 1)
+
+#define TIMEOUT                5000    /* Timeout in ms */
+
+enum {
+       REQ_READBULK = 0x82,
+       REQ_WRITEADDR,
+       REQ_READDATA,
+       REQ_WRITEDATA,
+};
+
+static int gl_write_address(libusb_device_handle *devh, unsigned int address)
+{
+       unsigned char packet[8] = { address & 0xFF };
+       int ret;
+
+       ret = libusb_control_transfer(devh, CTRL_OUT, 0xc, REQ_WRITEADDR,
+                                        0, packet, 1, TIMEOUT);
+       if (ret != 1)
+               sr_err("%s: %s.", __func__, libusb_error_name(ret));
+       return ret;
+}
+
+static int gl_write_data(libusb_device_handle *devh, unsigned int val)
+{
+       unsigned char packet[8] = { val & 0xFF };
+       int ret;
+
+       ret = libusb_control_transfer(devh, CTRL_OUT, 0xc, REQ_WRITEDATA,
+                                     0, packet, 1, TIMEOUT);
+       if (ret != 1)
+               sr_err("%s: %s.", __func__, libusb_error_name(ret));
+       return ret;
+}
+
+static int gl_read_data(libusb_device_handle *devh)
+{
+       unsigned char packet[8] = { 0 };
+       int ret;
+
+       ret = libusb_control_transfer(devh, CTRL_IN, 0xc, REQ_READDATA,
+                                     0, packet, 1, TIMEOUT);
+       if (ret != 1)
+               sr_err("%s: %s, val=%hhx.", __func__,
+                      libusb_error_name(ret), packet[0]);
+       return (ret == 1) ? packet[0] : ret;
+}
+
+SR_PRIV int gl_read_bulk(libusb_device_handle *devh, void *buffer,
+                        unsigned int size)
+{
+       unsigned char packet[8] =
+           { 0, 0, 0, 0, size & 0xff, (size & 0xff00) >> 8,
+             (size & 0xff0000) >> 16, (size & 0xff000000) >> 24 };
+       int ret, transferred = 0;
+
+       ret = libusb_control_transfer(devh, CTRL_OUT, 0x4, REQ_READBULK,
+                                     0, packet, 8, TIMEOUT);
+       if (ret != 8)
+               sr_err("%s: libusb_control_transfer: %s.", __func__,
+                      libusb_error_name(ret));
+
+       ret = libusb_bulk_transfer(devh, EP1_BULK_IN, buffer, size,
+                                  &transferred, TIMEOUT);
+       if (ret < 0)
+               sr_err("%s: libusb_bulk_transfer: %s.", __func__,
+                      libusb_error_name(ret));
+       return transferred;
+}
+
+SR_PRIV int gl_reg_write(libusb_device_handle *devh, unsigned int reg,
+                unsigned int val)
+{
+       int ret;
+
+       ret = gl_write_address(devh, reg);
+       if (ret < 0)
+               return ret;
+       ret = gl_write_data(devh, val);
+       return ret;
+}
+
+SR_PRIV int gl_reg_read(libusb_device_handle *devh, unsigned int reg)
+{
+       int ret;
+
+       ret = gl_write_address(devh, reg);
+       if (ret < 0)
+               return ret;
+       ret = gl_read_data(devh);
+       return ret;
+}
+
+SR_PRIV int gl_reg_read_buf(libusb_device_handle *devh, unsigned int reg,
+               unsigned char *buf, unsigned int len)
+{
+       int ret;
+       unsigned int i;
+
+       ret = gl_write_address(devh, reg);
+       if (ret < 0)
+               return ret;
+       for (i = 0; i < len; i++) {
+               ret = gl_read_data(devh);
+               if (ret < 0)
+                       return ret;
+               buf[i] = ret;
+       }
+       return 0;
+}
diff --git a/src/hardware/zeroplus-logic-cube/gl_usb.h b/src/hardware/zeroplus-logic-cube/gl_usb.h
new file mode 100644 (file)
index 0000000..c3a33fb
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010 Sven Peter <sven@fail0verflow.com>
+ * Copyright (C) 2010 Haxx Enterprises <bushing@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ *  THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_ZEROPLUS_LOGIC_CUBE_GL_USB_H
+#define LIBSIGROK_HARDWARE_ZEROPLUS_LOGIC_CUBE_GL_USB_H
+
+#include <libusb.h>
+#include "libsigrok.h"
+
+SR_PRIV int gl_read_bulk(libusb_device_handle *devh, void *buffer,
+                        unsigned int size);
+SR_PRIV int gl_reg_write(libusb_device_handle *devh, unsigned int reg,
+                        unsigned int val);
+SR_PRIV int gl_reg_read(libusb_device_handle *devh, unsigned int reg);
+SR_PRIV int gl_reg_read_buf(libusb_device_handle *devh, unsigned int reg,
+                       unsigned char *buf, unsigned int len);
+#endif
diff --git a/src/hardware/zeroplus-logic-cube/protocol.c b/src/hardware/zeroplus-logic-cube/protocol.c
new file mode 100644 (file)
index 0000000..ce20ccf
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.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 <math.h>
+#include "protocol.h"
+
+SR_PRIV unsigned int get_memory_size(int type)
+{
+       if (type == MEMORY_SIZE_8K)
+               return 8 * 1024;
+       else if (type <= MEMORY_SIZE_8M)
+               return (32 * 1024) << type;
+       else
+               return 0;
+}
+
+static int clz(unsigned int x)
+{
+       int n = 0;
+       if (x == 0)
+               return 32;
+       if (!(x & 0xFFFF0000)) {
+               n = n + 16;
+               x = x << 16;
+       }
+       if (!(x & 0xFF000000)) {
+               n = n + 8;
+               x = x << 8;
+       }
+       if (!(x & 0xF0000000)) {
+               n = n + 4;
+               x = x << 4;
+       }
+       if (!(x & 0xC0000000)) {
+               n = n + 2;
+               x = x << 2;
+       }
+       if (!(x & 0x80000000))
+               n = n + 1;
+       return n;
+}
+
+SR_PRIV int set_limit_samples(struct dev_context *devc, uint64_t samples)
+{
+       if (samples > devc->max_sample_depth)
+               samples = devc->max_sample_depth;
+
+       devc->limit_samples = samples;
+
+       if (samples <= 2 * 1024)
+               devc->memory_size = MEMORY_SIZE_8K;
+       else if (samples <= 16 * 1024)
+               devc->memory_size = MEMORY_SIZE_64K;
+       else
+               devc->memory_size = 19 - clz(samples - 1);
+
+       sr_info("Setting memory size to %dK.",
+               get_memory_size(devc->memory_size) / 1024);
+
+       analyzer_set_memory_size(devc->memory_size);
+
+       return SR_OK;
+}
+
+SR_PRIV int set_capture_ratio(struct dev_context *devc, uint64_t ratio)
+{
+       if (ratio > 100) {
+               sr_err("Invalid capture ratio: %" PRIu64 ".", ratio);
+               return SR_ERR_ARG;
+       }
+
+       devc->capture_ratio = ratio;
+
+       sr_info("Setting capture ratio to %d%%.", devc->capture_ratio);
+
+       return SR_OK;
+}
+
+SR_PRIV int set_voltage_threshold(struct dev_context *devc, double thresh)
+{
+       if (thresh > 6.0)
+               thresh = 6.0;
+       if (thresh < -6.0)
+               thresh = -6.0;
+
+       devc->cur_threshold = thresh;
+
+       analyzer_set_voltage_threshold((int) round(-9.1*thresh + 62.6));
+
+       sr_info("Setting voltage threshold to %fV.", devc->cur_threshold);
+
+       return SR_OK;
+}
+
+SR_PRIV void set_triggerbar(struct dev_context *devc)
+{
+       unsigned int trigger_depth, triggerbar, ramsize_trigger;
+
+       trigger_depth = get_memory_size(devc->memory_size) / 4;
+       if (devc->limit_samples < trigger_depth)
+               trigger_depth = devc->limit_samples;
+
+       if (devc->trigger)
+               triggerbar = trigger_depth * devc->capture_ratio / 100;
+       else
+               triggerbar = 0;
+
+       ramsize_trigger = trigger_depth - triggerbar;
+       /* Matches USB packet captures from official app/driver */
+       if (triggerbar > 2)
+               triggerbar -= 2;
+       else {
+               ramsize_trigger -= 1;
+               triggerbar = 0;
+       }
+
+       analyzer_set_triggerbar_address(triggerbar);
+       analyzer_set_ramsize_trigger_address(ramsize_trigger);
+
+       sr_dbg("triggerbar_address = %d(0x%x)", triggerbar, triggerbar);
+       sr_dbg("ramsize_triggerbar_address = %d(0x%x)",
+              ramsize_trigger, ramsize_trigger);
+}
diff --git a/src/hardware/zeroplus-logic-cube/protocol.h b/src/hardware/zeroplus-logic-cube/protocol.h
new file mode 100644 (file)
index 0000000..4b55b33
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#ifndef LIBSIGROK_HARDWARE_ZEROPLUS_LOGIC_CUBE_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_ZEROPLUS_LOGIC_CUBE_PROTOCOL_H
+
+#include <stdint.h>
+#include <glib.h>
+#include <libusb.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "analyzer.h"
+
+#define LOG_PREFIX "zeroplus"
+
+/* Private, per-device-instance driver context. */
+struct dev_context {
+       uint64_t cur_samplerate;
+       uint64_t max_samplerate;
+       uint64_t limit_samples;
+       int num_channels;
+       int memory_size;
+       unsigned int max_sample_depth;
+       //uint8_t channel_mask;
+       //uint8_t trigger_mask[NUM_TRIGGER_STAGES];
+       //uint8_t trigger_value[NUM_TRIGGER_STAGES];
+       // uint8_t trigger_buffer[NUM_TRIGGER_STAGES];
+       int trigger;
+       unsigned int capture_ratio;
+       double cur_threshold;
+       const struct zp_model *prof;
+};
+
+SR_PRIV unsigned int get_memory_size(int type);
+SR_PRIV int zp_set_samplerate(struct dev_context *devc, uint64_t samplerate);
+SR_PRIV int set_limit_samples(struct dev_context *devc, uint64_t samples);
+SR_PRIV int set_capture_ratio(struct dev_context *devc, uint64_t ratio);
+SR_PRIV int set_voltage_threshold(struct dev_context *devc, double thresh);
+SR_PRIV void set_triggerbar(struct dev_context *devc);
+
+#endif
diff --git a/src/hwdriver.c b/src/hwdriver.c
new file mode 100644 (file)
index 0000000..04d877a
--- /dev/null
@@ -0,0 +1,468 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert@biot.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 <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <string.h>
+#include <glib.h>
+#include "config.h" /* Needed for HAVE_LIBUSB_1_0 and others. */
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+/** @cond PRIVATE */
+#define LOG_PREFIX "hwdriver"
+/** @endcond */
+
+extern SR_PRIV struct sr_dev_driver *drivers_list[];
+
+/**
+ * @file
+ *
+ * Hardware driver handling in libsigrok.
+ */
+
+/**
+ * @defgroup grp_driver Hardware drivers
+ *
+ * Hardware driver handling in libsigrok.
+ *
+ * @{
+ */
+
+static struct sr_config_info sr_config_info_data[] = {
+       {SR_CONF_CONN, SR_T_STRING, "conn",
+               "Connection", NULL},
+       {SR_CONF_SERIALCOMM, SR_T_STRING, "serialcomm",
+               "Serial communication", NULL},
+       {SR_CONF_SAMPLERATE, SR_T_UINT64, "samplerate",
+               "Sample rate", NULL},
+       {SR_CONF_CAPTURE_RATIO, SR_T_UINT64, "captureratio",
+               "Pre-trigger capture ratio", NULL},
+       {SR_CONF_PATTERN_MODE, SR_T_STRING, "pattern",
+               "Pattern", NULL},
+       {SR_CONF_TRIGGER_MATCH, SR_T_INT32, "triggermatch",
+               "Trigger matches", NULL},
+       {SR_CONF_EXTERNAL_CLOCK, SR_T_BOOL, "external_clock",
+               "External clock mode", NULL},
+       {SR_CONF_SWAP, SR_T_BOOL, "swap",
+               "Swap channel order", NULL},
+       {SR_CONF_RLE, SR_T_BOOL, "rle",
+               "Run Length Encoding", NULL},
+       {SR_CONF_TRIGGER_SLOPE, SR_T_STRING, "triggerslope",
+               "Trigger slope", NULL},
+       {SR_CONF_TRIGGER_SOURCE, SR_T_STRING, "triggersource",
+               "Trigger source", NULL},
+       {SR_CONF_HORIZ_TRIGGERPOS, SR_T_FLOAT, "horiz_triggerpos",
+               "Horizontal trigger position", NULL},
+       {SR_CONF_BUFFERSIZE, SR_T_UINT64, "buffersize",
+               "Buffer size", NULL},
+       {SR_CONF_TIMEBASE, SR_T_RATIONAL_PERIOD, "timebase",
+               "Time base", NULL},
+       {SR_CONF_FILTER, SR_T_STRING, "filter",
+               "Filter targets", NULL},
+       {SR_CONF_VDIV, SR_T_RATIONAL_VOLT, "vdiv",
+               "Volts/div", NULL},
+       {SR_CONF_COUPLING, SR_T_STRING, "coupling",
+               "Coupling", NULL},
+       {SR_CONF_DATALOG, SR_T_BOOL, "datalog",
+               "Datalog", NULL},
+       {SR_CONF_SPL_WEIGHT_FREQ, SR_T_STRING, "spl_weight_freq",
+               "Sound pressure level frequency weighting", NULL},
+       {SR_CONF_SPL_WEIGHT_TIME, SR_T_STRING, "spl_weight_time",
+               "Sound pressure level time weighting", NULL},
+       {SR_CONF_HOLD_MAX, SR_T_BOOL, "hold_max",
+               "Hold max", NULL},
+       {SR_CONF_HOLD_MIN, SR_T_BOOL, "hold_min",
+               "Hold min", NULL},
+       {SR_CONF_SPL_MEASUREMENT_RANGE, SR_T_UINT64_RANGE, "spl_meas_range",
+               "Sound pressure level measurement range", NULL},
+       {SR_CONF_VOLTAGE_THRESHOLD, SR_T_DOUBLE_RANGE, "voltage_threshold",
+               "Voltage threshold", NULL },
+       {SR_CONF_POWER_OFF, SR_T_BOOL, "power_off",
+               "Power off", NULL},
+       {SR_CONF_DATA_SOURCE, SR_T_STRING, "data_source",
+               "Data source", NULL},
+       {SR_CONF_NUM_LOGIC_CHANNELS, SR_T_INT32, "logic_channels",
+               "Number of logic channels", NULL},
+       {SR_CONF_NUM_ANALOG_CHANNELS, SR_T_INT32, "analog_channels",
+               "Number of analog channels", NULL},
+       {SR_CONF_OUTPUT_VOLTAGE, SR_T_FLOAT, "output_voltage",
+               "Current output voltage", NULL},
+       {SR_CONF_OUTPUT_VOLTAGE_MAX, SR_T_FLOAT, "output_voltage_max",
+               "Maximum output voltage", NULL},
+       {SR_CONF_OUTPUT_CURRENT, SR_T_FLOAT, "output_current",
+               "Current output current", NULL},
+       {SR_CONF_OUTPUT_CURRENT_MAX, SR_T_FLOAT, "output_current_max",
+               "Maximum output current", NULL},
+       {SR_CONF_OUTPUT_ENABLED, SR_T_BOOL, "output_enabled",
+               "Output enabled", NULL},
+       {SR_CONF_OUTPUT_CHANNEL, SR_T_STRING, "output_channel",
+               "Output channel modes", NULL},
+       {SR_CONF_OVER_VOLTAGE_PROTECTION, SR_T_BOOL, "ovp",
+               "Over-voltage protection", NULL},
+       {SR_CONF_OVER_CURRENT_PROTECTION, SR_T_BOOL, "ocp",
+               "Over-current protection", NULL},
+       {SR_CONF_LIMIT_SAMPLES, SR_T_UINT64, "limit_samples",
+               "Sample limit", NULL},
+       {SR_CONF_CLOCK_EDGE, SR_T_STRING, "clock_edge",
+               "Clock edge", NULL},
+       {0, 0, NULL, NULL, NULL},
+};
+
+/**
+ * Return the list of supported hardware drivers.
+ *
+ * @return Pointer to the NULL-terminated list of hardware driver pointers.
+ *
+ * @since 0.1.0
+ */
+SR_API struct sr_dev_driver **sr_driver_list(void)
+{
+
+       return drivers_list;
+}
+
+/**
+ * Initialize a hardware driver.
+ *
+ * This usually involves memory allocations and variable initializations
+ * within the driver, but _not_ scanning for attached devices.
+ * The API call sr_driver_scan() is used for that.
+ *
+ * @param ctx A libsigrok context object allocated by a previous call to
+ *            sr_init(). Must not be NULL.
+ * @param driver The driver to initialize. This must be a pointer to one of
+ *               the entries returned by sr_driver_list(). Must not be NULL.
+ *
+ * @retval SR_OK Success
+ * @retval SR_ERR_ARG Invalid parameter(s).
+ * @retval SR_ERR_BUG Internal errors.
+ * @retval other Another negative error code upon other errors.
+ *
+ * @since 0.2.0
+ */
+SR_API int sr_driver_init(struct sr_context *ctx, struct sr_dev_driver *driver)
+{
+       int ret;
+
+       if (!ctx) {
+               sr_err("Invalid libsigrok context, can't initialize.");
+               return SR_ERR_ARG;
+       }
+
+       if (!driver) {
+               sr_err("Invalid driver, can't initialize.");
+               return SR_ERR_ARG;
+       }
+
+       sr_spew("Initializing driver '%s'.", driver->name);
+       if ((ret = driver->init(ctx)) < 0)
+               sr_err("Failed to initialize the driver: %d.", ret);
+
+       return ret;
+}
+
+/**
+ * Tell a hardware driver to scan for devices.
+ *
+ * In addition to the detection, the devices that are found are also
+ * initialized automatically. On some devices, this involves a firmware upload,
+ * or other such measures.
+ *
+ * The order in which the system is scanned for devices is not specified. The
+ * caller should not assume or rely on any specific order.
+ *
+ * Before calling sr_driver_scan(), the user must have previously initialized
+ * the driver by calling sr_driver_init().
+ *
+ * @param driver The driver that should scan. This must be a pointer to one of
+ *               the entries returned by sr_driver_list(). Must not be NULL.
+ * @param options A list of 'struct sr_hwopt' options to pass to the driver's
+ *                scanner. Can be NULL/empty.
+ *
+ * @return A GSList * of 'struct sr_dev_inst', or NULL if no devices were
+ *         found (or errors were encountered). This list must be freed by the
+ *         caller using g_slist_free(), but without freeing the data pointed
+ *         to in the list.
+ *
+ * @since 0.2.0
+ */
+SR_API GSList *sr_driver_scan(struct sr_dev_driver *driver, GSList *options)
+{
+       GSList *l;
+
+       if (!driver) {
+               sr_err("Invalid driver, can't scan for devices.");
+               return NULL;
+       }
+
+       if (!driver->priv) {
+               sr_err("Driver not initialized, can't scan for devices.");
+               return NULL;
+       }
+
+       l = driver->scan(options);
+
+       sr_spew("Scan of '%s' found %d devices.", driver->name,
+               g_slist_length(l));
+
+       return l;
+}
+
+/** Call driver cleanup function for all drivers.
+ *  @private */
+SR_PRIV void sr_hw_cleanup_all(void)
+{
+       int i;
+       struct sr_dev_driver **drivers;
+
+       drivers = sr_driver_list();
+       for (i = 0; drivers[i]; i++) {
+               if (drivers[i]->cleanup)
+                       drivers[i]->cleanup();
+       }
+}
+
+/** Allocate struct sr_config.
+ *  A floating reference can be passed in for data.
+ *  @private
+ */
+SR_PRIV struct sr_config *sr_config_new(int key, GVariant *data)
+{
+       struct sr_config *src;
+
+       if (!(src = g_try_malloc(sizeof(struct sr_config))))
+               return NULL;
+       src->key = key;
+       src->data = g_variant_ref_sink(data);
+
+       return src;
+}
+
+/** Free struct sr_config.
+ *  @private
+ */
+SR_PRIV void sr_config_free(struct sr_config *src)
+{
+
+       if (!src || !src->data) {
+               sr_err("%s: invalid data!", __func__);
+               return;
+       }
+
+       g_variant_unref(src->data);
+       g_free(src);
+
+}
+
+/**
+ * Query value of a configuration key at the given driver or device instance.
+ *
+ * @param[in] driver The sr_dev_driver struct to query.
+ * @param[in] sdi (optional) If the key is specific to a device, this must
+ *            contain a pointer to the struct sr_dev_inst to be checked.
+ *            Otherwise it must be NULL.
+ * @param[in] cg The channel group on the device for which to list the
+ *                    values, or NULL.
+ * @param[in] key The configuration key (SR_CONF_*).
+ * @param[in,out] data Pointer to a GVariant where the value will be stored.
+ *             Must not be NULL. The caller is given ownership of the GVariant
+ *             and must thus decrease the refcount after use. However if
+ *             this function returns an error code, the field should be
+ *             considered unused, and should not be unreferenced.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR Error.
+ * @retval SR_ERR_ARG The driver doesn't know that key, but this is not to be
+ *          interpreted as an error by the caller; merely as an indication
+ *          that it's not applicable.
+ *
+ * @since 0.3.0
+ */
+SR_API int sr_config_get(const struct sr_dev_driver *driver,
+               const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg,
+               int key, GVariant **data)
+{
+       int ret;
+
+       if (!driver || !data)
+               return SR_ERR;
+
+       if (!driver->config_get)
+               return SR_ERR_ARG;
+
+       if ((ret = driver->config_get(key, data, sdi, cg)) == SR_OK) {
+               /* Got a floating reference from the driver. Sink it here,
+                * caller will need to unref when done with it. */
+               g_variant_ref_sink(*data);
+       }
+
+       return ret;
+}
+
+/**
+ * Set value of a configuration key in a device instance.
+ *
+ * @param[in] sdi The device instance.
+ * @param[in] cg The channel group on the device for which to list the
+ *                    values, or NULL.
+ * @param[in] key The configuration key (SR_CONF_*).
+ * @param data The new value for the key, as a GVariant with GVariantType
+ *        appropriate to that key. A floating reference can be passed
+ *        in; its refcount will be sunk and unreferenced after use.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR Error.
+ * @retval SR_ERR_ARG The driver doesn't know that key, but this is not to be
+ *          interpreted as an error by the caller; merely as an indication
+ *          that it's not applicable.
+ *
+ * @since 0.3.0
+ */
+SR_API int sr_config_set(const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg,
+               int key, GVariant *data)
+{
+       int ret;
+
+       g_variant_ref_sink(data);
+
+       if (!sdi || !sdi->driver || !data)
+               ret = SR_ERR;
+       else if (!sdi->driver->config_set)
+               ret = SR_ERR_ARG;
+       else
+               ret = sdi->driver->config_set(key, data, sdi, cg);
+
+       g_variant_unref(data);
+
+       return ret;
+}
+
+/**
+ * Apply configuration settings to the device hardware.
+ *
+ * @param sdi The device instance.
+ *
+ * @return SR_OK upon success or SR_ERR in case of error.
+ *
+ * @since 0.3.0
+ */
+SR_API int sr_config_commit(const struct sr_dev_inst *sdi)
+{
+       int ret;
+
+       if (!sdi || !sdi->driver)
+               ret = SR_ERR;
+       else if (!sdi->driver->config_commit)
+               ret = SR_OK;
+       else
+               ret = sdi->driver->config_commit(sdi);
+
+       return ret;
+}
+
+/**
+ * List all possible values for a configuration key.
+ *
+ * @param[in] driver The sr_dev_driver struct to query.
+ * @param[in] sdi (optional) If the key is specific to a device, this must
+ *            contain a pointer to the struct sr_dev_inst to be checked.
+ * @param[in] cg The channel group on the device for which to list the
+ *                    values, or NULL.
+ * @param[in] key The configuration key (SR_CONF_*).
+ * @param[in,out] data A pointer to a GVariant where the list will be stored.
+ *             The caller is given ownership of the GVariant and must thus
+ *             unref the GVariant after use. However if this function
+ *             returns an error code, the field should be considered
+ *             unused, and should not be unreferenced.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR Error.
+ * @retval SR_ERR_ARG The driver doesn't know that key, but this is not to be
+ *          interpreted as an error by the caller; merely as an indication
+ *          that it's not applicable.
+ *
+ * @since 0.3.0
+ */
+SR_API int sr_config_list(const struct sr_dev_driver *driver,
+               const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg,
+               int key, GVariant **data)
+{
+       int ret;
+
+       if (!driver || !data)
+               ret = SR_ERR;
+       else if (!driver->config_list)
+               ret = SR_ERR_ARG;
+       else if ((ret = driver->config_list(key, data, sdi, cg)) == SR_OK)
+               g_variant_ref_sink(*data);
+
+       return ret;
+}
+
+/**
+ * Get information about a configuration key, by key.
+ *
+ * @param[in] key The configuration key.
+ *
+ * @return A pointer to a struct sr_config_info, or NULL if the key
+ *         was not found.
+ *
+ * @since 0.2.0
+ */
+SR_API const struct sr_config_info *sr_config_info_get(int key)
+{
+       int i;
+
+       for (i = 0; sr_config_info_data[i].key; i++) {
+               if (sr_config_info_data[i].key == key)
+                       return &sr_config_info_data[i];
+       }
+
+       return NULL;
+}
+
+/**
+ * Get information about a configuration key, by name.
+ *
+ * @param[in] optname The configuration key.
+ *
+ * @return A pointer to a struct sr_config_info, or NULL if the key
+ *         was not found.
+ *
+ * @since 0.2.0
+ */
+SR_API const struct sr_config_info *sr_config_info_name_get(const char *optname)
+{
+       int i;
+
+       for (i = 0; sr_config_info_data[i].key; i++) {
+               if (!strcmp(sr_config_info_data[i].id, optname))
+                       return &sr_config_info_data[i];
+       }
+
+       return NULL;
+}
+
+/** @} */
diff --git a/src/input/binary.c b/src/input/binary.c
new file mode 100644 (file)
index 0000000..e0d4c1d
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert@biot.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 <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "input/binary"
+
+#define CHUNKSIZE             (512 * 1024)
+#define DEFAULT_NUM_CHANNELS  8
+
+struct context {
+       uint64_t samplerate;
+};
+
+static int format_match(const char *filename)
+{
+       (void)filename;
+
+       /* This module will handle anything you throw at it. */
+       return TRUE;
+}
+
+static int init(struct sr_input *in, const char *filename)
+{
+       struct sr_channel *ch;
+       int num_channels, i;
+       char name[SR_MAX_CHANNELNAME_LEN + 1];
+       char *param;
+       struct context *ctx;
+
+       (void)filename;
+
+       if (!(ctx = g_try_malloc0(sizeof(*ctx)))) {
+               sr_err("Input format context malloc failed.");
+               return SR_ERR_MALLOC;
+       }
+
+       num_channels = DEFAULT_NUM_CHANNELS;
+       ctx->samplerate = 0;
+
+       if (in->param) {
+               param = g_hash_table_lookup(in->param, "numchannels");
+               if (param) {
+                       num_channels = strtoul(param, NULL, 10);
+                       if (num_channels < 1)
+                               return SR_ERR;
+               }
+
+               param = g_hash_table_lookup(in->param, "samplerate");
+               if (param) {
+                       if (sr_parse_sizestring(param, &ctx->samplerate) != SR_OK)
+                               return SR_ERR;
+               }
+       }
+
+       /* Create a virtual device. */
+       in->sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, NULL, NULL, NULL);
+       in->internal = ctx;
+
+       for (i = 0; i < num_channels; i++) {
+               snprintf(name, SR_MAX_CHANNELNAME_LEN, "%d", i);
+               /* TODO: Check return value. */
+               if (!(ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE, name)))
+                       return SR_ERR;
+               in->sdi->channels = g_slist_append(in->sdi->channels, ch);
+       }
+
+       return SR_OK;
+}
+
+static int loadfile(struct sr_input *in, const char *filename)
+{
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_meta meta;
+       struct sr_datafeed_logic logic;
+       struct sr_config *src;
+       unsigned char buffer[CHUNKSIZE];
+       int fd, size, num_channels;
+       struct context *ctx;
+
+       ctx = in->internal;
+
+       if ((fd = open(filename, O_RDONLY)) == -1)
+               return SR_ERR;
+
+       num_channels = g_slist_length(in->sdi->channels);
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(in->sdi, LOG_PREFIX);
+
+       if (ctx->samplerate) {
+               packet.type = SR_DF_META;
+               packet.payload = &meta;
+               src = sr_config_new(SR_CONF_SAMPLERATE,
+                               g_variant_new_uint64(ctx->samplerate));
+               meta.config = g_slist_append(NULL, src);
+               sr_session_send(in->sdi, &packet);
+               sr_config_free(src);
+       }
+
+       /* Chop up the input file into chunks & send it to the session bus. */
+       packet.type = SR_DF_LOGIC;
+       packet.payload = &logic;
+       logic.unitsize = (num_channels + 7) / 8;
+       logic.data = buffer;
+       while ((size = read(fd, buffer, CHUNKSIZE)) > 0) {
+               logic.length = size;
+               sr_session_send(in->sdi, &packet);
+       }
+       close(fd);
+
+       /* Send end packet to the session bus. */
+       packet.type = SR_DF_END;
+       sr_session_send(in->sdi, &packet);
+
+       g_free(ctx);
+       in->internal = NULL;
+
+       return SR_OK;
+}
+
+SR_PRIV struct sr_input_format input_binary = {
+       .id = "binary",
+       .description = "Raw binary",
+       .format_match = format_match,
+       .init = init,
+       .loadfile = loadfile,
+};
diff --git a/src/input/chronovu_la8.c b/src/input/chronovu_la8.c
new file mode 100644 (file)
index 0000000..dcedcf8
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2011 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "input/chronovu-la8"
+
+#define NUM_PACKETS            2048
+#define PACKET_SIZE            4096
+#define DEFAULT_NUM_CHANNELS   8
+
+/**
+ * Convert the LA8 'divcount' value to the respective samplerate (in Hz).
+ *
+ * LA8 hardware: sample period = (divcount + 1) * 10ns.
+ * Min. value for divcount: 0x00 (10ns sample period, 100MHz samplerate).
+ * Max. value for divcount: 0xfe (2550ns sample period, 392.15kHz samplerate).
+ *
+ * @param divcount The divcount value as needed by the hardware.
+ *
+ * @return The samplerate in Hz, or 0xffffffffffffffff upon errors.
+ */
+static uint64_t divcount_to_samplerate(uint8_t divcount)
+{
+       if (divcount == 0xff)
+               return 0xffffffffffffffffULL;
+
+       return SR_MHZ(100) / (divcount + 1);
+}
+
+static int format_match(const char *filename)
+{
+       struct stat stat_buf;
+       int ret;
+
+       if (!filename) {
+               sr_err("%s: filename was NULL", __func__);
+               // return SR_ERR; /* FIXME */
+               return FALSE;
+       }
+
+       if (!g_file_test(filename, G_FILE_TEST_EXISTS)) {
+               sr_err("%s: input file '%s' does not exist",
+                      __func__, filename);
+               // return SR_ERR; /* FIXME */
+               return FALSE;
+       }
+
+       if (!g_file_test(filename, G_FILE_TEST_IS_REGULAR)) {
+               sr_err("%s: input file '%s' not a regular file",
+                      __func__, filename);
+               // return SR_ERR; /* FIXME */
+               return FALSE;
+       }
+
+       /* Only accept files of length 8MB + 5 bytes. */
+       ret = stat(filename, &stat_buf);
+       if (ret != 0) {
+               sr_err("%s: Error getting file size of '%s'",
+                      __func__, filename);
+               return FALSE;
+       }
+       if (stat_buf.st_size != (8 * 1024 * 1024 + 5)) {
+               sr_dbg("%s: File size must be exactly 8388613 bytes ("
+                      "it actually is %d bytes in size), so this is not a "
+                      "ChronoVu LA8 file.", __func__, stat_buf.st_size);
+               return FALSE;
+       }
+
+       /* TODO: Check for divcount != 0xff. */
+
+       return TRUE;
+}
+
+static int init(struct sr_input *in, const char *filename)
+{
+       struct sr_channel *ch;
+       int num_channels, i;
+       char name[SR_MAX_CHANNELNAME_LEN + 1];
+       char *param;
+
+       (void)filename;
+
+       num_channels = DEFAULT_NUM_CHANNELS;
+
+       if (in->param) {
+               param = g_hash_table_lookup(in->param, "numchannels");
+               if (param) {
+                       num_channels = strtoul(param, NULL, 10);
+                       if (num_channels < 1) {
+                               sr_err("%s: strtoul failed", __func__);
+                               return SR_ERR;
+                       }
+               }
+       }
+
+       /* Create a virtual device. */
+       in->sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, NULL, NULL, NULL);
+
+       for (i = 0; i < num_channels; i++) {
+               snprintf(name, SR_MAX_CHANNELNAME_LEN, "%d", i);
+               /* TODO: Check return value. */
+               if (!(ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE, name)))
+                       return SR_ERR;
+               in->sdi->channels = g_slist_append(in->sdi->channels, ch);
+       }
+
+       return SR_OK;
+}
+
+static int loadfile(struct sr_input *in, const char *filename)
+{
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_meta meta;
+       struct sr_datafeed_logic logic;
+       struct sr_config *src;
+       uint8_t buf[PACKET_SIZE], divcount;
+       int i, fd, size, num_channels;
+       uint64_t samplerate;
+
+       /* TODO: Use glib functions! GIOChannel, g_fopen, etc. */
+       if ((fd = open(filename, O_RDONLY)) == -1) {
+               sr_err("%s: file open failed", __func__);
+               return SR_ERR;
+       }
+
+       num_channels = g_slist_length(in->sdi->channels);
+
+       /* Seek to the end of the file, and read the divcount byte. */
+       divcount = 0x00; /* TODO: Don't hardcode! */
+
+       /* Convert the divcount value to a samplerate. */
+       samplerate = divcount_to_samplerate(divcount);
+       if (samplerate == 0xffffffffffffffffULL) {
+               close(fd); /* FIXME */
+               return SR_ERR;
+       }
+       sr_dbg("%s: samplerate is %" PRIu64, __func__, samplerate);
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(in->sdi, LOG_PREFIX);
+
+       /* Send metadata about the SR_DF_LOGIC packets to come. */
+       packet.type = SR_DF_META;
+       packet.payload = &meta;
+       src = sr_config_new(SR_CONF_SAMPLERATE, g_variant_new_uint64(samplerate));
+       meta.config = g_slist_append(NULL, src);
+       sr_session_send(in->sdi, &packet);
+       sr_config_free(src);
+
+       /* TODO: Handle trigger point. */
+
+       /* Send data packets to the session bus. */
+       sr_dbg("%s: sending SR_DF_LOGIC data packets", __func__);
+       packet.type = SR_DF_LOGIC;
+       packet.payload = &logic;
+       logic.unitsize = (num_channels + 7) / 8;
+       logic.data = buf;
+
+       /* Send 8MB of total data to the session bus in small chunks. */
+       for (i = 0; i < NUM_PACKETS; i++) {
+               /* TODO: Handle errors, handle incomplete reads. */
+               size = read(fd, buf, PACKET_SIZE);
+               logic.length = size;
+               sr_session_send(in->sdi, &packet);
+       }
+       close(fd); /* FIXME */
+
+       /* Send end packet to the session bus. */
+       sr_dbg("%s: sending SR_DF_END", __func__);
+       packet.type = SR_DF_END;
+       packet.payload = NULL;
+       sr_session_send(in->sdi, &packet);
+
+       return SR_OK;
+}
+
+SR_PRIV struct sr_input_format input_chronovu_la8 = {
+       .id = "chronovu-la8",
+       .description = "ChronoVu LA8",
+       .format_match = format_match,
+       .init = init,
+       .loadfile = loadfile,
+};
diff --git a/src/input/csv.c b/src/input/csv.c
new file mode 100644 (file)
index 0000000..6dd06f4
--- /dev/null
@@ -0,0 +1,868 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Marc Schink <sigrok-dev@marcschink.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 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 <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "input/csv"
+
+/*
+ * The CSV input module has the following options:
+ *
+ * single-column: Specifies the column number which stores the sample data for
+ *                single column mode and enables single column mode. Multi
+ *                column mode is used if this parameter is omitted.
+ *
+ * numchannels:   Specifies the number of channels to use. In multi column mode
+ *                the number of channels are the number of columns and in single
+ *                column mode the number of bits (LSB first) beginning at
+ *                'first-channel'.
+ *
+ * delimiter:     Specifies the delimiter for columns. Must be at least one
+ *                character. Comma is used as default delimiter.
+ *
+ * format:        Specifies the format of the sample data in single column mode.
+ *                Available formats are: 'bin', 'hex' and 'oct'. The binary
+ *                format is used by default. This option has no effect in multi
+ *                column mode.
+ *
+ * comment:       Specifies the prefix character(s) for comments. No prefix
+ *                characters are used by default which disables removing of
+ *                comments.
+ *
+ * samplerate:    Samplerate which the sample data was captured with. Default
+ *                value is 0.
+ *
+ * first-channel: Column number of the first channel in multi column mode and
+ *                position of the bit for the first channel in single column mode.
+ *                Default value is 0.
+ *
+ * header:        Determines if the first line should be treated as header
+ *                and used for channel names in multi column mode. Empty header
+ *                names will be replaced by the channel number. If enabled in
+ *                single column mode the first line will be skipped. Usage of
+ *                header is disabled by default.
+ *
+ * startline:     Line number to start processing sample data. Must be greater
+ *                than 0. The default line number to start processing is 1.
+ */
+
+/* Single column formats. */
+enum {
+       FORMAT_BIN,
+       FORMAT_HEX,
+       FORMAT_OCT
+};
+
+struct context {
+       /* Current selected samplerate. */
+       uint64_t samplerate;
+
+       /* Number of channels. */
+       gsize num_channels;
+
+       /* Column delimiter character(s). */
+       GString *delimiter;
+
+       /* Comment prefix character(s). */
+       GString *comment;
+
+       /* Determines if sample data is stored in multiple columns. */
+       gboolean multi_column_mode;
+
+       /* Column number of the sample data in single column mode. */
+       gsize single_column;
+
+       /*
+        * Number of the first column to parse. Equivalent to the number of the
+        * first channel in multi column mode and the single column number in
+        * single column mode.
+        */
+       gsize first_column;
+
+       /*
+        * Column number of the first channel in multi column mode and position of
+        * the bit for the first channel in single column mode.
+        */
+       gsize first_channel;
+
+       /* Line number to start processing. */
+       gsize start_line;
+
+       /*
+        * Determines if the first line should be treated as header and used for
+        * channel names in multi column mode.
+        */
+       gboolean header;
+
+       /* Format sample data is stored in single column mode. */
+       int format;
+
+       /* Size of the sample buffer. */
+       gsize sample_buffer_size;
+
+       /* Buffer to store sample data. */
+       uint8_t *sample_buffer;
+
+       GIOChannel *channel;
+
+       /* Buffer for the current line. */
+       GString *buffer;
+
+       /* Current line number. */
+       gsize line_number;
+};
+
+static int format_match(const char *filename)
+{
+       if (!filename) {
+               sr_err("%s: filename was NULL.", __func__);
+               return FALSE;
+       }
+
+       if (!g_file_test(filename, G_FILE_TEST_EXISTS)) {
+               sr_err("Input file '%s' does not exist.", filename);
+               return FALSE;
+       }
+
+       if (!g_file_test(filename, G_FILE_TEST_IS_REGULAR)) {
+               sr_err("Input file '%s' not a regular file.", filename);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+static void free_context(struct context *ctx)
+{
+       if (!ctx)
+               return;
+
+       if (ctx->delimiter)
+               g_string_free(ctx->delimiter, TRUE);
+
+       if (ctx->comment)
+               g_string_free(ctx->comment, TRUE);
+
+       if (ctx->channel) {
+               g_io_channel_shutdown(ctx->channel, FALSE, NULL);
+               g_io_channel_unref(ctx->channel);
+       }
+
+       if (ctx->sample_buffer)
+               g_free(ctx->sample_buffer);
+
+       if (ctx->buffer)
+               g_string_free(ctx->buffer, TRUE);
+
+       g_free(ctx);
+}
+
+static void strip_comment(GString *string, const GString *prefix)
+{
+       char *ptr;
+
+       if (!prefix->len)
+               return;
+
+       if (!(ptr = strstr(string->str, prefix->str)))
+               return;
+
+       g_string_truncate(string, ptr - string->str);
+}
+
+static int parse_binstr(const char *str, struct context *ctx)
+{
+       gsize i, j, length;
+
+       length = strlen(str);
+
+       if (!length) {
+               sr_err("Column %zu in line %zu is empty.", ctx->single_column,
+                       ctx->line_number);
+               return SR_ERR;
+       }
+
+       /* Clear buffer in order to set bits only. */
+       memset(ctx->sample_buffer, 0, (ctx->num_channels + 7) >> 3);
+
+       i = ctx->first_channel;
+
+       for (j = 0; i < length && j < ctx->num_channels; i++, j++) {
+               if (str[length - i - 1] == '1') {
+                       ctx->sample_buffer[j / 8] |= (1 << (j % 8));
+               } else if (str[length - i - 1] != '0') {
+                       sr_err("Invalid value '%s' in column %zu in line %zu.",
+                               str, ctx->single_column, ctx->line_number);
+                       return SR_ERR;
+               }
+       }
+
+       return SR_OK;
+}
+
+static int parse_hexstr(const char *str, struct context *ctx)
+{
+       gsize i, j, k, length;
+       uint8_t value;
+       char c;
+
+       length = strlen(str);
+
+       if (!length) {
+               sr_err("Column %zu in line %zu is empty.", ctx->single_column,
+                       ctx->line_number);
+               return SR_ERR;
+       }
+
+       /* Clear buffer in order to set bits only. */
+       memset(ctx->sample_buffer, 0, (ctx->num_channels + 7) >> 3);
+
+       /* Calculate the position of the first hexadecimal digit. */
+       i = ctx->first_channel / 4;
+
+       for (j = 0; i < length && j < ctx->num_channels; i++) {
+               c = str[length - i - 1];
+
+               if (!g_ascii_isxdigit(c)) {
+                       sr_err("Invalid value '%s' in column %zu in line %zu.",
+                               str, ctx->single_column, ctx->line_number);
+                       return SR_ERR;
+               }
+
+               value = g_ascii_xdigit_value(c);
+
+               k = (ctx->first_channel + j) % 4;
+
+               for (; j < ctx->num_channels && k < 4; k++) {
+                       if (value & (1 << k))
+                               ctx->sample_buffer[j / 8] |= (1 << (j % 8));
+
+                       j++;
+               }
+       }
+
+       return SR_OK;
+}
+
+static int parse_octstr(const char *str, struct context *ctx)
+{
+       gsize i, j, k, length;
+       uint8_t value;
+       char c;
+
+       length = strlen(str);
+
+       if (!length) {
+               sr_err("Column %zu in line %zu is empty.", ctx->single_column,
+                       ctx->line_number);
+               return SR_ERR;
+       }
+
+       /* Clear buffer in order to set bits only. */
+       memset(ctx->sample_buffer, 0, (ctx->num_channels + 7) >> 3);
+
+       /* Calculate the position of the first octal digit. */
+       i = ctx->first_channel / 3;
+
+       for (j = 0; i < length && j < ctx->num_channels; i++) {
+               c = str[length - i - 1];
+
+               if (c < '0' || c > '7') {
+                       sr_err("Invalid value '%s' in column %zu in line %zu.",
+                               str, ctx->single_column, ctx->line_number);
+                       return SR_ERR;
+               }
+
+               value = g_ascii_xdigit_value(c);
+
+               k = (ctx->first_channel + j) % 3;
+
+               for (; j < ctx->num_channels && k < 3; k++) {
+                       if (value & (1 << k))
+                               ctx->sample_buffer[j / 8] |= (1 << (j % 8));
+
+                       j++;
+               }
+       }
+
+       return SR_OK;
+}
+
+static char **parse_line(const struct context *ctx, int max_columns)
+{
+       const char *str, *remainder;
+       GSList *list, *l;
+       char **columns;
+       char *column;
+       gsize n, k;
+
+       n = 0;
+       k = 0;
+       list = NULL;
+
+       remainder = ctx->buffer->str;
+       str = strstr(remainder, ctx->delimiter->str);
+
+       while (str && max_columns) {
+               if (n >= ctx->first_column) {
+                       column = g_strndup(remainder, str - remainder);
+                       list = g_slist_prepend(list, g_strstrip(column));
+
+                       max_columns--;
+                       k++;
+               }
+
+               remainder = str + ctx->delimiter->len;
+               str = strstr(remainder, ctx->delimiter->str);
+               n++;
+       }
+
+       if (ctx->buffer->len && max_columns && n >= ctx->first_column) {
+               column = g_strdup(remainder);
+               list = g_slist_prepend(list, g_strstrip(column));
+               k++;
+       }
+
+       if (!(columns = g_try_new(char *, k + 1)))
+               return NULL;
+
+       columns[k--] = NULL;
+
+       for (l = list; l; l = l->next)
+               columns[k--] = l->data;
+
+       g_slist_free(list);
+
+       return columns;
+}
+
+static int parse_multi_columns(char **columns, struct context *ctx)
+{
+       gsize i;
+
+       /* Clear buffer in order to set bits only. */
+       memset(ctx->sample_buffer, 0, (ctx->num_channels + 7) >> 3);
+
+       for (i = 0; i < ctx->num_channels; i++) {
+               if (columns[i][0] == '1') {
+                       ctx->sample_buffer[i / 8] |= (1 << (i % 8));
+               } else if (!strlen(columns[i])) {
+                       sr_err("Column %zu in line %zu is empty.",
+                               ctx->first_channel + i, ctx->line_number);
+                       return SR_ERR;
+               } else if (columns[i][0] != '0') {
+                       sr_err("Invalid value '%s' in column %zu in line %zu.",
+                               columns[i], ctx->first_channel + i,
+                               ctx->line_number);
+                       return SR_ERR;
+               }
+       }
+
+       return SR_OK;
+}
+
+static int parse_single_column(const char *column, struct context *ctx)
+{
+       int res;
+
+       res = SR_ERR;
+
+       switch(ctx->format) {
+       case FORMAT_BIN:
+               res = parse_binstr(column, ctx);
+               break;
+       case FORMAT_HEX:
+               res = parse_hexstr(column, ctx);
+               break;
+       case FORMAT_OCT:
+               res = parse_octstr(column, ctx);
+               break;
+       }
+
+       return res;
+}
+
+static int send_samples(const struct sr_dev_inst *sdi, uint8_t *buffer,
+                       gsize buffer_size, gsize count)
+{
+       int res;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_logic logic;
+       gsize i;
+
+       packet.type = SR_DF_LOGIC;
+       packet.payload = &logic;
+       logic.unitsize = buffer_size;
+       logic.length = buffer_size;
+       logic.data = buffer;
+
+       for (i = 0; i < count; i++) {
+               if ((res = sr_session_send(sdi, &packet)) != SR_OK)
+                       return res;
+       }
+
+       return SR_OK;
+}
+
+static int init(struct sr_input *in, const char *filename)
+{
+       int res;
+       struct context *ctx;
+       const char *param;
+       GIOStatus status;
+       gsize i, term_pos;
+       char channel_name[SR_MAX_CHANNELNAME_LEN + 1];
+       struct sr_channel *ch;
+       char **columns;
+       gsize num_columns;
+       char *ptr;
+
+       if (!(ctx = g_try_malloc0(sizeof(struct context)))) {
+               sr_err("Context malloc failed.");
+               return SR_ERR_MALLOC;
+       }
+
+       /* Create a virtual device. */
+       in->sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, NULL, NULL, NULL);
+       in->internal = ctx;
+
+       /* Set default samplerate. */
+       ctx->samplerate = 0;
+
+       /*
+        * Enable auto-detection of the number of channels in multi column mode
+        * and enforce the specification of the number of channels in single
+        * column mode.
+        */
+       ctx->num_channels = 0;
+
+       /* Set default delimiter. */
+       if (!(ctx->delimiter = g_string_new(","))) {
+               sr_err("Delimiter malloc failed.");
+               free_context(ctx);
+               return SR_ERR_MALLOC;
+       }
+
+       /*
+        * Set default comment prefix. Note that an empty comment prefix
+        * disables removing of comments.
+        */
+       if (!(ctx->comment = g_string_new(""))) {
+               sr_err("Comment malloc failed.");
+               free_context(ctx);
+               return SR_ERR_MALLOC;
+       }
+
+       /* Enable multi column mode by default. */
+       ctx->multi_column_mode = TRUE;
+
+       /* Use first column as default single column number. */
+       ctx->single_column = 0;
+
+       /*
+        * In multi column mode start parsing sample data at the first column
+        * and in single column mode at the first bit.
+        */
+       ctx->first_channel = 0;
+
+       /* Start at the beginning of the file. */
+       ctx->start_line = 1;
+
+       /* Disable the usage of the first line as header by default. */
+       ctx->header = FALSE;
+
+       /* Set default format for single column mode. */
+       ctx->format = FORMAT_BIN;
+
+       if (!(ctx->buffer = g_string_new(""))) {
+               sr_err("Line buffer malloc failed.");
+               free_context(ctx);
+               return SR_ERR_MALLOC;
+       }
+
+       if (in->param) {
+               if ((param = g_hash_table_lookup(in->param, "samplerate"))) {
+                       res = sr_parse_sizestring(param, &ctx->samplerate);
+
+                       if (res != SR_OK) {
+                               sr_err("Invalid samplerate: %s.", param);
+                               free_context(ctx);
+                               return SR_ERR_ARG;
+                       }
+               }
+
+               if ((param = g_hash_table_lookup(in->param, "numchannels")))
+                       ctx->num_channels = g_ascii_strtoull(param, NULL, 10);
+
+               if ((param = g_hash_table_lookup(in->param, "delimiter"))) {
+                       if (!strlen(param)) {
+                               sr_err("Delimiter must be at least one character.");
+                               free_context(ctx);
+                               return SR_ERR_ARG;
+                       }
+
+                       if (!g_ascii_strcasecmp(param, "\\t"))
+                               g_string_assign(ctx->delimiter, "\t");
+                       else
+                               g_string_assign(ctx->delimiter, param);
+               }
+
+               if ((param = g_hash_table_lookup(in->param, "comment")))
+                       g_string_assign(ctx->comment, param);
+
+               if ((param = g_hash_table_lookup(in->param, "single-column"))) {
+                       ctx->single_column = g_ascii_strtoull(param, &ptr, 10);
+                       ctx->multi_column_mode = FALSE;
+
+                       if (param == ptr) {
+                               sr_err("Invalid single-colum number: %s.",
+                                       param);
+                               free_context(ctx);
+                               return SR_ERR_ARG;
+                       }
+               }
+
+               if ((param = g_hash_table_lookup(in->param, "first-channel")))
+                       ctx->first_channel = g_ascii_strtoull(param, NULL, 10);
+
+               if ((param = g_hash_table_lookup(in->param, "startline"))) {
+                       ctx->start_line = g_ascii_strtoull(param, NULL, 10);
+
+                       if (ctx->start_line < 1) {
+                               sr_err("Invalid start line: %s.", param);
+                               free_context(ctx);
+                               return SR_ERR_ARG;
+                       }
+               }
+
+               if ((param = g_hash_table_lookup(in->param, "header")))
+                       ctx->header = sr_parse_boolstring(param);
+
+               if ((param = g_hash_table_lookup(in->param, "format"))) {
+                       if (!g_ascii_strncasecmp(param, "bin", 3)) {
+                               ctx->format = FORMAT_BIN;
+                       } else if (!g_ascii_strncasecmp(param, "hex", 3)) {
+                               ctx->format = FORMAT_HEX;
+                       } else if (!g_ascii_strncasecmp(param, "oct", 3)) {
+                               ctx->format = FORMAT_OCT;
+                       } else {
+                               sr_err("Invalid format: %s.", param);
+                               free_context(ctx);
+                               return SR_ERR;
+                       }
+               }
+       }
+
+       if (ctx->multi_column_mode)
+               ctx->first_column = ctx->first_channel;
+       else
+               ctx->first_column = ctx->single_column;
+
+       if (!ctx->multi_column_mode && !ctx->num_channels) {
+               sr_err("Number of channels needs to be specified in single column mode.");
+               free_context(ctx);
+               return SR_ERR;
+       }
+
+       if (!(ctx->channel = g_io_channel_new_file(filename, "r", NULL))) {
+               sr_err("Input file '%s' could not be opened.", filename);
+               free_context(ctx);
+               return SR_ERR;
+       }
+
+       while (TRUE) {
+               ctx->line_number++;
+               status = g_io_channel_read_line_string(ctx->channel,
+                       ctx->buffer, &term_pos, NULL);
+
+               if (status == G_IO_STATUS_EOF) {
+                       sr_err("Input file is empty.");
+                       free_context(ctx);
+                       return SR_ERR;
+               }
+
+               if (status != G_IO_STATUS_NORMAL) {
+                       sr_err("Error while reading line %zu.",
+                               ctx->line_number);
+                       free_context(ctx);
+                       return SR_ERR;
+               }
+
+               if (ctx->start_line > ctx->line_number) {
+                       sr_spew("Line %zu skipped.", ctx->line_number);
+                       continue;
+               }
+
+               /* Remove line termination character(s). */
+               g_string_truncate(ctx->buffer, term_pos);
+
+               if (!ctx->buffer->len) {
+                       sr_spew("Blank line %zu skipped.", ctx->line_number);
+                       continue;
+               }
+
+               /* Remove trailing comment. */
+               strip_comment(ctx->buffer, ctx->comment);
+
+               if (ctx->buffer->len)
+                       break;
+
+               sr_spew("Comment-only line %zu skipped.", ctx->line_number);
+       }
+
+       /*
+        * In order to determine the number of columns parse the current line
+        * without limiting the number of columns.
+        */
+       if (!(columns = parse_line(ctx, -1))) {
+               sr_err("Error while parsing line %zu.", ctx->line_number);
+               free_context(ctx);
+               return SR_ERR;
+       }
+
+       num_columns = g_strv_length(columns);
+
+       /* Ensure that the first column is not out of bounds. */
+       if (!num_columns) {
+               sr_err("Column %zu in line %zu is out of bounds.",
+                       ctx->first_column, ctx->line_number);
+               g_strfreev(columns);
+               free_context(ctx);
+               return SR_ERR;
+       }
+
+       if (ctx->multi_column_mode) {
+               /*
+                * Detect the number of channels in multi column mode
+                * automatically if not specified.
+                */
+               if (!ctx->num_channels) {
+                       ctx->num_channels = num_columns;
+                       sr_info("Number of auto-detected channels: %zu.",
+                               ctx->num_channels);
+               }
+
+               /*
+                * Ensure that the number of channels does not exceed the number
+                * of columns in multi column mode.
+                */
+               if (num_columns < ctx->num_channels) {
+                       sr_err("Not enough columns for desired number of channels in line %zu.",
+                               ctx->line_number);
+                       g_strfreev(columns);
+                       free_context(ctx);
+                       return SR_ERR;
+               }
+       }
+
+       for (i = 0; i < ctx->num_channels; i++) {
+               if (ctx->header && ctx->multi_column_mode && strlen(columns[i]))
+                       snprintf(channel_name, sizeof(channel_name), "%s",
+                               columns[i]);
+               else
+                       snprintf(channel_name, sizeof(channel_name), "%zu", i);
+
+               ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE, channel_name);
+
+               if (!ch) {
+                       sr_err("Channel creation failed.");
+                       free_context(ctx);
+                       g_strfreev(columns);
+                       return SR_ERR;
+               }
+
+               in->sdi->channels = g_slist_append(in->sdi->channels, ch);
+       }
+
+       g_strfreev(columns);
+
+       /*
+        * Calculate the minimum buffer size to store the sample data of the
+        * channels.
+        */
+       ctx->sample_buffer_size = (ctx->num_channels + 7) >> 3;
+
+       if (!(ctx->sample_buffer = g_try_malloc(ctx->sample_buffer_size))) {
+               sr_err("Sample buffer malloc failed.");
+               free_context(ctx);
+               return SR_ERR_MALLOC;
+       }
+
+       return SR_OK;
+}
+
+static int loadfile(struct sr_input *in, const char *filename)
+{
+       int res;
+       struct context *ctx;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_meta meta;
+       struct sr_config *cfg;
+       GIOStatus status;
+       gboolean read_new_line;
+       gsize term_pos;
+       char **columns;
+       gsize num_columns;
+       int max_columns;
+
+       (void)filename;
+
+       ctx = in->internal;
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(in->sdi, LOG_PREFIX);
+
+       if (ctx->samplerate) {
+               packet.type = SR_DF_META;
+               packet.payload = &meta;
+               cfg = sr_config_new(SR_CONF_SAMPLERATE,
+                       g_variant_new_uint64(ctx->samplerate));
+               meta.config = g_slist_append(NULL, cfg);
+               sr_session_send(in->sdi, &packet);
+               sr_config_free(cfg);
+       }
+
+       read_new_line = FALSE;
+
+       /* Limit the number of columns to parse. */
+       if (ctx->multi_column_mode)
+               max_columns = ctx->num_channels;
+       else
+               max_columns = 1;
+
+       while (TRUE) {
+               /*
+                * Skip reading a new line for the first time if the last read
+                * line was not a header because the sample data is not parsed
+                * yet.
+                */
+               if (read_new_line || ctx->header) {
+                       ctx->line_number++;
+                       status = g_io_channel_read_line_string(ctx->channel,
+                               ctx->buffer, &term_pos, NULL);
+
+                       if (status == G_IO_STATUS_EOF)
+                               break;
+
+                       if (status != G_IO_STATUS_NORMAL) {
+                               sr_err("Error while reading line %zu.",
+                                       ctx->line_number);
+                               free_context(ctx);
+                               return SR_ERR;
+                       }
+
+                       /* Remove line termination character(s). */
+                       g_string_truncate(ctx->buffer, term_pos);
+               }
+
+               read_new_line = TRUE;
+
+               if (!ctx->buffer->len) {
+                       sr_spew("Blank line %zu skipped.", ctx->line_number);
+                       continue;
+               }
+
+               /* Remove trailing comment. */
+               strip_comment(ctx->buffer, ctx->comment);
+
+               if (!ctx->buffer->len) {
+                       sr_spew("Comment-only line %zu skipped.",
+                               ctx->line_number);
+                       continue;
+               }
+
+               if (!(columns = parse_line(ctx, max_columns))) {
+                       sr_err("Error while parsing line %zu.",
+                               ctx->line_number);
+                       free_context(ctx);
+                       return SR_ERR;
+               }
+
+               num_columns = g_strv_length(columns);
+
+               /* Ensure that the first column is not out of bounds. */
+               if (!num_columns) {
+                       sr_err("Column %zu in line %zu is out of bounds.",
+                               ctx->first_column, ctx->line_number);
+                       g_strfreev(columns);
+                       free_context(ctx);
+                       return SR_ERR;
+               }
+
+               /*
+                * Ensure that the number of channels does not exceed the number
+                * of columns in multi column mode.
+                */
+               if (ctx->multi_column_mode && num_columns < ctx->num_channels) {
+                       sr_err("Not enough columns for desired number of channels in line %zu.",
+                               ctx->line_number);
+                       g_strfreev(columns);
+                       free_context(ctx);
+                       return SR_ERR;
+               }
+
+               if (ctx->multi_column_mode)
+                       res = parse_multi_columns(columns, ctx);
+               else
+                       res = parse_single_column(columns[0], ctx);
+
+               if (res != SR_OK) {
+                       g_strfreev(columns);
+                       free_context(ctx);
+                       return SR_ERR;
+               }
+
+               g_strfreev(columns);
+
+               /*
+                * TODO: Parse sample numbers / timestamps and use it for
+                * decompression.
+                */
+
+               /* Send sample data to the session bus. */
+               res = send_samples(in->sdi, ctx->sample_buffer,
+                       ctx->sample_buffer_size, 1);
+
+               if (res != SR_OK) {
+                       sr_err("Sending samples failed.");
+                       free_context(ctx);
+                       return SR_ERR;
+               }
+       }
+
+       /* Send end packet to the session bus. */
+       packet.type = SR_DF_END;
+       sr_session_send(in->sdi, &packet);
+
+       free_context(ctx);
+
+       return SR_OK;
+}
+
+SR_PRIV struct sr_input_format input_csv = {
+       .id = "csv",
+       .description = "Comma-separated values (CSV)",
+       .format_match = format_match,
+       .init = init,
+       .loadfile = loadfile,
+};
diff --git a/src/input/input.c b/src/input/input.c
new file mode 100644 (file)
index 0000000..d22b373
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.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 "libsigrok.h"
+#include "libsigrok-internal.h"
+
+/**
+ * @file
+ *
+ * Input file/data format handling.
+ */
+
+/**
+ * @defgroup grp_input Input formats
+ *
+ * Input file/data format handling.
+ *
+ * libsigrok can process acquisition data in several different ways.
+ * Aside from acquiring data from a hardware device, it can also take it from
+ * a file in various formats (binary, CSV, VCD, and so on).
+ *
+ * Like everything in libsigrok that handles data, processing is done in a
+ * streaming manner -- input should be supplied to libsigrok a chunk at a time.
+ * This way anything that processes data can do so in real time, without the
+ * user having to wait for the whole thing to be finished.
+ *
+ * Every input module is "pluggable", meaning it's handled as being separate
+ * from the main libsigrok, but linked in to it statically. To keep things
+ * modular and separate like this, functions within an input module should be
+ * declared static, with only the respective 'struct sr_input_format' being
+ * exported for use into the wider libsigrok namespace.
+ *
+ * @{
+ */
+
+/** @cond PRIVATE */
+extern SR_PRIV struct sr_input_format input_chronovu_la8;
+extern SR_PRIV struct sr_input_format input_csv;
+extern SR_PRIV struct sr_input_format input_binary;
+extern SR_PRIV struct sr_input_format input_vcd;
+extern SR_PRIV struct sr_input_format input_wav;
+/* @endcond */
+
+static struct sr_input_format *input_module_list[] = {
+       &input_vcd,
+       &input_chronovu_la8,
+       &input_wav,
+       &input_csv,
+       /* This one has to be last, because it will take any input. */
+       &input_binary,
+       NULL,
+};
+
+/** @since 0.1.0 */
+SR_API struct sr_input_format **sr_input_list(void)
+{
+       return input_module_list;
+}
+
+/** @} */
diff --git a/src/input/vcd.c b/src/input/vcd.c
new file mode 100644 (file)
index 0000000..6759d73
--- /dev/null
@@ -0,0 +1,546 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Petteri Aimonen <jpa@sr.mail.kapsi.fi>
+ *
+ * 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/>.
+ */
+
+/* The VCD input module has the following options:
+ *
+ * numchannels: Maximum number of channels to use. The channels are
+ *              detected in the same order as they are listed
+ *              in the $var sections of the VCD file.
+ *
+ * skip:        Allows skipping until given timestamp in the file.
+ *              This can speed up analyzing of long captures.
+ *            
+ *              Value < 0: Skip until first timestamp listed in
+ *              the file. (default)
+ *
+ *              Value = 0: Do not skip, instead generate samples
+ *              beginning from timestamp 0.
+ *
+ *              Value > 0: Start at the given timestamp.
+ *
+ * downsample:  Divide the samplerate by the given factor.
+ *              This can speed up analyzing of long captures.
+ *
+ * compress:    Compress idle periods longer than this value.
+ *              This can speed up analyzing of long captures.
+ *              Default 0 = don't compress.
+ *
+ * Based on Verilog standard IEEE Std 1364-2001 Version C
+ *
+ * Supported features:
+ * - $var with 'wire' and 'reg' types of scalar variables
+ * - $timescale definition for samplerate
+ * - multiple character variable identifiers
+ *
+ * Most important unsupported features:
+ * - vector variables (bit vectors etc.)
+ * - analog, integer and real number variables
+ * - $dumpvars initial value declaration
+ * - $scope namespaces
+ * - more than 64 channels
+ */
+
+#include <stdlib.h>
+#include <glib.h>
+#include <stdio.h>
+#include <string.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "input/vcd"
+
+#define DEFAULT_NUM_CHANNELS 8
+#define CHUNKSIZE 1024
+
+struct context {
+       uint64_t samplerate;
+       int maxchannels;
+       int channelcount;
+       int downsample;
+       unsigned compress;
+       int64_t skip;
+       GSList *channels;
+};
+
+struct vcd_channel {
+       gchar *name;
+       gchar *identifier;
+};
+
+
+/* Read until specific type of character occurs in file.
+ * Skip input if dest is NULL.
+ * Modes:
+ * 'W' read until whitespace
+ * 'N' read until non-whitespace, and ungetc() the character
+ * '$' read until $end
+ */
+static gboolean read_until(FILE *file, GString *dest, char mode)
+{
+       int  c;
+       char prev[4] = "";
+
+       for(;;) {
+               c = fgetc(file);
+
+               if (c == EOF) {
+                       if (mode == '$')
+                               sr_err("Unexpected EOF.");
+                       return FALSE;
+               }
+
+               if (mode == 'W' && g_ascii_isspace(c))
+                       return TRUE;
+
+               if (mode == 'N' && !g_ascii_isspace(c)) {
+                       ungetc(c, file);
+                       return TRUE;
+               }
+
+               if (mode == '$') {
+                       prev[0] = prev[1]; prev[1] = prev[2]; prev[2] = prev[3]; prev[3] = c;
+                       if (prev[0] == '$' && prev[1] == 'e' && prev[2] == 'n' && prev[3] == 'd') {
+                               if (dest != NULL)
+                                       g_string_truncate(dest, dest->len - 3);
+
+                               return TRUE;
+                       }
+               }
+
+               if (dest != NULL)
+                       g_string_append_c(dest, c);
+       }
+}
+
+/*
+ * Reads a single VCD section from input file and parses it to structure.
+ * e.g. $timescale 1ps $end  => "timescale" "1ps"
+ */
+static gboolean parse_section(FILE *file, gchar **name, gchar **contents)
+{
+       gboolean status;
+       GString *sname, *scontents;
+
+       /* Skip any initial white-space */
+       if (!read_until(file, NULL, 'N')) return FALSE;
+
+       /* Section tag should start with $. */
+       if (fgetc(file) != '$') {
+               sr_err("Expected $ at beginning of section.");
+               return FALSE;
+       }
+
+       /* Read the section tag */
+       sname = g_string_sized_new(32);
+       status = read_until(file, sname, 'W');
+
+       /* Skip whitespace before content */
+       status = status && read_until(file, NULL, 'N');
+
+       /* Read the content */
+       scontents = g_string_sized_new(128);
+       status = status && read_until(file, scontents, '$');
+       g_strchomp(scontents->str);
+
+       /* Release strings if status is FALSE, return them if status is TRUE */
+       *name = g_string_free(sname, !status);
+       *contents = g_string_free(scontents, !status);
+       return status;
+}
+
+static void free_channel(void *data)
+{
+       struct vcd_channel *vcd_ch = data;
+       g_free(vcd_ch->name);
+       g_free(vcd_ch->identifier);
+       g_free(vcd_ch);
+}
+
+static void release_context(struct context *ctx)
+{
+       g_slist_free_full(ctx->channels, free_channel);
+       g_free(ctx);
+}
+
+/* Remove empty parts from an array returned by g_strsplit. */
+static void remove_empty_parts(gchar **parts)
+{
+       gchar **src = parts;
+       gchar **dest = parts;
+       while (*src != NULL) {
+               if (**src != '\0')
+                       *dest++ = *src;
+               src++;
+       }
+
+       *dest = NULL;
+}
+
+/*
+ * Parse VCD header to get values for context structure.
+ * The context structure should be zeroed before calling this.
+ */
+static gboolean parse_header(FILE *file, struct context *ctx)
+{
+       uint64_t p, q;
+       gchar *name = NULL, *contents = NULL;
+       gboolean status = FALSE;
+       struct vcd_channel *vcd_ch;
+
+       while (parse_section(file, &name, &contents)) {
+               sr_dbg("Section '%s', contents '%s'.", name, contents);
+
+               if (g_strcmp0(name, "enddefinitions") == 0) {
+                       status = TRUE;
+                       break;
+               } else if (g_strcmp0(name, "timescale") == 0) {
+                       /*
+                        * The standard allows for values 1, 10 or 100
+                        * and units s, ms, us, ns, ps and fs.
+                        * */
+                       if (sr_parse_period(contents, &p, &q) == SR_OK) {
+                               ctx->samplerate = q / p;
+                               if (q % p != 0) {
+                                       /* Does not happen unless time value is non-standard */
+                                       sr_warn("Inexact rounding of samplerate, %" PRIu64 " / %" PRIu64 " to %" PRIu64 " Hz.",
+                                               q, p, ctx->samplerate);
+                               }
+
+                               sr_dbg("Samplerate: %" PRIu64, ctx->samplerate);
+                       } else {
+                               sr_err("Parsing timescale failed.");
+                       }
+               } else if (g_strcmp0(name, "var") == 0) {
+                       /* Format: $var type size identifier reference $end */
+                       gchar **parts = g_strsplit_set(contents, " \r\n\t", 0);
+                       remove_empty_parts(parts);
+
+                       if (g_strv_length(parts) != 4)
+                               sr_warn("$var section should have 4 items");
+                       else if (g_strcmp0(parts[0], "reg") != 0 && g_strcmp0(parts[0], "wire") != 0)
+                               sr_info("Unsupported signal type: '%s'", parts[0]);
+                       else if (strtol(parts[1], NULL, 10) != 1)
+                               sr_info("Unsupported signal size: '%s'", parts[1]);
+                       else if (ctx->channelcount >= ctx->maxchannels)
+                               sr_warn("Skipping '%s' because only %d channels requested.", parts[3], ctx->maxchannels);
+                       else {
+                               sr_info("Channel %d is '%s' identified by '%s'.", ctx->channelcount, parts[3], parts[2]);
+                               vcd_ch = g_malloc(sizeof(struct vcd_channel));
+                               vcd_ch->identifier = g_strdup(parts[2]);
+                               vcd_ch->name = g_strdup(parts[3]);
+                               ctx->channels = g_slist_append(ctx->channels, vcd_ch);
+                               ctx->channelcount++;
+                       }
+
+                       g_strfreev(parts);
+               }
+
+               g_free(name); name = NULL;
+               g_free(contents); contents = NULL;
+       }
+
+       g_free(name);
+       g_free(contents);
+
+       return status;
+}
+
+static int format_match(const char *filename)
+{
+       FILE *file;
+       gchar *name = NULL, *contents = NULL;
+       gboolean status;
+
+       file = fopen(filename, "r");
+       if (file == NULL)
+               return FALSE;
+
+       /*
+        * If we can parse the first section correctly,
+        * then it is assumed to be a VCD file.
+        */
+       status = parse_section(file, &name, &contents);
+       status = status && (*name != '\0');
+
+       g_free(name);
+       g_free(contents);
+       fclose(file);
+
+       return status;
+}
+
+static int init(struct sr_input *in, const char *filename)
+{
+       struct sr_channel *ch;
+       int num_channels, i;
+       char name[SR_MAX_CHANNELNAME_LEN + 1];
+       char *param;
+       struct context *ctx;
+
+       (void)filename;
+
+       if (!(ctx = g_try_malloc0(sizeof(*ctx)))) {
+               sr_err("Input format context malloc failed.");
+               return SR_ERR_MALLOC;
+       }
+
+       num_channels = DEFAULT_NUM_CHANNELS;
+       ctx->samplerate = 0;
+       ctx->downsample = 1;
+       ctx->skip = -1;
+
+       if (in->param) {
+               param = g_hash_table_lookup(in->param, "numchannels");
+               if (param) {
+                       num_channels = strtoul(param, NULL, 10);
+                       if (num_channels < 1) {
+                               release_context(ctx);
+                               return SR_ERR;
+                       } else if (num_channels > 64) {
+                               sr_err("No more than 64 channels supported.");
+                               return SR_ERR;
+                       }
+               }
+
+               param = g_hash_table_lookup(in->param, "downsample");
+               if (param) {
+                       ctx->downsample = strtoul(param, NULL, 10);
+                       if (ctx->downsample < 1)
+                               ctx->downsample = 1;
+               }
+
+               param = g_hash_table_lookup(in->param, "compress");
+               if (param)
+                       ctx->compress = strtoul(param, NULL, 10);
+
+               param = g_hash_table_lookup(in->param, "skip");
+               if (param)
+                       ctx->skip = strtoul(param, NULL, 10) / ctx->downsample;
+       }
+
+       /* Maximum number of channels to parse from the VCD */
+       ctx->maxchannels = num_channels;
+
+       /* Create a virtual device. */
+       in->sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, NULL, NULL, NULL);
+       in->internal = ctx;
+
+       for (i = 0; i < num_channels; i++) {
+               snprintf(name, SR_MAX_CHANNELNAME_LEN, "%d", i);
+
+               if (!(ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE, name))) {
+                       release_context(ctx);
+                       return SR_ERR;
+               }
+
+               in->sdi->channels = g_slist_append(in->sdi->channels, ch);
+       }
+
+       return SR_OK;
+}
+
+/* Send N samples of the given value. */
+static void send_samples(const struct sr_dev_inst *sdi, uint64_t sample, uint64_t count)
+{
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_logic logic;
+       uint64_t buffer[CHUNKSIZE];
+       uint64_t i;
+       unsigned chunksize = CHUNKSIZE;
+
+       if (count < chunksize)
+               chunksize = count;
+
+       for (i = 0; i < chunksize; i++)
+               buffer[i] = sample;
+
+       packet.type = SR_DF_LOGIC;
+       packet.payload = &logic;
+       logic.unitsize = sizeof(uint64_t);
+       logic.data = buffer;
+
+       while (count) {
+               if (count < chunksize)
+                       chunksize = count;
+
+               logic.length = sizeof(uint64_t) * chunksize;
+
+               sr_session_send(sdi, &packet);
+               count -= chunksize;
+       }
+}
+
+/* Parse the data section of VCD */
+static void parse_contents(FILE *file, const struct sr_dev_inst *sdi, struct context *ctx)
+{
+       GString *token = g_string_sized_new(32);
+
+       uint64_t prev_timestamp = 0;
+       uint64_t prev_values = 0;
+
+       /* Read one space-delimited token at a time. */
+       while (read_until(file, NULL, 'N') && read_until(file, token, 'W')) {
+               if (token->str[0] == '#' && g_ascii_isdigit(token->str[1])) {
+                       /* Numeric value beginning with # is a new timestamp value */
+                       uint64_t timestamp;
+                       timestamp = strtoull(token->str + 1, NULL, 10);
+
+                       if (ctx->downsample > 1)
+                               timestamp /= ctx->downsample;
+
+                       /*
+                        * Skip < 0 => skip until first timestamp.
+                        * Skip = 0 => don't skip
+                        * Skip > 0 => skip until timestamp >= skip.
+                        */
+                       if (ctx->skip < 0) {
+                               ctx->skip = timestamp;
+                               prev_timestamp = timestamp;
+                       } else if (ctx->skip > 0 && timestamp < (uint64_t)ctx->skip) {
+                               prev_timestamp = ctx->skip;
+                       }
+                       else if (timestamp == prev_timestamp) {
+                               /* Ignore repeated timestamps (e.g. sigrok outputs these) */
+                       }
+                       else {
+                               if (ctx->compress != 0 && timestamp - prev_timestamp > ctx->compress)
+                               {
+                                       /* Compress long idle periods */
+                                       prev_timestamp = timestamp - ctx->compress;
+                               }
+
+                               sr_dbg("New timestamp: %" PRIu64, timestamp);
+
+                               /* Generate samples from prev_timestamp up to timestamp - 1. */
+                               send_samples(sdi, prev_values, timestamp - prev_timestamp);
+                               prev_timestamp = timestamp;
+                       }
+               } else if (token->str[0] == '$' && token->len > 1) {
+                       /* This is probably a $dumpvars, $comment or similar.
+                        * $dump* contain useful data, but other tags will be skipped until $end. */
+                       if (g_strcmp0(token->str, "$dumpvars") == 0
+                                       || g_strcmp0(token->str, "$dumpon") == 0
+                                       || g_strcmp0(token->str, "$dumpoff") == 0
+                                       || g_strcmp0(token->str, "$end") == 0) {
+                               /* Ignore, parse contents as normally. */
+                       } else {
+                               /* Skip until $end */
+                               read_until(file, NULL, '$');
+                       }
+               }
+               else if (strchr("bBrR", token->str[0]) != NULL) {
+                       /* A vector value. Skip it and also the following identifier. */
+                       read_until(file, NULL, 'N');
+                       read_until(file, NULL, 'W');
+               } else if (strchr("01xXzZ", token->str[0]) != NULL) {
+                       /* A new 1-bit sample value */
+                       int i, bit;
+                       GSList *l;
+                       struct vcd_channel *vcd_ch;
+
+                       bit = (token->str[0] == '1');
+
+                       g_string_erase(token, 0, 1);
+                       if (token->len == 0) {
+                               /* There was a space between value and identifier.
+                                * Read in the rest.
+                                */
+                               read_until(file, NULL, 'N');
+                               read_until(file, token, 'W');
+                       }
+
+                       for (i = 0, l = ctx->channels; i < ctx->channelcount && l; i++, l = l->next) {
+                               vcd_ch = l->data;
+
+                               if (g_strcmp0(token->str, vcd_ch->identifier) == 0) {
+                                       /* Found our channel */
+                                       if (bit)
+                                               prev_values |= (uint64_t)1 << i;
+                                       else
+                                               prev_values &= ~((uint64_t)1 << i);
+
+                                       break;
+                               }
+                       }
+
+                       if (i == ctx->channelcount)
+                               sr_dbg("Did not find channel for identifier '%s'.", token->str);
+               } else {
+                       sr_warn("Skipping unknown token '%s'.", token->str);
+               }
+
+               g_string_truncate(token, 0);
+       }
+
+       g_string_free(token, TRUE);
+}
+
+static int loadfile(struct sr_input *in, const char *filename)
+{
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_meta meta;
+       struct sr_config *src;
+       FILE *file;
+       struct context *ctx;
+       uint64_t samplerate;
+
+       ctx = in->internal;
+
+       if ((file = fopen(filename, "r")) == NULL)
+               return SR_ERR;
+
+       if (!parse_header(file, ctx)) {
+               sr_err("VCD parsing failed");
+               fclose(file);
+               return SR_ERR;
+       }
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(in->sdi, LOG_PREFIX);
+
+       /* Send metadata about the SR_DF_LOGIC packets to come. */
+       packet.type = SR_DF_META;
+       packet.payload = &meta;
+       samplerate = ctx->samplerate / ctx->downsample;
+       src = sr_config_new(SR_CONF_SAMPLERATE, g_variant_new_uint64(samplerate));
+       meta.config = g_slist_append(NULL, src);
+       sr_session_send(in->sdi, &packet);
+       sr_config_free(src);
+
+       /* Parse the contents of the VCD file */
+       parse_contents(file, in->sdi, ctx);
+
+       /* Send end packet to the session bus. */
+       packet.type = SR_DF_END;
+       sr_session_send(in->sdi, &packet);
+
+       fclose(file);
+       release_context(ctx);
+       in->internal = NULL;
+
+       return SR_OK;
+}
+
+SR_PRIV struct sr_input_format input_vcd = {
+       .id = "vcd",
+       .description = "Value Change Dump",
+       .format_match = format_match,
+       .init = init,
+       .loadfile = loadfile,
+};
diff --git a/src/input/wav.c b/src/input/wav.c
new file mode 100644 (file)
index 0000000..1c3f050
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert@biot.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 <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "input/wav"
+
+#define CHUNK_SIZE 4096
+
+struct context {
+       uint64_t samplerate;
+       int samplesize;
+       int num_channels;
+};
+
+static int get_wav_header(const char *filename, char *buf)
+{
+       struct stat st;
+       int fd, l;
+
+       l = strlen(filename);
+       if (l <= 4 || strcasecmp(filename + l - 4, ".wav"))
+               return SR_ERR;
+
+       if (stat(filename, &st) == -1)
+               return SR_ERR;
+       if (st.st_size <= 45)
+               /* Minimum size of header + 1 8-bit mono PCM sample. */
+               return SR_ERR;
+
+       if ((fd = open(filename, O_RDONLY)) == -1)
+               return SR_ERR;
+
+       l = read(fd, buf, 40);
+       close(fd);
+       if (l != 40)
+               return SR_ERR;
+
+       return SR_OK;
+}
+
+static int format_match(const char *filename)
+{
+       char buf[40];
+
+       if (get_wav_header(filename, buf) != SR_OK)
+               return FALSE;
+
+       if (strncmp(buf, "RIFF", 4))
+               return FALSE;
+       if (strncmp(buf + 8, "WAVE", 4))
+               return FALSE;
+       if (strncmp(buf + 12, "fmt ", 4))
+               return FALSE;
+       if (GUINT16_FROM_LE(*(uint16_t *)(buf + 20)) != 1)
+               /* Not PCM. */
+               return FALSE;
+       if (strncmp(buf + 36, "data", 4))
+               return FALSE;
+
+       return TRUE;
+}
+
+static int init(struct sr_input *in, const char *filename)
+{
+       struct sr_channel *ch;
+       struct context *ctx;
+       char buf[40], channelname[8];
+       int i;
+
+       if (get_wav_header(filename, buf) != SR_OK)
+               return SR_ERR;
+
+       if (!(ctx = g_try_malloc0(sizeof(struct context))))
+               return SR_ERR_MALLOC;
+
+       /* Create a virtual device. */
+       in->sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, NULL, NULL, NULL);
+       in->sdi->priv = ctx;
+
+       ctx->samplerate = GUINT32_FROM_LE(*(uint32_t *)(buf + 24));
+       ctx->samplesize = GUINT16_FROM_LE(*(uint16_t *)(buf + 34)) / 8;
+       if (ctx->samplesize != 1 && ctx->samplesize != 2 && ctx->samplesize != 4) {
+               sr_err("only 8, 16 or 32 bits per sample supported.");
+               return SR_ERR;
+       }
+
+       if ((ctx->num_channels = GUINT16_FROM_LE(*(uint16_t *)(buf + 22))) > 20) {
+               sr_err("%d channels seems crazy.", ctx->num_channels);
+               return SR_ERR;
+       }
+
+       for (i = 0; i < ctx->num_channels; i++) {
+               snprintf(channelname, 8, "CH%d", i + 1);
+               if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, channelname)))
+                       return SR_ERR;
+               in->sdi->channels = g_slist_append(in->sdi->channels, ch);
+       }
+
+       return SR_OK;
+}
+
+static int loadfile(struct sr_input *in, const char *filename)
+{
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_meta meta;
+       struct sr_datafeed_analog analog;
+       struct sr_config *src;
+       struct context *ctx;
+       float fdata[CHUNK_SIZE];
+       uint64_t sample;
+       int num_samples, chunk_samples, s, c, fd, l;
+       char buf[CHUNK_SIZE];
+
+       ctx = in->sdi->priv;
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(in->sdi, LOG_PREFIX);
+
+       packet.type = SR_DF_META;
+       packet.payload = &meta;
+       src = sr_config_new(SR_CONF_SAMPLERATE,
+                       g_variant_new_uint64(ctx->samplerate));
+       meta.config = g_slist_append(NULL, src);
+       sr_session_send(in->sdi, &packet);
+       sr_config_free(src);
+
+       if ((fd = open(filename, O_RDONLY)) == -1)
+               return SR_ERR;
+
+       lseek(fd, 40, SEEK_SET);
+       l = read(fd, buf, 4);
+       num_samples = GUINT32_FROM_LE((uint32_t)*(buf));
+       num_samples /= ctx->samplesize / ctx->num_channels;
+       while (TRUE) {
+               if ((l = read(fd, buf, CHUNK_SIZE)) < 1)
+                       break;
+               chunk_samples = l / ctx->samplesize / ctx->num_channels;
+               for (s = 0; s < chunk_samples; s++) {
+                       for (c = 0; c < ctx->num_channels; c++) {
+                               sample = 0;
+                               memcpy(&sample, buf + s * ctx->samplesize + c, ctx->samplesize);
+                               switch (ctx->samplesize) {
+                               case 1:
+                                       /* 8-bit PCM samples are unsigned. */
+                                       fdata[s + c] = (uint8_t)sample / 255.0;
+                                       break;
+                               case 2:
+                                       fdata[s + c] = GINT16_FROM_LE(sample) / 32767.0;
+                                       break;
+                               case 4:
+                                       fdata[s + c] = GINT32_FROM_LE(sample) / 65535.0;
+                                       break;
+                               }
+                       }
+               }
+               packet.type = SR_DF_ANALOG;
+               packet.payload = &analog;
+               analog.channels = in->sdi->channels;
+               analog.num_samples = chunk_samples;
+               analog.mq = 0;
+               analog.unit = 0;
+               analog.data = fdata;
+               sr_session_send(in->sdi, &packet);
+       }
+
+       close(fd);
+       packet.type = SR_DF_END;
+       sr_session_send(in->sdi, &packet);
+
+       return SR_OK;
+}
+
+
+SR_PRIV struct sr_input_format input_wav = {
+       .id = "wav",
+       .description = "WAV file",
+       .format_match = format_match,
+       .init = init,
+       .loadfile = loadfile,
+};
+
diff --git a/src/libsigrok-internal.h b/src/libsigrok-internal.h
new file mode 100644 (file)
index 0000000..8c58bd9
--- /dev/null
@@ -0,0 +1,642 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert@biot.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/>.
+ */
+
+/** @file
+  * @internal
+  */
+
+#ifndef LIBSIGROK_LIBSIGROK_INTERNAL_H
+#define LIBSIGROK_LIBSIGROK_INTERNAL_H
+
+#include <stdarg.h>
+#include <glib.h>
+#include "config.h" /* Needed for HAVE_LIBUSB_1_0 and others. */
+#ifdef HAVE_LIBUSB_1_0
+#include <libusb.h>
+#endif
+#ifdef HAVE_LIBSERIALPORT
+#include <libserialport.h>
+#endif
+
+/**
+ * @file
+ *
+ * libsigrok private header file, only to be used internally.
+ */
+
+/*--- Macros ----------------------------------------------------------------*/
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#endif
+
+#ifndef ARRAY_AND_SIZE
+#define ARRAY_AND_SIZE(a) (a), ARRAY_SIZE(a)
+#endif
+
+/**
+ * Read a 8 bits integer out of memory.
+ * @param x a pointer to the input memory
+ * @return the corresponding integer
+ */
+#define R8(x)     ((unsigned)((const uint8_t*)(x))[0])
+
+/**
+ * Read a 16 bits big endian integer out of memory.
+ * @param x a pointer to the input memory
+ * @return the corresponding integer
+ */
+#define RB16(x)  (((unsigned)((const uint8_t*)(x))[0] <<  8) |  \
+                   (unsigned)((const uint8_t*)(x))[1])
+
+/**
+ * Read a 16 bits little endian integer out of memory.
+ * @param x a pointer to the input memory
+ * @return the corresponding integer
+ */
+#define RL16(x)  (((unsigned)((const uint8_t*)(x))[1] <<  8) | \
+                   (unsigned)((const uint8_t*)(x))[0])
+
+/**
+ * Read a 32 bits big endian integer out of memory.
+ * @param x a pointer to the input memory
+ * @return the corresponding integer
+ */
+#define RB32(x)  (((unsigned)((const uint8_t*)(x))[0] << 24) | \
+                  ((unsigned)((const uint8_t*)(x))[1] << 16) |  \
+                  ((unsigned)((const uint8_t*)(x))[2] <<  8) |  \
+                   (unsigned)((const uint8_t*)(x))[3])
+
+/**
+ * Read a 32 bits little endian integer out of memory.
+ * @param x a pointer to the input memory
+ * @return the corresponding integer
+ */
+#define RL32(x)  (((unsigned)((const uint8_t*)(x))[3] << 24) | \
+                  ((unsigned)((const uint8_t*)(x))[2] << 16) |  \
+                  ((unsigned)((const uint8_t*)(x))[1] <<  8) |  \
+                   (unsigned)((const uint8_t*)(x))[0])
+
+/**
+ * Write a 8 bits integer to memory.
+ * @param p a pointer to the output memory
+ * @param x the input integer
+ */
+#define W8(p, x)    do { ((uint8_t*)(p))[0] = (uint8_t) (x);      } while(0)
+
+/**
+ * Write a 16 bits integer to memory stored as big endian.
+ * @param p a pointer to the output memory
+ * @param x the input integer
+ */
+#define WB16(p, x)  do { ((uint8_t*)(p))[1] = (uint8_t) (x);      \
+                         ((uint8_t*)(p))[0] = (uint8_t)((x)>>8);  } while(0)
+
+/**
+ * Write a 16 bits integer to memory stored as little endian.
+ * @param p a pointer to the output memory
+ * @param x the input integer
+ */
+#define WL16(p, x)  do { ((uint8_t*)(p))[0] = (uint8_t) (x);      \
+                         ((uint8_t*)(p))[1] = (uint8_t)((x)>>8);  } while(0)
+
+/**
+ * Write a 32 bits integer to memory stored as big endian.
+ * @param p a pointer to the output memory
+ * @param x the input integer
+ */
+#define WB32(p, x)  do { ((uint8_t*)(p))[3] = (uint8_t) (x);      \
+                         ((uint8_t*)(p))[2] = (uint8_t)((x)>>8);  \
+                         ((uint8_t*)(p))[1] = (uint8_t)((x)>>16); \
+                         ((uint8_t*)(p))[0] = (uint8_t)((x)>>24); } while(0)
+
+/**
+ * Write a 32 bits integer to memory stored as little endian.
+ * @param p a pointer to the output memory
+ * @param x the input integer
+ */
+#define WL32(p, x)  do { ((uint8_t*)(p))[0] = (uint8_t) (x);      \
+                         ((uint8_t*)(p))[1] = (uint8_t)((x)>>8);  \
+                         ((uint8_t*)(p))[2] = (uint8_t)((x)>>16); \
+                         ((uint8_t*)(p))[3] = (uint8_t)((x)>>24); } while(0)
+
+/* Portability fixes for FreeBSD. */
+#ifdef __FreeBSD__
+#define LIBUSB_CLASS_APPLICATION 0xfe
+#define libusb_handle_events_timeout_completed(ctx, tv, c) \
+       libusb_handle_events_timeout(ctx, tv)
+#endif
+
+struct sr_context {
+#ifdef HAVE_LIBUSB_1_0
+       libusb_context *libusb_ctx;
+       gboolean usb_source_present;
+#ifdef _WIN32
+       GThread *usb_thread;
+       gboolean usb_thread_running;
+       GMutex usb_mutex;
+       HANDLE usb_event;
+       GPollFD usb_pollfd;
+       sr_receive_data_callback usb_cb;
+       void *usb_cb_data;
+#endif
+#endif
+};
+
+#ifdef HAVE_LIBUSB_1_0
+/** USB device instance */
+struct sr_usb_dev_inst {
+       /** USB bus */
+       uint8_t bus;
+       /** Device address on USB bus */
+       uint8_t address;
+       /** libusb device handle */
+       struct libusb_device_handle *devhdl;
+};
+#endif
+
+#ifdef HAVE_LIBSERIALPORT
+#define SERIAL_PARITY_NONE SP_PARITY_NONE
+#define SERIAL_PARITY_EVEN SP_PARITY_EVEN
+#define SERIAL_PARITY_ODD  SP_PARITY_ODD
+struct sr_serial_dev_inst {
+       /** Port name, e.g. '/dev/tty42'. */
+       char *port;
+       /** Comm params for serial_set_paramstr(). */
+       char *serialcomm;
+       /** Port is non-blocking. */
+       int nonblocking;
+       /** libserialport port handle */
+       struct sp_port *data;
+       /** libserialport event set */
+       struct sp_event_set *event_set;
+       /** GPollFDs for event polling */
+       GPollFD *pollfds;
+};
+#endif
+
+struct sr_usbtmc_dev_inst {
+       char *device;
+       int fd;
+};
+
+/* Private driver context. */
+struct drv_context {
+       /** sigrok context */
+       struct sr_context *sr_ctx;
+       GSList *instances;
+};
+
+/*--- log.c -----------------------------------------------------------------*/
+
+SR_PRIV int sr_log(int loglevel, const char *format, ...);
+SR_PRIV int sr_spew(const char *format, ...);
+SR_PRIV int sr_dbg(const char *format, ...);
+SR_PRIV int sr_info(const char *format, ...);
+SR_PRIV int sr_warn(const char *format, ...);
+SR_PRIV int sr_err(const char *format, ...);
+
+/* Message logging helpers with subsystem-specific prefix string. */
+#ifndef NO_LOG_WRAPPERS
+#define sr_log(l, s, args...) sr_log(l, "%s: " s, LOG_PREFIX, ## args)
+#define sr_spew(s, args...) sr_spew("%s: " s, LOG_PREFIX, ## args)
+#define sr_dbg(s, args...) sr_dbg("%s: " s, LOG_PREFIX, ## args)
+#define sr_info(s, args...) sr_info("%s: " s, LOG_PREFIX, ## args)
+#define sr_warn(s, args...) sr_warn("%s: " s, LOG_PREFIX, ## args)
+#define sr_err(s, args...) sr_err("%s: " s, LOG_PREFIX, ## args)
+#endif
+
+/*--- device.c --------------------------------------------------------------*/
+
+/** Values for the changes argument of sr_dev_driver.config_channel_set. */
+enum {
+       /** The enabled state of the channel has been changed. */
+       SR_CHANNEL_SET_ENABLED = 1 << 0,
+};
+
+SR_PRIV struct sr_channel *sr_channel_new(int index, int type,
+               gboolean enabled, const char *name);
+
+/* Generic device instances */
+SR_PRIV struct sr_dev_inst *sr_dev_inst_new(int index, int status,
+               const char *vendor, const char *model, const char *version);
+SR_PRIV void sr_dev_inst_free(struct sr_dev_inst *sdi);
+
+#ifdef HAVE_LIBUSB_1_0
+/* USB-specific instances */
+SR_PRIV struct sr_usb_dev_inst *sr_usb_dev_inst_new(uint8_t bus,
+               uint8_t address, struct libusb_device_handle *hdl);
+SR_PRIV void sr_usb_dev_inst_free(struct sr_usb_dev_inst *usb);
+#endif
+
+#ifdef HAVE_LIBSERIALPORT
+/* Serial-specific instances */
+SR_PRIV struct sr_serial_dev_inst *sr_serial_dev_inst_new(const char *port,
+               const char *serialcomm);
+SR_PRIV void sr_serial_dev_inst_free(struct sr_serial_dev_inst *serial);
+#endif
+
+/* USBTMC-specific instances */
+SR_PRIV struct sr_usbtmc_dev_inst *sr_usbtmc_dev_inst_new(const char *device);
+SR_PRIV void sr_usbtmc_dev_inst_free(struct sr_usbtmc_dev_inst *usbtmc);
+
+/*--- hwdriver.c ------------------------------------------------------------*/
+
+SR_PRIV void sr_hw_cleanup_all(void);
+SR_PRIV struct sr_config *sr_config_new(int key, GVariant *data);
+SR_PRIV void sr_config_free(struct sr_config *src);
+SR_PRIV int sr_source_remove(int fd);
+SR_PRIV int sr_source_remove_pollfd(GPollFD *pollfd);
+SR_PRIV int sr_source_remove_channel(GIOChannel *channel);
+SR_PRIV int sr_source_add(int fd, int events, int timeout,
+               sr_receive_data_callback cb, void *cb_data);
+SR_PRIV int sr_source_add_pollfd(GPollFD *pollfd, int timeout,
+               sr_receive_data_callback cb, void *cb_data);
+SR_PRIV int sr_source_add_channel(GIOChannel *channel, int events, int timeout,
+               sr_receive_data_callback cb, void *cb_data);
+
+/*--- session.c -------------------------------------------------------------*/
+
+struct sr_session {
+       /** List of struct sr_dev pointers. */
+       GSList *devs;
+       /** List of struct datafeed_callback pointers. */
+       GSList *datafeed_callbacks;
+       struct sr_trigger *trigger;
+       GTimeVal starttime;
+       gboolean running;
+
+       unsigned int num_sources;
+
+       /*
+        * Both "sources" and "pollfds" are of the same size and contain pairs
+        * of descriptor and callback function. We can not embed the GPollFD
+        * into the source struct since we want to be able to pass the array
+        * of all poll descriptors to g_poll().
+        */
+       struct source *sources;
+       GPollFD *pollfds;
+       int source_timeout;
+
+       /*
+        * These are our synchronization primitives for stopping the session in
+        * an async fashion. We need to make sure the session is stopped from
+        * within the session thread itself.
+        */
+       /** Mutex protecting access to abort_session. */
+       GMutex stop_mutex;
+       /** Abort current session. See sr_session_stop(). */
+       gboolean abort_session;
+};
+
+SR_PRIV int sr_session_send(const struct sr_dev_inst *sdi,
+               const struct sr_datafeed_packet *packet);
+SR_PRIV int sr_session_stop_sync(struct sr_session *session);
+SR_PRIV int sr_sessionfile_check(const char *filename);
+
+/*--- std.c -----------------------------------------------------------------*/
+
+typedef int (*dev_close_callback)(struct sr_dev_inst *sdi);
+typedef void (*std_dev_clear_callback)(void *priv);
+
+SR_PRIV int std_init(struct sr_context *sr_ctx, struct sr_dev_driver *di,
+               const char *prefix);
+#ifdef HAVE_LIBSERIALPORT
+SR_PRIV int std_serial_dev_open(struct sr_dev_inst *sdi);
+SR_PRIV int std_serial_dev_acquisition_stop(struct sr_dev_inst *sdi,
+               void *cb_data, dev_close_callback dev_close_fn,
+               struct sr_serial_dev_inst *serial, const char *prefix);
+#endif
+SR_PRIV int std_session_send_df_header(const struct sr_dev_inst *sdi,
+               const char *prefix);
+SR_PRIV int std_dev_clear(const struct sr_dev_driver *driver,
+               std_dev_clear_callback clear_private);
+SR_PRIV int std_serial_dev_close(struct sr_dev_inst *sdi);
+
+/*--- strutil.c -------------------------------------------------------------*/
+
+SR_PRIV int sr_atol(const char *str, long *ret);
+SR_PRIV int sr_atoi(const char *str, int *ret);
+SR_PRIV int sr_atod(const char *str, double *ret);
+SR_PRIV int sr_atof(const char *str, float *ret);
+SR_PRIV int sr_atof_ascii(const char *str, float *ret);
+
+/*--- soft-trigger.c --------------------------------------------------------*/
+
+struct soft_trigger_logic {
+       const struct sr_dev_inst *sdi;
+       const struct sr_trigger *trigger;
+       int count;
+       int unitsize;
+       int cur_stage;
+       uint8_t *prev_sample;
+};
+
+SR_PRIV struct soft_trigger_logic *soft_trigger_logic_new(
+               const struct sr_dev_inst *sdi, struct sr_trigger *trigger);
+SR_PRIV void soft_trigger_logic_free(struct soft_trigger_logic *st);
+SR_PRIV int soft_trigger_logic_check(struct soft_trigger_logic *st, uint8_t *buf,
+               int len);
+
+/*--- hardware/common/serial.c ----------------------------------------------*/
+
+#ifdef HAVE_LIBSERIALPORT
+enum {
+       SERIAL_RDWR = 1,
+       SERIAL_RDONLY = 2,
+       SERIAL_NONBLOCK = 4,
+};
+
+typedef gboolean (*packet_valid_callback)(const uint8_t *buf);
+
+SR_PRIV int serial_open(struct sr_serial_dev_inst *serial, int flags);
+SR_PRIV int serial_close(struct sr_serial_dev_inst *serial);
+SR_PRIV int serial_flush(struct sr_serial_dev_inst *serial);
+SR_PRIV int serial_write(struct sr_serial_dev_inst *serial,
+               const void *buf, size_t count);
+SR_PRIV int serial_write_blocking(struct sr_serial_dev_inst *serial,
+               const void *buf, size_t count);
+SR_PRIV int serial_write_nonblocking(struct sr_serial_dev_inst *serial,
+               const void *buf, size_t count);
+SR_PRIV int serial_read(struct sr_serial_dev_inst *serial, void *buf,
+               size_t count);
+SR_PRIV int serial_read_blocking(struct sr_serial_dev_inst *serial, void *buf,
+               size_t count);
+SR_PRIV int serial_read_nonblocking(struct sr_serial_dev_inst *serial, void *buf,
+               size_t count);
+SR_PRIV int serial_set_params(struct sr_serial_dev_inst *serial, int baudrate,
+               int bits, int parity, int stopbits, int flowcontrol, int rts, int dtr);
+SR_PRIV int serial_set_paramstr(struct sr_serial_dev_inst *serial,
+               const char *paramstr);
+SR_PRIV int serial_readline(struct sr_serial_dev_inst *serial, char **buf,
+               int *buflen, gint64 timeout_ms);
+SR_PRIV int serial_stream_detect(struct sr_serial_dev_inst *serial,
+                                uint8_t *buf, size_t *buflen,
+                                size_t packet_size,
+                                packet_valid_callback is_valid,
+                                uint64_t timeout_ms, int baudrate);
+SR_PRIV int sr_serial_extract_options(GSList *options, const char **serial_device,
+                                     const char **serial_options);
+SR_PRIV int serial_source_add(struct sr_session *session,
+               struct sr_serial_dev_inst *serial, int events, int timeout,
+               sr_receive_data_callback cb, void *cb_data);
+SR_PRIV int serial_source_remove(struct sr_session *session,
+               struct sr_serial_dev_inst *serial);
+SR_PRIV GSList *sr_serial_find_usb(uint16_t vendor_id, uint16_t product_id);
+#endif
+
+/*--- hardware/common/ezusb.c -----------------------------------------------*/
+
+#ifdef HAVE_LIBUSB_1_0
+SR_PRIV int ezusb_reset(struct libusb_device_handle *hdl, int set_clear);
+SR_PRIV int ezusb_install_firmware(libusb_device_handle *hdl,
+                                  const char *filename);
+SR_PRIV int ezusb_upload_firmware(libusb_device *dev, int configuration,
+                                 const char *filename);
+#endif
+
+/*--- hardware/common/usb.c -------------------------------------------------*/
+
+#ifdef HAVE_LIBUSB_1_0
+SR_PRIV GSList *sr_usb_find(libusb_context *usb_ctx, const char *conn);
+SR_PRIV int sr_usb_open(libusb_context *usb_ctx, struct sr_usb_dev_inst *usb);
+SR_PRIV int usb_source_add(struct sr_session *session, struct sr_context *ctx,
+               int timeout, sr_receive_data_callback cb, void *cb_data);
+SR_PRIV int usb_source_remove(struct sr_session *session, struct sr_context *ctx);
+#endif
+
+/*--- hardware/common/scpi.c ------------------------------------------------*/
+
+#define SCPI_CMD_IDN "*IDN?"
+#define SCPI_CMD_OPC "*OPC?"
+
+enum {
+       SCPI_CMD_SET_TRIGGER_SOURCE,
+       SCPI_CMD_SET_TIMEBASE,
+       SCPI_CMD_SET_VERTICAL_DIV,
+       SCPI_CMD_SET_TRIGGER_SLOPE,
+       SCPI_CMD_SET_COUPLING,
+       SCPI_CMD_SET_HORIZ_TRIGGERPOS,
+       SCPI_CMD_GET_ANALOG_CHAN_STATE,
+       SCPI_CMD_GET_DIG_CHAN_STATE,
+       SCPI_CMD_GET_TIMEBASE,
+       SCPI_CMD_GET_VERTICAL_DIV,
+       SCPI_CMD_GET_VERTICAL_OFFSET,
+       SCPI_CMD_GET_TRIGGER_SOURCE,
+       SCPI_CMD_GET_HORIZ_TRIGGERPOS,
+       SCPI_CMD_GET_TRIGGER_SLOPE,
+       SCPI_CMD_GET_COUPLING,
+       SCPI_CMD_SET_ANALOG_CHAN_STATE,
+       SCPI_CMD_SET_DIG_CHAN_STATE,
+       SCPI_CMD_GET_DIG_POD_STATE,
+       SCPI_CMD_SET_DIG_POD_STATE,
+       SCPI_CMD_GET_ANALOG_DATA,
+       SCPI_CMD_GET_DIG_DATA,
+       SCPI_CMD_GET_SAMPLE_RATE,
+       SCPI_CMD_GET_SAMPLE_RATE_LIVE,
+};
+
+struct sr_scpi_hw_info {
+       char *manufacturer;
+       char *model;
+       char *serial_number;
+       char *firmware_version;
+};
+
+struct sr_scpi_dev_inst {
+       const char *name;
+       const char *prefix;
+       int priv_size;
+       GSList *(*scan)(struct drv_context *drvc);
+       int (*dev_inst_new)(void *priv, struct drv_context *drvc,
+               const char *resource, char **params, const char *serialcomm);
+       int (*open)(void *priv);
+       int (*source_add)(struct sr_session *session, void *priv, int events,
+               int timeout, sr_receive_data_callback cb, void *cb_data);
+       int (*source_remove)(struct sr_session *session, void *priv);
+       int (*send)(void *priv, const char *command);
+       int (*read_begin)(void *priv);
+       int (*read_data)(void *priv, char *buf, int maxlen);
+       int (*read_complete)(void *priv);
+       int (*close)(void *priv);
+       void (*free)(void *priv);
+       void *priv;
+};
+
+SR_PRIV GSList *sr_scpi_scan(struct drv_context *drvc, GSList *options,
+               struct sr_dev_inst *(*probe_device)(struct sr_scpi_dev_inst *scpi));
+SR_PRIV struct sr_scpi_dev_inst *scpi_dev_inst_new(struct drv_context *drvc,
+               const char *resource, const char *serialcomm);
+SR_PRIV int sr_scpi_open(struct sr_scpi_dev_inst *scpi);
+SR_PRIV int sr_scpi_source_add(struct sr_session *session,
+               struct sr_scpi_dev_inst *scpi, int events, int timeout,
+               sr_receive_data_callback cb, void *cb_data);
+SR_PRIV int sr_scpi_source_remove(struct sr_session *session,
+               struct sr_scpi_dev_inst *scpi);
+SR_PRIV int sr_scpi_send(struct sr_scpi_dev_inst *scpi,
+               const char *format, ...);
+SR_PRIV int sr_scpi_send_variadic(struct sr_scpi_dev_inst *scpi,
+               const char *format, va_list args);
+SR_PRIV int sr_scpi_read_begin(struct sr_scpi_dev_inst *scpi);
+SR_PRIV int sr_scpi_read_data(struct sr_scpi_dev_inst *scpi, char *buf, int maxlen);
+SR_PRIV int sr_scpi_read_complete(struct sr_scpi_dev_inst *scpi);
+SR_PRIV int sr_scpi_close(struct sr_scpi_dev_inst *scpi);
+SR_PRIV void sr_scpi_free(struct sr_scpi_dev_inst *scpi);
+
+SR_PRIV int sr_scpi_get_string(struct sr_scpi_dev_inst *scpi,
+                       const char *command, char **scpi_response);
+SR_PRIV int sr_scpi_get_bool(struct sr_scpi_dev_inst *scpi,
+                       const char *command, gboolean *scpi_response);
+SR_PRIV int sr_scpi_get_int(struct sr_scpi_dev_inst *scpi,
+                       const char *command, int *scpi_response);
+SR_PRIV int sr_scpi_get_float(struct sr_scpi_dev_inst *scpi,
+                       const char *command, float *scpi_response);
+SR_PRIV int sr_scpi_get_double(struct sr_scpi_dev_inst *scpi,
+                       const char *command, double *scpi_response);
+SR_PRIV int sr_scpi_get_opc(struct sr_scpi_dev_inst *scpi);
+SR_PRIV int sr_scpi_get_floatv(struct sr_scpi_dev_inst *scpi,
+                       const char *command, GArray **scpi_response);
+SR_PRIV int sr_scpi_get_uint8v(struct sr_scpi_dev_inst *scpi,
+                       const char *command, GArray **scpi_response);
+SR_PRIV int sr_scpi_get_hw_id(struct sr_scpi_dev_inst *scpi,
+                       struct sr_scpi_hw_info **scpi_response);
+SR_PRIV void sr_scpi_hw_info_free(struct sr_scpi_hw_info *hw_info);
+
+/*--- hardware/common/dmm/es519xx.c -----------------------------------------*/
+
+/**
+ * All 11-byte es519xx chips repeat each block twice for each conversion cycle
+ * so always read 2 blocks at a time.
+ */
+#define ES519XX_11B_PACKET_SIZE (11 * 2)
+#define ES519XX_14B_PACKET_SIZE 14
+
+struct es519xx_info {
+       gboolean is_judge, is_voltage, is_auto, is_micro, is_current;
+       gboolean is_milli, is_resistance, is_continuity, is_diode;
+       gboolean is_frequency, is_rpm, is_capacitance, is_duty_cycle;
+       gboolean is_temperature, is_celsius, is_fahrenheit;
+       gboolean is_adp0, is_adp1, is_adp2, is_adp3;
+       gboolean is_sign, is_batt, is_ol, is_pmax, is_pmin, is_apo;
+       gboolean is_dc, is_ac, is_vahz, is_min, is_max, is_rel, is_hold;
+       gboolean is_digit4, is_ul, is_vasel, is_vbar, is_lpf1, is_lpf0, is_rmr;
+       uint32_t baudrate;
+       int packet_size;
+       gboolean alt_functions, fivedigits, clampmeter, selectable_lpf;
+};
+
+SR_PRIV gboolean sr_es519xx_2400_11b_packet_valid(const uint8_t *buf);
+SR_PRIV int sr_es519xx_2400_11b_parse(const uint8_t *buf, float *floatval,
+               struct sr_datafeed_analog *analog, void *info);
+SR_PRIV gboolean sr_es519xx_2400_11b_altfn_packet_valid(const uint8_t *buf);
+SR_PRIV int sr_es519xx_2400_11b_altfn_parse(const uint8_t *buf,
+               float *floatval, struct sr_datafeed_analog *analog, void *info);
+SR_PRIV gboolean sr_es519xx_19200_11b_5digits_packet_valid(const uint8_t *buf);
+SR_PRIV int sr_es519xx_19200_11b_5digits_parse(const uint8_t *buf,
+               float *floatval, struct sr_datafeed_analog *analog, void *info);
+SR_PRIV gboolean sr_es519xx_19200_11b_clamp_packet_valid(const uint8_t *buf);
+SR_PRIV int sr_es519xx_19200_11b_clamp_parse(const uint8_t *buf,
+               float *floatval, struct sr_datafeed_analog *analog, void *info);
+SR_PRIV gboolean sr_es519xx_19200_11b_packet_valid(const uint8_t *buf);
+SR_PRIV int sr_es519xx_19200_11b_parse(const uint8_t *buf, float *floatval,
+               struct sr_datafeed_analog *analog, void *info);
+SR_PRIV gboolean sr_es519xx_19200_14b_packet_valid(const uint8_t *buf);
+SR_PRIV int sr_es519xx_19200_14b_parse(const uint8_t *buf, float *floatval,
+               struct sr_datafeed_analog *analog, void *info);
+SR_PRIV gboolean sr_es519xx_19200_14b_sel_lpf_packet_valid(const uint8_t *buf);
+SR_PRIV int sr_es519xx_19200_14b_sel_lpf_parse(const uint8_t *buf,
+               float *floatval, struct sr_datafeed_analog *analog, void *info);
+
+/*--- hardware/common/dmm/fs9922.c ------------------------------------------*/
+
+#define FS9922_PACKET_SIZE 14
+
+struct fs9922_info {
+       gboolean is_auto, is_dc, is_ac, is_rel, is_hold, is_bpn, is_z1, is_z2;
+       gboolean is_max, is_min, is_apo, is_bat, is_nano, is_z3, is_micro;
+       gboolean is_milli, is_kilo, is_mega, is_beep, is_diode, is_percent;
+       gboolean is_z4, is_volt, is_ampere, is_ohm, is_hfe, is_hertz, is_farad;
+       gboolean is_celsius, is_fahrenheit;
+       int bargraph_sign, bargraph_value;
+};
+
+SR_PRIV gboolean sr_fs9922_packet_valid(const uint8_t *buf);
+SR_PRIV int sr_fs9922_parse(const uint8_t *buf, float *floatval,
+                           struct sr_datafeed_analog *analog, void *info);
+SR_PRIV void sr_fs9922_z1_diode(struct sr_datafeed_analog *analog, void *info);
+
+/*--- hardware/common/dmm/fs9721.c ------------------------------------------*/
+
+#define FS9721_PACKET_SIZE 14
+
+struct fs9721_info {
+       gboolean is_ac, is_dc, is_auto, is_rs232, is_micro, is_nano, is_kilo;
+       gboolean is_diode, is_milli, is_percent, is_mega, is_beep, is_farad;
+       gboolean is_ohm, is_rel, is_hold, is_ampere, is_volt, is_hz, is_bat;
+       gboolean is_c2c1_11, is_c2c1_10, is_c2c1_01, is_c2c1_00, is_sign;
+};
+
+SR_PRIV gboolean sr_fs9721_packet_valid(const uint8_t *buf);
+SR_PRIV int sr_fs9721_parse(const uint8_t *buf, float *floatval,
+                           struct sr_datafeed_analog *analog, void *info);
+SR_PRIV void sr_fs9721_00_temp_c(struct sr_datafeed_analog *analog, void *info);
+SR_PRIV void sr_fs9721_01_temp_c(struct sr_datafeed_analog *analog, void *info);
+SR_PRIV void sr_fs9721_10_temp_c(struct sr_datafeed_analog *analog, void *info);
+SR_PRIV void sr_fs9721_01_10_temp_f_c(struct sr_datafeed_analog *analog, void *info);
+SR_PRIV void sr_fs9721_max_c_min(struct sr_datafeed_analog *analog, void *info);
+
+/*--- hardware/common/dmm/m2110.c -----------------------------------------*/
+
+#define BBCGM_M2110_PACKET_SIZE 9
+
+SR_PRIV gboolean sr_m2110_packet_valid(const uint8_t *buf);
+SR_PRIV int sr_m2110_parse(const uint8_t *buf, float *floatval,
+                            struct sr_datafeed_analog *analog, void *info);
+
+/*--- hardware/common/dmm/metex14.c -----------------------------------------*/
+
+#define METEX14_PACKET_SIZE 14
+
+struct metex14_info {
+       gboolean is_ac, is_dc, is_resistance, is_capacity, is_temperature;
+       gboolean is_diode, is_frequency, is_ampere, is_volt, is_farad;
+       gboolean is_hertz, is_ohm, is_celsius, is_pico, is_nano, is_micro;
+       gboolean is_milli, is_kilo, is_mega, is_gain, is_decibel, is_hfe;
+       gboolean is_unitless, is_logic;
+};
+
+#ifdef HAVE_LIBSERIALPORT
+SR_PRIV int sr_metex14_packet_request(struct sr_serial_dev_inst *serial);
+#endif
+SR_PRIV gboolean sr_metex14_packet_valid(const uint8_t *buf);
+SR_PRIV int sr_metex14_parse(const uint8_t *buf, float *floatval,
+                            struct sr_datafeed_analog *analog, void *info);
+
+/*--- hardware/common/dmm/rs9lcd.c ------------------------------------------*/
+
+#define RS9LCD_PACKET_SIZE 9
+
+/* Dummy info struct. The parser does not use it. */
+struct rs9lcd_info { int dummy; };
+
+SR_PRIV gboolean sr_rs9lcd_packet_valid(const uint8_t *buf);
+SR_PRIV int sr_rs9lcd_parse(const uint8_t *buf, float *floatval,
+                           struct sr_datafeed_analog *analog, void *info);
+
+#endif
diff --git a/src/log.c b/src/log.c
new file mode 100644 (file)
index 0000000..db16c30
--- /dev/null
+++ b/src/log.c
@@ -0,0 +1,302 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2011-2012 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include "libsigrok.h"
+/** @cond PRIVATE */
+#define NO_LOG_WRAPPERS
+/** @endcond */
+#include "libsigrok-internal.h"
+
+/**
+ * @file
+ *
+ * Controlling the libsigrok message logging functionality.
+ */
+
+/**
+ * @defgroup grp_logging Logging
+ *
+ * Controlling the libsigrok message logging functionality.
+ *
+ * @{
+ */
+
+/* Currently selected libsigrok loglevel. Default: SR_LOG_WARN. */
+static int cur_loglevel = SR_LOG_WARN; /* Show errors+warnings per default. */
+
+/* Function prototype. */
+static int sr_logv(void *cb_data, int loglevel, const char *format,
+                  va_list args);
+
+/* Pointer to the currently selected log callback. Default: sr_logv(). */
+static sr_log_callback sr_log_cb = sr_logv;
+
+/*
+ * Pointer to private data that can be passed to the log callback.
+ * This can be used (for example) by C++ GUIs to pass a "this" pointer.
+ */
+static void *sr_log_cb_data = NULL;
+
+/* Log domain (a short string that is used as prefix for all messages). */
+/** @cond PRIVATE */
+#define LOGDOMAIN_MAXLEN 30
+#define LOGDOMAIN_DEFAULT "sr: "
+/** @endcond */
+static char sr_log_domain[LOGDOMAIN_MAXLEN + 1] = LOGDOMAIN_DEFAULT;
+
+/**
+ * Set the libsigrok loglevel.
+ *
+ * This influences the amount of log messages (debug messages, error messages,
+ * and so on) libsigrok will output. Using SR_LOG_NONE disables all messages.
+ *
+ * Note that this function itself will also output log messages. After the
+ * loglevel has changed, it will output a debug message with SR_LOG_DBG for
+ * example. Whether this message is shown depends on the (new) loglevel.
+ *
+ * @param loglevel The loglevel to set (SR_LOG_NONE, SR_LOG_ERR, SR_LOG_WARN,
+ *                 SR_LOG_INFO, SR_LOG_DBG, or SR_LOG_SPEW).
+ *
+ * @return SR_OK upon success, SR_ERR_ARG upon invalid loglevel.
+ *
+ * @since 0.1.0
+ */
+SR_API int sr_log_loglevel_set(int loglevel)
+{
+       if (loglevel < SR_LOG_NONE || loglevel > SR_LOG_SPEW) {
+               sr_err("Invalid loglevel %d.", loglevel);
+               return SR_ERR_ARG;
+       }
+
+       cur_loglevel = loglevel;
+
+       sr_dbg("libsigrok loglevel set to %d.", loglevel);
+
+       return SR_OK;
+}
+
+/**
+ * Get the libsigrok loglevel.
+ *
+ * @return The currently configured libsigrok loglevel.
+ *
+ * @since 0.1.0
+ */
+SR_API int sr_log_loglevel_get(void)
+{
+       return cur_loglevel;
+}
+
+/**
+ * Set the libsigrok logdomain string.
+ *
+ * @param logdomain The string to use as logdomain for libsigrok log
+ *                  messages from now on. Must not be NULL. The maximum
+ *                  length of the string is 30 characters (this does not
+ *                  include the trailing NUL-byte). Longer strings are
+ *                  silently truncated.
+ *                  In order to not use a logdomain, pass an empty string.
+ *                  The function makes its own copy of the input string, i.e.
+ *                  the caller does not need to keep it around.
+ *
+ * @return SR_OK upon success, SR_ERR_ARG upon invalid logdomain.
+ *
+ * @since 0.1.0
+ */
+SR_API int sr_log_logdomain_set(const char *logdomain)
+{
+       if (!logdomain) {
+               sr_err("log: %s: logdomain was NULL", __func__);
+               return SR_ERR_ARG;
+       }
+
+       /* TODO: Error handling. */
+       snprintf((char *)&sr_log_domain, LOGDOMAIN_MAXLEN, "%s", logdomain);
+
+       sr_dbg("Log domain set to '%s'.", (const char *)&sr_log_domain);
+
+       return SR_OK;
+}
+
+/**
+ * Get the currently configured libsigrok logdomain.
+ *
+ * @return A copy of the currently configured libsigrok logdomain
+ *         string. The caller is responsible for g_free()ing the string when
+ *         it is no longer needed.
+ *
+ * @since 0.1.0
+ */
+SR_API char *sr_log_logdomain_get(void)
+{
+       return g_strdup((const char *)&sr_log_domain);
+}
+
+/**
+ * Set the libsigrok log callback to the specified function.
+ *
+ * @param cb Function pointer to the log callback function to use.
+ *           Must not be NULL.
+ * @param cb_data Pointer to private data to be passed on. This can be used by
+ *                the caller to pass arbitrary data to the log functions. This
+ *                pointer is only stored or passed on by libsigrok, and is
+ *                never used or interpreted in any way. The pointer is allowed
+ *                to be NULL if the caller doesn't need/want to pass any data.
+ *
+ * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments.
+ *
+ * @since 0.3.0
+ */
+SR_API int sr_log_callback_set(sr_log_callback cb, void *cb_data)
+{
+       if (!cb) {
+               sr_err("log: %s: cb was NULL", __func__);
+               return SR_ERR_ARG;
+       }
+
+       /* Note: 'cb_data' is allowed to be NULL. */
+
+       sr_log_cb = cb;
+       sr_log_cb_data = cb_data;
+
+       return SR_OK;
+}
+
+/**
+ * Set the libsigrok log callback to the default built-in one.
+ *
+ * Additionally, the internal 'sr_log_cb_data' pointer is set to NULL.
+ *
+ * @return SR_OK upon success, a negative error code otherwise.
+ *
+ * @since 0.1.0
+ */
+SR_API int sr_log_callback_set_default(void)
+{
+       /*
+        * Note: No log output in this function, as it should safely work
+        * even if the currently set log callback is buggy/broken.
+        */
+       sr_log_cb = sr_logv;
+       sr_log_cb_data = NULL;
+
+       return SR_OK;
+}
+
+static int sr_logv(void *cb_data, int loglevel, const char *format, va_list args)
+{
+       int ret;
+
+       /* This specific log callback doesn't need the void pointer data. */
+       (void)cb_data;
+
+       /* Only output messages of at least the selected loglevel(s). */
+       if (loglevel > cur_loglevel)
+               return SR_OK; /* TODO? */
+
+       if (sr_log_domain[0] != '\0')
+               fprintf(stderr, "%s", sr_log_domain);
+       ret = vfprintf(stderr, format, args);
+       fprintf(stderr, "\n");
+
+       return ret;
+}
+
+/** @private */
+SR_PRIV int sr_log(int loglevel, const char *format, ...)
+{
+       int ret;
+       va_list args;
+
+       va_start(args, format);
+       ret = sr_log_cb(sr_log_cb_data, loglevel, format, args);
+       va_end(args);
+
+       return ret;
+}
+
+/** @private */
+SR_PRIV int sr_spew(const char *format, ...)
+{
+       int ret;
+       va_list args;
+
+       va_start(args, format);
+       ret = sr_log_cb(sr_log_cb_data, SR_LOG_SPEW, format, args);
+       va_end(args);
+
+       return ret;
+}
+
+/** @private */
+SR_PRIV int sr_dbg(const char *format, ...)
+{
+       int ret;
+       va_list args;
+
+       va_start(args, format);
+       ret = sr_log_cb(sr_log_cb_data, SR_LOG_DBG, format, args);
+       va_end(args);
+
+       return ret;
+}
+
+/** @private */
+SR_PRIV int sr_info(const char *format, ...)
+{
+       int ret;
+       va_list args;
+
+       va_start(args, format);
+       ret = sr_log_cb(sr_log_cb_data, SR_LOG_INFO, format, args);
+       va_end(args);
+
+       return ret;
+}
+
+/** @private */
+SR_PRIV int sr_warn(const char *format, ...)
+{
+       int ret;
+       va_list args;
+
+       va_start(args, format);
+       ret = sr_log_cb(sr_log_cb_data, SR_LOG_WARN, format, args);
+       va_end(args);
+
+       return ret;
+}
+
+/** @private */
+SR_PRIV int sr_err(const char *format, ...)
+{
+       int ret;
+       va_list args;
+
+       va_start(args, format);
+       ret = sr_log_cb(sr_log_cb_data, SR_LOG_ERR, format, args);
+       va_end(args);
+
+       return ret;
+}
+
+/** @} */
diff --git a/src/output/analog.c b/src/output/analog.c
new file mode 100644 (file)
index 0000000..fbc41d8
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert@biot.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 <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "output/analog"
+
+struct context {
+       int num_enabled_channels;
+       GPtrArray *channellist;
+};
+
+static int init(struct sr_output *o)
+{
+       struct context *ctx;
+       struct sr_channel *ch;
+       GSList *l;
+
+       sr_spew("Initializing output module.");
+
+       if (!o || !o->sdi)
+               return SR_ERR_ARG;
+
+       if (!(ctx = g_try_malloc0(sizeof(struct context)))) {
+               sr_err("Output module context malloc failed.");
+               return SR_ERR_MALLOC;
+       }
+       o->internal = ctx;
+
+       /* Get the number of channels and their names. */
+       ctx->channellist = g_ptr_array_new();
+       for (l = o->sdi->channels; l; l = l->next) {
+               ch = l->data;
+               if (!ch || !ch->enabled)
+                       continue;
+               g_ptr_array_add(ctx->channellist, ch->name);
+               ctx->num_enabled_channels++;
+       }
+
+       return SR_OK;
+}
+
+static void si_printf(float value, GString *out, char *unitstr)
+{
+       float v;
+
+       if (signbit(value))
+               v = -(value);
+       else
+               v = value;
+
+       if (v < 1e-12 || v > 1e+12)
+               g_string_append_printf(out, "%f %s", value, unitstr);
+       else if (v > 1e+9)
+               g_string_append_printf(out, "%f G%s", value / 1e+9, unitstr);
+       else if (v > 1e+6)
+               g_string_append_printf(out, "%f M%s", value / 1e+6, unitstr);
+       else if (v > 1e+3)
+               g_string_append_printf(out, "%f k%s", value / 1e+3, unitstr);
+       else if (v < 1e-9)
+               g_string_append_printf(out, "%f n%s", value * 1e+9, unitstr);
+       else if (v < 1e-6)
+               g_string_append_printf(out, "%f u%s", value * 1e+6, unitstr);
+       else if (v < 1e-3)
+               g_string_append_printf(out, "%f m%s", value * 1e+3, unitstr);
+       else
+               g_string_append_printf(out, "%f %s", value, unitstr);
+
+}
+
+static void fancyprint(int unit, int mqflags, float value, GString *out)
+{
+       switch (unit) {
+       case SR_UNIT_VOLT:
+               si_printf(value, out, "V");
+               break;
+       case SR_UNIT_AMPERE:
+               si_printf(value, out, "A");
+               break;
+       case SR_UNIT_OHM:
+               si_printf(value, out, "");
+               g_string_append_unichar(out, 0x2126);
+               break;
+       case SR_UNIT_FARAD:
+               si_printf(value, out, "F");
+               break;
+       case SR_UNIT_KELVIN:
+               si_printf(value, out, "K");
+               break;
+       case SR_UNIT_CELSIUS:
+               si_printf(value, out, "");
+               g_string_append_unichar(out, 0x00b0);
+               g_string_append_c(out, 'C');
+               break;
+       case SR_UNIT_FAHRENHEIT:
+               si_printf(value, out, "");
+               g_string_append_unichar(out, 0x00b0);
+               g_string_append_c(out, 'F');
+               break;
+       case SR_UNIT_HERTZ:
+               si_printf(value, out, "Hz");
+               break;
+       case SR_UNIT_PERCENTAGE:
+               g_string_append_printf(out, "%f %%", value);
+               break;
+       case SR_UNIT_BOOLEAN:
+               if (value > 0)
+                       g_string_append_printf(out, "TRUE");
+               else
+                       g_string_append_printf(out, "FALSE");
+               break;
+       case SR_UNIT_SECOND:
+               si_printf(value, out, "s");
+               break;
+       case SR_UNIT_SIEMENS:
+               si_printf(value, out, "S");
+               break;
+       case SR_UNIT_DECIBEL_MW:
+               si_printf(value, out, "dBu");
+               break;
+       case SR_UNIT_DECIBEL_VOLT:
+               si_printf(value, out, "dBV");
+               break;
+       case SR_UNIT_DECIBEL_SPL:
+               if (mqflags & SR_MQFLAG_SPL_FREQ_WEIGHT_A)
+                       si_printf(value, out, "dB(A)");
+               else if (mqflags & SR_MQFLAG_SPL_FREQ_WEIGHT_C)
+                       si_printf(value, out, "dB(C)");
+               else if (mqflags & SR_MQFLAG_SPL_FREQ_WEIGHT_Z)
+                       si_printf(value, out, "dB(Z)");
+               else
+                       /* No frequency weighting, or non-standard "flat" */
+                       si_printf(value, out, "dB(SPL)");
+               if (mqflags & SR_MQFLAG_SPL_TIME_WEIGHT_S)
+                       g_string_append(out, " S");
+               else if (mqflags & SR_MQFLAG_SPL_TIME_WEIGHT_F)
+                       g_string_append(out, " F");
+               if (mqflags & SR_MQFLAG_SPL_LAT)
+                       g_string_append(out, " LAT");
+               else if (mqflags & SR_MQFLAG_SPL_PCT_OVER_ALARM)
+                       /* Not a standard function for SLMs, so this is
+                        * a made-up notation. */
+                       g_string_append(out, " %oA");
+               break;
+       case SR_UNIT_CONCENTRATION:
+               g_string_append_printf(out, "%f ppm", value * 1000000);
+               break;
+       case SR_UNIT_REVOLUTIONS_PER_MINUTE:
+               si_printf(value, out, "RPM");
+               break;
+       case SR_UNIT_VOLT_AMPERE:
+               si_printf(value, out, "VA");
+               break;
+       case SR_UNIT_WATT:
+               si_printf(value, out, "W");
+               break;
+       case SR_UNIT_WATT_HOUR:
+               si_printf(value, out, "Wh");
+               break;
+       case SR_UNIT_METER_SECOND:
+               si_printf(value, out, "m/s");
+               break;
+       case SR_UNIT_HECTOPASCAL:
+               si_printf(value, out, "hPa");
+               break;
+       case SR_UNIT_HUMIDITY_293K:
+               si_printf(value, out, "%rF");
+               break;
+       default:
+               si_printf(value, out, "");
+               break;
+       }
+
+       if (mqflags & SR_MQFLAG_AC)
+               g_string_append_printf(out, " AC");
+       if (mqflags & SR_MQFLAG_DC)
+               g_string_append_printf(out, " DC");
+       if (mqflags & SR_MQFLAG_RMS)
+               g_string_append_printf(out, " RMS");
+       if (mqflags & SR_MQFLAG_DIODE)
+               g_string_append_printf(out, " DIODE");
+       if (mqflags & SR_MQFLAG_HOLD)
+               g_string_append_printf(out, " HOLD");
+       if (mqflags & SR_MQFLAG_MAX)
+               g_string_append_printf(out, " MAX");
+       if (mqflags & SR_MQFLAG_MIN)
+               g_string_append_printf(out, " MIN");
+       if (mqflags & SR_MQFLAG_AUTORANGE)
+               g_string_append_printf(out, " AUTO");
+       if (mqflags & SR_MQFLAG_RELATIVE)
+               g_string_append_printf(out, " REL");
+       if (mqflags & SR_MQFLAG_AVG)
+               g_string_append_printf(out, " AVG");
+       g_string_append_c(out, '\n');
+}
+
+static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
+               GString **out)
+{
+       const struct sr_datafeed_analog *analog;
+       struct sr_channel *ch;
+       GSList *l;
+       const float *fdata;
+       int i, p;
+
+       *out = NULL;
+       if (!o || !o->sdi)
+               return SR_ERR_ARG;
+
+       switch (packet->type) {
+       case SR_DF_FRAME_BEGIN:
+               *out = g_string_new("FRAME-BEGIN\n");
+               break;
+       case SR_DF_FRAME_END:
+               *out = g_string_new("FRAME-END\n");
+               break;
+       case SR_DF_ANALOG:
+               analog = packet->payload;
+               fdata = (const float *)analog->data;
+               *out = g_string_sized_new(512);
+               for (i = 0; i < analog->num_samples; i++) {
+                       for (l = analog->channels, p = 0; l; l = l->next, p++) {
+                               ch = l->data;
+                               g_string_append_printf(*out, "%s: ", ch->name);
+                               fancyprint(analog->unit, analog->mqflags,
+                                               fdata[i + p], *out);
+                       }
+               }
+               break;
+       }
+
+       return SR_OK;
+}
+
+static int cleanup(struct sr_output *o)
+{
+       struct context *ctx;
+
+       if (!o || !o->sdi)
+               return SR_ERR_ARG;
+       ctx = o->internal;
+
+       g_ptr_array_free(ctx->channellist, 1);
+       g_free(ctx);
+       o->internal = NULL;
+
+       return SR_OK;
+}
+
+SR_PRIV struct sr_output_format output_analog = {
+       .id = "analog",
+       .description = "Analog data",
+       .init = init,
+       .receive = receive,
+       .cleanup = cleanup
+};
diff --git a/src/output/ascii.c b/src/output/ascii.c
new file mode 100644 (file)
index 0000000..d068942
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2011 HÃ¥vard Espeland <gus@ping.uio.no>
+ * Copyright (C) 2014 Bert Vermeulen <bert@biot.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 <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "output/hex"
+
+#define DEFAULT_SAMPLES_PER_LINE 74
+
+struct context {
+       unsigned int num_enabled_channels;
+       int samples_per_line;
+       int bit_cnt;
+       int spl_cnt;
+       int trigger;
+       uint64_t samplerate;
+       int *channel_index;
+       char **channel_names;
+       char **line_values;
+       uint8_t *prev_sample;
+       gboolean header_done;
+       GString **lines;
+       GString *header;
+};
+
+static int init(struct sr_output *o)
+{
+       struct context *ctx;
+       struct sr_channel *ch;
+       GSList *l;
+       GHashTableIter iter;
+       gpointer key, value;
+       unsigned int i, j;
+       int spl;
+
+       if (!o || !o->sdi)
+               return SR_ERR_ARG;
+
+       spl = DEFAULT_SAMPLES_PER_LINE;
+       g_hash_table_iter_init(&iter, o->params);
+       while (g_hash_table_iter_next(&iter, &key, &value)) {
+               if (!strcmp(key, "width")) {
+                       if ((spl = strtoul(value, NULL, 10)) < 1) {
+                               sr_err("Invalid width.");
+                               return SR_ERR_ARG;
+                       }
+               } else {
+                       sr_err("Unknown parameter '%s'.", key);
+                       return SR_ERR_ARG;
+               }
+       }
+
+       ctx = g_malloc0(sizeof(struct context));
+       o->internal = ctx;
+       ctx->trigger = -1;
+       ctx->samples_per_line = spl;
+
+       for (l = o->sdi->channels; l; l = l->next) {
+               ch = l->data;
+               if (ch->type != SR_CHANNEL_LOGIC)
+                       continue;
+               if (!ch->enabled)
+                       continue;
+               ctx->num_enabled_channels++;
+       }
+       ctx->channel_index = g_malloc(sizeof(int) * ctx->num_enabled_channels);
+       ctx->channel_names = g_malloc(sizeof(char *) * ctx->num_enabled_channels);
+       ctx->lines = g_malloc(sizeof(GString *) * ctx->num_enabled_channels);
+       ctx->prev_sample = g_malloc(g_slist_length(o->sdi->channels));
+
+       j = 0;
+       for (i = 0, l = o->sdi->channels; l; l = l->next, i++) {
+               ch = l->data;
+               if (ch->type != SR_CHANNEL_LOGIC)
+                       continue;
+               if (!ch->enabled)
+                       continue;
+               ctx->channel_index[j] = ch->index;
+               ctx->channel_names[j] = ch->name;
+               ctx->lines[j] = g_string_sized_new(80);
+               g_string_printf(ctx->lines[j], "%s:", ch->name);
+               j++;
+       }
+
+       return SR_OK;
+}
+
+static GString *gen_header(struct sr_output *o)
+{
+       struct context *ctx;
+       GVariant *gvar;
+       GString *header;
+       int num_channels;
+       char *samplerate_s;
+
+       ctx = o->internal;
+       if (ctx->samplerate == 0) {
+               if (sr_config_get(o->sdi->driver, o->sdi, NULL, SR_CONF_SAMPLERATE,
+                               &gvar) == SR_OK) {
+                       ctx->samplerate = g_variant_get_uint64(gvar);
+                       g_variant_unref(gvar);
+               }
+       }
+
+       header = g_string_sized_new(512);
+       g_string_printf(header, "%s\n", PACKAGE_STRING);
+       num_channels = g_slist_length(o->sdi->channels);
+       g_string_append_printf(header, "Acquisition with %d/%d channels",
+                       ctx->num_enabled_channels, num_channels);
+       if (ctx->samplerate != 0) {
+               samplerate_s = sr_samplerate_string(ctx->samplerate);
+               g_string_append_printf(header, " at %s", samplerate_s);
+               g_free(samplerate_s);
+       }
+       g_string_append_printf(header, "\n");
+
+       return header;
+}
+
+static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
+               GString **out)
+{
+       const struct sr_datafeed_meta *meta;
+       const struct sr_datafeed_logic *logic;
+       const struct sr_config *src;
+       GSList *l;
+       struct context *ctx;
+       int idx, offset, curbit, prevbit;
+       uint64_t i, j;
+       gchar *p, c;
+
+       *out = NULL;
+       if (!o || !o->sdi)
+               return SR_ERR_ARG;
+       if (!(ctx = o->internal))
+               return SR_ERR_ARG;
+
+       switch (packet->type) {
+       case SR_DF_META:
+               meta = packet->payload;
+               for (l = meta->config; l; l = l->next) {
+                       src = l->data;
+                       if (src->key != SR_CONF_SAMPLERATE)
+                               continue;
+                       ctx->samplerate = g_variant_get_uint64(src->data);
+               }
+               break;
+       case SR_DF_TRIGGER:
+               ctx->trigger = ctx->spl_cnt;
+               break;
+       case SR_DF_LOGIC:
+               if (!ctx->header_done) {
+                       *out = gen_header(o);
+                       ctx->header_done = TRUE;
+               } else
+                       *out = g_string_sized_new(512);
+
+               logic = packet->payload;
+               for (i = 0; i <= logic->length - logic->unitsize; i += logic->unitsize) {
+                       ctx->spl_cnt++;
+                       for (j = 0; j < ctx->num_enabled_channels; j++) {
+                               idx = ctx->channel_index[j];
+                               p = logic->data + i + idx / 8;
+                               curbit = *p & (1 << (idx % 8));
+                               prevbit = (ctx->prev_sample[idx / 8] & ((uint8_t) 1 << (idx % 8)));
+
+                               c = curbit ? '"' : '.';
+                               if (ctx->spl_cnt > 1) {
+                                       if (curbit < prevbit)
+                                               c = '\\';
+                                       else if (curbit > prevbit)
+                                               c = '/';
+                               }
+                               g_string_append_c(ctx->lines[j], c);
+
+                               if (ctx->spl_cnt == ctx->samples_per_line) {
+                                       /* Flush line buffers. */
+                                       g_string_append_len(*out, ctx->lines[j]->str, ctx->lines[j]->len);
+                                       g_string_append_c(*out, '\n');
+                                       if (j == ctx->num_enabled_channels  - 1 && ctx->trigger > -1) {
+                                               offset = ctx->trigger + ctx->trigger / 8;
+                                               g_string_append_printf(*out, "T:%*s^ %d\n", offset, "", ctx->trigger);
+                                               ctx->trigger = -1;
+                                       }
+                                       g_string_printf(ctx->lines[j], "%s:", ctx->channel_names[j]);
+                               }
+                       }
+                       if (ctx->spl_cnt == ctx->samples_per_line)
+                               /* Line buffers were already flushed. */
+                               ctx->spl_cnt = 0;
+                       memcpy(ctx->prev_sample, logic->data + i, logic->unitsize);
+               }
+               break;
+       case SR_DF_END:
+               if (ctx->spl_cnt) {
+                       /* Line buffers need flushing. */
+                       *out = g_string_sized_new(512);
+                       for (i = 0; i < ctx->num_enabled_channels; i++) {
+                               g_string_append_len(*out, ctx->lines[i]->str, ctx->lines[i]->len);
+                               g_string_append_c(*out, '\n');
+                       }
+               }
+               break;
+       }
+
+       return SR_OK;
+}
+
+static int cleanup(struct sr_output *o)
+{
+       struct context *ctx;
+       unsigned int i;
+
+       if (!o)
+               return SR_ERR_ARG;
+
+       if (!(ctx = o->internal))
+               return SR_OK;
+
+       g_free(ctx->channel_index);
+       g_free(ctx->prev_sample);
+       g_free(ctx->channel_names);
+       for (i = 0; i < ctx->num_enabled_channels; i++)
+               g_string_free(ctx->lines[i], TRUE);
+       g_free(ctx->lines);
+       g_free(ctx);
+       o->internal = NULL;
+
+       return SR_OK;
+}
+
+SR_PRIV struct sr_output_format output_ascii = {
+       .id = "ascii",
+       .description = "ASCII",
+       .init = init,
+       .receive = receive,
+       .cleanup = cleanup,
+};
+
+
diff --git a/src/output/binary.c b/src/output/binary.c
new file mode 100644 (file)
index 0000000..6e2531d
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "output/binary"
+
+static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
+               GString **out)
+{
+       const struct sr_datafeed_logic *logic;
+
+       (void)o;
+
+       *out = NULL;
+       if (packet->type != SR_DF_LOGIC)
+               return SR_OK;
+       logic = packet->payload;
+       *out = g_string_new_len(logic->data, logic->length);
+
+       return SR_OK;
+}
+
+SR_PRIV struct sr_output_format output_binary = {
+       .id = "binary",
+       .description = "Raw binary",
+       .receive = receive,
+};
diff --git a/src/output/bits.c b/src/output/bits.c
new file mode 100644 (file)
index 0000000..b44f105
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Bert Vermeulen <bert@biot.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 <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "output/bits"
+
+#define DEFAULT_SAMPLES_PER_LINE 64
+
+struct context {
+       unsigned int num_enabled_channels;
+       int samples_per_line;
+       int spl_cnt;
+       int trigger;
+       uint64_t samplerate;
+       int *channel_index;
+       char **channel_names;
+       gboolean header_done;
+       GString **lines;
+};
+
+static int init(struct sr_output *o)
+{
+       struct context *ctx;
+       struct sr_channel *ch;
+       GSList *l;
+       GHashTableIter iter;
+       gpointer key, value;
+       unsigned int i, j;
+       int spl;
+
+       if (!o || !o->sdi)
+               return SR_ERR_ARG;
+
+       spl = DEFAULT_SAMPLES_PER_LINE;
+       g_hash_table_iter_init(&iter, o->params);
+       while (g_hash_table_iter_next(&iter, &key, &value)) {
+               if (!strcmp(key, "width")) {
+                       if ((spl = strtoul(value, NULL, 10)) < 1) {
+                               sr_err("Invalid width.");
+                               return SR_ERR_ARG;
+                       }
+               } else {
+                       sr_err("Unknown parameter '%s'.", key);
+                       return SR_ERR_ARG;
+               }
+       }
+
+       ctx = g_malloc0(sizeof(struct context));
+       o->internal = ctx;
+       ctx->trigger = -1;
+       ctx->samples_per_line = spl;
+
+       for (l = o->sdi->channels; l; l = l->next) {
+               ch = l->data;
+               if (ch->type != SR_CHANNEL_LOGIC)
+                       continue;
+               if (!ch->enabled)
+                       continue;
+               ctx->num_enabled_channels++;
+       }
+       ctx->channel_index = g_malloc(sizeof(int) * ctx->num_enabled_channels);
+       ctx->channel_names = g_malloc(sizeof(char *) * ctx->num_enabled_channels);
+       ctx->lines = g_malloc(sizeof(GString *) * ctx->num_enabled_channels);
+
+       j = 0;
+       for (i = 0, l = o->sdi->channels; l; l = l->next, i++) {
+               ch = l->data;
+               if (ch->type != SR_CHANNEL_LOGIC)
+                       continue;
+               if (!ch->enabled)
+                       continue;
+               ctx->channel_index[j] = ch->index;
+               ctx->channel_names[j] = ch->name;
+               ctx->lines[j] = g_string_sized_new(80);
+               g_string_printf(ctx->lines[j], "%s:", ch->name);
+               j++;
+       }
+
+       return SR_OK;
+}
+
+static GString *gen_header(struct sr_output *o)
+{
+       struct context *ctx;
+       GVariant *gvar;
+       GString *header;
+       int num_channels;
+       char *samplerate_s;
+
+       ctx = o->internal;
+       if (ctx->samplerate == 0) {
+               if (sr_config_get(o->sdi->driver, o->sdi, NULL, SR_CONF_SAMPLERATE,
+                               &gvar) == SR_OK) {
+                       ctx->samplerate = g_variant_get_uint64(gvar);
+                       g_variant_unref(gvar);
+               }
+       }
+
+       header = g_string_sized_new(512);
+       g_string_printf(header, "%s\n", PACKAGE_STRING);
+       num_channels = g_slist_length(o->sdi->channels);
+       g_string_append_printf(header, "Acquisition with %d/%d channels",
+                       ctx->num_enabled_channels, num_channels);
+       if (ctx->samplerate != 0) {
+               samplerate_s = sr_samplerate_string(ctx->samplerate);
+               g_string_append_printf(header, " at %s", samplerate_s);
+               g_free(samplerate_s);
+       }
+       g_string_append_printf(header, "\n");
+
+       return header;
+}
+
+static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
+               GString **out)
+{
+       const struct sr_datafeed_meta *meta;
+       const struct sr_datafeed_logic *logic;
+       const struct sr_config *src;
+       struct context *ctx;
+       GSList *l;
+       int idx, offset;
+       uint64_t i, j;
+       gchar *p, c;
+
+       *out = NULL;
+       if (!o || !o->sdi)
+               return SR_ERR_ARG;
+       if (!(ctx = o->internal))
+               return SR_ERR_ARG;
+
+       switch (packet->type) {
+       case SR_DF_META:
+               meta = packet->payload;
+               for (l = meta->config; l; l = l->next) {
+                       src = l->data;
+                       if (src->key != SR_CONF_SAMPLERATE)
+                               continue;
+                       ctx->samplerate = g_variant_get_uint64(src->data);
+               }
+               break;
+       case SR_DF_TRIGGER:
+               ctx->trigger = ctx->spl_cnt;
+               break;
+       case SR_DF_LOGIC:
+               if (!ctx->header_done) {
+                       *out = gen_header(o);
+                       ctx->header_done = TRUE;
+               } else
+                       *out = g_string_sized_new(512);
+
+               logic = packet->payload;
+               for (i = 0; i <= logic->length - logic->unitsize; i += logic->unitsize) {
+                       ctx->spl_cnt++;
+                       for (j = 0; j < ctx->num_enabled_channels; j++) {
+                               idx = ctx->channel_index[j];
+                               p = logic->data + i + idx / 8;
+                               c = (*p & (1 << (idx % 8))) ? '1' : '0';
+                               g_string_append_c(ctx->lines[j], c);
+
+                               if (ctx->spl_cnt == ctx->samples_per_line) {
+                                       /* Flush line buffers. */
+                                       g_string_append_len(*out, ctx->lines[j]->str, ctx->lines[j]->len);
+                                       g_string_append_c(*out, '\n');
+                                       if (j == ctx->num_enabled_channels  - 1 && ctx->trigger > -1) {
+                                               offset = ctx->trigger + ctx->trigger / 8;
+                                               g_string_append_printf(*out, "T:%*s^ %d\n", offset, "", ctx->trigger);
+                                               ctx->trigger = -1;
+                                       }
+                                       g_string_printf(ctx->lines[j], "%s:", ctx->channel_names[j]);
+                               } else if ((ctx->spl_cnt & 7) == 0) {
+                                       /* Add a space every 8th bit. */
+                                       g_string_append_c(ctx->lines[j], ' ');
+                               }
+                       }
+                       if (ctx->spl_cnt == ctx->samples_per_line)
+                               /* Line buffers were already flushed. */
+                               ctx->spl_cnt = 0;
+               }
+               break;
+       case SR_DF_END:
+               if (ctx->spl_cnt) {
+                       /* Line buffers need flushing. */
+                       *out = g_string_sized_new(512);
+                       for (i = 0; i < ctx->num_enabled_channels; i++) {
+                               g_string_append_len(*out, ctx->lines[i]->str, ctx->lines[i]->len);
+                               g_string_append_c(*out, '\n');
+                       }
+               }
+               break;
+       }
+
+       return SR_OK;
+}
+
+static int cleanup(struct sr_output *o)
+{
+       struct context *ctx;
+       unsigned int i;
+
+       if (!o)
+               return SR_ERR_ARG;
+
+       if (!(ctx = o->internal))
+               return SR_OK;
+
+       g_free(ctx->channel_index);
+       g_free(ctx->channel_names);
+       for (i = 0; i < ctx->num_enabled_channels; i++)
+               g_string_free(ctx->lines[i], TRUE);
+       g_free(ctx->lines);
+       g_free(ctx);
+       o->internal = NULL;
+
+       return SR_OK;
+}
+
+SR_PRIV struct sr_output_format output_bits = {
+       .id = "bits",
+       .description = "Bits",
+       .init = init,
+       .receive = receive,
+       .cleanup = cleanup,
+};
diff --git a/src/output/chronovu_la8.c b/src/output/chronovu_la8.c
new file mode 100644 (file)
index 0000000..ad0b5d3
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2011 Uwe Hermann <uwe@hermann-uwe.de>
+ * Copyright (C) 2014 Bert Vermeulen <bert@biot.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 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/>.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "output/chronovu-la8"
+
+struct context {
+       unsigned int num_enabled_channels;
+       gboolean triggered;
+       uint64_t samplerate;
+       uint64_t samplecount;
+       int *channel_index;
+       GString *pretrig_buf;
+};
+
+/**
+ * Check if the given samplerate is supported by the LA8 hardware.
+ *
+ * @param samplerate The samplerate (in Hz) to check.
+ *
+ * @return 1 if the samplerate is supported/valid, 0 otherwise.
+ */
+static gboolean is_valid_samplerate(uint64_t samplerate)
+{
+       unsigned int i;
+
+       for (i = 0; i < 255; i++) {
+               if (samplerate == (SR_MHZ(100) / (i + 1)))
+                       return TRUE;
+       }
+
+       return FALSE;
+}
+
+/**
+ * Convert a samplerate (in Hz) to the 'divcount' value the LA8 wants.
+ *
+ * LA8 hardware: sample period = (divcount + 1) * 10ns.
+ * Min. value for divcount: 0x00 (10ns sample period, 100MHz samplerate).
+ * Max. value for divcount: 0xfe (2550ns sample period, 392.15kHz samplerate).
+ *
+ * @param samplerate The samplerate in Hz.
+ *
+ * @return The divcount value as needed by the hardware, or 0xff upon errors.
+ */
+static uint8_t samplerate_to_divcount(uint64_t samplerate)
+{
+       if (samplerate == 0 || !is_valid_samplerate(samplerate)) {
+               sr_warn("Invalid samplerate (%" PRIu64 "Hz)", samplerate);
+               return 0xff;
+       }
+
+       return (SR_MHZ(100) / samplerate) - 1;
+}
+
+static int init(struct sr_output *o)
+{
+       struct context *ctx;
+       struct sr_channel *ch;
+       GSList *l;
+
+       if (!o || !o->sdi)
+               return SR_ERR_ARG;
+
+       ctx = g_malloc0(sizeof(struct context));
+       o->internal = ctx;
+
+       for (l = o->sdi->channels; l; l = l->next) {
+               ch = l->data;
+               if (ch->type != SR_CHANNEL_LOGIC)
+                       continue;
+               if (!ch->enabled)
+                       continue;
+               ctx->num_enabled_channels++;
+       }
+       ctx->channel_index = g_malloc(sizeof(int) * ctx->num_enabled_channels);
+       ctx->pretrig_buf = g_string_sized_new(1024);
+
+       return SR_OK;
+}
+
+static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
+               GString **out)
+{
+       const struct sr_datafeed_logic *logic;
+       struct context *ctx;
+       GVariant *gvar;
+       uint64_t samplerate;
+       gchar c[4];
+
+       *out = NULL;
+       if (!o || !o->sdi)
+               return SR_ERR_ARG;
+       if (!(ctx = o->internal))
+               return SR_ERR_ARG;
+
+       switch (packet->type) {
+       case SR_DF_HEADER:
+               /* One byte for the 'divcount' value. */
+               if (sr_config_get(o->sdi->driver, o->sdi, NULL, SR_CONF_SAMPLERATE,
+                               &gvar) == SR_OK) {
+                       samplerate = g_variant_get_uint64(gvar);
+                       g_variant_unref(gvar);
+               } else
+                       samplerate = 0;
+               c[0] = samplerate_to_divcount(samplerate);
+               *out = g_string_new_len(c, 1);
+               ctx->triggered = FALSE;
+               break;
+       case SR_DF_TRIGGER:
+               /* Four bytes (little endian) for the trigger point. */
+               c[0] = ctx->samplecount & 0xff;
+               c[1] = (ctx->samplecount >> 8) & 0xff;
+               c[2] = (ctx->samplecount >> 16) & 0xff;
+               c[3] = (ctx->samplecount >> 24) & 0xff;
+               *out = g_string_new_len(c, 4);
+               /* Flush the pre-trigger buffer. */
+               if (ctx->pretrig_buf->len)
+                       g_string_append_len(*out, ctx->pretrig_buf->str,
+                                       ctx->pretrig_buf->len);
+               ctx->triggered = TRUE;
+               break;
+       case SR_DF_LOGIC:
+               logic = packet->payload;
+               if (!ctx->triggered)
+                       g_string_append_len(ctx->pretrig_buf, logic->data, logic->length);
+               else
+                       *out = g_string_new_len(logic->data, logic->length);
+               ctx->samplecount += logic->length / logic->unitsize;
+               break;
+       case SR_DF_END:
+               if (!ctx->triggered && ctx->pretrig_buf->len) {
+                       /* We never got a trigger, submit an empty one. */
+                       *out = g_string_sized_new(ctx->pretrig_buf->len + 4);
+                       g_string_append_len(*out, "\x00\x00\x00\x00", 4);
+                       g_string_append_len(*out, ctx->pretrig_buf->str, ctx->pretrig_buf->len);
+               }
+               break;
+       }
+
+       return SR_OK;
+}
+
+static int cleanup(struct sr_output *o)
+{
+       struct context *ctx;
+
+       if (!o || !o->sdi)
+               return SR_ERR_ARG;
+
+       if (o->internal) {
+               ctx = o->internal;
+               g_string_free(ctx->pretrig_buf, TRUE);
+               g_free(ctx->channel_index);
+               g_free(o->internal);
+               o->internal = NULL;
+       }
+
+       return SR_OK;
+}
+
+SR_PRIV struct sr_output_format output_chronovu_la8 = {
+       .id = "chronovu-la8",
+       .description = "ChronoVu LA8",
+       .init = init,
+       .receive = receive,
+       .cleanup = cleanup,
+};
diff --git a/src/output/csv.c b/src/output/csv.c
new file mode 100644 (file)
index 0000000..d17969e
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2011 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include "config.h" /* Needed for PACKAGE_STRING and others. */
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "output/csv"
+
+struct context {
+       unsigned int num_enabled_channels;
+       uint64_t samplerate;
+       char separator;
+       gboolean header_done;
+       int *channel_index;
+};
+
+/*
+ * TODO:
+ *  - Option to specify delimiter character and/or string.
+ *  - Option to (not) print metadata as comments.
+ *  - Option to specify the comment character(s), e.g. # or ; or C/C++-style.
+ *  - Option to (not) print samplenumber / time as extra column.
+ *  - Option to "compress" output (only print changed samples, VCD-like).
+ *  - Option to print comma-separated bits, or whole bytes/words (for 8/16
+ *    channel LAs) as ASCII/hex etc. etc.
+ *  - Trigger support.
+ */
+
+static int init(struct sr_output *o)
+{
+       struct context *ctx;
+       struct sr_channel *ch;
+       GSList *l;
+       int i;
+
+       if (!o || !o->sdi)
+               return SR_ERR_ARG;
+
+       ctx = g_malloc0(sizeof(struct context));
+       o->internal = ctx;
+       ctx->separator = ',';
+
+       /* Get the number of channels, and the unitsize. */
+       for (l = o->sdi->channels; l; l = l->next) {
+               ch = l->data;
+               if (ch->type != SR_CHANNEL_LOGIC)
+                       continue;
+               if (!ch->enabled)
+                       continue;
+               ctx->num_enabled_channels++;
+       }
+       ctx->channel_index = g_malloc(sizeof(int) * ctx->num_enabled_channels);
+
+       /* Once more to map the enabled channels. */
+       for (i = 0, l = o->sdi->channels; l; l = l->next) {
+               ch = l->data;
+               if (ch->type != SR_CHANNEL_LOGIC)
+                       continue;
+               if (!ch->enabled)
+                       continue;
+               ctx->channel_index[i++] = ch->index;
+       }
+
+       return SR_OK;
+}
+
+static GString *gen_header(struct sr_output *o)
+{
+       struct context *ctx;
+       struct sr_channel *ch;
+       GVariant *gvar;
+       GString *header;
+       GSList *l;
+       time_t t;
+       int num_channels, i;
+       char *samplerate_s;
+
+       ctx = o->internal;
+       header = g_string_sized_new(512);
+
+       /* Some metadata */
+       t = time(NULL);
+       g_string_append_printf(header, "; CSV, generated by %s on %s",
+                       PACKAGE_STRING, ctime(&t));
+
+       /* Columns / channels */
+       num_channels = g_slist_length(o->sdi->channels);
+       g_string_append_printf(header, "; Channels (%d/%d):",
+                       ctx->num_enabled_channels, num_channels);
+       for (i = 0, l = o->sdi->channels; l; l = l->next, i++) {
+               ch = l->data;
+               if (ch->type != SR_CHANNEL_LOGIC)
+                       continue;
+               if (!ch->enabled)
+                       continue;
+               g_string_append_printf(header, " %s,", ch->name);
+       }
+       if (o->sdi->channels)
+               /* Drop last separator. */
+               g_string_truncate(header, header->len - 1);
+       g_string_append_printf(header, "\n");
+
+       if (ctx->samplerate == 0) {
+               if (sr_config_get(o->sdi->driver, o->sdi, NULL, SR_CONF_SAMPLERATE,
+                               &gvar) == SR_OK) {
+                       ctx->samplerate = g_variant_get_uint64(gvar);
+                       g_variant_unref(gvar);
+               }
+       }
+       if (ctx->samplerate != 0) {
+               samplerate_s = sr_samplerate_string(ctx->samplerate);
+               g_string_append_printf(header, "; Samplerate: %s\n", samplerate_s);
+               g_free(samplerate_s);
+       }
+
+       return header;
+}
+
+static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
+               GString **out)
+{
+       const struct sr_datafeed_meta *meta;
+       const struct sr_datafeed_logic *logic;
+       const struct sr_config *src;
+       GSList *l;
+       struct context *ctx;
+       int idx;
+       uint64_t i, j;
+       gchar *p, c;
+
+       *out = NULL;
+       if (!o || !o->sdi)
+               return SR_ERR_ARG;
+       if (!(ctx = o->internal))
+               return SR_ERR_ARG;
+
+       switch (packet->type) {
+       case SR_DF_META:
+               meta = packet->payload;
+               for (l = meta->config; l; l = l->next) {
+                       src = l->data;
+                       if (src->key != SR_CONF_SAMPLERATE)
+                               continue;
+                       ctx->samplerate = g_variant_get_uint64(src->data);
+               }
+               break;
+       case SR_DF_LOGIC:
+               logic = packet->payload;
+               if (!ctx->header_done) {
+                       *out = gen_header(o);
+                       ctx->header_done = TRUE;
+               } else {
+                       *out = g_string_sized_new(512);
+               }
+
+               for (i = 0; i <= logic->length - logic->unitsize; i += logic->unitsize) {
+                       for (j = 0; j < ctx->num_enabled_channels; j++) {
+                               idx = ctx->channel_index[j];
+                               p = logic->data + i + idx / 8;
+                               c = *p & (1 << (idx % 8));
+                               g_string_append_c(*out, c ? '1' : '0');
+                               g_string_append_c(*out, ctx->separator);
+                       }
+                       if (j) {
+                               /* Drop last separator. */
+                               g_string_truncate(*out, (*out)->len - 1);
+                       }
+                       g_string_append_printf(*out, "\n");
+               }
+               break;
+       }
+
+       return SR_OK;
+}
+
+static int cleanup(struct sr_output *o)
+{
+       struct context *ctx;
+
+       if (!o || !o->sdi)
+               return SR_ERR_ARG;
+
+       if (o->internal) {
+               ctx = o->internal;
+               g_free(ctx->channel_index);
+               g_free(o->internal);
+               o->internal = NULL;
+       }
+
+       return SR_OK;
+}
+
+SR_PRIV struct sr_output_format output_csv = {
+       .id = "csv",
+       .description = "Comma-separated values (CSV)",
+       .init = init,
+       .receive = receive,
+       .cleanup = cleanup,
+};
diff --git a/src/output/gnuplot.c b/src/output/gnuplot.c
new file mode 100644 (file)
index 0000000..a9feec6
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include "config.h" /* Needed for PACKAGE_STRING and others. */
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "output/gnuplot"
+
+struct context {
+       unsigned int num_enabled_channels;
+       uint64_t samplerate;
+       uint64_t samplecount;
+       gboolean header_done;
+       uint8_t *prevsample;
+       int *channel_index;
+};
+
+static const char *gnuplot_header = "\
+# Sample data in space-separated columns format usable by gnuplot.\n";
+static const char *gnuplot_header2 = "\
+#\n# Column\tChannel\n\
+# -----------------------------------------------------------------------------\n\
+# 0\t\tSample counter (for internal gnuplot purposes)\n";
+
+
+static int init(struct sr_output *o)
+{
+       struct context *ctx;
+       struct sr_channel *ch;
+       GSList *l;
+       unsigned int i;
+
+       if (!o || !o->sdi)
+               return SR_ERR_ARG;
+
+       ctx = g_malloc0(sizeof(struct context));
+       o->internal = ctx;
+       ctx->num_enabled_channels = 0;
+       for (l = o->sdi->channels; l; l = l->next) {
+               ch = l->data;
+               if (ch->type != SR_CHANNEL_LOGIC)
+                       continue;
+               if (!ch->enabled)
+                       continue;
+               ctx->num_enabled_channels++;
+       }
+       if (ctx->num_enabled_channels <= 0) {
+               sr_err("No logic channel enabled.");
+               return SR_ERR;
+       }
+       ctx->channel_index = g_malloc(sizeof(int) * ctx->num_enabled_channels);
+
+       /* Once more to map the enabled channels. */
+       for (i = 0, l = o->sdi->channels; l; l = l->next) {
+               ch = l->data;
+               if (ch->type != SR_CHANNEL_LOGIC)
+                       continue;
+               if (!ch->enabled)
+                       continue;
+               ctx->channel_index[i++] = ch->index;
+       }
+
+       return SR_OK;
+}
+
+static GString *gen_header(struct sr_output *o)
+{
+       struct context *ctx;
+       struct sr_channel *ch;
+       GVariant *gvar;
+       GString *header;
+       time_t t;
+       unsigned int num_channels, i;
+       char *samplerate_s;
+
+       ctx = o->internal;
+       if (ctx->samplerate == 0) {
+               if (sr_config_get(o->sdi->driver, o->sdi, NULL, SR_CONF_SAMPLERATE,
+                               &gvar) == SR_OK) {
+                       ctx->samplerate = g_variant_get_uint64(gvar);
+                       g_variant_unref(gvar);
+               }
+       }
+
+       t = time(NULL);
+       header = g_string_sized_new(512);
+       g_string_printf(header, "%s", gnuplot_header);
+       g_string_append_printf(header, "# Generated by %s on %s",
+                       PACKAGE_STRING, ctime(&t));
+
+       num_channels = g_slist_length(o->sdi->channels);
+       g_string_append_printf(header, "# Acquisition with %d/%d channels",
+                       ctx->num_enabled_channels, num_channels);
+       if (ctx->samplerate != 0) {
+               samplerate_s = sr_samplerate_string(ctx->samplerate);
+               g_string_append_printf(header, " at %s", samplerate_s);
+               g_free(samplerate_s);
+       }
+       g_string_append_printf(header, "\n");
+
+       g_string_append_printf(header, "%s", gnuplot_header2);
+
+       /* Columns / channels */
+       for (i = 0; i < ctx->num_enabled_channels; i++) {
+               ch = g_slist_nth_data(o->sdi->channels, ctx->channel_index[i]);
+               g_string_append_printf(header, "# %d\t\t%s\n", i + 1, ch->name);
+       }
+
+       return header;
+}
+
+static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
+               GString **out)
+{
+       const struct sr_datafeed_meta *meta;
+       const struct sr_datafeed_logic *logic;
+       const struct sr_config *src;
+       GSList *l;
+       struct context *ctx;
+       const uint8_t *sample;
+       unsigned int curbit, p, idx, i;
+
+       *out = NULL;
+       if (!o || !o->internal)
+               return SR_ERR_BUG;
+       ctx = o->internal;
+
+       if (packet->type == SR_DF_META) {
+               meta = packet->payload;
+               for (l = meta->config; l; l = l->next) {
+                       src = l->data;
+                       if (src->key != SR_CONF_SAMPLERATE)
+                               continue;
+                       ctx->samplerate = g_variant_get_uint64(src->data);
+               }
+       }
+
+       if (packet->type != SR_DF_LOGIC)
+               return SR_OK;
+       logic = packet->payload;
+
+       if (!ctx->prevsample) {
+               /* Can't allocate this until we know the stream's unitsize. */
+               ctx->prevsample = g_malloc0(logic->unitsize);
+       }
+
+       if (!ctx->header_done) {
+               *out = gen_header(o);
+               ctx->header_done = TRUE;
+       } else {
+               *out = g_string_sized_new(512);
+       }
+
+       for (i = 0; i <= logic->length - logic->unitsize; i += logic->unitsize) {
+               sample = logic->data + i;
+               ctx->samplecount++;
+
+               /*
+                * Don't output the same sample multiple times, but make
+                * sure to output at least the first and last sample.
+                */
+               if (i > 0 && i < logic->length - logic->unitsize) {
+                       if (!memcmp(sample, ctx->prevsample, logic->unitsize))
+                               continue;
+               }
+               memcpy(ctx->prevsample, sample, logic->unitsize);
+
+               /* The first column is a counter (needed for gnuplot). */
+               g_string_append_printf(*out, "%" PRIu64 "\t", ctx->samplecount);
+
+               /* The next columns are the values of all channels. */
+               for (p = 0; p < ctx->num_enabled_channels; p++) {
+                       idx = ctx->channel_index[p];
+                       curbit = (sample[idx / 8] & ((uint8_t) (1 << (idx % 8)))) >> (idx % 8);
+                       g_string_append_printf(*out, "%d ", curbit);
+               }
+               g_string_append_printf(*out, "\n");
+       }
+
+       return SR_OK;
+}
+
+static int cleanup(struct sr_output *o)
+{
+       struct context *ctx;
+
+       if (!o || !o->internal)
+               return SR_ERR_BUG;
+       ctx = o->internal;
+       g_free(ctx->channel_index);
+       g_free(ctx->prevsample);
+       g_free(ctx);
+
+       return SR_OK;
+}
+
+SR_PRIV struct sr_output_format output_gnuplot = {
+       .id = "gnuplot",
+       .description = "Gnuplot",
+       .init = init,
+       .receive = receive,
+       .cleanup = cleanup,
+};
diff --git a/src/output/hex.c b/src/output/hex.c
new file mode 100644 (file)
index 0000000..07a430c
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Bert Vermeulen <bert@biot.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 <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "output/hex"
+
+#define DEFAULT_SAMPLES_PER_LINE 192
+
+struct context {
+       unsigned int num_enabled_channels;
+       int samples_per_line;
+       int bit_cnt;
+       int spl_cnt;
+       int trigger;
+       uint64_t samplerate;
+       int *channel_index;
+       char **channel_names;
+       char **line_values;
+       uint8_t *sample_buf;
+       gboolean header_done;
+       GString **lines;
+};
+
+static int init(struct sr_output *o)
+{
+       struct context *ctx;
+       struct sr_channel *ch;
+       GSList *l;
+       GHashTableIter iter;
+       gpointer key, value;
+       unsigned int i, j;
+       int spl;
+
+       if (!o || !o->sdi)
+               return SR_ERR_ARG;
+
+       spl = DEFAULT_SAMPLES_PER_LINE;
+       g_hash_table_iter_init(&iter, o->params);
+       while (g_hash_table_iter_next(&iter, &key, &value)) {
+               if (!strcmp(key, "width")) {
+                       if ((spl = strtoul(value, NULL, 10)) < 1) {
+                               sr_err("Invalid width.");
+                               return SR_ERR_ARG;
+                       }
+               } else {
+                       sr_err("Unknown parameter '%s'.", key);
+                       return SR_ERR_ARG;
+               }
+       }
+
+       ctx = g_malloc0(sizeof(struct context));
+       o->internal = ctx;
+       ctx->trigger = -1;
+       ctx->samples_per_line = spl;
+
+       for (l = o->sdi->channels; l; l = l->next) {
+               ch = l->data;
+               if (ch->type != SR_CHANNEL_LOGIC)
+                       continue;
+               if (!ch->enabled)
+                       continue;
+               ctx->num_enabled_channels++;
+       }
+       ctx->channel_index = g_malloc(sizeof(int) * ctx->num_enabled_channels);
+       ctx->channel_names = g_malloc(sizeof(char *) * ctx->num_enabled_channels);
+       ctx->lines = g_malloc(sizeof(GString *) * ctx->num_enabled_channels);
+       ctx->sample_buf = g_malloc(ctx->num_enabled_channels);
+
+       j = 0;
+       for (i = 0, l = o->sdi->channels; l; l = l->next, i++) {
+               ch = l->data;
+               if (ch->type != SR_CHANNEL_LOGIC)
+                       continue;
+               if (!ch->enabled)
+                       continue;
+               ctx->channel_index[j] = ch->index;
+               ctx->channel_names[j] = ch->name;
+               ctx->lines[j] = g_string_sized_new(80);
+               ctx->sample_buf[j] = 0;
+               g_string_printf(ctx->lines[j], "%s:", ch->name);
+               j++;
+       }
+
+       return SR_OK;
+}
+
+static GString *gen_header(struct sr_output *o)
+{
+       struct context *ctx;
+       GVariant *gvar;
+       GString *header;
+       int num_channels;
+       char *samplerate_s;
+
+       ctx = o->internal;
+       if (ctx->samplerate == 0) {
+               if (sr_config_get(o->sdi->driver, o->sdi, NULL, SR_CONF_SAMPLERATE,
+                               &gvar) == SR_OK) {
+                       ctx->samplerate = g_variant_get_uint64(gvar);
+                       g_variant_unref(gvar);
+               }
+       }
+
+       header = g_string_sized_new(512);
+       g_string_printf(header, "%s\n", PACKAGE_STRING);
+       num_channels = g_slist_length(o->sdi->channels);
+       g_string_append_printf(header, "Acquisition with %d/%d channels",
+                       ctx->num_enabled_channels, num_channels);
+       if (ctx->samplerate != 0) {
+               samplerate_s = sr_samplerate_string(ctx->samplerate);
+               g_string_append_printf(header, " at %s", samplerate_s);
+               g_free(samplerate_s);
+       }
+       g_string_append_printf(header, "\n");
+
+       return header;
+}
+
+static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
+               GString **out)
+{
+       const struct sr_datafeed_meta *meta;
+       const struct sr_datafeed_logic *logic;
+       const struct sr_config *src;
+       GSList *l;
+       struct context *ctx;
+       int idx, pos, offset;
+       uint64_t i, j;
+       gchar *p;
+
+       *out = NULL;
+       if (!o || !o->sdi)
+               return SR_ERR_ARG;
+       if (!(ctx = o->internal))
+               return SR_ERR_ARG;
+
+       switch (packet->type) {
+       case SR_DF_META:
+               meta = packet->payload;
+               for (l = meta->config; l; l = l->next) {
+                       src = l->data;
+                       if (src->key != SR_CONF_SAMPLERATE)
+                               continue;
+                       ctx->samplerate = g_variant_get_uint64(src->data);
+               }
+               break;
+       case SR_DF_TRIGGER:
+               ctx->trigger = ctx->spl_cnt;
+               break;
+       case SR_DF_LOGIC:
+               if (!ctx->header_done) {
+                       *out = gen_header(o);
+                       ctx->header_done = TRUE;
+               } else
+                       *out = g_string_sized_new(512);
+
+               logic = packet->payload;
+               for (i = 0; i <= logic->length - logic->unitsize; i += logic->unitsize) {
+                       ctx->spl_cnt++;
+                       pos = ctx->spl_cnt & 7;
+                       for (j = 0; j < ctx->num_enabled_channels; j++) {
+                               idx = ctx->channel_index[j];
+                               p = logic->data + i + idx / 8;
+                               ctx->sample_buf[j] <<= 1;
+                               if (*p & (1 << (idx % 8)))
+                                       ctx->sample_buf[j] |= 1;
+                               if (ctx->spl_cnt && pos == 0) {
+                                       /* Buffered a byte's worth, output hex. */
+                                       g_string_append_printf(ctx->lines[j], "%.2x ",
+                                                       ctx->sample_buf[j]);
+                                       ctx->sample_buf[j] = 0;
+                               }
+
+                               if (ctx->spl_cnt == ctx->samples_per_line) {
+                                       /* Flush line buffers. */
+                                       g_string_append_len(*out, ctx->lines[j]->str, ctx->lines[j]->len);
+                                       g_string_append_c(*out, '\n');
+                                       if (j == ctx->num_enabled_channels  - 1 && ctx->trigger > -1) {
+                                               offset = ctx->trigger + ctx->trigger / 8;
+                                               g_string_append_printf(*out, "T:%*s^ %d\n", offset, "", ctx->trigger);
+                                               ctx->trigger = -1;
+                                       }
+                                       g_string_printf(ctx->lines[j], "%s:", ctx->channel_names[j]);
+                               }
+                       }
+                       if (ctx->spl_cnt == ctx->samples_per_line)
+                               /* Line buffers were already flushed. */
+                               ctx->spl_cnt = 0;
+               }
+               break;
+       case SR_DF_END:
+               if (ctx->spl_cnt) {
+                       /* Line buffers need flushing. */
+                       *out = g_string_sized_new(512);
+                       for (i = 0; i < ctx->num_enabled_channels; i++) {
+                               if (ctx->spl_cnt & 7)
+                                       g_string_append_printf(ctx->lines[i], "%.2x ",
+                                                       ctx->sample_buf[i] << (8 - (ctx->spl_cnt & 7)));
+                               g_string_append_len(*out, ctx->lines[i]->str, ctx->lines[i]->len);
+                               g_string_append_c(*out, '\n');
+                       }
+               }
+               break;
+       }
+
+       return SR_OK;
+}
+
+static int cleanup(struct sr_output *o)
+{
+       struct context *ctx;
+       unsigned int i;
+
+       if (!o)
+               return SR_ERR_ARG;
+
+       if (!(ctx = o->internal))
+               return SR_OK;
+
+       g_free(ctx->channel_index);
+       g_free(ctx->sample_buf);
+       g_free(ctx->channel_names);
+       for (i = 0; i < ctx->num_enabled_channels; i++)
+               g_string_free(ctx->lines[i], TRUE);
+       g_free(ctx->lines);
+       g_free(ctx);
+       o->internal = NULL;
+
+       return SR_OK;
+}
+
+SR_PRIV struct sr_output_format output_hex = {
+       .id = "hex",
+       .description = "Hexadecimal",
+       .init = init,
+       .receive = receive,
+       .cleanup = cleanup,
+};
+
diff --git a/src/output/ols.c b/src/output/ols.c
new file mode 100644 (file)
index 0000000..78a41bb
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2011 Uwe Hermann <uwe@hermann-uwe.de>
+ * Copyright (C) 2013 Bert Vermeulen <bert@biot.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 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/*
+ * This implements version 1.3 of the output format for the OpenBench Logic
+ * Sniffer "Alternative" Java client. Details:
+ * https://github.com/jawi/ols/wiki/OLS-data-file-format
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "output/ols"
+
+struct context {
+       uint64_t samplerate;
+       uint64_t num_samples;
+};
+
+static int init(struct sr_output *o)
+{
+       struct context *ctx;
+
+       if (!(ctx = g_try_malloc(sizeof(struct context)))) {
+               sr_err("%s: ctx malloc failed", __func__);
+               return SR_ERR_MALLOC;
+       }
+       o->internal = ctx;
+
+       ctx->samplerate = 0;
+       ctx->num_samples = 0;
+
+       return SR_OK;
+}
+
+static GString *gen_header(const struct sr_dev_inst *sdi, struct context *ctx)
+{
+       struct sr_channel *ch;
+       GSList *l;
+       GString *s;
+       GVariant *gvar;
+       int num_enabled_channels;
+
+       if (!ctx->samplerate && sr_config_get(sdi->driver, sdi, NULL,
+                       SR_CONF_SAMPLERATE, &gvar) == SR_OK) {
+               ctx->samplerate = g_variant_get_uint64(gvar);
+               g_variant_unref(gvar);
+       }
+
+       num_enabled_channels = 0;
+       for (l = sdi->channels; l; l = l->next) {
+               ch = l->data;
+               if (ch->type != SR_CHANNEL_LOGIC)
+                       continue;
+               if (!ch->enabled)
+                       continue;
+               num_enabled_channels++;
+       }
+
+       s = g_string_sized_new(512);
+       g_string_append_printf(s, ";Rate: %"PRIu64"\n", ctx->samplerate);
+       g_string_append_printf(s, ";Channels: %d\n", num_enabled_channels);
+       g_string_append_printf(s, ";EnabledChannels: -1\n");
+       g_string_append_printf(s, ";Compressed: true\n");
+       g_string_append_printf(s, ";CursorEnabled: false\n");
+
+       return s;
+}
+
+static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
+               GString **out)
+{
+       struct context *ctx;
+       const struct sr_datafeed_meta *meta;
+       const struct sr_datafeed_logic *logic;
+       const struct sr_config *src;
+       GSList *l;
+       unsigned int i, j;
+       uint8_t c;
+
+       *out = NULL;
+       if (!o || !o->sdi)
+               return SR_ERR_ARG;
+       ctx = o->internal;
+
+       switch (packet->type) {
+       case SR_DF_META:
+               meta = packet->payload;
+               for (l = meta->config; l; l = l->next) {
+                       src = l->data;
+                       if (src->key == SR_CONF_SAMPLERATE)
+                               ctx->samplerate = g_variant_get_uint64(src->data);
+               }
+               break;
+       case SR_DF_LOGIC:
+               logic = packet->payload;
+               if (ctx->num_samples == 0) {
+                       /* First logic packet in the feed. */
+                       *out = gen_header(o->sdi, ctx);
+               } else
+                       *out = g_string_sized_new(512);
+               for (i = 0; i <= logic->length - logic->unitsize; i += logic->unitsize) {
+                       for (j = 0; j < logic->unitsize; j++) {
+                               /* The OLS format wants the samples presented MSB first. */
+                               c = *((uint8_t *)logic->data + i + logic->unitsize - 1 - j);
+                               g_string_append_printf(*out, "%02x", c);
+                       }
+                       g_string_append_printf(*out, "@%"PRIu64"\n", ctx->num_samples++);
+               }
+               break;
+       }
+
+       return SR_OK;
+}
+
+static int cleanup(struct sr_output *o)
+{
+       struct context *ctx;
+
+       if (!o || !o->sdi)
+               return SR_ERR_ARG;
+
+       ctx = o->internal;
+       g_free(ctx);
+       o->internal = NULL;
+
+       return SR_OK;
+}
+
+SR_PRIV struct sr_output_format output_ols = {
+       .id = "ols",
+       .description = "OpenBench Logic Sniffer",
+       .init = init,
+       .receive = receive,
+       .cleanup = cleanup
+};
diff --git a/src/output/output.c b/src/output/output.c
new file mode 100644 (file)
index 0000000..4cf78f6
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.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 "libsigrok.h"
+#include "libsigrok-internal.h"
+
+/**
+ * @file
+ *
+ * Output file/data format handling.
+ */
+
+/**
+ * @defgroup grp_output Output formats
+ *
+ * Output file/data format handling.
+ *
+ * libsigrok supports several output (file) formats, e.g. binary, VCD,
+ * gnuplot, and so on. It provides an output API that frontends can use.
+ * New output formats can be added/implemented in libsigrok without having
+ * to change the frontends at all.
+ *
+ * All output modules are fed data in a stream. Devices that can stream data
+ * into libsigrok, instead of storing and then transferring the whole buffer,
+ * can thus generate output live.
+ *
+ * Output modules generate a newly allocated GString. The caller is then
+ * expected to free this with g_string_free() when finished with it.
+ *
+ * @{
+ */
+
+/** @cond PRIVATE */
+extern SR_PRIV struct sr_output_format output_bits;
+extern SR_PRIV struct sr_output_format output_hex;
+extern SR_PRIV struct sr_output_format output_ascii;
+extern SR_PRIV struct sr_output_format output_binary;
+extern SR_PRIV struct sr_output_format output_vcd;
+extern SR_PRIV struct sr_output_format output_ols;
+extern SR_PRIV struct sr_output_format output_gnuplot;
+extern SR_PRIV struct sr_output_format output_chronovu_la8;
+extern SR_PRIV struct sr_output_format output_csv;
+extern SR_PRIV struct sr_output_format output_analog;
+/* @endcond */
+
+static struct sr_output_format *output_module_list[] = {
+       &output_ascii,
+       &output_binary,
+       &output_bits,
+       &output_csv,
+       &output_gnuplot,
+       &output_hex,
+       &output_ols,
+       &output_vcd,
+       &output_chronovu_la8,
+       &output_analog,
+       NULL,
+};
+
+/** @since 0.1.0 */
+SR_API struct sr_output_format **sr_output_list(void)
+{
+       return output_module_list;
+}
+
+/** @since 0.3.0 */
+SR_API struct sr_output *sr_output_new(struct sr_output_format *of,
+               GHashTable *params, const struct sr_dev_inst *sdi)
+{
+       struct sr_output *o;
+
+       o = g_malloc(sizeof(struct sr_output));
+       o->format = of;
+       o->sdi = sdi;
+       o->params = params;
+       if (o->format->init && o->format->init(o) != SR_OK) {
+               g_free(o);
+               o = NULL;
+       }
+
+       return o;
+}
+
+/** @since 0.3.0 */
+SR_API int sr_output_send(struct sr_output *o,
+               const struct sr_datafeed_packet *packet, GString **out)
+{
+       return o->format->receive(o, packet, out);
+}
+
+/** @since 0.3.0 */
+SR_API int sr_output_free(struct sr_output *o)
+{
+       int ret;
+
+       ret = SR_OK;
+       if (o->format->cleanup)
+               ret = o->format->cleanup(o);
+       g_free(o);
+
+       return ret;
+}
+
+/** @} */
diff --git a/src/output/vcd.c b/src/output/vcd.c
new file mode 100644 (file)
index 0000000..87f8049
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
+ * Copyright (C) 2013 Bert Vermeulen <bert@biot.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 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include "config.h" /* Needed for PACKAGE and others. */
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "output/vcd"
+
+struct context {
+       int num_enabled_channels;
+       GArray *channelindices;
+       uint8_t *prevsample;
+       gboolean header_done;
+       int period;
+       int *channel_index;
+       uint64_t samplerate;
+       uint64_t samplecount;
+};
+
+static const char *const vcd_header_comment =
+       "$comment\n  Acquisition with %d/%d channels at %s\n$end\n";
+
+static int init(struct sr_output *o)
+{
+       struct context *ctx;
+       struct sr_channel *ch;
+       GSList *l;
+       int num_enabled_channels, i;
+
+       num_enabled_channels = 0;
+       for (l = o->sdi->channels; l; l = l->next) {
+               ch = l->data;
+               if (ch->type != SR_CHANNEL_LOGIC)
+                       continue;
+               if (!ch->enabled)
+                       continue;
+               num_enabled_channels++;
+       }
+       if (num_enabled_channels > 94) {
+               sr_err("VCD only supports 94 channels.");
+               return SR_ERR;
+       }
+
+       ctx = g_malloc0(sizeof(struct context));
+       o->internal = ctx;
+       ctx->num_enabled_channels = num_enabled_channels;
+       ctx->channel_index = g_malloc(sizeof(int) * ctx->num_enabled_channels);
+
+       /* Once more to map the enabled channels. */
+       for (i = 0, l = o->sdi->channels; l; l = l->next) {
+               ch = l->data;
+               if (ch->type != SR_CHANNEL_LOGIC)
+                       continue;
+               if (!ch->enabled)
+                       continue;
+               ctx->channel_index[i++] = ch->index;
+       }
+
+       return SR_OK;
+}
+
+static GString *gen_header(struct sr_output *o)
+{
+       struct context *ctx;
+       struct sr_channel *ch;
+       GVariant *gvar;
+       GString *header;
+       GSList *l;
+       time_t t;
+       int num_channels, i;
+       char *samplerate_s, *frequency_s, *timestamp;
+
+       ctx = o->internal;
+       header = g_string_sized_new(512);
+       num_channels = g_slist_length(o->sdi->channels);
+
+       /* timestamp */
+       t = time(NULL);
+       timestamp = g_strdup(ctime(&t));
+       timestamp[strlen(timestamp)-1] = 0;
+       g_string_printf(header, "$date %s $end\n", timestamp);
+       g_free(timestamp);
+
+       /* generator */
+       g_string_append_printf(header, "$version %s %s $end\n",
+                       PACKAGE, PACKAGE_VERSION);
+       g_string_append_printf(header, "$comment\n  Acquisition with "
+                       "%d/%d channels", ctx->num_enabled_channels, num_channels);
+
+       if (ctx->samplerate == 0) {
+               if (sr_config_get(o->sdi->driver, o->sdi, NULL, SR_CONF_SAMPLERATE,
+                               &gvar) == SR_OK) {
+                       ctx->samplerate = g_variant_get_uint64(gvar);
+                       g_variant_unref(gvar);
+               }
+       }
+       if (ctx->samplerate != 0) {
+               samplerate_s = sr_samplerate_string(ctx->samplerate);
+               g_string_append_printf(header, " at %s", samplerate_s);
+               g_free(samplerate_s);
+       }
+       g_string_append_printf(header, "\n$end\n");
+
+       /* timescale */
+       /* VCD can only handle 1/10/100 (s - fs), so scale up first */
+       if (ctx->samplerate > SR_MHZ(1))
+               ctx->period = SR_GHZ(1);
+       else if (ctx->samplerate > SR_KHZ(1))
+               ctx->period = SR_MHZ(1);
+       else
+               ctx->period = SR_KHZ(1);
+       frequency_s = sr_period_string(ctx->period);
+       g_string_append_printf(header, "$timescale %s $end\n", frequency_s);
+       g_free(frequency_s);
+
+       /* scope */
+       g_string_append_printf(header, "$scope module %s $end\n", PACKAGE);
+
+       /* Wires / channels */
+       for (i = 0, l = o->sdi->channels; l; l = l->next, i++) {
+               ch = l->data;
+               if (ch->type != SR_CHANNEL_LOGIC)
+                       continue;
+               if (!ch->enabled)
+                       continue;
+               g_string_append_printf(header, "$var wire 1 %c %s $end\n",
+                               (char)('!' + i), ch->name);
+       }
+
+       g_string_append(header, "$upscope $end\n$enddefinitions $end\n");
+
+       return header;
+}
+
+static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
+               GString **out)
+{
+       const struct sr_datafeed_meta *meta;
+       const struct sr_datafeed_logic *logic;
+       const struct sr_config *src;
+       GSList *l;
+       struct context *ctx;
+       unsigned int i;
+       int p, curbit, prevbit, index;
+       uint8_t *sample;
+       gboolean timestamp_written;
+
+       *out = NULL;
+       if (!o || !o->internal)
+               return SR_ERR_BUG;
+       ctx = o->internal;
+
+       switch (packet->type) {
+       case SR_DF_META:
+               meta = packet->payload;
+               for (l = meta->config; l; l = l->next) {
+                       src = l->data;
+                       if (src->key != SR_CONF_SAMPLERATE)
+                               continue;
+                       ctx->samplerate = g_variant_get_uint64(src->data);
+               }
+               break;
+       case SR_DF_LOGIC:
+               logic = packet->payload;
+
+               if (!ctx->header_done) {
+                       *out = gen_header(o);
+                       ctx->header_done = TRUE;
+               } else {
+                       *out = g_string_sized_new(512);
+               }
+
+               if (!ctx->prevsample) {
+                       /* Can't allocate this until we know the stream's unitsize. */
+                       ctx->prevsample = g_malloc0(logic->unitsize);
+               }
+
+               for (i = 0; i <= logic->length - logic->unitsize; i += logic->unitsize) {
+                       sample = logic->data + i;
+                       timestamp_written = FALSE;
+
+                       for (p = 0; p < ctx->num_enabled_channels; p++) {
+                               index = ctx->channel_index[p];
+
+                               curbit = ((unsigned)sample[index / 8]
+                                               >> (index % 8)) & 1;
+                               prevbit = ((unsigned)ctx->prevsample[index / 8]
+                                               >> (index % 8)) & 1;
+
+                               /* VCD only contains deltas/changes of signals. */
+                               if (prevbit == curbit && ctx->samplecount > 0)
+                                       continue;
+
+                               /* Output timestamp of subsequent signal changes. */
+                               if (!timestamp_written)
+                                       g_string_append_printf(*out, "#%.0f",
+                                               (double)ctx->samplecount /
+                                                       ctx->samplerate * ctx->period);
+
+                               /* Output which signal changed to which value. */
+                               g_string_append_c(*out, ' ');
+                               g_string_append_c(*out, '0' + curbit);
+                               g_string_append_c(*out, '!' + p);
+
+                               timestamp_written = TRUE;
+                       }
+
+                       if (timestamp_written)
+                               g_string_append_c(*out, '\n');
+
+                       ctx->samplecount++;
+                       memcpy(ctx->prevsample, sample, logic->unitsize);
+               }
+               break;
+       case SR_DF_END:
+               /* Write final timestamp as length indicator. */
+               *out = g_string_sized_new(512);
+               g_string_printf(*out, "#%.0f\n",
+                               (double)ctx->samplecount / ctx->samplerate * ctx->period);
+               break;
+       }
+
+       return SR_OK;
+}
+
+static int cleanup(struct sr_output *o)
+{
+       struct context *ctx;
+
+       if (!o || !o->internal)
+               return SR_ERR_ARG;
+
+       ctx = o->internal;
+       g_free(ctx->prevsample);
+       g_free(ctx->channel_index);
+       g_free(ctx);
+
+       return SR_OK;
+}
+
+struct sr_output_format output_vcd = {
+       .id = "vcd",
+       .description = "Value Change Dump (VCD)",
+       .init = init,
+       .receive = receive,
+       .cleanup = cleanup,
+};
diff --git a/src/scpi/scpi.c b/src/scpi/scpi.c
new file mode 100644 (file)
index 0000000..829a4c8
--- /dev/null
@@ -0,0 +1,754 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * 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 "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#include <glib.h>
+#include <string.h>
+
+#define LOG_PREFIX "scpi"
+
+#define SCPI_READ_RETRIES 100
+#define SCPI_READ_RETRY_TIMEOUT 10000
+
+/**
+ * Parse a string representation of a boolean-like value into a gboolean.
+ * Similar to sr_parse_boolstring but rejects strings which do not represent
+ * a boolean-like value.
+ *
+ * @param str String to convert.
+ * @param ret Pointer to a gboolean where the result of the conversion will be
+ * stored.
+ *
+ * @return SR_OK on success, SR_ERR on failure.
+ */
+static int parse_strict_bool(const char *str, gboolean *ret)
+{
+       if (!str)
+               return SR_ERR_ARG;
+
+       if (!g_strcmp0(str, "1") ||
+           !g_ascii_strncasecmp(str, "y", 1) ||
+           !g_ascii_strncasecmp(str, "t", 1) ||
+           !g_ascii_strncasecmp(str, "yes", 3) ||
+           !g_ascii_strncasecmp(str, "true", 4) ||
+           !g_ascii_strncasecmp(str, "on", 2)) {
+               *ret = TRUE;
+               return SR_OK;
+       } else if (!g_strcmp0(str, "0") ||
+                  !g_ascii_strncasecmp(str, "n", 1) ||
+                  !g_ascii_strncasecmp(str, "f", 1) ||
+                  !g_ascii_strncasecmp(str, "no", 2) ||
+                  !g_ascii_strncasecmp(str, "false", 5) ||
+                  !g_ascii_strncasecmp(str, "off", 3)) {
+               *ret = FALSE;
+               return SR_OK;
+       }
+
+       return SR_ERR;
+}
+
+SR_PRIV extern const struct sr_scpi_dev_inst scpi_serial_dev;
+SR_PRIV extern const struct sr_scpi_dev_inst scpi_tcp_raw_dev;
+SR_PRIV extern const struct sr_scpi_dev_inst scpi_tcp_rigol_dev;
+SR_PRIV extern const struct sr_scpi_dev_inst scpi_usbtmc_libusb_dev;
+SR_PRIV extern const struct sr_scpi_dev_inst scpi_vxi_dev;
+SR_PRIV extern const struct sr_scpi_dev_inst scpi_visa_dev;
+
+static const struct sr_scpi_dev_inst *scpi_devs[] = {
+       &scpi_tcp_raw_dev,
+       &scpi_tcp_rigol_dev,
+#ifdef HAVE_LIBUSB_1_0
+       &scpi_usbtmc_libusb_dev,
+#endif
+#if HAVE_RPC
+       &scpi_vxi_dev,
+#endif
+#ifdef HAVE_LIBREVISA
+       &scpi_visa_dev,
+#endif
+#ifdef HAVE_LIBSERIALPORT
+       &scpi_serial_dev,  /* must be last as it matches any resource */
+#endif
+};
+
+static struct sr_dev_inst *sr_scpi_scan_resource(struct drv_context *drvc,
+               const char *resource, const char *serialcomm,
+               struct sr_dev_inst *(*probe_device)(struct sr_scpi_dev_inst *scpi))
+{
+       struct sr_scpi_dev_inst *scpi;
+       struct sr_dev_inst *sdi;
+
+       if (!(scpi = scpi_dev_inst_new(drvc, resource, serialcomm)))
+               return NULL;
+
+       if (sr_scpi_open(scpi) != SR_OK) {
+               sr_info("Couldn't open SCPI device.");
+               sr_scpi_free(scpi);
+               return NULL;
+       };
+
+       if ((sdi = probe_device(scpi)))
+               return sdi;
+
+       sr_scpi_close(scpi);
+       sr_scpi_free(scpi);
+       return NULL;
+}
+
+SR_PRIV GSList *sr_scpi_scan(struct drv_context *drvc, GSList *options,
+               struct sr_dev_inst *(*probe_device)(struct sr_scpi_dev_inst *scpi))
+{
+       GSList *resources, *l, *devices;
+       struct sr_dev_inst *sdi;
+       const char *resource = NULL;
+       const char *serialcomm = NULL;
+       gchar **res;
+       unsigned i;
+
+       for (l = options; l; l = l->next) {
+               struct sr_config *src = l->data;
+               switch (src->key) {
+               case SR_CONF_CONN:
+                       resource = g_variant_get_string(src->data, NULL);
+                       break;
+               case SR_CONF_SERIALCOMM:
+                       serialcomm = g_variant_get_string(src->data, NULL);
+                       break;
+               }
+       }
+
+       devices = NULL;
+       for (i = 0; i < ARRAY_SIZE(scpi_devs); i++) {
+               if ((resource && strcmp(resource, scpi_devs[i]->prefix))
+                   || !scpi_devs[i]->scan)
+                       continue;
+               resources = scpi_devs[i]->scan(drvc);
+               for (l = resources; l; l = l->next) {
+                       res = g_strsplit(l->data, ":", 2);
+                       if (res[0] && (sdi = sr_scpi_scan_resource(drvc, res[0],
+                                      serialcomm ? serialcomm : res[1], probe_device)))
+                               devices = g_slist_append(devices, sdi);
+                       g_strfreev(res);
+               }
+               g_slist_free_full(resources, g_free);
+       }
+
+       if (!devices && resource) {
+               sdi = sr_scpi_scan_resource(drvc, resource, serialcomm, probe_device);
+               devices = g_slist_append(NULL, sdi);
+       }
+
+       /* Tack a copy of the newly found devices onto the driver list. */
+       if (devices)
+               drvc->instances = g_slist_concat(drvc->instances, g_slist_copy(devices));
+
+       return devices;
+}
+
+SR_PRIV struct sr_scpi_dev_inst *scpi_dev_inst_new(struct drv_context *drvc,
+               const char *resource, const char *serialcomm)
+{
+       struct sr_scpi_dev_inst *scpi = NULL;
+       const struct sr_scpi_dev_inst *scpi_dev;
+       gchar **params;
+       unsigned i;
+
+       for (i = 0; i < ARRAY_SIZE(scpi_devs); i++) {
+               scpi_dev = scpi_devs[i];
+               if (!strncmp(resource, scpi_dev->prefix, strlen(scpi_dev->prefix))) {
+                       sr_dbg("Opening %s device %s.", scpi_dev->name, resource);
+                       scpi = g_malloc(sizeof(*scpi));
+                       *scpi = *scpi_dev;
+                       scpi->priv = g_malloc0(scpi->priv_size);
+                       params = g_strsplit(resource, "/", 0);
+                       if (scpi->dev_inst_new(scpi->priv, drvc, resource,
+                                              params, serialcomm) != SR_OK) {
+                               sr_scpi_free(scpi);
+                               scpi = NULL;
+                       }
+                       g_strfreev(params);
+                       break;
+               }
+       }
+
+       return scpi;
+}
+
+/**
+ * Open SCPI device.
+ *
+ * @param scpi Previously initialized SCPI device structure.
+ *
+ * @return SR_OK on success, SR_ERR on failure.
+ */
+SR_PRIV int sr_scpi_open(struct sr_scpi_dev_inst *scpi)
+{
+       return scpi->open(scpi->priv);
+}
+
+/**
+ * Add an event source for an SCPI device.
+ *
+ * @param scpi Previously initialized SCPI device structure.
+ * @param events Events to check for.
+ * @param timeout Max time to wait before the callback is called, ignored if 0.
+ * @param cb Callback function to add. Must not be NULL.
+ * @param cb_data Data for the callback function. Can be NULL.
+ *
+ * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments, or
+ *         SR_ERR_MALLOC upon memory allocation errors.
+ */
+SR_PRIV int sr_scpi_source_add(struct sr_session *session,
+               struct sr_scpi_dev_inst *scpi, int events, int timeout,
+               sr_receive_data_callback cb, void *cb_data)
+{
+       return scpi->source_add(session, scpi->priv, events, timeout, cb, cb_data);
+}
+
+/**
+ * Remove event source for an SCPI device.
+ *
+ * @param scpi Previously initialized SCPI device structure.
+ *
+ * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments, or
+ *         SR_ERR_MALLOC upon memory allocation errors, SR_ERR_BUG upon
+ *         internal errors.
+ */
+SR_PRIV int sr_scpi_source_remove(struct sr_session *session,
+               struct sr_scpi_dev_inst *scpi)
+{
+       return scpi->source_remove(session, scpi->priv);
+}
+
+/**
+ * Send a SCPI command.
+ *
+ * @param scpi Previously initialized SCPI device structure.
+ * @param format Format string, to be followed by any necessary arguments.
+ *
+ * @return SR_OK on success, SR_ERR on failure.
+ */
+SR_PRIV int sr_scpi_send(struct sr_scpi_dev_inst *scpi,
+                        const char *format, ...)
+{
+       va_list args;
+       int ret;
+
+       va_start(args, format);
+       ret = sr_scpi_send_variadic(scpi, format, args);
+       va_end(args);
+
+       return ret;
+}
+
+/**
+ * Send a SCPI command with a variadic argument list.
+ *
+ * @param scpi Previously initialized SCPI device structure.
+ * @param format Format string.
+ * @param args Argument list.
+ *
+ * @return SR_OK on success, SR_ERR on failure.
+ */
+SR_PRIV int sr_scpi_send_variadic(struct sr_scpi_dev_inst *scpi,
+                        const char *format, va_list args)
+{
+       va_list args_copy;
+       char *buf;
+       int len, ret;
+
+       /* Get length of buffer required. */
+       va_copy(args_copy, args);
+       len = vsnprintf(NULL, 0, format, args_copy);
+       va_end(args_copy);
+
+       /* Allocate buffer and write out command. */
+       buf = g_malloc(len + 1);
+       vsprintf(buf, format, args);
+
+       /* Send command. */
+       ret = scpi->send(scpi->priv, buf);
+
+       /* Free command buffer. */
+       g_free(buf);
+
+       return ret;
+}
+
+/**
+ * Begin receiving an SCPI reply.
+ *
+ * @param scpi Previously initialised SCPI device structure.
+ *
+ * @return SR_OK on success, SR_ERR on failure.
+ */
+SR_PRIV int sr_scpi_read_begin(struct sr_scpi_dev_inst *scpi)
+{
+       return scpi->read_begin(scpi->priv);
+}
+
+/**
+ * Read part of a response from SCPI device.
+ *
+ * @param scpi Previously initialised SCPI device structure.
+ * @param buf Buffer to store result.
+ * @param maxlen Maximum number of bytes to read.
+ *
+ * @return Number of bytes read, or SR_ERR upon failure.
+ */
+SR_PRIV int sr_scpi_read_data(struct sr_scpi_dev_inst *scpi,
+                       char *buf, int maxlen)
+{
+       return scpi->read_data(scpi->priv, buf, maxlen);
+}
+
+/**
+ * Check whether a complete SCPI response has been received.
+ *
+ * @param scpi Previously initialised SCPI device structure.
+ *
+ * @return 1 if complete, 0 otherwise.
+ */
+SR_PRIV int sr_scpi_read_complete(struct sr_scpi_dev_inst *scpi)
+{
+       return scpi->read_complete(scpi->priv);
+}
+
+/**
+ * Close SCPI device.
+ *
+ * @param scpi Previously initialized SCPI device structure.
+ *
+ * @return SR_OK on success, SR_ERR on failure.
+ */
+SR_PRIV int sr_scpi_close(struct sr_scpi_dev_inst *scpi)
+{
+       return scpi->close(scpi->priv);
+}
+
+/**
+ * Free SCPI device.
+ *
+ * @param scpi Previously initialized SCPI device structure.
+ *
+ * @return SR_OK on success, SR_ERR on failure.
+ */
+SR_PRIV void sr_scpi_free(struct sr_scpi_dev_inst *scpi)
+{
+       scpi->free(scpi->priv);
+       g_free(scpi->priv);
+       g_free(scpi);
+}
+
+/**
+ * Send a SCPI command, receive the reply and store the reply in scpi_response.
+ *
+ * @param scpi Previously initialised SCPI device structure.
+ * @param command The SCPI command to send to the device (can be NULL).
+ * @param scpi_response Pointer where to store the SCPI response.
+ *
+ * @return SR_OK on success, SR_ERR on failure.
+ */
+SR_PRIV int sr_scpi_get_string(struct sr_scpi_dev_inst *scpi,
+                              const char *command, char **scpi_response)
+{
+       char buf[256];
+       int len;
+       GString *response;
+
+       if (command)
+               if (sr_scpi_send(scpi, command) != SR_OK)
+                       return SR_ERR;
+
+       if (sr_scpi_read_begin(scpi) != SR_OK)
+               return SR_ERR;
+
+       response = g_string_new("");
+
+       *scpi_response = NULL;
+
+       while (!sr_scpi_read_complete(scpi)) {
+               len = sr_scpi_read_data(scpi, buf, sizeof(buf));
+               if (len < 0) {
+                       g_string_free(response, TRUE);
+                       return SR_ERR;
+               }
+               g_string_append_len(response, buf, len);
+       }
+
+       /* Get rid of trailing linefeed if present */
+       if (response->len >= 1 && response->str[response->len - 1] == '\n')
+               g_string_truncate(response, response->len - 1);
+
+       *scpi_response = response->str;
+       g_string_free(response, FALSE);
+
+       sr_spew("Got response: '%.70s'.", *scpi_response);
+
+       return SR_OK;
+}
+
+/**
+ * Send a SCPI command, read the reply, parse it as a bool value and store the
+ * result in scpi_response.
+ *
+ * @param scpi Previously initialised SCPI device structure.
+ * @param command The SCPI command to send to the device (can be NULL).
+ * @param scpi_response Pointer where to store the parsed result.
+ *
+ * @return SR_OK on success, SR_ERR on failure.
+ */
+SR_PRIV int sr_scpi_get_bool(struct sr_scpi_dev_inst *scpi,
+                            const char *command, gboolean *scpi_response)
+{
+       int ret;
+       char *response;
+
+       response = NULL;
+
+       if (sr_scpi_get_string(scpi, command, &response) != SR_OK)
+               if (!response)
+                       return SR_ERR;
+
+       if (parse_strict_bool(response, scpi_response) == SR_OK)
+               ret = SR_OK;
+       else
+               ret = SR_ERR;
+
+       g_free(response);
+
+       return ret;
+}
+
+/**
+ * Send a SCPI command, read the reply, parse it as an integer and store the
+ * result in scpi_response.
+ *
+ * @param scpi Previously initialised SCPI device structure.
+ * @param command The SCPI command to send to the device (can be NULL).
+ * @param scpi_response Pointer where to store the parsed result.
+ *
+ * @return SR_OK on success, SR_ERR on failure.
+ */
+SR_PRIV int sr_scpi_get_int(struct sr_scpi_dev_inst *scpi,
+                           const char *command, int *scpi_response)
+{
+       int ret;
+       char *response;
+
+       response = NULL;
+
+       if (sr_scpi_get_string(scpi, command, &response) != SR_OK)
+               if (!response)
+                       return SR_ERR;
+
+       if (sr_atoi(response, scpi_response) == SR_OK)
+               ret = SR_OK;
+       else
+               ret = SR_ERR;
+
+       g_free(response);
+
+       return ret;
+}
+
+/**
+ * Send a SCPI command, read the reply, parse it as a float and store the
+ * result in scpi_response.
+ *
+ * @param scpi Previously initialised SCPI device structure.
+ * @param command The SCPI command to send to the device (can be NULL).
+ * @param scpi_response Pointer where to store the parsed result.
+ *
+ * @return SR_OK on success, SR_ERR on failure.
+ */
+SR_PRIV int sr_scpi_get_float(struct sr_scpi_dev_inst *scpi,
+                             const char *command, float *scpi_response)
+{
+       int ret;
+       char *response;
+
+       response = NULL;
+
+       if (sr_scpi_get_string(scpi, command, &response) != SR_OK)
+               if (!response)
+                       return SR_ERR;
+
+       if (sr_atof_ascii(response, scpi_response) == SR_OK)
+               ret = SR_OK;
+       else
+               ret = SR_ERR;
+
+       g_free(response);
+
+       return ret;
+}
+
+/**
+ * Send a SCPI command, read the reply, parse it as a double and store the
+ * result in scpi_response.
+ *
+ * @param scpi Previously initialised SCPI device structure.
+ * @param command The SCPI command to send to the device (can be NULL).
+ * @param scpi_response Pointer where to store the parsed result.
+ *
+ * @return SR_OK on success, SR_ERR on failure.
+ */
+SR_PRIV int sr_scpi_get_double(struct sr_scpi_dev_inst *scpi,
+                              const char *command, double *scpi_response)
+{
+       int ret;
+       char *response;
+
+       response = NULL;
+
+       if (sr_scpi_get_string(scpi, command, &response) != SR_OK)
+               if (!response)
+                       return SR_ERR;
+
+       if (sr_atod(response, scpi_response) == SR_OK)
+               ret = SR_OK;
+       else
+               ret = SR_ERR;
+
+       g_free(response);
+
+       return ret;
+}
+
+/**
+ * Send a SCPI *OPC? command, read the reply and return the result of the
+ * command.
+ *
+ * @param scpi Previously initialised SCPI device structure.
+ *
+ * @return SR_OK on success, SR_ERR on failure.
+ */
+SR_PRIV int sr_scpi_get_opc(struct sr_scpi_dev_inst *scpi)
+{
+       unsigned int i;
+       gboolean opc;
+
+       for (i = 0; i < SCPI_READ_RETRIES; ++i) {
+               sr_scpi_get_bool(scpi, SCPI_CMD_OPC, &opc);
+               if (opc)
+                       return SR_OK;
+               g_usleep(SCPI_READ_RETRY_TIMEOUT);
+       }
+
+       return SR_ERR;
+}
+
+/**
+ * Send a SCPI command, read the reply, parse it as comma separated list of
+ * floats and store the as an result in scpi_response.
+ *
+ * @param scpi Previously initialised SCPI device structure.
+ * @param command The SCPI command to send to the device (can be NULL).
+ * @param scpi_response Pointer where to store the parsed result.
+ *
+ * @return SR_OK upon successfully parsing all values, SR_ERR upon a parsing
+ *         error or upon no response. The allocated response must be freed by
+ *         the caller in the case of an SR_OK as well as in the case of
+ *         parsing error.
+ */
+SR_PRIV int sr_scpi_get_floatv(struct sr_scpi_dev_inst *scpi,
+                              const char *command, GArray **scpi_response)
+{
+       int ret;
+       float tmp;
+       char *response;
+       gchar **ptr, **tokens;
+       GArray *response_array;
+
+       ret = SR_OK;
+       response = NULL;
+       tokens = NULL;
+
+       if (sr_scpi_get_string(scpi, command, &response) != SR_OK)
+               if (!response)
+                       return SR_ERR;
+
+       tokens = g_strsplit(response, ",", 0);
+       ptr = tokens;
+
+       response_array = g_array_sized_new(TRUE, FALSE, sizeof(float), 256);
+
+       while (*ptr) {
+               if (sr_atof_ascii(*ptr, &tmp) == SR_OK)
+                       response_array = g_array_append_val(response_array,
+                                                           tmp);
+               else
+                       ret = SR_ERR;
+
+               ptr++;
+       }
+       g_strfreev(tokens);
+       g_free(response);
+
+       if (ret == SR_ERR && response_array->len == 0) {
+               g_array_free(response_array, TRUE);
+               *scpi_response = NULL;
+               return SR_ERR;
+       }
+
+       *scpi_response = response_array;
+
+       return ret;
+}
+
+/**
+ * Send a SCPI command, read the reply, parse it as comma separated list of
+ * unsigned 8 bit integers and store the as an result in scpi_response.
+ *
+ * @param scpi Previously initialised SCPI device structure.
+ * @param command The SCPI command to send to the device (can be NULL).
+ * @param scpi_response Pointer where to store the parsed result.
+ *
+ * @return SR_OK upon successfully parsing all values, SR_ERR upon a parsing
+ *         error or upon no response. The allocated response must be freed by
+ *         the caller in the case of an SR_OK as well as in the case of
+ *         parsing error.
+ */
+SR_PRIV int sr_scpi_get_uint8v(struct sr_scpi_dev_inst *scpi,
+                              const char *command, GArray **scpi_response)
+{
+       int tmp, ret;
+       char *response;
+       gchar **ptr, **tokens;
+       GArray *response_array;
+
+       ret = SR_OK;
+       response = NULL;
+       tokens = NULL;
+
+       if (sr_scpi_get_string(scpi, command, &response) != SR_OK)
+               if (!response)
+                       return SR_ERR;
+
+       tokens = g_strsplit(response, ",", 0);
+       ptr = tokens;
+
+       response_array = g_array_sized_new(TRUE, FALSE, sizeof(uint8_t), 256);
+
+       while (*ptr) {
+               if (sr_atoi(*ptr, &tmp) == SR_OK)
+                       response_array = g_array_append_val(response_array,
+                                                           tmp);
+               else
+                       ret = SR_ERR;
+
+               ptr++;
+       }
+       g_strfreev(tokens);
+       g_free(response);
+
+       if (response_array->len == 0) {
+               g_array_free(response_array, TRUE);
+               *scpi_response = NULL;
+               return SR_ERR;
+       }
+
+       *scpi_response = response_array;
+
+       return ret;
+}
+
+/**
+ * Send the *IDN? SCPI command, receive the reply, parse it and store the
+ * reply as a sr_scpi_hw_info structure in the supplied scpi_response pointer.
+ *
+ * The hw_info structure must be freed by the caller via sr_scpi_hw_info_free().
+ *
+ * @param scpi Previously initialised SCPI device structure.
+ * @param scpi_response Pointer where to store the hw_info structure.
+ *
+ * @return SR_OK upon success, SR_ERR on failure.
+ */
+SR_PRIV int sr_scpi_get_hw_id(struct sr_scpi_dev_inst *scpi,
+                             struct sr_scpi_hw_info **scpi_response)
+{
+       int num_tokens;
+       char *response;
+       gchar **tokens;
+       struct sr_scpi_hw_info *hw_info;
+
+       response = NULL;
+       tokens = NULL;
+
+       if (sr_scpi_get_string(scpi, SCPI_CMD_IDN, &response) != SR_OK)
+               if (!response)
+                       return SR_ERR;
+
+       sr_info("Got IDN string: '%s'", response);
+
+       /*
+        * The response to a '*IDN?' is specified by the SCPI spec. It contains
+        * a comma-separated list containing the manufacturer name, instrument
+        * model, serial number of the instrument and the firmware version.
+        */
+       tokens = g_strsplit(response, ",", 0);
+
+       for (num_tokens = 0; tokens[num_tokens] != NULL; num_tokens++);
+
+       if (num_tokens != 4) {
+               sr_dbg("IDN response not according to spec: %80.s.", response);
+               g_strfreev(tokens);
+               g_free(response);
+               return SR_ERR;
+       }
+       g_free(response);
+
+       hw_info = g_try_malloc(sizeof(struct sr_scpi_hw_info));
+       if (!hw_info) {
+               g_strfreev(tokens);
+               return SR_ERR_MALLOC;
+       }
+
+       hw_info->manufacturer = g_strdup(tokens[0]);
+       hw_info->model = g_strdup(tokens[1]);
+       hw_info->serial_number = g_strdup(tokens[2]);
+       hw_info->firmware_version = g_strdup(tokens[3]);
+
+       g_strfreev(tokens);
+
+       *scpi_response = hw_info;
+
+       return SR_OK;
+}
+
+/**
+ * Free a sr_scpi_hw_info struct.
+ *
+ * @param hw_info Pointer to the struct to free.
+ *
+ * This function is safe to call with a NULL pointer.
+ */
+SR_PRIV void sr_scpi_hw_info_free(struct sr_scpi_hw_info *hw_info)
+{
+       if (hw_info) {
+               g_free(hw_info->manufacturer);
+               g_free(hw_info->model);
+               g_free(hw_info->serial_number);
+               g_free(hw_info->firmware_version);
+               g_free(hw_info);
+       }
+}
diff --git a/src/scpi/scpi_serial.c b/src/scpi/scpi_serial.c
new file mode 100644 (file)
index 0000000..feb3317
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 poljar (Damir Jelić) <poljarinho@gmail.com>
+ * Copyright (C) 2013 Martin Ling <martin-sigrok@earth.li>
+ *
+ * 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 "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#include <glib.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define LOG_PREFIX "scpi_serial"
+
+#define BUFFER_SIZE 1024
+
+struct scpi_serial {
+       struct sr_serial_dev_inst *serial;
+       char buffer[BUFFER_SIZE];
+       size_t count;
+       size_t read;
+};
+
+static struct {
+       uint16_t vendor_id;
+       uint16_t product_id;
+       const char *serialcomm;
+} scpi_serial_usb_ids[] = {
+       { 0x0403, 0xed72, "115200/8n1/flow=1" }, /* Hameg HO720 */
+       { 0x0403, 0xed73, "115200/8n1/flow=1" }, /* Hameg HO730 */
+};
+
+static GSList *scpi_serial_scan(struct drv_context *drvc)
+{
+       GSList *l, *r, *resources = NULL;
+       gchar *res;
+       unsigned i;
+
+       (void)drvc;
+
+       for (i = 0; i < ARRAY_SIZE(scpi_serial_usb_ids); i++) {
+               if ((l = sr_serial_find_usb(scpi_serial_usb_ids[i].vendor_id,
+                                           scpi_serial_usb_ids[i].product_id)) == NULL)
+                       continue;
+               for (r = l; r; r = r->next) {
+                       if (scpi_serial_usb_ids[i].serialcomm)
+                               res = g_strdup_printf("%s:%s", (char *) r->data,
+                                                     scpi_serial_usb_ids[i].serialcomm);
+                       else
+                               res = g_strdup(r->data);
+                       resources = g_slist_append(resources, res);
+               }
+               g_slist_free_full(l, g_free);
+       }
+
+       return resources;
+}
+
+static int scpi_serial_dev_inst_new(void *priv, struct drv_context *drvc,
+               const char *resource, char **params, const char *serialcomm)
+{
+       struct scpi_serial *sscpi = priv;
+
+       (void)drvc;
+       (void)params;
+
+       if (!(sscpi->serial = sr_serial_dev_inst_new(resource, serialcomm)))
+               return SR_ERR;
+
+       return SR_OK;
+}
+
+static int scpi_serial_open(void *priv)
+{
+       struct scpi_serial *sscpi = priv;
+       struct sr_serial_dev_inst *serial = sscpi->serial;
+
+       if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
+               return SR_ERR;
+
+       if (serial_flush(serial) != SR_OK)
+               return SR_ERR;
+
+       sscpi->count = 0;
+       sscpi->read = 0;
+
+       return SR_OK;
+}
+
+static int scpi_serial_source_add(struct sr_session *session, void *priv,
+               int events, int timeout, sr_receive_data_callback cb, void *cb_data)
+{
+       struct scpi_serial *sscpi = priv;
+       struct sr_serial_dev_inst *serial = sscpi->serial;
+
+       return serial_source_add(session, serial, events, timeout, cb, cb_data);
+}
+
+static int scpi_serial_source_remove(struct sr_session *session, void *priv)
+{
+       struct scpi_serial *sscpi = priv;
+       struct sr_serial_dev_inst *serial = sscpi->serial;
+
+       return serial_source_remove(session, serial);
+}
+
+static int scpi_serial_send(void *priv, const char *command)
+{
+       int len, result, written;
+       gchar *terminated_command;
+       struct scpi_serial *sscpi = priv;
+       struct sr_serial_dev_inst *serial = sscpi->serial;
+
+       terminated_command = g_strconcat(command, "\n", NULL);
+       len = strlen(terminated_command);
+       written = 0;
+       while (written < len) {
+               result = serial_write(serial, terminated_command + written, len - written);
+               if (result < 0) {
+                       sr_err("Error while sending SCPI command: '%s'.", command);
+                       g_free(terminated_command);
+                       return SR_ERR;
+               }
+               written += result;
+       }
+
+       g_free(terminated_command);
+
+       sr_spew("Successfully sent SCPI command: '%s'.", command);
+
+       return SR_OK;
+}
+
+static int scpi_serial_read_begin(void *priv)
+{
+       (void) priv;
+
+       return SR_OK;
+}
+
+static int scpi_serial_read_data(void *priv, char *buf, int maxlen)
+{
+       struct scpi_serial *sscpi = priv;
+       int len, ret;
+
+       len = BUFFER_SIZE - sscpi->count;
+
+       /* Try to read new data into the buffer if there is space. */
+       if (len > 0) {
+               ret = serial_read(sscpi->serial, sscpi->buffer + sscpi->read,
+                               BUFFER_SIZE - sscpi->count);
+
+               if (ret < 0)
+                       return ret;
+
+               sscpi->count += ret;
+
+               if (ret > 0)
+                       sr_spew("Read %d bytes into buffer.", ret);
+       }
+
+       /* Return as many bytes as possible from buffer, excluding any trailing newline. */
+       if (sscpi->read < sscpi->count) {
+               len = sscpi->count - sscpi->read;
+               if (len > maxlen)
+                       len = maxlen;
+               if (sscpi->buffer[sscpi->read + len - 1] == '\n')
+                       len--;
+               sr_spew("Returning %d bytes from buffer.", len);
+               memcpy(buf, sscpi->buffer + sscpi->read, len);
+               sscpi->read += len;
+               if (sscpi->read == BUFFER_SIZE) {
+                       sr_spew("Resetting buffer.");
+                       sscpi->count = 0;
+                       sscpi->read = 0;
+               }
+               return len;
+       }
+
+       return 0;
+}
+
+static int scpi_serial_read_complete(void *priv)
+{
+       struct scpi_serial *sscpi = priv;
+
+       /* If the next character is a newline, discard it and report complete. */
+       if (sscpi->read < sscpi->count && sscpi->buffer[sscpi->read] == '\n') {
+               sscpi->read++;
+               return 1;
+       } else {
+               return 0;
+       }
+}
+
+static int scpi_serial_close(void *priv)
+{
+       struct scpi_serial *sscpi = priv;
+
+       return serial_close(sscpi->serial);
+}
+
+static void scpi_serial_free(void *priv)
+{
+       struct scpi_serial *sscpi = priv;
+
+       sr_serial_dev_inst_free(sscpi->serial);
+}
+
+SR_PRIV const struct sr_scpi_dev_inst scpi_serial_dev = {
+       .name          = "serial",
+       .prefix        = "",
+       .priv_size     = sizeof(struct scpi_serial),
+       .scan          = scpi_serial_scan,
+       .dev_inst_new  = scpi_serial_dev_inst_new,
+       .open          = scpi_serial_open,
+       .source_add    = scpi_serial_source_add,
+       .source_remove = scpi_serial_source_remove,
+       .send          = scpi_serial_send,
+       .read_begin    = scpi_serial_read_begin,
+       .read_data     = scpi_serial_read_data,
+       .read_complete = scpi_serial_read_complete,
+       .close         = scpi_serial_close,
+       .free          = scpi_serial_free,
+};
diff --git a/src/scpi/scpi_tcp.c b/src/scpi/scpi_tcp.c
new file mode 100644 (file)
index 0000000..ef3a6c7
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Martin Ling <martin-sigrok@earth.li>
+ *
+ * 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/>.
+ */
+
+#ifdef _WIN32
+#define _WIN32_WINNT 0x0501
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#endif
+
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#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>
+
+#define LOG_PREFIX "scpi_tcp"
+
+#define LENGTH_BYTES 4
+
+struct scpi_tcp {
+       char *address;
+       char *port;
+       int socket;
+       char length_buf[LENGTH_BYTES];
+       int length_bytes_read;
+       int response_length;
+       int response_bytes_read;
+};
+
+static int scpi_tcp_dev_inst_new(void *priv, struct drv_context *drvc,
+               const char *resource, char **params, const char *serialcomm)
+{
+       struct scpi_tcp *tcp = priv;
+
+       (void)drvc;
+       (void)resource;
+       (void)serialcomm;
+
+       if (!params || !params[1] || !params[2]) {
+               sr_err("Invalid parameters.");
+               return SR_ERR;
+       }
+
+       tcp->address = g_strdup(params[1]);
+       tcp->port    = g_strdup(params[2]);
+       tcp->socket  = -1;
+
+       return SR_OK;
+}
+
+static int scpi_tcp_open(void *priv)
+{
+       struct scpi_tcp *tcp = priv;
+       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(tcp->address, tcp->port, &hints, &results);
+
+       if (err) {
+               sr_err("Address lookup failed: %s:%d: %s", tcp->address, tcp->port,
+                       gai_strerror(err));
+               return SR_ERR;
+       }
+
+       for (res = results; res; res = res->ai_next) {
+               if ((tcp->socket = socket(res->ai_family, res->ai_socktype,
+                                               res->ai_protocol)) < 0)
+                       continue;
+               if (connect(tcp->socket, res->ai_addr, res->ai_addrlen) != 0) {
+                       close(tcp->socket);
+                       tcp->socket = -1;
+                       continue;
+               }
+               break;
+       }
+
+       freeaddrinfo(results);
+
+       if (tcp->socket < 0) {
+               sr_err("Failed to connect to %s:%s: %s", tcp->address, tcp->port,
+                               strerror(errno));
+               return SR_ERR;
+       }
+
+       return SR_OK;
+}
+
+static int scpi_tcp_source_add(struct sr_session *session, void *priv,
+               int events, int timeout, sr_receive_data_callback cb, void *cb_data)
+{
+       struct scpi_tcp *tcp = priv;
+
+       return sr_session_source_add(session, tcp->socket, events, timeout,
+                       cb, cb_data);
+}
+
+static int scpi_tcp_source_remove(struct sr_session *session, void *priv)
+{
+       struct scpi_tcp *tcp = priv;
+
+       return sr_session_source_remove(session, tcp->socket);
+}
+
+static int scpi_tcp_send(void *priv, const char *command)
+{
+       struct scpi_tcp *tcp = priv;
+       int len, out;
+       char *terminated_command;
+
+       terminated_command = g_strdup_printf("%s\r\n", command);
+       len = strlen(terminated_command);
+       out = send(tcp->socket, terminated_command, len, 0);
+       g_free(terminated_command);
+
+       if (out < 0) {
+               sr_err("Send error: %s", strerror(errno));
+               return SR_ERR;
+       }
+
+       if (out < len) {
+               sr_dbg("Only sent %d/%d bytes of SCPI command: '%s'.", out,
+                      len, command);
+       }
+
+       sr_spew("Successfully sent SCPI command: '%s'.", command);
+
+       return SR_OK;
+}
+
+static int scpi_tcp_read_begin(void *priv)
+{
+       struct scpi_tcp *tcp = priv;
+
+       tcp->response_bytes_read = 0;
+       tcp->length_bytes_read = 0;
+
+       return SR_OK;
+}
+
+static int scpi_tcp_raw_read_data(void *priv, char *buf, int maxlen)
+{
+       struct scpi_tcp *tcp = priv;
+       int len;
+
+       len = recv(tcp->socket, buf, maxlen, 0);
+
+       if (len < 0) {
+               sr_err("Receive error: %s", strerror(errno));
+               return SR_ERR;
+       }
+
+       tcp->length_bytes_read = LENGTH_BYTES;
+       tcp->response_length = len < maxlen ? len : maxlen + 1;
+       tcp->response_bytes_read = len;
+
+       return len;
+}
+
+static int scpi_tcp_rigol_read_data(void *priv, char *buf, int maxlen)
+{
+       struct scpi_tcp *tcp = priv;
+       int len;
+
+       if (tcp->length_bytes_read < LENGTH_BYTES) {
+               len = recv(tcp->socket, tcp->length_buf + tcp->length_bytes_read,
+                               LENGTH_BYTES - tcp->length_bytes_read, 0);
+               if (len < 0) {
+                       sr_err("Receive error: %s", strerror(errno));
+                       return SR_ERR;
+               }
+
+               tcp->length_bytes_read += len;
+
+               if (tcp->length_bytes_read < LENGTH_BYTES)
+                       return 0;
+               else
+                       tcp->response_length = RL32(tcp->length_buf);
+       }
+
+       if (tcp->response_bytes_read >= tcp->response_length)
+               return SR_ERR;
+
+       len = recv(tcp->socket, buf, maxlen, 0);
+
+       if (len < 0) {
+               sr_err("Receive error: %s", strerror(errno));
+               return SR_ERR;
+       }
+
+       tcp->response_bytes_read += len;
+
+       return len;
+}
+
+static int scpi_tcp_read_complete(void *priv)
+{
+       struct scpi_tcp *tcp = priv;
+
+       return (tcp->length_bytes_read == LENGTH_BYTES &&
+                       tcp->response_bytes_read >= tcp->response_length);
+}
+
+static int scpi_tcp_close(void *priv)
+{
+       struct scpi_tcp *tcp = priv;
+
+       if (close(tcp->socket) < 0)
+               return SR_ERR;
+
+       return SR_OK;
+}
+
+static void scpi_tcp_free(void *priv)
+{
+       struct scpi_tcp *tcp = priv;
+
+       g_free(tcp->address);
+       g_free(tcp->port);
+}
+
+SR_PRIV const struct sr_scpi_dev_inst scpi_tcp_raw_dev = {
+       .name          = "RAW TCP",
+       .prefix        = "tcp-raw",
+       .priv_size     = sizeof(struct scpi_tcp),
+       .dev_inst_new  = scpi_tcp_dev_inst_new,
+       .open          = scpi_tcp_open,
+       .source_add    = scpi_tcp_source_add,
+       .source_remove = scpi_tcp_source_remove,
+       .send          = scpi_tcp_send,
+       .read_begin    = scpi_tcp_read_begin,
+       .read_data     = scpi_tcp_raw_read_data,
+       .read_complete = scpi_tcp_read_complete,
+       .close         = scpi_tcp_close,
+       .free          = scpi_tcp_free,
+};
+
+SR_PRIV const struct sr_scpi_dev_inst scpi_tcp_rigol_dev = {
+       .name          = "RIGOL TCP",
+       .prefix        = "tcp-rigol",
+       .priv_size     = sizeof(struct scpi_tcp),
+       .dev_inst_new  = scpi_tcp_dev_inst_new,
+       .open          = scpi_tcp_open,
+       .source_add    = scpi_tcp_source_add,
+       .source_remove = scpi_tcp_source_remove,
+       .send          = scpi_tcp_send,
+       .read_begin    = scpi_tcp_read_begin,
+       .read_data     = scpi_tcp_rigol_read_data,
+       .read_complete = scpi_tcp_read_complete,
+       .close         = scpi_tcp_close,
+       .free          = scpi_tcp_free,
+};
diff --git a/src/scpi/scpi_usbtmc_libusb.c b/src/scpi/scpi_usbtmc_libusb.c
new file mode 100644 (file)
index 0000000..c4470b5
--- /dev/null
@@ -0,0 +1,585 @@
+/*
+ * 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 <string.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "scpi_usbtmc"
+
+#define MAX_TRANSFER_LENGTH 2048
+#define TRANSFER_TIMEOUT 1000
+
+struct scpi_usbtmc_libusb {
+       struct sr_context *ctx;
+       struct sr_usb_dev_inst *usb;
+       int detached_kernel_driver;
+       uint8_t interface;
+       uint8_t bulk_in_ep;
+       uint8_t bulk_out_ep;
+       uint8_t interrupt_ep;
+       uint8_t usbtmc_int_cap;
+       uint8_t usbtmc_dev_cap;
+       uint8_t usb488_dev_cap;
+       uint8_t bTag;
+       uint8_t bulkin_attributes;
+       uint8_t buffer[MAX_TRANSFER_LENGTH];
+       int response_length;
+       int response_bytes_read;
+       int remaining_length;
+       int rigol_ds1000;
+};
+
+/* Some USBTMC-specific enums, as defined in the USBTMC standard. */
+#define SUBCLASS_USBTMC  0x03
+#define USBTMC_USB488    0x01
+
+enum {
+       /* USBTMC control requests */
+       INITIATE_ABORT_BULK_OUT     =   1,
+       CHECK_ABORT_BULK_OUT_STATUS =   2,
+       INITIATE_ABORT_BULK_IN      =   3,
+       CHECK_ABORT_BULK_IN_STATUS  =   4,
+       INITIATE_CLEAR              =   5,
+       CHECK_CLEAR_STATUS          =   6,
+       GET_CAPABILITIES            =   7,
+       INDICATOR_PULSE             =  64,
+
+       /* USB488 control requests */
+       READ_STATUS_BYTE            = 128,
+       REN_CONTROL                 = 160,
+       GO_TO_LOCAL                 = 161,
+       LOCAL_LOCKOUT               = 162,
+};
+
+/* USBTMC capabilities */
+#define USBTMC_INT_CAP_LISTEN_ONLY 0x01
+#define USBTMC_INT_CAP_TALK_ONLY   0x02
+#define USBTMC_INT_CAP_INDICATOR   0x04
+
+#define USBTMC_DEV_CAP_TERMCHAR    0x01
+
+#define USB488_DEV_CAP_DT1         0x01
+#define USB488_DEV_CAP_RL1         0x02
+#define USB488_DEV_CAP_SR1         0x04
+#define USB488_DEV_CAP_SCPI        0x08
+
+/* Bulk messages constants */
+#define USBTMC_BULK_HEADER_SIZE  12
+
+/* Bulk MsgID values */
+#define DEV_DEP_MSG_OUT         1
+#define REQUEST_DEV_DEP_MSG_IN  2
+#define DEV_DEP_MSG_IN          2
+
+/* bmTransferAttributes */
+#define EOM                0x01
+#define TERM_CHAR_ENABLED  0x02
+
+
+static GSList *scpi_usbtmc_libusb_scan(struct drv_context *drvc)
+{
+       struct libusb_device **devlist;
+       struct libusb_device_descriptor des;
+       struct libusb_config_descriptor *confdes;
+       const struct libusb_interface_descriptor *intfdes;
+       GSList *resources = NULL;
+       int confidx, intfidx, ret, i;
+       char *res;
+
+       ret = libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
+       if (ret < 0) {
+               sr_err("Failed to get device list: %s.",
+                      libusb_error_name(ret));
+               return NULL;
+       }
+       for (i = 0; devlist[i]; i++) {
+               if ((ret = libusb_get_device_descriptor(devlist[i], &des)) < 0) {
+                       sr_err("Failed to get device descriptor: %s.",
+                              libusb_error_name(ret));
+                       continue;
+               }
+
+               for (confidx = 0; confidx < des.bNumConfigurations; confidx++) {
+                       if ((ret = libusb_get_config_descriptor(devlist[i], confidx, &confdes)) < 0) {
+                               sr_dbg("Failed to get configuration descriptor: %s, "
+                                      "ignoring device.", libusb_error_name(ret));
+                               break;
+                       }
+                       for (intfidx = 0; intfidx < confdes->bNumInterfaces; intfidx++) {
+                               intfdes = confdes->interface[intfidx].altsetting;
+                               if (intfdes->bInterfaceClass    != LIBUSB_CLASS_APPLICATION ||
+                                   intfdes->bInterfaceSubClass != SUBCLASS_USBTMC          ||
+                                   intfdes->bInterfaceProtocol != USBTMC_USB488)
+                                       continue;
+                               sr_dbg("Found USBTMC device (VID:PID = %04x:%04x, "
+                                      "bus.address = %d.%d).", des.idVendor, des.idProduct,
+                                      libusb_get_bus_number(devlist[i]),
+                                      libusb_get_device_address(devlist[i]));
+                               res = g_strdup_printf("usbtmc/%d.%d",
+                                                     libusb_get_bus_number(devlist[i]),
+                                                     libusb_get_device_address(devlist[i]));
+                               resources = g_slist_append(resources, res);
+                       }
+                       libusb_free_config_descriptor(confdes);
+               }
+       }
+       libusb_free_device_list(devlist, 1);
+
+       sr_dbg("Found %d device(s).", g_slist_length(resources));
+
+       return resources;
+}
+
+static int scpi_usbtmc_libusb_dev_inst_new(void *priv, struct drv_context *drvc,
+               const char *resource, char **params, const char *serialcomm)
+{
+       struct scpi_usbtmc_libusb *uscpi = priv;
+       GSList *devices;
+
+       (void)resource;
+       (void)serialcomm;
+
+       if (!params || !params[1]) {
+               sr_err("Invalid parameters.");
+               return SR_ERR;
+       }
+
+       uscpi->ctx = drvc->sr_ctx;
+       devices = sr_usb_find(uscpi->ctx->libusb_ctx, params[1]);
+       if (g_slist_length(devices) != 1) {
+               sr_err("Failed to find USB device '%s'.", params[1]);
+               g_slist_free_full(devices, (GDestroyNotify)sr_usb_dev_inst_free);
+               return SR_ERR;
+       }
+       uscpi->usb = devices->data;
+       g_slist_free(devices);
+
+       return SR_OK;
+}
+
+static int scpi_usbtmc_libusb_open(void *priv)
+{
+       struct scpi_usbtmc_libusb *uscpi = priv;
+       struct sr_usb_dev_inst *usb = uscpi->usb;
+       struct libusb_device *dev;
+       struct libusb_device_descriptor des;
+       struct libusb_config_descriptor *confdes;
+       const struct libusb_interface_descriptor *intfdes;
+       const struct libusb_endpoint_descriptor *ep;
+       int confidx, intfidx, epidx, config = 0;
+       uint8_t capabilities[24];
+       int ret, found = 0;
+
+       if (usb->devhdl)
+               return SR_OK;
+
+       if (sr_usb_open(uscpi->ctx->libusb_ctx, usb) != SR_OK)
+               return SR_ERR;
+
+       dev = libusb_get_device(usb->devhdl);
+       if ((ret = libusb_get_device_descriptor(dev, &des)) < 0) {
+               sr_err("Failed to get device descriptor: %s.",
+                      libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+       for (confidx = 0; confidx < des.bNumConfigurations; confidx++) {
+               if ((ret = libusb_get_config_descriptor(dev, confidx, &confdes)) < 0) {
+                       sr_dbg("Failed to get configuration descriptor: %s, "
+                              "ignoring device.", libusb_error_name(ret));
+                       continue;
+               }
+               for (intfidx = 0; intfidx < confdes->bNumInterfaces; intfidx++) {
+                       intfdes = confdes->interface[intfidx].altsetting;
+                       if (intfdes->bInterfaceClass    != LIBUSB_CLASS_APPLICATION ||
+                           intfdes->bInterfaceSubClass != SUBCLASS_USBTMC          ||
+                           intfdes->bInterfaceProtocol != USBTMC_USB488)
+                               continue;
+                       uscpi->interface = intfdes->bInterfaceNumber;
+                       sr_dbg("Interface %d", uscpi->interface);
+                       config = confdes->bConfigurationValue;
+                       sr_dbg("Configuration %d", config);
+                       for (epidx = 0; epidx < intfdes->bNumEndpoints; epidx++) {
+                               ep = &intfdes->endpoint[epidx];
+                               if (ep->bmAttributes == LIBUSB_TRANSFER_TYPE_BULK &&
+                                   !(ep->bEndpointAddress & (LIBUSB_ENDPOINT_DIR_MASK))) {
+                                       uscpi->bulk_out_ep = ep->bEndpointAddress;
+                                       sr_dbg("Bulk OUT EP %d", uscpi->bulk_out_ep);
+                               }
+                               if (ep->bmAttributes == LIBUSB_TRANSFER_TYPE_BULK &&
+                                   ep->bEndpointAddress & (LIBUSB_ENDPOINT_DIR_MASK)) {
+                                       uscpi->bulk_in_ep = ep->bEndpointAddress;
+                                       sr_dbg("Bulk IN EP %d", uscpi->bulk_in_ep);
+                               }
+                               if (ep->bmAttributes == LIBUSB_TRANSFER_TYPE_INTERRUPT &&
+                                   ep->bEndpointAddress & (LIBUSB_ENDPOINT_DIR_MASK)) {
+                                       uscpi->interrupt_ep = ep->bEndpointAddress;
+                                       sr_dbg("Interrupt EP %d", uscpi->interrupt_ep);
+                               }
+                       }
+                       found = 1;
+                       uscpi->rigol_ds1000 = des.idVendor  == 0x1ab1 &&
+                                             des.idProduct == 0x0588;
+               }
+               libusb_free_config_descriptor(confdes);
+               if (found)
+                       break;
+       }
+
+       if (!found) {
+               sr_err("Failed to find USBTMC interface.");
+               return SR_ERR;
+       }
+
+       if (libusb_kernel_driver_active(usb->devhdl, uscpi->interface) == 1) {
+               if ((ret = libusb_detach_kernel_driver(usb->devhdl,
+                                                      uscpi->interface)) < 0) {
+                       sr_err("Failed to detach kernel driver: %s.",
+                              libusb_error_name(ret));
+                       return SR_ERR;
+               }
+               uscpi->detached_kernel_driver = 1;
+       }
+
+       if ((ret = libusb_set_configuration(usb->devhdl, config)) < 0) {
+               sr_err("Failed to set configuration: %s.",
+                      libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+       if ((ret = libusb_claim_interface(usb->devhdl, uscpi->interface)) < 0) {
+               sr_err("Failed to claim interface: %s.",
+                      libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+       if (!uscpi->rigol_ds1000) {
+       if ((ret = libusb_clear_halt(usb->devhdl, uscpi->bulk_in_ep)) < 0) {
+               sr_err("Failed to clear halt/stall condition for EP %d: %s.",
+                      uscpi->bulk_in_ep, libusb_error_name(ret));
+               return SR_ERR;
+       }
+       if ((ret = libusb_clear_halt(usb->devhdl, uscpi->bulk_out_ep)) < 0) {
+               sr_err("Failed to clear halt/stall condition for EP %d: %s.",
+                      uscpi->bulk_out_ep, libusb_error_name(ret));
+               return SR_ERR;
+       }
+       if ((ret = libusb_clear_halt(usb->devhdl, uscpi->interrupt_ep)) < 0) {
+               sr_err("Failed to clear halt/stall condition for EP %d: %s.",
+                      uscpi->interrupt_ep, libusb_error_name(ret));
+               return SR_ERR;
+       }
+       }
+
+       /* Get capabilities. */
+       ret = libusb_control_transfer(usb->devhdl,
+                                     LIBUSB_ENDPOINT_IN         |
+                                     LIBUSB_REQUEST_TYPE_CLASS  |
+                                     LIBUSB_RECIPIENT_INTERFACE,
+                                     GET_CAPABILITIES, 0,
+                                     uscpi->interface,
+                                     capabilities, sizeof(capabilities),
+                                     TRANSFER_TIMEOUT);
+       if (ret == sizeof(capabilities)) {
+               uscpi->usbtmc_int_cap = capabilities[ 4];
+               uscpi->usbtmc_dev_cap = capabilities[ 5];
+               uscpi->usb488_dev_cap = capabilities[15];
+       }
+       sr_dbg("Device capabilities: %s%s%s%s%s, %s, %s",
+              uscpi->usb488_dev_cap & USB488_DEV_CAP_SCPI       ? "SCPI, "    : "",
+              uscpi->usbtmc_dev_cap & USBTMC_DEV_CAP_TERMCHAR   ? "TermChar, ": "",
+              uscpi->usbtmc_int_cap & USBTMC_INT_CAP_LISTEN_ONLY? "L3, " :
+              uscpi->usbtmc_int_cap & USBTMC_INT_CAP_TALK_ONLY  ? ""     : "L4, ",
+              uscpi->usbtmc_int_cap & USBTMC_INT_CAP_TALK_ONLY  ? "T5, " :
+              uscpi->usbtmc_int_cap & USBTMC_INT_CAP_LISTEN_ONLY? ""     : "T6, ",
+              uscpi->usb488_dev_cap & USB488_DEV_CAP_SR1        ? "SR1"  : "SR0",
+              uscpi->usb488_dev_cap & USB488_DEV_CAP_RL1        ? "RL1"  : "RL0",
+              uscpi->usb488_dev_cap & USB488_DEV_CAP_DT1        ? "DT1"  : "DT0");
+
+       return SR_OK;
+}
+
+static int scpi_usbtmc_libusb_source_add(struct sr_session *session,
+               void *priv, int events, int timeout, sr_receive_data_callback cb,
+               void *cb_data)
+{
+       struct scpi_usbtmc_libusb *uscpi = priv;
+       (void)events;
+       return usb_source_add(session, uscpi->ctx, timeout, cb, cb_data);
+}
+
+static int scpi_usbtmc_libusb_source_remove(struct sr_session *session,
+               void *priv)
+{
+       struct scpi_usbtmc_libusb *uscpi = priv;
+       return usb_source_remove(session, uscpi->ctx);
+}
+
+static void usbtmc_bulk_out_header_write(void *header, uint8_t MsgID,
+                                         uint8_t bTag,
+                                         uint32_t TransferSize,
+                                         uint8_t bmTransferAttributes,
+                                         char TermChar)
+{
+         W8(header+ 0, MsgID);
+         W8(header+ 1, bTag);
+         W8(header+ 2, ~bTag);
+         W8(header+ 3, 0);
+       WL32(header+ 4, TransferSize);
+         W8(header+ 8, bmTransferAttributes);
+         W8(header+ 9, TermChar);
+       WL16(header+10, 0);
+}
+
+static int usbtmc_bulk_in_header_read(void *header, uint8_t MsgID,
+                                      unsigned char bTag,
+                                      int32_t *TransferSize,
+                                      uint8_t *bmTransferAttributes)
+{
+       if (R8(header+0) != MsgID ||
+           R8(header+1) != bTag  ||
+           R8(header+2) != (unsigned char)~bTag)
+               return SR_ERR;
+       if (TransferSize)
+               *TransferSize = RL32(header+4);
+       if (bmTransferAttributes)
+               *bmTransferAttributes = R8(header+8);
+       return SR_OK;
+}
+
+static int scpi_usbtmc_bulkout(struct scpi_usbtmc_libusb *uscpi,
+                               uint8_t msg_id, const void *data, int32_t size,
+                               uint8_t transfer_attributes)
+{
+       struct sr_usb_dev_inst *usb = uscpi->usb;
+       int padded_size, ret, transferred;
+
+       if (data && size+USBTMC_BULK_HEADER_SIZE+3 > (int)sizeof(uscpi->buffer)) {
+               sr_err("USBTMC bulk out transfer is too big.");
+               return SR_ERR;
+       }
+
+       uscpi->bTag++;
+       uscpi->bTag += !uscpi->bTag;  /* bTag == 0 is invalid so avoid it. */
+
+       usbtmc_bulk_out_header_write(uscpi->buffer, msg_id, uscpi->bTag,
+                                    size, transfer_attributes, 0);
+       if (data)
+               memcpy(uscpi->buffer+USBTMC_BULK_HEADER_SIZE, data, size);
+       else
+               size = 0;
+       size += USBTMC_BULK_HEADER_SIZE;
+       padded_size = (size + 3) & ~0x3;
+       memset(uscpi->buffer+size, 0, padded_size - size);
+
+       ret = libusb_bulk_transfer(usb->devhdl, uscpi->bulk_out_ep,
+                                  uscpi->buffer, padded_size, &transferred,
+                                  TRANSFER_TIMEOUT);
+       if (ret < 0) {
+               sr_err("USBTMC bulk out transfer error: %s.",
+                      libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+       if (transferred < padded_size) {
+               sr_dbg("USBTMC bulk out partial transfer (%d/%d bytes).",
+                      transferred, padded_size);
+               return SR_ERR;
+       }
+
+       return transferred - USBTMC_BULK_HEADER_SIZE;
+}
+
+static int scpi_usbtmc_bulkin_start(struct scpi_usbtmc_libusb *uscpi,
+                                    uint8_t msg_id, void *data, int32_t size,
+                                    uint8_t *transfer_attributes)
+{
+       struct sr_usb_dev_inst *usb = uscpi->usb;
+       int ret, transferred, message_size;
+
+       ret = libusb_bulk_transfer(usb->devhdl, uscpi->bulk_in_ep, data, size,
+                                  &transferred, TRANSFER_TIMEOUT);
+       if (ret < 0) {
+               sr_err("USBTMC bulk in transfer error: %s.",
+                      libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+       if (usbtmc_bulk_in_header_read(data, msg_id, uscpi->bTag, &message_size,
+                                      transfer_attributes) != SR_OK) {
+               sr_err("USBTMC invalid bulk in header.");
+               return SR_ERR;
+       }
+
+       message_size += USBTMC_BULK_HEADER_SIZE;
+       uscpi->response_length = MIN(transferred, message_size);
+       uscpi->response_bytes_read = USBTMC_BULK_HEADER_SIZE;
+       uscpi->remaining_length = message_size - uscpi->response_length;
+
+       return transferred - USBTMC_BULK_HEADER_SIZE;
+}
+
+static int scpi_usbtmc_bulkin_continue(struct scpi_usbtmc_libusb *uscpi,
+                                       void *data, int size)
+{
+       struct sr_usb_dev_inst *usb = uscpi->usb;
+       int ret, transferred;
+
+       ret = libusb_bulk_transfer(usb->devhdl, uscpi->bulk_in_ep, data, size,
+                                  &transferred, TRANSFER_TIMEOUT);
+       if (ret < 0) {
+               sr_err("USBTMC bulk in transfer error: %s.",
+                      libusb_error_name(ret));
+               return SR_ERR;
+       }
+
+       uscpi->response_length = MIN(transferred, uscpi->remaining_length);
+       uscpi->response_bytes_read = 0;
+       uscpi->remaining_length -= uscpi->response_length;
+
+       return transferred;
+}
+
+static int scpi_usbtmc_libusb_send(void *priv, const char *command)
+{
+       struct scpi_usbtmc_libusb *uscpi = priv;
+
+       if (scpi_usbtmc_bulkout(uscpi, DEV_DEP_MSG_OUT,
+                               command, strlen(command), EOM) <= 0)
+               return SR_ERR;
+
+       sr_spew("Successfully sent SCPI command: '%s'.", command);
+
+       return SR_OK;
+}
+
+static int scpi_usbtmc_libusb_read_begin(void *priv)
+{
+       struct scpi_usbtmc_libusb *uscpi = priv;
+
+       uscpi->remaining_length = 0;
+
+       if (scpi_usbtmc_bulkout(uscpi, REQUEST_DEV_DEP_MSG_IN,
+           NULL, INT32_MAX, 0) < 0)
+               return SR_ERR;
+       if (scpi_usbtmc_bulkin_start(uscpi, DEV_DEP_MSG_IN,
+                                    uscpi->buffer, sizeof(uscpi->buffer),
+                                    &uscpi->bulkin_attributes) < 0)
+               return SR_ERR;
+
+       return SR_OK;
+}
+
+static int scpi_usbtmc_libusb_read_data(void *priv, char *buf, int maxlen)
+{
+       struct scpi_usbtmc_libusb *uscpi = priv;
+       int read_length;
+
+       if (uscpi->response_bytes_read >= uscpi->response_length) {
+               if (uscpi->remaining_length > 0) {
+                       if (scpi_usbtmc_bulkin_continue(uscpi, uscpi->buffer,
+                                                       sizeof(uscpi->buffer)) <= 0)
+                               return SR_ERR;
+               } else {
+                       if (uscpi->bulkin_attributes & EOM)
+                               return SR_ERR;
+                       if (scpi_usbtmc_libusb_read_begin(uscpi) < 0)
+                               return SR_ERR;
+               }
+       }
+
+       read_length = MIN(uscpi->response_length - uscpi->response_bytes_read, maxlen);
+
+       memcpy(buf, uscpi->buffer + uscpi->response_bytes_read, read_length);
+
+       uscpi->response_bytes_read += read_length;
+
+       return read_length;
+}
+
+static int scpi_usbtmc_libusb_read_complete(void *priv)
+{
+       struct scpi_usbtmc_libusb *uscpi = priv;
+       return uscpi->response_bytes_read >= uscpi->response_length &&
+              uscpi->remaining_length <= 0 &&
+              uscpi->bulkin_attributes & EOM;
+}
+
+static int scpi_usbtmc_libusb_close(void *priv)
+{
+       int ret;
+       struct scpi_usbtmc_libusb *uscpi = priv;
+       struct sr_usb_dev_inst *usb = uscpi->usb;
+
+       if (!usb->devhdl)
+               return SR_ERR;
+
+       if (!uscpi->rigol_ds1000) {
+       if ((ret = libusb_clear_halt(usb->devhdl, uscpi->bulk_in_ep)) < 0)
+               sr_err("Failed to clear halt/stall condition for EP %d: %s.",
+                      uscpi->bulk_in_ep, libusb_error_name(ret));
+       if ((ret = libusb_clear_halt(usb->devhdl, uscpi->bulk_out_ep)) < 0)
+               sr_err("Failed to clear halt/stall condition for EP %d: %s.",
+                      uscpi->bulk_out_ep, libusb_error_name(ret));
+       if ((ret = libusb_clear_halt(usb->devhdl, uscpi->interrupt_ep)) < 0)
+               sr_err("Failed to clear halt/stall condition for EP %d: %s.",
+                      uscpi->interrupt_ep, libusb_error_name(ret));
+       }
+
+       if ((ret = libusb_release_interface(usb->devhdl, uscpi->interface)) < 0)
+               sr_err("Failed to release interface: %s.",
+                      libusb_error_name(ret));
+       
+       if (uscpi->detached_kernel_driver) {
+               if ((ret = libusb_attach_kernel_driver(usb->devhdl,
+                                               uscpi->interface)) < 0)
+                       sr_err("Failed to re-attach kernel driver: %s.",
+                              libusb_error_name(ret));
+
+               uscpi->detached_kernel_driver = 0;
+       }
+       libusb_close(usb->devhdl);
+       usb->devhdl = NULL;
+
+       return SR_OK;
+}
+
+static void scpi_usbtmc_libusb_free(void *priv)
+{
+       struct scpi_usbtmc_libusb *uscpi = priv;
+       sr_usb_dev_inst_free(uscpi->usb);
+}
+
+SR_PRIV const struct sr_scpi_dev_inst scpi_usbtmc_libusb_dev = {
+       .name          = "USBTMC",
+       .prefix        = "usbtmc",
+       .priv_size     = sizeof(struct scpi_usbtmc_libusb),
+       .scan          = scpi_usbtmc_libusb_scan,
+       .dev_inst_new  = scpi_usbtmc_libusb_dev_inst_new,
+       .open          = scpi_usbtmc_libusb_open,
+       .source_add    = scpi_usbtmc_libusb_source_add,
+       .source_remove = scpi_usbtmc_libusb_source_remove,
+       .send          = scpi_usbtmc_libusb_send,
+       .read_begin    = scpi_usbtmc_libusb_read_begin,
+       .read_data     = scpi_usbtmc_libusb_read_data,
+       .read_complete = scpi_usbtmc_libusb_read_complete,
+       .close         = scpi_usbtmc_libusb_close,
+       .free          = scpi_usbtmc_libusb_free,
+};
diff --git a/src/scpi/scpi_visa.c b/src/scpi/scpi_visa.c
new file mode 100644 (file)
index 0000000..cf34a55
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Martin Ling <martin-sigrok@earth.li>
+ *
+ * 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 "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#include <visa.h>
+#include <string.h>
+
+#define LOG_PREFIX "scpi_visa"
+
+struct scpi_visa {
+       char *resource;
+       ViSession rmgr;
+       ViSession vi;
+};
+
+static int scpi_visa_dev_inst_new(void *priv, struct drv_context *drvc,
+               const char *resource, char **params, const char *serialcomm)
+{
+       struct scpi_visa *vscpi = priv;
+
+       (void)drvc;
+       (void)resource;
+       (void)serialcomm;
+
+       if (!params || !params[1]) {
+               sr_err("Invalid parameters.");
+               return SR_ERR_BUG;
+       }
+
+       vscpi->resource = g_strdup(params[1]);
+
+       return SR_OK;
+}
+
+static int scpi_visa_open(void *priv)
+{
+       struct scpi_visa *vscpi = priv;
+
+       if (viOpenDefaultRM(&vscpi->rmgr) != VI_SUCCESS) {
+               sr_err("Cannot open default resource manager.");
+               return SR_ERR;
+       }
+
+       if (viOpen(vscpi->rmgr, vscpi->resource, VI_NO_LOCK, 0, &vscpi->vi) != VI_SUCCESS) {
+               sr_err("Cannot open resource.");
+               return SR_ERR;
+       }
+
+       return SR_OK;
+}
+
+static int scpi_visa_source_add(struct sr_session *session, void *priv,
+               int events, int timeout, sr_receive_data_callback cb, void *cb_data)
+{
+       (void) priv;
+
+       /* Hook up a dummy handler to receive data from the device. */
+       return sr_session_source_add(session, -1, events, timeout, cb, cb_data);
+}
+
+static int scpi_visa_source_remove(struct sr_session *session, void *priv)
+{
+       (void) priv;
+
+       return sr_session_source_remove(session, -1);
+}
+
+static int scpi_visa_send(void *priv, const char *command)
+{
+       struct scpi_visa *vscpi = priv;
+       gchar *terminated_command;
+       ViUInt32 written = 0;
+       int len;
+
+       terminated_command = g_strconcat(command, "\n", NULL);
+       len = strlen(terminated_command);
+       if (viWrite(vscpi->vi, (ViBuf) (terminated_command + written), len,
+                       &written) != VI_SUCCESS) {
+               sr_err("Error while sending SCPI command: '%s'.", command);
+               g_free(terminated_command);
+               return SR_ERR;
+       }
+
+       g_free(terminated_command);
+
+       sr_spew("Successfully sent SCPI command: '%s'.", command);
+
+       return SR_OK;
+}
+
+static int scpi_visa_read_begin(void *priv)
+{
+       (void) priv;
+
+       return SR_OK;
+}
+
+static int scpi_visa_read_data(void *priv, char *buf, int maxlen)
+{
+       struct scpi_visa *vscpi = priv;
+       ViUInt32 count;
+
+       if (viRead(vscpi->vi, (ViBuf) buf, maxlen, &count) != VI_SUCCESS) {
+               sr_err("Read failed.");
+               return SR_ERR;
+       }
+
+       return count;
+}
+
+static int scpi_visa_read_complete(void *priv)
+{
+       struct scpi_visa *vscpi = priv;
+       ViUInt16 status;
+
+       if (viReadSTB(vscpi->vi, &status) != VI_SUCCESS) {
+               sr_err("Failed to read status.");
+               return SR_ERR;
+       }
+
+       return !(status & 16);
+}
+
+static int scpi_visa_close(void *priv)
+{
+       struct scpi_visa *vscpi = priv;
+
+       viClose(vscpi->vi);
+       viClose(vscpi->rmgr);
+
+       return SR_OK;
+}
+
+static void scpi_visa_free(void *priv)
+{
+       struct scpi_visa *vscpi = priv;
+
+       g_free(vscpi->resource);
+       g_free(vscpi);
+}
+
+SR_PRIV const struct sr_scpi_dev_inst scpi_visa_dev = {
+       .name = "VISA",
+       .prefix = "visa",
+       .priv_size = sizeof(struct scpi_visa),
+       .dev_inst_new = scpi_visa_dev_inst_new,
+       .open = scpi_visa_open,
+       .source_add = scpi_visa_source_add,
+       .source_remove = scpi_visa_source_remove,
+       .send = scpi_visa_send,
+       .read_begin = scpi_visa_read_begin,
+       .read_data = scpi_visa_read_data,
+       .read_complete = scpi_visa_read_complete,
+       .close = scpi_visa_close,
+       .free = scpi_visa_free,
+};
diff --git a/src/scpi/scpi_vxi.c b/src/scpi/scpi_vxi.c
new file mode 100644 (file)
index 0000000..271917b
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
+ *
+ * Inspired by the VXI11 Ethernet Protocol for Linux:
+ * http://optics.eee.nottingham.ac.uk/vxi11/
+ *
+ * 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 <rpc/rpc.h>
+#include <string.h>
+
+#include "vxi.h"
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "scpi_vxi"
+#define VXI_DEFAULT_TIMEOUT  2000  /* in ms */
+
+struct scpi_vxi {
+       char *address;
+       char *instrument;
+       CLIENT *client;
+       Device_Link link;
+       unsigned int max_send_size;
+       unsigned int read_complete;
+};
+
+static int scpi_vxi_dev_inst_new(void *priv, struct drv_context *drvc,
+               const char *resource, char **params, const char *serialcomm)
+{
+       struct scpi_vxi *vxi = priv;
+
+       (void)drvc;
+       (void)resource;
+       (void)serialcomm;
+
+       if (!params || !params[1]) {
+               sr_err("Invalid parameters.");
+               return SR_ERR;
+       }
+
+       vxi->address    = g_strdup(params[1]);
+       vxi->instrument = g_strdup(params[2] ? params[2] : "inst0");
+
+       return SR_OK;
+}
+
+static int scpi_vxi_open(void *priv)
+{
+       struct scpi_vxi *vxi = priv;
+       Create_LinkParms link_parms;
+       Create_LinkResp *link_resp;
+
+       vxi->client = clnt_create(vxi->address, DEVICE_CORE, DEVICE_CORE_VERSION, "tcp");
+       if (vxi->client == NULL) {
+               sr_err("Client creation failed for %s", vxi->address);
+               return SR_ERR;
+       }
+
+       /* Set link parameters */
+       link_parms.clientId = (long) vxi->client;
+       link_parms.lockDevice = 0;
+       link_parms.lock_timeout = VXI_DEFAULT_TIMEOUT;
+       link_parms.device = "inst0";
+
+       if (!(link_resp = create_link_1(&link_parms, vxi->client))) {
+               sr_err("Link creation failed for %s", vxi->address);
+               return SR_ERR;
+       }
+       vxi->link = link_resp->lid;
+       vxi->max_send_size = link_resp->maxRecvSize;
+
+       /* Set a default maxRecvSize for devices which do not specify it */
+       if (vxi->max_send_size <= 0)
+               vxi->max_send_size = 4096;
+
+       return SR_OK;
+}
+
+static int scpi_vxi_source_add(struct sr_session *session, void *priv,
+               int events, int timeout, sr_receive_data_callback cb, void *cb_data)
+{
+       (void)priv;
+
+       /* Hook up a dummy handler to receive data from the device. */
+       return sr_session_source_add(session, -1, events, timeout, cb, cb_data);
+}
+
+static int scpi_vxi_source_remove(struct sr_session *session, void *priv)
+{
+       (void)priv;
+
+       return sr_session_source_remove(session, -1);
+}
+
+/* Operation Flags */
+#define DF_WAITLOCK  0x01  /* wait if the operation is locked by another link */
+#define DF_END       0x08  /* an END indicator is sent with last byte of buffer */
+#define DF_TERM      0x80  /* a termination char is set during a read */
+
+static int scpi_vxi_send(void *priv, const char *command)
+{
+       struct scpi_vxi *vxi = priv;
+       Device_WriteResp *write_resp;
+       Device_WriteParms write_parms;
+       char *terminated_command;
+       unsigned int len;
+
+       terminated_command = g_strdup_printf("%s\r\n", command);
+       len = strlen(terminated_command);
+
+       write_parms.lid           = vxi->link;
+       write_parms.io_timeout    = VXI_DEFAULT_TIMEOUT;
+       write_parms.lock_timeout  = VXI_DEFAULT_TIMEOUT;
+       write_parms.flags         = DF_END;
+       write_parms.data.data_len = MIN(len, vxi->max_send_size);
+       write_parms.data.data_val = terminated_command;
+
+       if (!(write_resp = device_write_1(&write_parms, vxi->client))
+           || write_resp->error) {
+               sr_err("Device write failed for %s with error %d",
+                      vxi->address, write_resp->error);
+               return SR_ERR;
+       }
+
+       g_free(terminated_command);
+
+       if (write_resp->size < len)
+               sr_dbg("Only sent %d/%d bytes of SCPI command: '%s'.",
+                      write_resp->size, len, command);
+       else
+               sr_spew("Successfully sent SCPI command: '%s'.", command);
+
+       return SR_OK;
+}
+
+static int scpi_vxi_read_begin(void *priv)
+{
+       struct scpi_vxi *vxi = priv;
+
+       vxi->read_complete = 0;
+
+       return SR_OK;
+}
+
+/* Read Response Reason Flags */
+#define RRR_SIZE  0x01  /* requestSize bytes have been transferred */
+#define RRR_TERM  0x02  /* a termination char has been read */
+#define RRR_END   0x04  /* an END indicator has been read */
+
+static int scpi_vxi_read_data(void *priv, char *buf, int maxlen)
+{
+       struct scpi_vxi *vxi = priv;
+       Device_ReadParms read_parms;
+       Device_ReadResp *read_resp;
+
+       read_parms.lid          = vxi->link;
+       read_parms.io_timeout   = VXI_DEFAULT_TIMEOUT;
+       read_parms.lock_timeout = VXI_DEFAULT_TIMEOUT;
+       read_parms.flags        = 0;
+       read_parms.termChar     = 0;
+       read_parms.requestSize  = maxlen;
+
+       if (!(read_resp = device_read_1(&read_parms, vxi->client))
+           || read_resp->error) {
+               sr_err("Device read failed for %s with error %d",
+                      vxi->address, read_resp->error);
+               return SR_ERR;
+       }
+
+       memcpy(buf, read_resp->data.data_val, read_resp->data.data_len);
+       vxi->read_complete = read_resp->reason & (RRR_SIZE | RRR_TERM | RRR_END);
+       return read_resp->data.data_len;  /* actual number of bytes received */
+}
+
+static int scpi_vxi_read_complete(void *priv)
+{
+       struct scpi_vxi *vxi = priv;
+
+       return vxi->read_complete;
+}
+
+static int scpi_vxi_close(void *priv)
+{
+       struct scpi_vxi *vxi = priv;
+       Device_Error *dev_error;
+
+       if (!vxi->client)
+               return SR_ERR;
+
+       if (!(dev_error = destroy_link_1(&vxi->link, vxi->client))) {
+               sr_err("Link destruction failed for %s", vxi->address);
+               return SR_ERR;
+       }
+
+       clnt_destroy(vxi->client);
+       vxi->client = NULL;
+
+       return SR_OK;
+}
+
+static void scpi_vxi_free(void *priv)
+{
+       struct scpi_vxi *vxi = priv;
+
+       g_free(vxi->address);
+       g_free(vxi->instrument);
+}
+
+SR_PRIV const struct sr_scpi_dev_inst scpi_vxi_dev = {
+       .name          = "VXI",
+       .prefix        = "vxi",
+       .priv_size     = sizeof(struct scpi_vxi),
+       .dev_inst_new  = scpi_vxi_dev_inst_new,
+       .open          = scpi_vxi_open,
+       .source_add    = scpi_vxi_source_add,
+       .source_remove = scpi_vxi_source_remove,
+       .send          = scpi_vxi_send,
+       .read_begin    = scpi_vxi_read_begin,
+       .read_data     = scpi_vxi_read_data,
+       .read_complete = scpi_vxi_read_complete,
+       .close         = scpi_vxi_close,
+       .free          = scpi_vxi_free,
+};
diff --git a/src/scpi/vxi.h b/src/scpi/vxi.h
new file mode 100644 (file)
index 0000000..61a51f6
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+ * Please do not edit this file.
+ * It was generated using rpcgen.
+ */
+
+#ifndef _VXI_H_RPCGEN
+#define _VXI_H_RPCGEN
+
+#include <rpc/rpc.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef long Device_Link;
+
+enum Device_AddrFamily {
+       DEVICE_TCP = 0,
+       DEVICE_UDP = 1,
+};
+typedef enum Device_AddrFamily Device_AddrFamily;
+
+typedef long Device_Flags;
+
+typedef long Device_ErrorCode;
+
+struct Device_Error {
+       Device_ErrorCode error;
+};
+typedef struct Device_Error Device_Error;
+
+struct Create_LinkParms {
+       long clientId;
+       bool_t lockDevice;
+       u_long lock_timeout;
+       char *device;
+};
+typedef struct Create_LinkParms Create_LinkParms;
+
+struct Create_LinkResp {
+       Device_ErrorCode error;
+       Device_Link lid;
+       u_short abortPort;
+       u_long maxRecvSize;
+};
+typedef struct Create_LinkResp Create_LinkResp;
+
+struct Device_WriteParms {
+       Device_Link lid;
+       u_long io_timeout;
+       u_long lock_timeout;
+       Device_Flags flags;
+       struct {
+               u_int data_len;
+               char *data_val;
+       } data;
+};
+typedef struct Device_WriteParms Device_WriteParms;
+
+struct Device_WriteResp {
+       Device_ErrorCode error;
+       u_long size;
+};
+typedef struct Device_WriteResp Device_WriteResp;
+
+struct Device_ReadParms {
+       Device_Link lid;
+       u_long requestSize;
+       u_long io_timeout;
+       u_long lock_timeout;
+       Device_Flags flags;
+       char termChar;
+};
+typedef struct Device_ReadParms Device_ReadParms;
+
+struct Device_ReadResp {
+       Device_ErrorCode error;
+       long reason;
+       struct {
+               u_int data_len;
+               char *data_val;
+       } data;
+};
+typedef struct Device_ReadResp Device_ReadResp;
+
+struct Device_ReadStbResp {
+       Device_ErrorCode error;
+       u_char stb;
+};
+typedef struct Device_ReadStbResp Device_ReadStbResp;
+
+struct Device_GenericParms {
+       Device_Link lid;
+       Device_Flags flags;
+       u_long lock_timeout;
+       u_long io_timeout;
+};
+typedef struct Device_GenericParms Device_GenericParms;
+
+struct Device_RemoteFunc {
+       u_long hostAddr;
+       u_short hostPort;
+       u_long progNum;
+       u_long progVers;
+       Device_AddrFamily progFamily;
+};
+typedef struct Device_RemoteFunc Device_RemoteFunc;
+
+struct Device_EnableSrqParms {
+       Device_Link lid;
+       bool_t enable;
+       struct {
+               u_int handle_len;
+               char *handle_val;
+       } handle;
+};
+typedef struct Device_EnableSrqParms Device_EnableSrqParms;
+
+struct Device_LockParms {
+       Device_Link lid;
+       Device_Flags flags;
+       u_long lock_timeout;
+};
+typedef struct Device_LockParms Device_LockParms;
+
+struct Device_DocmdParms {
+       Device_Link lid;
+       Device_Flags flags;
+       u_long io_timeout;
+       u_long lock_timeout;
+       long cmd;
+       bool_t network_order;
+       long datasize;
+       struct {
+               u_int data_in_len;
+               char *data_in_val;
+       } data_in;
+};
+typedef struct Device_DocmdParms Device_DocmdParms;
+
+struct Device_DocmdResp {
+       Device_ErrorCode error;
+       struct {
+               u_int data_out_len;
+               char *data_out_val;
+       } data_out;
+};
+typedef struct Device_DocmdResp Device_DocmdResp;
+
+struct Device_SrqParms {
+       struct {
+               u_int handle_len;
+               char *handle_val;
+       } handle;
+};
+typedef struct Device_SrqParms Device_SrqParms;
+
+#define DEVICE_ASYNC 0x0607B0
+#define DEVICE_ASYNC_VERSION 1
+
+#if defined(__STDC__) || defined(__cplusplus)
+#define device_abort 1
+extern  Device_Error * device_abort_1(Device_Link *, CLIENT *);
+extern  Device_Error * device_abort_1_svc(Device_Link *, struct svc_req *);
+extern int device_async_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
+
+#else /* K&R C */
+#define device_abort 1
+extern  Device_Error * device_abort_1();
+extern  Device_Error * device_abort_1_svc();
+extern int device_async_1_freeresult ();
+#endif /* K&R C */
+
+#define DEVICE_CORE 0x0607AF
+#define DEVICE_CORE_VERSION 1
+
+#if defined(__STDC__) || defined(__cplusplus)
+#define create_link 10
+extern  Create_LinkResp * create_link_1(Create_LinkParms *, CLIENT *);
+extern  Create_LinkResp * create_link_1_svc(Create_LinkParms *, struct svc_req *);
+#define device_write 11
+extern  Device_WriteResp * device_write_1(Device_WriteParms *, CLIENT *);
+extern  Device_WriteResp * device_write_1_svc(Device_WriteParms *, struct svc_req *);
+#define device_read 12
+extern  Device_ReadResp * device_read_1(Device_ReadParms *, CLIENT *);
+extern  Device_ReadResp * device_read_1_svc(Device_ReadParms *, struct svc_req *);
+#define device_readstb 13
+extern  Device_ReadStbResp * device_readstb_1(Device_GenericParms *, CLIENT *);
+extern  Device_ReadStbResp * device_readstb_1_svc(Device_GenericParms *, struct svc_req *);
+#define device_trigger 14
+extern  Device_Error * device_trigger_1(Device_GenericParms *, CLIENT *);
+extern  Device_Error * device_trigger_1_svc(Device_GenericParms *, struct svc_req *);
+#define device_clear 15
+extern  Device_Error * device_clear_1(Device_GenericParms *, CLIENT *);
+extern  Device_Error * device_clear_1_svc(Device_GenericParms *, struct svc_req *);
+#define device_remote 16
+extern  Device_Error * device_remote_1(Device_GenericParms *, CLIENT *);
+extern  Device_Error * device_remote_1_svc(Device_GenericParms *, struct svc_req *);
+#define device_local 17
+extern  Device_Error * device_local_1(Device_GenericParms *, CLIENT *);
+extern  Device_Error * device_local_1_svc(Device_GenericParms *, struct svc_req *);
+#define device_lock 18
+extern  Device_Error * device_lock_1(Device_LockParms *, CLIENT *);
+extern  Device_Error * device_lock_1_svc(Device_LockParms *, struct svc_req *);
+#define device_unlock 19
+extern  Device_Error * device_unlock_1(Device_Link *, CLIENT *);
+extern  Device_Error * device_unlock_1_svc(Device_Link *, struct svc_req *);
+#define device_enable_srq 20
+extern  Device_Error * device_enable_srq_1(Device_EnableSrqParms *, CLIENT *);
+extern  Device_Error * device_enable_srq_1_svc(Device_EnableSrqParms *, struct svc_req *);
+#define device_docmd 22
+extern  Device_DocmdResp * device_docmd_1(Device_DocmdParms *, CLIENT *);
+extern  Device_DocmdResp * device_docmd_1_svc(Device_DocmdParms *, struct svc_req *);
+#define destroy_link 23
+extern  Device_Error * destroy_link_1(Device_Link *, CLIENT *);
+extern  Device_Error * destroy_link_1_svc(Device_Link *, struct svc_req *);
+#define create_intr_chan 25
+extern  Device_Error * create_intr_chan_1(Device_RemoteFunc *, CLIENT *);
+extern  Device_Error * create_intr_chan_1_svc(Device_RemoteFunc *, struct svc_req *);
+#define destroy_intr_chan 26
+extern  Device_Error * destroy_intr_chan_1(void *, CLIENT *);
+extern  Device_Error * destroy_intr_chan_1_svc(void *, struct svc_req *);
+extern int device_core_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
+
+#else /* K&R C */
+#define create_link 10
+extern  Create_LinkResp * create_link_1();
+extern  Create_LinkResp * create_link_1_svc();
+#define device_write 11
+extern  Device_WriteResp * device_write_1();
+extern  Device_WriteResp * device_write_1_svc();
+#define device_read 12
+extern  Device_ReadResp * device_read_1();
+extern  Device_ReadResp * device_read_1_svc();
+#define device_readstb 13
+extern  Device_ReadStbResp * device_readstb_1();
+extern  Device_ReadStbResp * device_readstb_1_svc();
+#define device_trigger 14
+extern  Device_Error * device_trigger_1();
+extern  Device_Error * device_trigger_1_svc();
+#define device_clear 15
+extern  Device_Error * device_clear_1();
+extern  Device_Error * device_clear_1_svc();
+#define device_remote 16
+extern  Device_Error * device_remote_1();
+extern  Device_Error * device_remote_1_svc();
+#define device_local 17
+extern  Device_Error * device_local_1();
+extern  Device_Error * device_local_1_svc();
+#define device_lock 18
+extern  Device_Error * device_lock_1();
+extern  Device_Error * device_lock_1_svc();
+#define device_unlock 19
+extern  Device_Error * device_unlock_1();
+extern  Device_Error * device_unlock_1_svc();
+#define device_enable_srq 20
+extern  Device_Error * device_enable_srq_1();
+extern  Device_Error * device_enable_srq_1_svc();
+#define device_docmd 22
+extern  Device_DocmdResp * device_docmd_1();
+extern  Device_DocmdResp * device_docmd_1_svc();
+#define destroy_link 23
+extern  Device_Error * destroy_link_1();
+extern  Device_Error * destroy_link_1_svc();
+#define create_intr_chan 25
+extern  Device_Error * create_intr_chan_1();
+extern  Device_Error * create_intr_chan_1_svc();
+#define destroy_intr_chan 26
+extern  Device_Error * destroy_intr_chan_1();
+extern  Device_Error * destroy_intr_chan_1_svc();
+extern int device_core_1_freeresult ();
+#endif /* K&R C */
+
+#define DEVICE_INTR 0x0607B1
+#define DEVICE_INTR_VERSION 1
+
+#if defined(__STDC__) || defined(__cplusplus)
+#define device_intr_srq 30
+extern  void * device_intr_srq_1(Device_SrqParms *, CLIENT *);
+extern  void * device_intr_srq_1_svc(Device_SrqParms *, struct svc_req *);
+extern int device_intr_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
+
+#else /* K&R C */
+#define device_intr_srq 30
+extern  void * device_intr_srq_1();
+extern  void * device_intr_srq_1_svc();
+extern int device_intr_1_freeresult ();
+#endif /* K&R C */
+
+/* the xdr functions */
+
+#if defined(__STDC__) || defined(__cplusplus)
+extern  bool_t xdr_Device_Link (XDR *, Device_Link*);
+extern  bool_t xdr_Device_AddrFamily (XDR *, Device_AddrFamily*);
+extern  bool_t xdr_Device_Flags (XDR *, Device_Flags*);
+extern  bool_t xdr_Device_ErrorCode (XDR *, Device_ErrorCode*);
+extern  bool_t xdr_Device_Error (XDR *, Device_Error*);
+extern  bool_t xdr_Create_LinkParms (XDR *, Create_LinkParms*);
+extern  bool_t xdr_Create_LinkResp (XDR *, Create_LinkResp*);
+extern  bool_t xdr_Device_WriteParms (XDR *, Device_WriteParms*);
+extern  bool_t xdr_Device_WriteResp (XDR *, Device_WriteResp*);
+extern  bool_t xdr_Device_ReadParms (XDR *, Device_ReadParms*);
+extern  bool_t xdr_Device_ReadResp (XDR *, Device_ReadResp*);
+extern  bool_t xdr_Device_ReadStbResp (XDR *, Device_ReadStbResp*);
+extern  bool_t xdr_Device_GenericParms (XDR *, Device_GenericParms*);
+extern  bool_t xdr_Device_RemoteFunc (XDR *, Device_RemoteFunc*);
+extern  bool_t xdr_Device_EnableSrqParms (XDR *, Device_EnableSrqParms*);
+extern  bool_t xdr_Device_LockParms (XDR *, Device_LockParms*);
+extern  bool_t xdr_Device_DocmdParms (XDR *, Device_DocmdParms*);
+extern  bool_t xdr_Device_DocmdResp (XDR *, Device_DocmdResp*);
+extern  bool_t xdr_Device_SrqParms (XDR *, Device_SrqParms*);
+
+#else /* K&R C */
+extern bool_t xdr_Device_Link ();
+extern bool_t xdr_Device_AddrFamily ();
+extern bool_t xdr_Device_Flags ();
+extern bool_t xdr_Device_ErrorCode ();
+extern bool_t xdr_Device_Error ();
+extern bool_t xdr_Create_LinkParms ();
+extern bool_t xdr_Create_LinkResp ();
+extern bool_t xdr_Device_WriteParms ();
+extern bool_t xdr_Device_WriteResp ();
+extern bool_t xdr_Device_ReadParms ();
+extern bool_t xdr_Device_ReadResp ();
+extern bool_t xdr_Device_ReadStbResp ();
+extern bool_t xdr_Device_GenericParms ();
+extern bool_t xdr_Device_RemoteFunc ();
+extern bool_t xdr_Device_EnableSrqParms ();
+extern bool_t xdr_Device_LockParms ();
+extern bool_t xdr_Device_DocmdParms ();
+extern bool_t xdr_Device_DocmdResp ();
+extern bool_t xdr_Device_SrqParms ();
+
+#endif /* K&R C */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !_VXI_H_RPCGEN */
diff --git a/src/scpi/vxi.x b/src/scpi/vxi.x
new file mode 100644 (file)
index 0000000..31ca4c4
--- /dev/null
@@ -0,0 +1,143 @@
+/* This is taken straight from Appendix C of the specification */
+
+typedef long Device_Link;
+
+enum Device_AddrFamily {
+       DEVICE_TCP,
+       DEVICE_UDP
+};
+
+typedef long Device_Flags;
+
+typedef long Device_ErrorCode;
+
+struct Device_Error {
+       Device_ErrorCode  error;
+};
+
+struct Create_LinkParms {
+       long              clientId;      /* implementation specific value */
+       bool              lockDevice;    /* attempt to lock the device */
+       unsigned long     lock_timeout;  /* time to wait on a lock */
+       string            device<>;      /* name of device */
+};
+
+struct Create_LinkResp {
+       Device_ErrorCode  error;
+       Device_Link       lid;
+       unsigned short    abortPort;     /* for the abort RPC */
+       unsigned long     maxRecvSize;   /* specifies max data size in bytes
+                                           device will accept on a write */
+};
+
+struct Device_WriteParms {
+       Device_Link       lid;           /* link id from create_link */
+       unsigned long     io_timeout;    /* time to wait for I/O */
+       unsigned long     lock_timeout;  /* time to wait for lock */
+       Device_Flags      flags;
+       opaque            data<>;        /* data length and the data itself */
+};
+
+struct Device_WriteResp {
+       Device_ErrorCode  error;
+       unsigned          long size;     /* number of bytes written */
+};
+
+struct Device_ReadParms {
+       Device_Link       lid;           /* link id from create_link */
+       unsigned long     requestSize;   /* bytes requested */
+       unsigned long     io_timeout;    /* time to wait for I/O */
+       unsigned long     lock_timeout;  /* time to wait for lock */
+       Device_Flags      flags;
+       char              termChar;      /* valid if flags & termchrset */
+};
+
+struct Device_ReadResp {
+       Device_ErrorCode  error;
+       long              reason;        /* reason(s) read completed */
+       opaque            data<>;        /* data.len and data.val */
+};
+
+struct Device_ReadStbResp {
+       Device_ErrorCode  error;         /* error code */
+       unsigned char     stb;           /* the returned status byte */
+};
+
+struct Device_GenericParms {
+       Device_Link       lid;           /* Device_Link id from connect call */
+       Device_Flags      flags;         /* flags with options */
+       unsigned long     lock_timeout;  /* time to wait for lock */
+       unsigned long     io_timeout;    /* time to wait for I/O */
+};
+
+struct Device_RemoteFunc {
+       unsigned long     hostAddr;      /* host servicing interrupt */
+       unsigned short    hostPort;      /* valid port # on client */
+       unsigned long     progNum;       /* DEVICE_INTR */
+       unsigned long     progVers;      /* DEVICE_INTR_VERSION */
+       Device_AddrFamily progFamily;    /* DEVICE_UDP | DEVICE_TCP */
+};
+
+struct Device_EnableSrqParms {
+       Device_Link       lid;
+       bool              enable;        /* enable or disable interrupts */
+       opaque            handle<40>;    /* host specific data */
+};
+
+struct Device_LockParms {
+       Device_Link       lid;           /* link id from create_link */
+       Device_Flags      flags;         /* contains the waitlock flag */
+       unsigned long     lock_timeout;  /* time to wait to acquire lock */
+};
+
+struct Device_DocmdParms {
+       Device_Link       lid;           /* link id from create_link */
+       Device_Flags      flags;         /* flags specifying various options */
+       unsigned long     io_timeout;    /* time to wait for I/O to complete */
+       unsigned long     lock_timeout;  /* time to wait on a lock */
+       long              cmd;           /* which command to execute */
+       bool              network_order; /* client's byte order */
+       long              datasize;      /* size of individual data elements */
+       opaque            data_in<>;     /* docmd data parameters */
+};
+
+struct Device_DocmdResp {
+       Device_ErrorCode  error;         /* returned status */
+       opaque            data_out<>;    /* returned data parameter */
+};
+
+struct Device_SrqParms {
+       opaque            handle<>;
+};
+
+program DEVICE_ASYNC{
+       version DEVICE_ASYNC_VERSION {
+               Device_Error       device_abort(Device_Link)               =  1;
+       } = 1;
+} = 0x0607B0;
+
+program DEVICE_CORE {
+       version DEVICE_CORE_VERSION {
+               Create_LinkResp    create_link(Create_LinkParms)           = 10;
+               Device_WriteResp   device_write(Device_WriteParms)         = 11;
+               Device_ReadResp    device_read(Device_ReadParms)           = 12;
+               Device_ReadStbResp device_readstb(Device_GenericParms)     = 13;
+               Device_Error       device_trigger(Device_GenericParms)     = 14;
+               Device_Error       device_clear(Device_GenericParms)       = 15;
+               Device_Error       device_remote(Device_GenericParms)      = 16;
+               Device_Error       device_local(Device_GenericParms)       = 17;
+               Device_Error       device_lock(Device_LockParms)           = 18;
+               Device_Error       device_unlock(Device_Link)              = 19;
+               Device_Error       device_enable_srq(Device_EnableSrqParms)= 20;
+               Device_DocmdResp   device_docmd(Device_DocmdParms)         = 22;
+               Device_Error       destroy_link(Device_Link)               = 23;
+               Device_Error       create_intr_chan(Device_RemoteFunc)     = 25;
+               Device_Error       destroy_intr_chan(void)                 = 26;
+       } = 1;
+} = 0x0607AF;
+
+program DEVICE_INTR {
+       version DEVICE_INTR_VERSION {
+               void               device_intr_srq(Device_SrqParms)        = 30;
+       } = 1;
+} = 0x0607B1;
diff --git a/src/scpi/vxi_clnt.c b/src/scpi/vxi_clnt.c
new file mode 100644 (file)
index 0000000..55a72dc
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * Please do not edit this file.
+ * It was generated using rpcgen.
+ */
+
+#include <memory.h> /* for memset */
+#include "vxi.h"
+
+/* Default timeout can be changed using clnt_control() */
+static struct timeval TIMEOUT = { 25, 0 };
+
+Device_Error *
+device_abort_1(Device_Link *argp, CLIENT *clnt)
+{
+       static Device_Error clnt_res;
+
+       memset((char *)&clnt_res, 0, sizeof(clnt_res));
+       if (clnt_call (clnt, device_abort,
+               (xdrproc_t) xdr_Device_Link, (caddr_t) argp,
+               (xdrproc_t) xdr_Device_Error, (caddr_t) &clnt_res,
+               TIMEOUT) != RPC_SUCCESS) {
+               return (NULL);
+       }
+       return (&clnt_res);
+}
+
+Create_LinkResp *
+create_link_1(Create_LinkParms *argp, CLIENT *clnt)
+{
+       static Create_LinkResp clnt_res;
+
+       memset((char *)&clnt_res, 0, sizeof(clnt_res));
+       if (clnt_call (clnt, create_link,
+               (xdrproc_t) xdr_Create_LinkParms, (caddr_t) argp,
+               (xdrproc_t) xdr_Create_LinkResp, (caddr_t) &clnt_res,
+               TIMEOUT) != RPC_SUCCESS) {
+               return (NULL);
+       }
+       return (&clnt_res);
+}
+
+Device_WriteResp *
+device_write_1(Device_WriteParms *argp, CLIENT *clnt)
+{
+       static Device_WriteResp clnt_res;
+
+       memset((char *)&clnt_res, 0, sizeof(clnt_res));
+       if (clnt_call (clnt, device_write,
+               (xdrproc_t) xdr_Device_WriteParms, (caddr_t) argp,
+               (xdrproc_t) xdr_Device_WriteResp, (caddr_t) &clnt_res,
+               TIMEOUT) != RPC_SUCCESS) {
+               return (NULL);
+       }
+       return (&clnt_res);
+}
+
+Device_ReadResp *
+device_read_1(Device_ReadParms *argp, CLIENT *clnt)
+{
+       static Device_ReadResp clnt_res;
+
+       memset((char *)&clnt_res, 0, sizeof(clnt_res));
+       if (clnt_call (clnt, device_read,
+               (xdrproc_t) xdr_Device_ReadParms, (caddr_t) argp,
+               (xdrproc_t) xdr_Device_ReadResp, (caddr_t) &clnt_res,
+               TIMEOUT) != RPC_SUCCESS) {
+               return (NULL);
+       }
+       return (&clnt_res);
+}
+
+Device_ReadStbResp *
+device_readstb_1(Device_GenericParms *argp, CLIENT *clnt)
+{
+       static Device_ReadStbResp clnt_res;
+
+       memset((char *)&clnt_res, 0, sizeof(clnt_res));
+       if (clnt_call (clnt, device_readstb,
+               (xdrproc_t) xdr_Device_GenericParms, (caddr_t) argp,
+               (xdrproc_t) xdr_Device_ReadStbResp, (caddr_t) &clnt_res,
+               TIMEOUT) != RPC_SUCCESS) {
+               return (NULL);
+       }
+       return (&clnt_res);
+}
+
+Device_Error *
+device_trigger_1(Device_GenericParms *argp, CLIENT *clnt)
+{
+       static Device_Error clnt_res;
+
+       memset((char *)&clnt_res, 0, sizeof(clnt_res));
+       if (clnt_call (clnt, device_trigger,
+               (xdrproc_t) xdr_Device_GenericParms, (caddr_t) argp,
+               (xdrproc_t) xdr_Device_Error, (caddr_t) &clnt_res,
+               TIMEOUT) != RPC_SUCCESS) {
+               return (NULL);
+       }
+       return (&clnt_res);
+}
+
+Device_Error *
+device_clear_1(Device_GenericParms *argp, CLIENT *clnt)
+{
+       static Device_Error clnt_res;
+
+       memset((char *)&clnt_res, 0, sizeof(clnt_res));
+       if (clnt_call (clnt, device_clear,
+               (xdrproc_t) xdr_Device_GenericParms, (caddr_t) argp,
+               (xdrproc_t) xdr_Device_Error, (caddr_t) &clnt_res,
+               TIMEOUT) != RPC_SUCCESS) {
+               return (NULL);
+       }
+       return (&clnt_res);
+}
+
+Device_Error *
+device_remote_1(Device_GenericParms *argp, CLIENT *clnt)
+{
+       static Device_Error clnt_res;
+
+       memset((char *)&clnt_res, 0, sizeof(clnt_res));
+       if (clnt_call (clnt, device_remote,
+               (xdrproc_t) xdr_Device_GenericParms, (caddr_t) argp,
+               (xdrproc_t) xdr_Device_Error, (caddr_t) &clnt_res,
+               TIMEOUT) != RPC_SUCCESS) {
+               return (NULL);
+       }
+       return (&clnt_res);
+}
+
+Device_Error *
+device_local_1(Device_GenericParms *argp, CLIENT *clnt)
+{
+       static Device_Error clnt_res;
+
+       memset((char *)&clnt_res, 0, sizeof(clnt_res));
+       if (clnt_call (clnt, device_local,
+               (xdrproc_t) xdr_Device_GenericParms, (caddr_t) argp,
+               (xdrproc_t) xdr_Device_Error, (caddr_t) &clnt_res,
+               TIMEOUT) != RPC_SUCCESS) {
+               return (NULL);
+       }
+       return (&clnt_res);
+}
+
+Device_Error *
+device_lock_1(Device_LockParms *argp, CLIENT *clnt)
+{
+       static Device_Error clnt_res;
+
+       memset((char *)&clnt_res, 0, sizeof(clnt_res));
+       if (clnt_call (clnt, device_lock,
+               (xdrproc_t) xdr_Device_LockParms, (caddr_t) argp,
+               (xdrproc_t) xdr_Device_Error, (caddr_t) &clnt_res,
+               TIMEOUT) != RPC_SUCCESS) {
+               return (NULL);
+       }
+       return (&clnt_res);
+}
+
+Device_Error *
+device_unlock_1(Device_Link *argp, CLIENT *clnt)
+{
+       static Device_Error clnt_res;
+
+       memset((char *)&clnt_res, 0, sizeof(clnt_res));
+       if (clnt_call (clnt, device_unlock,
+               (xdrproc_t) xdr_Device_Link, (caddr_t) argp,
+               (xdrproc_t) xdr_Device_Error, (caddr_t) &clnt_res,
+               TIMEOUT) != RPC_SUCCESS) {
+               return (NULL);
+       }
+       return (&clnt_res);
+}
+
+Device_Error *
+device_enable_srq_1(Device_EnableSrqParms *argp, CLIENT *clnt)
+{
+       static Device_Error clnt_res;
+
+       memset((char *)&clnt_res, 0, sizeof(clnt_res));
+       if (clnt_call (clnt, device_enable_srq,
+               (xdrproc_t) xdr_Device_EnableSrqParms, (caddr_t) argp,
+               (xdrproc_t) xdr_Device_Error, (caddr_t) &clnt_res,
+               TIMEOUT) != RPC_SUCCESS) {
+               return (NULL);
+       }
+       return (&clnt_res);
+}
+
+Device_DocmdResp *
+device_docmd_1(Device_DocmdParms *argp, CLIENT *clnt)
+{
+       static Device_DocmdResp clnt_res;
+
+       memset((char *)&clnt_res, 0, sizeof(clnt_res));
+       if (clnt_call (clnt, device_docmd,
+               (xdrproc_t) xdr_Device_DocmdParms, (caddr_t) argp,
+               (xdrproc_t) xdr_Device_DocmdResp, (caddr_t) &clnt_res,
+               TIMEOUT) != RPC_SUCCESS) {
+               return (NULL);
+       }
+       return (&clnt_res);
+}
+
+Device_Error *
+destroy_link_1(Device_Link *argp, CLIENT *clnt)
+{
+       static Device_Error clnt_res;
+
+       memset((char *)&clnt_res, 0, sizeof(clnt_res));
+       if (clnt_call (clnt, destroy_link,
+               (xdrproc_t) xdr_Device_Link, (caddr_t) argp,
+               (xdrproc_t) xdr_Device_Error, (caddr_t) &clnt_res,
+               TIMEOUT) != RPC_SUCCESS) {
+               return (NULL);
+       }
+       return (&clnt_res);
+}
+
+Device_Error *
+create_intr_chan_1(Device_RemoteFunc *argp, CLIENT *clnt)
+{
+       static Device_Error clnt_res;
+
+       memset((char *)&clnt_res, 0, sizeof(clnt_res));
+       if (clnt_call (clnt, create_intr_chan,
+               (xdrproc_t) xdr_Device_RemoteFunc, (caddr_t) argp,
+               (xdrproc_t) xdr_Device_Error, (caddr_t) &clnt_res,
+               TIMEOUT) != RPC_SUCCESS) {
+               return (NULL);
+       }
+       return (&clnt_res);
+}
+
+Device_Error *
+destroy_intr_chan_1(void *argp, CLIENT *clnt)
+{
+       static Device_Error clnt_res;
+
+       memset((char *)&clnt_res, 0, sizeof(clnt_res));
+       if (clnt_call (clnt, destroy_intr_chan,
+               (xdrproc_t) xdr_void, (caddr_t) argp,
+               (xdrproc_t) xdr_Device_Error, (caddr_t) &clnt_res,
+               TIMEOUT) != RPC_SUCCESS) {
+               return (NULL);
+       }
+       return (&clnt_res);
+}
+
+void *
+device_intr_srq_1(Device_SrqParms *argp, CLIENT *clnt)
+{
+       static char clnt_res;
+
+       memset((char *)&clnt_res, 0, sizeof(clnt_res));
+       if (clnt_call (clnt, device_intr_srq,
+               (xdrproc_t) xdr_Device_SrqParms, (caddr_t) argp,
+               (xdrproc_t) xdr_void, (caddr_t) &clnt_res,
+               TIMEOUT) != RPC_SUCCESS) {
+               return (NULL);
+       }
+       return ((void *)&clnt_res);
+}
diff --git a/src/scpi/vxi_xdr.c b/src/scpi/vxi_xdr.c
new file mode 100644 (file)
index 0000000..bc7d79f
--- /dev/null
@@ -0,0 +1,428 @@
+/*
+ * Please do not edit this file.
+ * It was generated using rpcgen.
+ */
+
+#include "vxi.h"
+
+bool_t
+xdr_Device_Link (XDR *xdrs, Device_Link *objp)
+{
+        if (!xdr_long (xdrs, objp))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_Device_AddrFamily (XDR *xdrs, Device_AddrFamily *objp)
+{
+        if (!xdr_enum (xdrs, (enum_t *) objp))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_Device_Flags (XDR *xdrs, Device_Flags *objp)
+{
+        if (!xdr_long (xdrs, objp))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_Device_ErrorCode (XDR *xdrs, Device_ErrorCode *objp)
+{
+        if (!xdr_long (xdrs, objp))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_Device_Error (XDR *xdrs, Device_Error *objp)
+{
+        if (!xdr_Device_ErrorCode (xdrs, &objp->error))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_Create_LinkParms (XDR *xdrs, Create_LinkParms *objp)
+{
+       register int32_t *buf;
+
+       if (xdrs->x_op == XDR_ENCODE) {
+               buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT);
+               if (buf == NULL) {
+                        if (!xdr_long (xdrs, &objp->clientId))
+                                return FALSE;
+                        if (!xdr_bool (xdrs, &objp->lockDevice))
+                                return FALSE;
+                        if (!xdr_u_long (xdrs, &objp->lock_timeout))
+                                return FALSE;
+
+               } else {
+               IXDR_PUT_LONG(buf, objp->clientId);
+               IXDR_PUT_BOOL(buf, objp->lockDevice);
+               IXDR_PUT_U_LONG(buf, objp->lock_timeout);
+               }
+                if (!xdr_string (xdrs, &objp->device, ~0))
+                        return FALSE;
+               return TRUE;
+       } else if (xdrs->x_op == XDR_DECODE) {
+               buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT);
+               if (buf == NULL) {
+                        if (!xdr_long (xdrs, &objp->clientId))
+                                return FALSE;
+                        if (!xdr_bool (xdrs, &objp->lockDevice))
+                                return FALSE;
+                        if (!xdr_u_long (xdrs, &objp->lock_timeout))
+                                return FALSE;
+
+               } else {
+               objp->clientId = IXDR_GET_LONG(buf);
+               objp->lockDevice = IXDR_GET_BOOL(buf);
+               objp->lock_timeout = IXDR_GET_U_LONG(buf);
+               }
+                if (!xdr_string (xdrs, &objp->device, ~0))
+                        return FALSE;
+        return TRUE;
+       }
+
+        if (!xdr_long (xdrs, &objp->clientId))
+                return FALSE;
+        if (!xdr_bool (xdrs, &objp->lockDevice))
+                return FALSE;
+        if (!xdr_u_long (xdrs, &objp->lock_timeout))
+                return FALSE;
+        if (!xdr_string (xdrs, &objp->device, ~0))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_Create_LinkResp (XDR *xdrs, Create_LinkResp *objp)
+{
+        if (!xdr_Device_ErrorCode (xdrs, &objp->error))
+                return FALSE;
+        if (!xdr_Device_Link (xdrs, &objp->lid))
+                return FALSE;
+        if (!xdr_u_short (xdrs, &objp->abortPort))
+                return FALSE;
+        if (!xdr_u_long (xdrs, &objp->maxRecvSize))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_Device_WriteParms (XDR *xdrs, Device_WriteParms *objp)
+{
+        if (!xdr_Device_Link (xdrs, &objp->lid))
+                return FALSE;
+        if (!xdr_u_long (xdrs, &objp->io_timeout))
+                return FALSE;
+        if (!xdr_u_long (xdrs, &objp->lock_timeout))
+                return FALSE;
+        if (!xdr_Device_Flags (xdrs, &objp->flags))
+                return FALSE;
+        if (!xdr_bytes (xdrs, (char **)&objp->data.data_val, (u_int *) &objp->data.data_len, ~0))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_Device_WriteResp (XDR *xdrs, Device_WriteResp *objp)
+{
+        if (!xdr_Device_ErrorCode (xdrs, &objp->error))
+                return FALSE;
+        if (!xdr_u_long (xdrs, &objp->size))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_Device_ReadParms (XDR *xdrs, Device_ReadParms *objp)
+{
+       register int32_t *buf;
+
+       if (xdrs->x_op == XDR_ENCODE) {
+                if (!xdr_Device_Link (xdrs, &objp->lid))
+                        return FALSE;
+               buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT);
+               if (buf == NULL) {
+                        if (!xdr_u_long (xdrs, &objp->requestSize))
+                                return FALSE;
+                        if (!xdr_u_long (xdrs, &objp->io_timeout))
+                                return FALSE;
+                        if (!xdr_u_long (xdrs, &objp->lock_timeout))
+                                return FALSE;
+
+               } else {
+               IXDR_PUT_U_LONG(buf, objp->requestSize);
+               IXDR_PUT_U_LONG(buf, objp->io_timeout);
+               IXDR_PUT_U_LONG(buf, objp->lock_timeout);
+               }
+                if (!xdr_Device_Flags (xdrs, &objp->flags))
+                        return FALSE;
+                if (!xdr_char (xdrs, &objp->termChar))
+                        return FALSE;
+               return TRUE;
+       } else if (xdrs->x_op == XDR_DECODE) {
+                if (!xdr_Device_Link (xdrs, &objp->lid))
+                        return FALSE;
+               buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT);
+               if (buf == NULL) {
+                        if (!xdr_u_long (xdrs, &objp->requestSize))
+                                return FALSE;
+                        if (!xdr_u_long (xdrs, &objp->io_timeout))
+                                return FALSE;
+                        if (!xdr_u_long (xdrs, &objp->lock_timeout))
+                                return FALSE;
+
+               } else {
+               objp->requestSize = IXDR_GET_U_LONG(buf);
+               objp->io_timeout = IXDR_GET_U_LONG(buf);
+               objp->lock_timeout = IXDR_GET_U_LONG(buf);
+               }
+                if (!xdr_Device_Flags (xdrs, &objp->flags))
+                        return FALSE;
+                if (!xdr_char (xdrs, &objp->termChar))
+                        return FALSE;
+        return TRUE;
+       }
+
+        if (!xdr_Device_Link (xdrs, &objp->lid))
+                return FALSE;
+        if (!xdr_u_long (xdrs, &objp->requestSize))
+                return FALSE;
+        if (!xdr_u_long (xdrs, &objp->io_timeout))
+                return FALSE;
+        if (!xdr_u_long (xdrs, &objp->lock_timeout))
+                return FALSE;
+        if (!xdr_Device_Flags (xdrs, &objp->flags))
+                return FALSE;
+        if (!xdr_char (xdrs, &objp->termChar))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_Device_ReadResp (XDR *xdrs, Device_ReadResp *objp)
+{
+        if (!xdr_Device_ErrorCode (xdrs, &objp->error))
+                return FALSE;
+        if (!xdr_long (xdrs, &objp->reason))
+                return FALSE;
+        if (!xdr_bytes (xdrs, (char **)&objp->data.data_val, (u_int *) &objp->data.data_len, ~0))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_Device_ReadStbResp (XDR *xdrs, Device_ReadStbResp *objp)
+{
+        if (!xdr_Device_ErrorCode (xdrs, &objp->error))
+                return FALSE;
+        if (!xdr_u_char (xdrs, &objp->stb))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_Device_GenericParms (XDR *xdrs, Device_GenericParms *objp)
+{
+        if (!xdr_Device_Link (xdrs, &objp->lid))
+                return FALSE;
+        if (!xdr_Device_Flags (xdrs, &objp->flags))
+                return FALSE;
+        if (!xdr_u_long (xdrs, &objp->lock_timeout))
+                return FALSE;
+        if (!xdr_u_long (xdrs, &objp->io_timeout))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_Device_RemoteFunc (XDR *xdrs, Device_RemoteFunc *objp)
+{
+       register int32_t *buf;
+
+       if (xdrs->x_op == XDR_ENCODE) {
+               buf = XDR_INLINE (xdrs, 4 * BYTES_PER_XDR_UNIT);
+               if (buf == NULL) {
+                        if (!xdr_u_long (xdrs, &objp->hostAddr))
+                                return FALSE;
+                        if (!xdr_u_short (xdrs, &objp->hostPort))
+                                return FALSE;
+                        if (!xdr_u_long (xdrs, &objp->progNum))
+                                return FALSE;
+                        if (!xdr_u_long (xdrs, &objp->progVers))
+                                return FALSE;
+
+               } else {
+               IXDR_PUT_U_LONG(buf, objp->hostAddr);
+               IXDR_PUT_U_SHORT(buf, objp->hostPort);
+               IXDR_PUT_U_LONG(buf, objp->progNum);
+               IXDR_PUT_U_LONG(buf, objp->progVers);
+               }
+                if (!xdr_Device_AddrFamily (xdrs, &objp->progFamily))
+                        return FALSE;
+               return TRUE;
+       } else if (xdrs->x_op == XDR_DECODE) {
+               buf = XDR_INLINE (xdrs, 4 * BYTES_PER_XDR_UNIT);
+               if (buf == NULL) {
+                        if (!xdr_u_long (xdrs, &objp->hostAddr))
+                                return FALSE;
+                        if (!xdr_u_short (xdrs, &objp->hostPort))
+                                return FALSE;
+                        if (!xdr_u_long (xdrs, &objp->progNum))
+                                return FALSE;
+                        if (!xdr_u_long (xdrs, &objp->progVers))
+                                return FALSE;
+
+               } else {
+               objp->hostAddr = IXDR_GET_U_LONG(buf);
+               objp->hostPort = IXDR_GET_U_SHORT(buf);
+               objp->progNum = IXDR_GET_U_LONG(buf);
+               objp->progVers = IXDR_GET_U_LONG(buf);
+               }
+                if (!xdr_Device_AddrFamily (xdrs, &objp->progFamily))
+                        return FALSE;
+        return TRUE;
+       }
+
+        if (!xdr_u_long (xdrs, &objp->hostAddr))
+                return FALSE;
+        if (!xdr_u_short (xdrs, &objp->hostPort))
+                return FALSE;
+        if (!xdr_u_long (xdrs, &objp->progNum))
+                return FALSE;
+        if (!xdr_u_long (xdrs, &objp->progVers))
+                return FALSE;
+        if (!xdr_Device_AddrFamily (xdrs, &objp->progFamily))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_Device_EnableSrqParms (XDR *xdrs, Device_EnableSrqParms *objp)
+{
+        if (!xdr_Device_Link (xdrs, &objp->lid))
+                return FALSE;
+        if (!xdr_bool (xdrs, &objp->enable))
+                return FALSE;
+        if (!xdr_bytes (xdrs, (char **)&objp->handle.handle_val, (u_int *) &objp->handle.handle_len, 40))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_Device_LockParms (XDR *xdrs, Device_LockParms *objp)
+{
+        if (!xdr_Device_Link (xdrs, &objp->lid))
+                return FALSE;
+        if (!xdr_Device_Flags (xdrs, &objp->flags))
+                return FALSE;
+        if (!xdr_u_long (xdrs, &objp->lock_timeout))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_Device_DocmdParms (XDR *xdrs, Device_DocmdParms *objp)
+{
+       register int32_t *buf;
+
+       if (xdrs->x_op == XDR_ENCODE) {
+                if (!xdr_Device_Link (xdrs, &objp->lid))
+                        return FALSE;
+                if (!xdr_Device_Flags (xdrs, &objp->flags))
+                        return FALSE;
+               buf = XDR_INLINE (xdrs, 5 * BYTES_PER_XDR_UNIT);
+               if (buf == NULL) {
+                        if (!xdr_u_long (xdrs, &objp->io_timeout))
+                                return FALSE;
+                        if (!xdr_u_long (xdrs, &objp->lock_timeout))
+                                return FALSE;
+                        if (!xdr_long (xdrs, &objp->cmd))
+                                return FALSE;
+                        if (!xdr_bool (xdrs, &objp->network_order))
+                                return FALSE;
+                        if (!xdr_long (xdrs, &objp->datasize))
+                                return FALSE;
+
+               } else {
+               IXDR_PUT_U_LONG(buf, objp->io_timeout);
+               IXDR_PUT_U_LONG(buf, objp->lock_timeout);
+               IXDR_PUT_LONG(buf, objp->cmd);
+               IXDR_PUT_BOOL(buf, objp->network_order);
+               IXDR_PUT_LONG(buf, objp->datasize);
+               }
+                if (!xdr_bytes (xdrs, (char **)&objp->data_in.data_in_val, (u_int *) &objp->data_in.data_in_len, ~0))
+                        return FALSE;
+               return TRUE;
+       } else if (xdrs->x_op == XDR_DECODE) {
+                if (!xdr_Device_Link (xdrs, &objp->lid))
+                        return FALSE;
+                if (!xdr_Device_Flags (xdrs, &objp->flags))
+                        return FALSE;
+               buf = XDR_INLINE (xdrs, 5 * BYTES_PER_XDR_UNIT);
+               if (buf == NULL) {
+                        if (!xdr_u_long (xdrs, &objp->io_timeout))
+                                return FALSE;
+                        if (!xdr_u_long (xdrs, &objp->lock_timeout))
+                                return FALSE;
+                        if (!xdr_long (xdrs, &objp->cmd))
+                                return FALSE;
+                        if (!xdr_bool (xdrs, &objp->network_order))
+                                return FALSE;
+                        if (!xdr_long (xdrs, &objp->datasize))
+                                return FALSE;
+
+               } else {
+               objp->io_timeout = IXDR_GET_U_LONG(buf);
+               objp->lock_timeout = IXDR_GET_U_LONG(buf);
+               objp->cmd = IXDR_GET_LONG(buf);
+               objp->network_order = IXDR_GET_BOOL(buf);
+               objp->datasize = IXDR_GET_LONG(buf);
+               }
+                if (!xdr_bytes (xdrs, (char **)&objp->data_in.data_in_val, (u_int *) &objp->data_in.data_in_len, ~0))
+                        return FALSE;
+        return TRUE;
+       }
+
+        if (!xdr_Device_Link (xdrs, &objp->lid))
+                return FALSE;
+        if (!xdr_Device_Flags (xdrs, &objp->flags))
+                return FALSE;
+        if (!xdr_u_long (xdrs, &objp->io_timeout))
+                return FALSE;
+        if (!xdr_u_long (xdrs, &objp->lock_timeout))
+                return FALSE;
+        if (!xdr_long (xdrs, &objp->cmd))
+                return FALSE;
+        if (!xdr_bool (xdrs, &objp->network_order))
+                return FALSE;
+        if (!xdr_long (xdrs, &objp->datasize))
+                return FALSE;
+        if (!xdr_bytes (xdrs, (char **)&objp->data_in.data_in_val, (u_int *) &objp->data_in.data_in_len, ~0))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_Device_DocmdResp (XDR *xdrs, Device_DocmdResp *objp)
+{
+        if (!xdr_Device_ErrorCode (xdrs, &objp->error))
+                return FALSE;
+        if (!xdr_bytes (xdrs, (char **)&objp->data_out.data_out_val, (u_int *) &objp->data_out.data_out_len, ~0))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_Device_SrqParms (XDR *xdrs, Device_SrqParms *objp)
+{
+        if (!xdr_bytes (xdrs, (char **)&objp->handle.handle_val, (u_int *) &objp->handle.handle_len, ~0))
+                return FALSE;
+       return TRUE;
+}
diff --git a/src/serial.c b/src/serial.c
new file mode 100644 (file)
index 0000000..9a9a0d9
--- /dev/null
@@ -0,0 +1,911 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com>
+ * Copyright (C) 2010-2012 Uwe Hermann <uwe@hermann-uwe.de>
+ * 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 <string.h>
+#include <stdlib.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <libserialport.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "serial"
+
+/**
+ * Open the specified serial port.
+ *
+ * @param serial Previously initialized serial port structure.
+ * @param[in] flags Flags to use when opening the serial port. Possible flags
+ *              include SERIAL_RDWR, SERIAL_RDONLY, SERIAL_NONBLOCK.
+ *
+ * If the serial structure contains a serialcomm string, it will be
+ * passed to serial_set_paramstr() after the port is opened.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR Failure.
+ */
+SR_PRIV int serial_open(struct sr_serial_dev_inst *serial, int flags)
+{
+       int ret;
+       char *error;
+       int sp_flags = 0;
+
+       if (!serial) {
+               sr_dbg("Invalid serial port.");
+               return SR_ERR;
+       }
+
+       sr_spew("Opening serial port '%s' (flags %d).", serial->port, flags);
+
+       sp_get_port_by_name(serial->port, &serial->data);
+
+       if (flags & SERIAL_RDWR)
+               sp_flags = (SP_MODE_READ | SP_MODE_WRITE);
+       else if (flags & SERIAL_RDONLY)
+               sp_flags = SP_MODE_READ;
+
+       serial->nonblocking = (flags & SERIAL_NONBLOCK) ? 1 : 0;
+
+       ret = sp_open(serial->data, sp_flags);
+
+       switch (ret) {
+       case SP_ERR_ARG:
+               sr_err("Attempt to open serial port with invalid parameters.");
+               return SR_ERR_ARG;
+       case SP_ERR_FAIL:
+               error = sp_last_error_message();
+               sr_err("Error opening port (%d): %s.",
+                       sp_last_error_code(), error);
+               sp_free_error_message(error);
+               return SR_ERR;
+       }
+
+       if (serial->serialcomm)
+               return serial_set_paramstr(serial, serial->serialcomm);
+       else
+               return SR_OK;
+}
+
+/**
+ * Close the specified serial port.
+ *
+ * @param serial Previously initialized serial port structure.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR Failure.
+ */
+SR_PRIV int serial_close(struct sr_serial_dev_inst *serial)
+{
+       int ret;
+       char *error;
+
+       if (!serial) {
+               sr_dbg("Invalid serial port.");
+               return SR_ERR;
+       }
+
+       if (!serial->data) {
+               sr_dbg("Cannot close unopened serial port %s.", serial->port);
+               return SR_ERR;
+       }
+
+       sr_spew("Closing serial port %s.", serial->port);
+
+       ret = sp_close(serial->data);
+
+       switch (ret) {
+       case SP_ERR_ARG:
+               sr_err("Attempt to close an invalid serial port.");
+               return SR_ERR_ARG;
+       case SP_ERR_FAIL:
+               error = sp_last_error_message();
+               sr_err("Error closing port (%d): %s.",
+                       sp_last_error_code(), error);
+               sp_free_error_message(error);
+               return SR_ERR;
+       }
+
+       sp_free_port(serial->data);
+       serial->data = NULL;
+
+       return SR_OK;
+}
+
+/**
+ * Flush serial port buffers.
+ *
+ * @param serial Previously initialized serial port structure.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR Failure.
+ */
+SR_PRIV int serial_flush(struct sr_serial_dev_inst *serial)
+{
+       int ret;
+       char *error;
+
+       if (!serial) {
+               sr_dbg("Invalid serial port.");
+               return SR_ERR;
+       }
+
+       if (!serial->data) {
+               sr_dbg("Cannot flush unopened serial port %s.", serial->port);
+               return SR_ERR;
+       }
+
+       sr_spew("Flushing serial port %s.", serial->port);
+
+       ret = sp_flush(serial->data, SP_BUF_BOTH);
+
+       switch (ret) {
+       case SP_ERR_ARG:
+               sr_err("Attempt to flush an invalid serial port.");
+               return SR_ERR_ARG;
+       case SP_ERR_FAIL:
+               error = sp_last_error_message();
+               sr_err("Error flushing port (%d): %s.",
+                       sp_last_error_code(), error);
+               sp_free_error_message(error);
+               return SR_ERR;
+       }
+
+       return SR_OK;
+}
+
+static int _serial_write(struct sr_serial_dev_inst *serial,
+               const void *buf, size_t count, int nonblocking)
+{
+       ssize_t ret;
+       char *error;
+
+       if (!serial) {
+               sr_dbg("Invalid serial port.");
+               return SR_ERR;
+       }
+
+       if (!serial->data) {
+               sr_dbg("Cannot use unopened serial port %s.", serial->port);
+               return SR_ERR;
+       }
+
+       if (nonblocking)
+               ret = sp_nonblocking_write(serial->data, buf, count);
+       else
+               ret = sp_blocking_write(serial->data, buf, count, 0);
+
+       switch (ret) {
+       case SP_ERR_ARG:
+               sr_err("Attempted serial port write with invalid arguments.");
+               return SR_ERR_ARG;
+       case SP_ERR_FAIL:
+               error = sp_last_error_message();
+               sr_err("Write error (%d): %s.", sp_last_error_code(), error);
+               sp_free_error_message(error);
+               return SR_ERR;
+       }
+
+       sr_spew("Wrote %d/%d bytes.", ret, count);
+
+       return ret;
+}
+
+/**
+ * Write a number of bytes to the specified serial port.
+ *
+ * @param serial Previously initialized serial port structure.
+ * @param[in] buf Buffer containing the bytes to write.
+ * @param[in] count Number of bytes to write.
+ *
+ * @retval SR_ERR_ARG Invalid argument.
+ * @retval SR_ERR Other error.
+ * @retval other The number of bytes written.
+ */
+SR_PRIV int serial_write(struct sr_serial_dev_inst *serial,
+               const void *buf, size_t count)
+{
+       return _serial_write(serial, buf, count, serial->nonblocking);
+}
+
+/**
+ * Write a number of bytes to the specified serial port, blocking until finished.
+ * @copydetails serial_write()
+ */
+SR_PRIV int serial_write_blocking(struct sr_serial_dev_inst *serial,
+               const void *buf, size_t count)
+{
+       return _serial_write(serial, buf, count, 0);
+}
+
+/**
+ * Write a number of bytes to the specified serial port, return immediately.
+ * @copydetails serial_write()
+*/
+SR_PRIV int serial_write_nonblocking(struct sr_serial_dev_inst *serial,
+               const void *buf, size_t count)
+{
+       return _serial_write(serial, buf, count, 1);
+}
+
+static int _serial_read(struct sr_serial_dev_inst *serial, void *buf,
+               size_t count, int nonblocking)
+{
+       ssize_t ret;
+       char *error;
+
+       if (!serial) {
+               sr_dbg("Invalid serial port.");
+               return SR_ERR;
+       }
+
+       if (!serial->data) {
+               sr_dbg("Cannot use unopened serial port %s.", serial->port);
+               return SR_ERR;
+       }
+
+       if (nonblocking)
+               ret = sp_nonblocking_read(serial->data, buf, count);
+       else
+               ret = sp_blocking_read(serial->data, buf, count, 0);
+
+       switch (ret) {
+       case SP_ERR_ARG:
+               sr_err("Attempted serial port read with invalid arguments.");
+               return SR_ERR_ARG;
+       case SP_ERR_FAIL:
+               error = sp_last_error_message();
+               sr_err("Read error (%d): %s.", sp_last_error_code(), error);
+               sp_free_error_message(error);
+               return SR_ERR;
+       }
+
+       if (ret > 0)
+               sr_spew("Read %d/%d bytes.", ret, count);
+
+       return ret;
+}
+
+/**
+ * Read a number of bytes from the specified serial port.
+ *
+ * @param serial Previously initialized serial port structure.
+ * @param buf Buffer where to store the bytes that are read.
+ * @param[in] count The number of bytes to read.
+ *
+ * @retval SR_ERR_ARG Invalid argument.
+ * @retval SR_ERR     Other error.
+ * @retval other      The number of bytes read.
+ */
+SR_PRIV int serial_read(struct sr_serial_dev_inst *serial, void *buf,
+               size_t count)
+{
+       return _serial_read(serial, buf, count, serial->nonblocking);
+}
+
+/**
+ * Read a number of bytes from the specified serial port, block until finished.
+ * @copydetails serial_read()
+ */
+SR_PRIV int serial_read_blocking(struct sr_serial_dev_inst *serial, void *buf,
+               size_t count)
+{
+       return _serial_read(serial, buf, count, 0);
+}
+
+/**
+ * Try to read up to @a count bytes from the specified serial port, return
+ * immediately with what's available.
+ * @copydetails serial_read()
+ */
+SR_PRIV int serial_read_nonblocking(struct sr_serial_dev_inst *serial, void *buf,
+               size_t count)
+{
+       return _serial_read(serial, buf, count, 1);
+}
+
+/**
+ * Set serial parameters for the specified serial port.
+ *
+ * @param serial Previously initialized serial port structure.
+ * @param[in] baudrate The baudrate to set.
+ * @param[in] bits The number of data bits to use (5, 6, 7 or 8).
+ * @param[in] parity The parity setting to use (0 = none, 1 = even, 2 = odd).
+ * @param[in] stopbits The number of stop bits to use (1 or 2).
+ * @param[in] flowcontrol The flow control settings to use (0 = none,
+ *                      1 = RTS/CTS, 2 = XON/XOFF).
+ * @param[in] rts Status of RTS line (0 or 1; required by some interfaces).
+ * @param[in] dtr Status of DTR line (0 or 1; required by some interfaces).
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR Failure.
+ */
+SR_PRIV int serial_set_params(struct sr_serial_dev_inst *serial, int baudrate,
+                             int bits, int parity, int stopbits,
+                             int flowcontrol, int rts, int dtr)
+{
+       int ret;
+       char *error;
+       struct sp_port_config *config;
+
+       if (!serial) {
+               sr_dbg("Invalid serial port.");
+               return SR_ERR;
+       }
+
+       if (!serial->data) {
+               sr_dbg("Cannot configure unopened serial port %s.", serial->port);
+               return SR_ERR;
+       }
+
+       sr_spew("Setting serial parameters on port %s.", serial->port);
+
+       sp_new_config(&config);
+       sp_set_config_baudrate(config, baudrate);
+       sp_set_config_bits(config, bits);
+       switch (parity) {
+       case 0:
+               sp_set_config_parity(config, SP_PARITY_NONE);
+               break;
+       case 1:
+               sp_set_config_parity(config, SP_PARITY_EVEN);
+               break;
+       case 2:
+               sp_set_config_parity(config, SP_PARITY_ODD);
+               break;
+       default:
+               return SR_ERR_ARG;
+       }
+       sp_set_config_stopbits(config, stopbits);
+       sp_set_config_rts(config, flowcontrol == 1 ? SP_RTS_FLOW_CONTROL : rts);
+       sp_set_config_cts(config, flowcontrol == 1 ? SP_CTS_FLOW_CONTROL : SP_CTS_IGNORE);
+       sp_set_config_dtr(config, dtr);
+       sp_set_config_dsr(config, SP_DSR_IGNORE);
+       sp_set_config_xon_xoff(config, flowcontrol == 2 ? SP_XONXOFF_INOUT : SP_XONXOFF_DISABLED);
+
+       ret = sp_set_config(serial->data, config);
+       sp_free_config(config);
+
+       switch (ret) {
+       case SP_ERR_ARG:
+               sr_err("Invalid arguments for setting serial port parameters.");
+               return SR_ERR_ARG;
+       case SP_ERR_FAIL:
+               error = sp_last_error_message();
+               sr_err("Error setting serial port parameters (%d): %s.",
+                       sp_last_error_code(), error);
+               sp_free_error_message(error);
+               return SR_ERR;
+       }
+
+       return SR_OK;
+}
+
+/**
+ * Set serial parameters for the specified serial port from parameter string.
+ *
+ * @param serial Previously initialized serial port structure.
+ * @param[in] paramstr A serial communication parameters string of the form
+ * "<baudrate>/<bits><parity><stopbits>{/<option>}".\n
+ *  Examples: "9600/8n1", "600/7o2/dtr=1/rts=0" or "460800/8n1/flow=2".\n
+ * \<baudrate\>=integer Baud rate.\n
+ * \<bits\>=5|6|7|8 Number of data bits.\n
+ * \<parity\>=n|e|o None, even, odd.\n
+ * \<stopbits\>=1|2 One or two stop bits.\n
+ * Options:\n
+ * dtr=0|1 Set DTR off resp. on.\n
+ * flow=0|1|2 Flow control. 0 for none, 1 for RTS/CTS, 2 for XON/XOFF.\n
+ * rts=0|1 Set RTS off resp. on.\n
+ * Please note that values and combinations of these parameters must be
+ * supported by the concrete serial interface hardware and the drivers for it.
+ * @retval SR_OK Success.
+ * @retval SR_ERR Failure.
+ */
+SR_PRIV int serial_set_paramstr(struct sr_serial_dev_inst *serial,
+               const char *paramstr)
+{
+#define SERIAL_COMM_SPEC "^(\\d+)/([5678])([neo])([12])(.*)$"
+
+       GRegex *reg;
+       GMatchInfo *match;
+       int speed, databits, parity, stopbits, flow, rts, dtr, i;
+       char *mstr, **opts, **kv;
+
+       speed = databits = parity = stopbits = flow = 0;
+       rts = dtr = -1;
+       sr_spew("Parsing parameters from \"%s\".", paramstr);
+       reg = g_regex_new(SERIAL_COMM_SPEC, 0, 0, NULL);
+       if (g_regex_match(reg, paramstr, 0, &match)) {
+               if ((mstr = g_match_info_fetch(match, 1)))
+                       speed = strtoul(mstr, NULL, 10);
+               g_free(mstr);
+               if ((mstr = g_match_info_fetch(match, 2)))
+                       databits = strtoul(mstr, NULL, 10);
+               g_free(mstr);
+               if ((mstr = g_match_info_fetch(match, 3))) {
+                       switch (mstr[0]) {
+                       case 'n':
+                               parity = SERIAL_PARITY_NONE;
+                               break;
+                       case 'e':
+                               parity = SERIAL_PARITY_EVEN;
+                               break;
+                       case 'o':
+                               parity = SERIAL_PARITY_ODD;
+                               break;
+                       }
+               }
+               g_free(mstr);
+               if ((mstr = g_match_info_fetch(match, 4)))
+                       stopbits = strtoul(mstr, NULL, 10);
+               g_free(mstr);
+               if ((mstr = g_match_info_fetch(match, 5)) && mstr[0] != '\0') {
+                       if (mstr[0] != '/') {
+                               sr_dbg("missing separator before extra options");
+                               speed = 0;
+                       } else {
+                               /* A set of "key=value" options separated by / */
+                               opts = g_strsplit(mstr + 1, "/", 0);
+                               for (i = 0; opts[i]; i++) {
+                                       kv = g_strsplit(opts[i], "=", 2);
+                                       if (!strncmp(kv[0], "rts", 3)) {
+                                               if (kv[1][0] == '1')
+                                                       rts = 1;
+                                               else if (kv[1][0] == '0')
+                                                       rts = 0;
+                                               else {
+                                                       sr_dbg("invalid value for rts: %c", kv[1][0]);
+                                                       speed = 0;
+                                               }
+                                       } else if (!strncmp(kv[0], "dtr", 3)) {
+                                               if (kv[1][0] == '1')
+                                                       dtr = 1;
+                                               else if (kv[1][0] == '0')
+                                                       dtr = 0;
+                                               else {
+                                                       sr_dbg("invalid value for dtr: %c", kv[1][0]);
+                                                       speed = 0;
+                                               }
+                                       } else if (!strncmp(kv[0], "flow", 4)) {
+                                               if (kv[1][0] == '0')
+                                                       flow = 0;
+                                               else if (kv[1][0] == '1')
+                                                       flow = 1;
+                                               else if (kv[1][0] == '2')
+                                                       flow = 2;
+                                               else {
+                                                       sr_dbg("invalid value for flow: %c", kv[1][0]);
+                                                       speed = 0;
+                                               }
+                                       }
+                                       g_strfreev(kv);
+                               }
+                               g_strfreev(opts);
+                       }
+               }
+               g_free(mstr);
+       }
+       g_match_info_unref(match);
+       g_regex_unref(reg);
+
+       if (speed) {
+               return serial_set_params(serial, speed, databits, parity,
+                                        stopbits, flow, rts, dtr);
+       } else {
+               sr_dbg("Could not infer speed from parameter string.");
+               return SR_ERR_ARG;
+       }
+}
+
+/**
+ * Read a line from the specified serial port.
+ *
+ * @param serial Previously initialized serial port structure.
+ * @param buf Buffer where to store the bytes that are read.
+ * @param buflen Size of the buffer.
+ * @param[in] timeout_ms How long to wait for a line to come in.
+ *
+ * Reading stops when CR of LR is found, which is stripped from the buffer.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR Failure.
+ */
+SR_PRIV int serial_readline(struct sr_serial_dev_inst *serial, char **buf,
+               int *buflen, gint64 timeout_ms)
+{
+       gint64 start;
+       int maxlen, len;
+
+       if (!serial) {
+               sr_dbg("Invalid serial port.");
+               return SR_ERR;
+       }
+
+       if (!serial->data) {
+               sr_dbg("Cannot use unopened serial port %s.", serial->port);
+               return -1;
+       }
+
+       timeout_ms *= 1000;
+       start = g_get_monotonic_time();
+
+       maxlen = *buflen;
+       *buflen = len = 0;
+       while(1) {
+               len = maxlen - *buflen - 1;
+               if (len < 1)
+                       break;
+               len = serial_read(serial, *buf + *buflen, 1);
+               if (len > 0) {
+                       *buflen += len;
+                       *(*buf + *buflen) = '\0';
+                       if (*buflen > 0 && (*(*buf + *buflen - 1) == '\r'
+                                       || *(*buf + *buflen - 1) == '\n')) {
+                               /* Strip CR/LF and terminate. */
+                               *(*buf + --*buflen) = '\0';
+                               break;
+                       }
+               }
+               if (g_get_monotonic_time() - start > timeout_ms)
+                       /* Timeout */
+                       break;
+               if (len < 1)
+                       g_usleep(2000);
+       }
+       if (*buflen)
+               sr_dbg("Received %d: '%s'.", *buflen, *buf);
+
+       return SR_OK;
+}
+
+/**
+ * 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[in] packet_size Size, in bytes, of a valid packet.
+ * @param is_valid Callback that assesses whether the packet is valid or not.
+ * @param[in] timeout_ms The timeout after which, if no packet is detected, to
+ *                   abort scanning.
+ * @param[in] baudrate The baudrate of the serial port. This parameter is not
+ *                 critical, but it helps fine tune the serial port polling
+ *                 delay.
+ *
+ * @retval SR_OK Valid packet was found within the given timeout.
+ * @retval SR_ERR Failure.
+ */
+SR_PRIV int serial_stream_detect(struct sr_serial_dev_inst *serial,
+                                uint8_t *buf, size_t *buflen,
+                                size_t packet_size,
+                                packet_valid_callback is_valid,
+                                uint64_t timeout_ms, int baudrate)
+{
+       uint64_t start, time, byte_delay_us;
+       size_t ibuf, i, maxlen;
+       int len;
+
+       maxlen = *buflen;
+
+       sr_dbg("Detecting packets on %s (timeout = %" PRIu64
+              "ms, baudrate = %d).", serial->port, timeout_ms, baudrate);
+
+       if (maxlen < (packet_size / 2) ) {
+               sr_err("Buffer size must be at least twice the packet size.");
+               return SR_ERR;
+       }
+
+       /* Assume 8n1 transmission. That is 10 bits for every byte. */
+       byte_delay_us = 10 * (1000000 / baudrate);
+       start = g_get_monotonic_time();
+
+       i = ibuf = len = 0;
+       while (ibuf < maxlen) {
+               len = serial_read(serial, &buf[ibuf], 1);
+               if (len > 0) {
+                       ibuf += len;
+               } else if (len == 0) {
+                       /* No logging, already done in serial_read(). */
+               } else {
+                       /* Error reading byte, but continuing anyway. */
+               }
+
+               time = g_get_monotonic_time() - start;
+               time /= 1000;
+
+               if ((ibuf - i) >= packet_size) {
+                       /* 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.", (ibuf - i), time);
+                               *buflen = ibuf;
+                               return SR_OK;
+                       } else {
+                               sr_spew("Got %d bytes, but not a valid "
+                                       "packet.", (ibuf - i));
+                       }
+                       /* Not a valid packet. Continue searching. */
+                       i++;
+               }
+               if (time >= timeout_ms) {
+                       /* Timeout */
+                       sr_dbg("Detection timed out after %dms.", time);
+                       break;
+               }
+               if (len < 1)
+                       g_usleep(byte_delay_us);
+       }
+
+       *buflen = ibuf;
+
+       sr_err("Didn't find a valid packet (read %d bytes).", *buflen);
+
+       return SR_ERR;
+}
+
+/**
+ * Extract the serial device and options from the options linked list.
+ *
+ * @param options List of options passed from the command line.
+ * @param serial_device Pointer where to store the exctracted serial device.
+ * @param serial_options Pointer where to store the optional extracted serial
+ * options.
+ *
+ * @return SR_OK if a serial_device is found, SR_ERR if no device is found. The
+ * returned string should not be freed by the caller.
+ */
+SR_PRIV int sr_serial_extract_options(GSList *options, const char **serial_device,
+                                     const char **serial_options)
+{
+       GSList *l;
+       struct sr_config *src;
+
+       *serial_device = NULL;
+
+       for (l = options; l; l = l->next) {
+               src = l->data;
+               switch (src->key) {
+               case SR_CONF_CONN:
+                       *serial_device = g_variant_get_string(src->data, NULL);
+                       sr_dbg("Parsed serial device: %s", *serial_device);
+                       break;
+
+               case SR_CONF_SERIALCOMM:
+                       *serial_options = g_variant_get_string(src->data, NULL);
+                       sr_dbg("Parsed serial options: %s", *serial_options);
+                       break;
+               }
+       }
+
+       if (!*serial_device) {
+               sr_dbg("No serial device specified");
+               return SR_ERR;
+       }
+
+       return SR_OK;
+}
+
+#ifdef _WIN32
+typedef HANDLE event_handle;
+#else
+typedef int event_handle;
+#endif
+
+SR_PRIV int serial_source_add(struct sr_session *session,
+               struct sr_serial_dev_inst *serial, int events, int timeout,
+               sr_receive_data_callback cb, void *cb_data)
+{
+       enum sp_event mask = 0;
+       unsigned int i;
+
+       if (sp_new_event_set(&serial->event_set) != SP_OK)
+               return SR_ERR;
+
+       if (events & G_IO_IN)
+               mask |= SP_EVENT_RX_READY;
+       if (events & G_IO_OUT)
+               mask |= SP_EVENT_TX_READY;
+       if (events & G_IO_ERR)
+               mask |= SP_EVENT_ERROR;
+
+       if (sp_add_port_events(serial->event_set, serial->data, mask) != SP_OK) {
+               sp_free_event_set(serial->event_set);
+               return SR_ERR;
+       }
+
+       serial->pollfds = (GPollFD *) g_malloc0(sizeof(GPollFD) * serial->event_set->count);
+
+       for (i = 0; i < serial->event_set->count; i++) {
+
+               serial->pollfds[i].fd = ((event_handle *) serial->event_set->handles)[i];
+
+               mask = serial->event_set->masks[i];
+
+               if (mask & SP_EVENT_RX_READY)
+                       serial->pollfds[i].events |= G_IO_IN;
+               if (mask & SP_EVENT_TX_READY)
+                       serial->pollfds[i].events |= G_IO_OUT;
+               if (mask & SP_EVENT_ERROR)
+                       serial->pollfds[i].events |= G_IO_ERR;
+
+               if (sr_session_source_add_pollfd(session, &serial->pollfds[i],
+                                       timeout, cb, cb_data) != SR_OK)
+                       return SR_ERR;
+       }
+
+       return SR_OK;
+}
+
+SR_PRIV int serial_source_remove(struct sr_session *session,
+               struct sr_serial_dev_inst *serial)
+{
+       unsigned int i;
+
+       for (i = 0; i < serial->event_set->count; i++)
+               if (sr_session_source_remove_pollfd(session, &serial->pollfds[i]) != SR_OK)
+                       return SR_ERR;
+
+       g_free(serial->pollfds);
+       sp_free_event_set(serial->event_set);
+
+       serial->pollfds = NULL;
+       serial->event_set = NULL;
+
+       return SR_OK;
+}
+
+/**
+ * Find USB serial devices via the USB vendor ID and product ID.
+ *
+ * @param[in] vendor_id Vendor ID of the USB device.
+ * @param[in] product_id Product ID of the USB device.
+ *
+ * @return A GSList of strings containing the path of the serial device or
+ *         NULL if no serial device is found. The returned list must be freed
+ *         by the caller.
+ */
+SR_PRIV GSList *sr_serial_find_usb(uint16_t vendor_id, uint16_t product_id)
+{
+#ifdef __linux__
+       const gchar *usb_dev;
+       const char device_tree[] = "/sys/bus/usb/devices/";
+       GDir *devices_dir, *device_dir;
+       GSList *l = NULL;
+       GSList *tty_devs;
+       GSList *matched_paths;
+       FILE *fd;
+       char tmp[5];
+       gchar *vendor_path, *product_path, *path_copy;
+       gchar *prefix, *subdir_path, *device_path, *tty_path;
+       unsigned long read_vendor_id, read_product_id;
+       const char *file;
+
+       l = NULL;
+       tty_devs = NULL;
+       matched_paths = NULL;
+
+       if (!(devices_dir = g_dir_open(device_tree, 0, NULL)))
+               return NULL;
+
+       /*
+        * Find potential candidates using the vendor ID and product ID
+        * and store them in matched_paths.
+        */
+       while ((usb_dev = g_dir_read_name(devices_dir))) {
+               vendor_path = g_strconcat(device_tree,
+                                         usb_dev, "/idVendor", NULL);
+               product_path = g_strconcat(device_tree,
+                                          usb_dev, "/idProduct", NULL);
+
+               if (!g_file_test(vendor_path, G_FILE_TEST_EXISTS) ||
+                   !g_file_test(product_path, G_FILE_TEST_EXISTS))
+                       goto skip_device;
+
+               if ((fd = g_fopen(vendor_path, "r")) == NULL)
+                       goto skip_device;
+
+               if (fgets(tmp, sizeof(tmp), fd) == NULL) {
+                       fclose(fd);
+                       goto skip_device;
+               }
+               read_vendor_id = strtoul(tmp, NULL, 16);
+
+               fclose(fd);
+
+               if ((fd = g_fopen(product_path, "r")) == NULL)
+                       goto skip_device;
+
+               if (fgets(tmp, sizeof(tmp), fd) == NULL) {
+                       fclose(fd);
+                       goto skip_device;
+               }
+               read_product_id = strtoul(tmp, NULL, 16);
+
+               fclose(fd);
+
+               if (vendor_id == read_vendor_id &&
+                   product_id == read_product_id) {
+                       path_copy = g_strdup(usb_dev);
+                       matched_paths = g_slist_prepend(matched_paths,
+                                                       path_copy);
+               }
+
+skip_device:
+               g_free(vendor_path);
+               g_free(product_path);
+       }
+       g_dir_close(devices_dir);
+
+       /* For every matched device try to find a ttyUSBX subfolder. */
+       for (l = matched_paths; l; l = l->next) {
+               subdir_path = NULL;
+
+               device_path = g_strconcat(device_tree, l->data, NULL);
+
+               if (!(device_dir = g_dir_open(device_path, 0, NULL))) {
+                       g_free(device_path);
+                       continue;
+               }
+
+               prefix = g_strconcat(l->data, ":", NULL);
+
+               while ((file = g_dir_read_name(device_dir))) {
+                       if (g_str_has_prefix(file, prefix)) {
+                               subdir_path = g_strconcat(device_path,
+                                               "/", file, NULL);
+                               break;
+                       }
+               }
+               g_dir_close(device_dir);
+
+               g_free(prefix);
+               g_free(device_path);
+
+               if (subdir_path) {
+                       if (!(device_dir = g_dir_open(subdir_path, 0, NULL))) {
+                               g_free(subdir_path);
+                               continue;
+                       }
+                       g_free(subdir_path);
+
+                       while ((file = g_dir_read_name(device_dir))) {
+                               if (g_str_has_prefix(file, "ttyUSB")) {
+                                       tty_path = g_strconcat("/dev/",
+                                                              file, NULL);
+                                       sr_dbg("Found USB device %04x:%04x attached to %s.",
+                                              vendor_id, product_id, tty_path);
+                                       tty_devs = g_slist_prepend(tty_devs,
+                                                       tty_path);
+                                       break;
+                               }
+                       }
+                       g_dir_close(device_dir);
+               }
+       }
+       g_slist_free_full(matched_paths, g_free);
+
+       return tty_devs;
+#else
+       (void)vendor_id;
+       (void)product_id;
+
+       return NULL;
+#endif
+}
diff --git a/src/session.c b/src/session.c
new file mode 100644 (file)
index 0000000..d8a3b00
--- /dev/null
@@ -0,0 +1,910 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+/** @cond PRIVATE */
+#define LOG_PREFIX "session"
+/** @endcond */
+
+/**
+ * @file
+ *
+ * Creating, using, or destroying libsigrok sessions.
+ */
+
+/**
+ * @defgroup grp_session Session handling
+ *
+ * Creating, using, or destroying libsigrok sessions.
+ *
+ * @{
+ */
+
+struct source {
+       int timeout;
+       sr_receive_data_callback cb;
+       void *cb_data;
+
+       /* This is used to keep track of the object (fd, pollfd or channel) which is
+        * being polled and will be used to match the source when removing it again.
+        */
+       gintptr poll_object;
+};
+
+struct datafeed_callback {
+       sr_datafeed_callback cb;
+       void *cb_data;
+};
+
+/**
+ * Create a new session.
+ * Currently, there can be only one session at a time within the same process.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_BUG A session exists already.
+ *
+ * @since 0.4.0
+ */
+SR_API int sr_session_new(struct sr_session **new_session)
+{
+       struct sr_session *session;
+
+       session = g_malloc0(sizeof(struct sr_session));
+
+       session->source_timeout = -1;
+       session->running = FALSE;
+       session->abort_session = FALSE;
+       g_mutex_init(&session->stop_mutex);
+
+       *new_session = session;
+
+       return SR_OK;
+}
+
+/**
+ * Destroy a session.
+ * This frees up all memory used by the session.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_ARG Invalid session passed.
+ *
+ * @since 0.4.0
+ */
+SR_API int sr_session_destroy(struct sr_session *session)
+{
+       if (!session) {
+               sr_err("%s: session was NULL", __func__);
+               return SR_ERR_ARG;
+       }
+
+       sr_session_dev_remove_all(session);
+       g_mutex_clear(&session->stop_mutex);
+       if (session->trigger)
+               sr_trigger_free(session->trigger);
+
+       g_free(session);
+
+       return SR_OK;
+}
+
+/**
+ * Remove all the devices from a session.
+ *
+ * The session itself (i.e., the struct sr_session) is not free'd and still
+ * exists after this function returns.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_BUG Invalid session passed.
+ *
+ * @since 0.4.0
+ */
+SR_API int sr_session_dev_remove_all(struct sr_session *session)
+{
+       struct sr_dev_inst *sdi;
+       GSList *l;
+
+       if (!session) {
+               sr_err("%s: session was NULL", __func__);
+               return SR_ERR_ARG;
+       }
+
+       for (l = session->devs; l; l = l->next) {
+               sdi = (struct sr_dev_inst *) l->data;
+               sdi->session = NULL;
+       }
+
+       g_slist_free(session->devs);
+       session->devs = NULL;
+
+       return SR_OK;
+}
+
+/**
+ * Add a device instance to a session.
+ *
+ * @param sdi The device instance to add to a session. Must not
+ *            be NULL. Also, sdi->driver and sdi->driver->dev_open must
+ *            not be NULL.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_ARG Invalid argument.
+ *
+ * @since 0.4.0
+ */
+SR_API int sr_session_dev_add(struct sr_session *session,
+               struct sr_dev_inst *sdi)
+{
+       int ret;
+
+       if (!sdi) {
+               sr_err("%s: sdi was NULL", __func__);
+               return SR_ERR_ARG;
+       }
+
+       if (!session) {
+               sr_err("%s: session was NULL", __func__);
+               return SR_ERR_ARG;
+       }
+
+       /* If sdi->session is not NULL, the device is already in this or
+        * another session. */
+       if (sdi->session) {
+               sr_err("%s: already assigned to session", __func__);
+               return SR_ERR_ARG;
+       }
+
+       /* If sdi->driver is NULL, this is a virtual device. */
+       if (!sdi->driver) {
+               sr_dbg("%s: sdi->driver was NULL, this seems to be "
+                      "a virtual device; continuing", __func__);
+               /* Just add the device, don't run dev_open(). */
+               session->devs = g_slist_append(session->devs, (gpointer)sdi);
+               sdi->session = session;
+               return SR_OK;
+       }
+
+       /* sdi->driver is non-NULL (i.e. we have a real device). */
+       if (!sdi->driver->dev_open) {
+               sr_err("%s: sdi->driver->dev_open was NULL", __func__);
+               return SR_ERR_BUG;
+       }
+
+       session->devs = g_slist_append(session->devs, (gpointer)sdi);
+       sdi->session = session;
+
+       if (session->running) {
+               /* Adding a device to a running session. Commit settings
+                * and start acquisition on that device now. */
+               if ((ret = sr_config_commit(sdi)) != SR_OK) {
+                       sr_err("Failed to commit device settings before "
+                              "starting acquisition in running session (%s)",
+                              sr_strerror(ret));
+                       return ret;
+               }
+               if ((ret = sdi->driver->dev_acquisition_start(sdi,
+                                               (void *)sdi)) != SR_OK) {
+                       sr_err("Failed to start acquisition of device in "
+                              "running session (%s)", sr_strerror(ret));
+                       return ret;
+               }
+       }
+
+       return SR_OK;
+}
+
+/**
+ * List all device instances attached to a session.
+ *
+ * @param devlist A pointer where the device instance list will be
+ *                stored on return. If no devices are in the session,
+ *                this will be NULL. Each element in the list points
+ *                to a struct sr_dev_inst *.
+ *                The list must be freed by the caller, but not the
+ *                elements pointed to.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_ARG Invalid argument.
+ *
+ * @since 0.4.0
+ */
+SR_API int sr_session_dev_list(struct sr_session *session, GSList **devlist)
+{
+       if (!session)
+               return SR_ERR_ARG;
+
+       if (!devlist)
+               return SR_ERR_ARG;
+
+       *devlist = g_slist_copy(session->devs);
+
+       return SR_OK;
+}
+
+/**
+ * Remove all datafeed callbacks in a session.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_ARG Invalid session passed.
+ *
+ * @since 0.4.0
+ */
+SR_API int sr_session_datafeed_callback_remove_all(struct sr_session *session)
+{
+       if (!session) {
+               sr_err("%s: session was NULL", __func__);
+               return SR_ERR_ARG;
+       }
+
+       g_slist_free_full(session->datafeed_callbacks, g_free);
+       session->datafeed_callbacks = NULL;
+
+       return SR_OK;
+}
+
+/**
+ * Add a datafeed callback to a session.
+ *
+ * @param cb Function to call when a chunk of data is received.
+ *           Must not be NULL.
+ * @param cb_data Opaque pointer passed in by the caller.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_BUG No session exists.
+ *
+ * @since 0.3.0
+ */
+SR_API int sr_session_datafeed_callback_add(struct sr_session *session,
+               sr_datafeed_callback cb, void *cb_data)
+{
+       struct datafeed_callback *cb_struct;
+
+       if (!session) {
+               sr_err("%s: session was NULL", __func__);
+               return SR_ERR_BUG;
+       }
+
+       if (!cb) {
+               sr_err("%s: cb was NULL", __func__);
+               return SR_ERR_ARG;
+       }
+
+       if (!(cb_struct = g_try_malloc0(sizeof(struct datafeed_callback))))
+               return SR_ERR_MALLOC;
+
+       cb_struct->cb = cb;
+       cb_struct->cb_data = cb_data;
+
+       session->datafeed_callbacks =
+           g_slist_append(session->datafeed_callbacks, cb_struct);
+
+       return SR_OK;
+}
+
+SR_API struct sr_trigger *sr_session_trigger_get(struct sr_session *session)
+{
+       return session->trigger;
+}
+
+SR_API int sr_session_trigger_set(struct sr_session *session, struct sr_trigger *trig)
+{
+       session->trigger = trig;
+
+       return SR_OK;
+}
+
+/**
+ * Call every device in the current session's callback.
+ *
+ * For sessions not driven by select loops such as sr_session_run(),
+ * but driven by another scheduler, this can be used to poll the devices
+ * from within that scheduler.
+ *
+ * @param block If TRUE, this call will wait for any of the session's
+ *              sources to fire an event on the file descriptors, or
+ *              any of their timeouts to activate. In other words, this
+ *              can be used as a select loop.
+ *              If FALSE, all sources have their callback run, regardless
+ *              of file descriptor or timeout status.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR Error occured.
+ */
+static int sr_session_iteration(struct sr_session *session, gboolean block)
+{
+       unsigned int i;
+       int ret;
+
+       ret = g_poll(session->pollfds, session->num_sources,
+                       block ? session->source_timeout : 0);
+       for (i = 0; i < session->num_sources; i++) {
+               if (session->pollfds[i].revents > 0 || (ret == 0
+                       && session->source_timeout == session->sources[i].timeout)) {
+                       /*
+                        * Invoke the source's callback on an event,
+                        * or if the poll timed out and this source
+                        * asked for that timeout.
+                        */
+                       if (!session->sources[i].cb(session->pollfds[i].fd,
+                                       session->pollfds[i].revents,
+                                       session->sources[i].cb_data))
+                               sr_session_source_remove(session,
+                                               session->sources[i].poll_object);
+               }
+               /*
+                * We want to take as little time as possible to stop
+                * the session if we have been told to do so. Therefore,
+                * we check the flag after processing every source, not
+                * just once per main event loop.
+                */
+               g_mutex_lock(&session->stop_mutex);
+               if (session->abort_session) {
+                       sr_session_stop_sync(session);
+                       /* But once is enough. */
+                       session->abort_session = FALSE;
+               }
+               g_mutex_unlock(&session->stop_mutex);
+       }
+
+       return SR_OK;
+}
+
+
+static int verify_trigger(struct sr_trigger *trigger)
+{
+       struct sr_trigger_stage *stage;
+       struct sr_trigger_match *match;
+       GSList *l, *m;
+
+       if (!trigger->stages) {
+               sr_err("No trigger stages defined.");
+               return SR_ERR;
+       }
+
+       sr_spew("Checking trigger:");
+       for (l = trigger->stages; l; l = l->next) {
+               stage = l->data;
+               if (!stage->matches) {
+                       sr_err("Stage %d has no matches defined.", stage->stage);
+                       return SR_ERR;
+               }
+               for (m = stage->matches; m; m = m->next) {
+                       match = m->data;
+                       if (!match->channel) {
+                               sr_err("Stage %d match has no channel.", stage->stage);
+                               return SR_ERR;
+                       }
+                       if (!match->match) {
+                               sr_err("Stage %d match is not defined.", stage->stage);
+                               return SR_ERR;
+                       }
+                       sr_spew("Stage %d match on channel %s, match %d", stage->stage,
+                                       match->channel->name, match->match);
+               }
+       }
+
+       return SR_OK;
+}
+/**
+ * Start a session.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_ARG Invalid session passed.
+ *
+ * @since 0.4.0
+ */
+SR_API int sr_session_start(struct sr_session *session)
+{
+       struct sr_dev_inst *sdi;
+       GSList *l;
+       int ret;
+
+       if (!session) {
+               sr_err("%s: session was NULL", __func__);
+               return SR_ERR_ARG;
+       }
+
+       if (!session->devs) {
+               sr_err("%s: session->devs was NULL; a session "
+                      "cannot be started without devices.", __func__);
+               return SR_ERR_ARG;
+       }
+
+       if (session->trigger && verify_trigger(session->trigger) != SR_OK)
+               return SR_ERR;
+
+       sr_info("Starting.");
+
+       ret = SR_OK;
+       for (l = session->devs; l; l = l->next) {
+               sdi = l->data;
+               if ((ret = sr_config_commit(sdi)) != SR_OK) {
+                       sr_err("Failed to commit device settings before "
+                              "starting acquisition (%s)", sr_strerror(ret));
+                       break;
+               }
+               if ((ret = sdi->driver->dev_acquisition_start(sdi, sdi)) != SR_OK) {
+                       sr_err("%s: could not start an acquisition "
+                              "(%s)", __func__, sr_strerror(ret));
+                       break;
+               }
+       }
+
+       /* TODO: What if there are multiple devices? Which return code? */
+
+       return ret;
+}
+
+/**
+ * Run a session.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_ARG Invalid session passed.
+ *
+ * @since 0.4.0
+ */
+SR_API int sr_session_run(struct sr_session *session)
+{
+       if (!session) {
+               sr_err("%s: session was NULL", __func__);
+               return SR_ERR_ARG;
+       }
+
+       if (!session->devs) {
+               /* TODO: Actually the case? */
+               sr_err("%s: session->devs was NULL; a session "
+                      "cannot be run without devices.", __func__);
+               return SR_ERR_ARG;
+       }
+       session->running = TRUE;
+
+       sr_info("Running.");
+
+       /* Do we have real sources? */
+       if (session->num_sources == 1 && session->pollfds[0].fd == -1) {
+               /* Dummy source, freewheel over it. */
+               while (session->num_sources)
+                       session->sources[0].cb(-1, 0, session->sources[0].cb_data);
+       } else {
+               /* Real sources, use g_poll() main loop. */
+               while (session->num_sources)
+                       sr_session_iteration(session, TRUE);
+       }
+
+       return SR_OK;
+}
+
+/**
+ * Stop a session.
+ *
+ * The session is stopped immediately, with all acquisition sessions stopped
+ * and hardware drivers cleaned up.
+ *
+ * This must be called from within the session thread, to prevent freeing
+ * resources that the session thread will try to use.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_ARG Invalid session passed.
+ *
+ * @private
+ */
+SR_PRIV int sr_session_stop_sync(struct sr_session *session)
+{
+       struct sr_dev_inst *sdi;
+       GSList *l;
+
+       if (!session) {
+               sr_err("%s: session was NULL", __func__);
+               return SR_ERR_ARG;
+       }
+
+       sr_info("Stopping.");
+
+       for (l = session->devs; l; l = l->next) {
+               sdi = l->data;
+               if (sdi->driver) {
+                       if (sdi->driver->dev_acquisition_stop)
+                               sdi->driver->dev_acquisition_stop(sdi, sdi);
+               }
+       }
+       session->running = FALSE;
+
+       return SR_OK;
+}
+
+/**
+ * Stop a session.
+ *
+ * The session is stopped immediately, with all acquisition sessions being
+ * stopped and hardware drivers cleaned up.
+ *
+ * If the session is run in a separate thread, this function will not block
+ * until the session is finished executing. It is the caller's responsibility
+ * to wait for the session thread to return before assuming that the session is
+ * completely decommissioned.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_ARG Invalid session passed.
+ *
+ * @since 0.4.0
+ */
+SR_API int sr_session_stop(struct sr_session *session)
+{
+       if (!session) {
+               sr_err("%s: session was NULL", __func__);
+               return SR_ERR_BUG;
+       }
+
+       g_mutex_lock(&session->stop_mutex);
+       session->abort_session = TRUE;
+       g_mutex_unlock(&session->stop_mutex);
+
+       return SR_OK;
+}
+
+/**
+ * Debug helper.
+ *
+ * @param packet The packet to show debugging information for.
+ */
+static void datafeed_dump(const struct sr_datafeed_packet *packet)
+{
+       const struct sr_datafeed_logic *logic;
+       const struct sr_datafeed_analog *analog;
+
+       switch (packet->type) {
+       case SR_DF_HEADER:
+               sr_dbg("bus: Received SR_DF_HEADER packet.");
+               break;
+       case SR_DF_TRIGGER:
+               sr_dbg("bus: Received SR_DF_TRIGGER packet.");
+               break;
+       case SR_DF_META:
+               sr_dbg("bus: Received SR_DF_META packet.");
+               break;
+       case SR_DF_LOGIC:
+               logic = packet->payload;
+               sr_dbg("bus: Received SR_DF_LOGIC packet (%" PRIu64 " bytes, "
+                      "unitsize = %d).", logic->length, logic->unitsize);
+               break;
+       case SR_DF_ANALOG:
+               analog = packet->payload;
+               sr_dbg("bus: Received SR_DF_ANALOG packet (%d samples).",
+                      analog->num_samples);
+               break;
+       case SR_DF_END:
+               sr_dbg("bus: Received SR_DF_END packet.");
+               break;
+       case SR_DF_FRAME_BEGIN:
+               sr_dbg("bus: Received SR_DF_FRAME_BEGIN packet.");
+               break;
+       case SR_DF_FRAME_END:
+               sr_dbg("bus: Received SR_DF_FRAME_END packet.");
+               break;
+       default:
+               sr_dbg("bus: Received unknown packet type: %d.", packet->type);
+               break;
+       }
+}
+
+/**
+ * Send a packet to whatever is listening on the datafeed bus.
+ *
+ * Hardware drivers use this to send a data packet to the frontend.
+ *
+ * @param sdi TODO.
+ * @param packet The datafeed packet to send to the session bus.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_ARG Invalid argument.
+ *
+ * @private
+ */
+SR_PRIV int sr_session_send(const struct sr_dev_inst *sdi,
+                           const struct sr_datafeed_packet *packet)
+{
+       GSList *l;
+       struct datafeed_callback *cb_struct;
+
+       if (!sdi) {
+               sr_err("%s: sdi was NULL", __func__);
+               return SR_ERR_ARG;
+       }
+
+       if (!packet) {
+               sr_err("%s: packet was NULL", __func__);
+               return SR_ERR_ARG;
+       }
+
+       for (l = sdi->session->datafeed_callbacks; l; l = l->next) {
+               if (sr_log_loglevel_get() >= SR_LOG_DBG)
+                       datafeed_dump(packet);
+               cb_struct = l->data;
+               cb_struct->cb(sdi, packet, cb_struct->cb_data);
+       }
+
+       return SR_OK;
+}
+
+/**
+ * Add an event source for a file descriptor.
+ *
+ * @param pollfd The GPollFD.
+ * @param[in] timeout Max time to wait before the callback is called,
+ *              ignored if 0.
+ * @param cb Callback function to add. Must not be NULL.
+ * @param cb_data Data for the callback function. Can be NULL.
+ * @param poll_object TODO.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_ARG Invalid argument.
+ * @retval SR_ERR_MALLOC Memory allocation error.
+ */
+static int _sr_session_source_add(struct sr_session *session, GPollFD *pollfd,
+               int timeout, sr_receive_data_callback cb, void *cb_data, gintptr poll_object)
+{
+       struct source *new_sources, *s;
+       GPollFD *new_pollfds;
+
+       if (!cb) {
+               sr_err("%s: cb was NULL", __func__);
+               return SR_ERR_ARG;
+       }
+
+       /* Note: cb_data can be NULL, that's not a bug. */
+
+       new_pollfds = g_try_realloc(session->pollfds,
+                       sizeof(GPollFD) * (session->num_sources + 1));
+       if (!new_pollfds) {
+               sr_err("%s: new_pollfds malloc failed", __func__);
+               return SR_ERR_MALLOC;
+       }
+
+       new_sources = g_try_realloc(session->sources, sizeof(struct source) *
+                       (session->num_sources + 1));
+       if (!new_sources) {
+               sr_err("%s: new_sources malloc failed", __func__);
+               return SR_ERR_MALLOC;
+       }
+
+       new_pollfds[session->num_sources] = *pollfd;
+       s = &new_sources[session->num_sources++];
+       s->timeout = timeout;
+       s->cb = cb;
+       s->cb_data = cb_data;
+       s->poll_object = poll_object;
+       session->pollfds = new_pollfds;
+       session->sources = new_sources;
+
+       if (timeout != session->source_timeout && timeout > 0
+           && (session->source_timeout == -1 || timeout < session->source_timeout))
+               session->source_timeout = timeout;
+
+       return SR_OK;
+}
+
+/**
+ * Add an event source for a file descriptor.
+ *
+ * @param fd The file descriptor.
+ * @param events Events to check for.
+ * @param timeout Max time to wait before the callback is called, ignored if 0.
+ * @param cb Callback function to add. Must not be NULL.
+ * @param cb_data Data for the callback function. Can be NULL.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_ARG Invalid argument.
+ * @retval SR_ERR_MALLOC Memory allocation error.
+ *
+ * @since 0.3.0
+ */
+SR_API int sr_session_source_add(struct sr_session *session, int fd,
+               int events, int timeout, sr_receive_data_callback cb, void *cb_data)
+{
+       GPollFD p;
+
+       (void) session;
+
+       p.fd = fd;
+       p.events = events;
+
+       return _sr_session_source_add(session, &p, timeout, cb, cb_data, (gintptr)fd);
+}
+
+/**
+ * Add an event source for a GPollFD.
+ *
+ * @param pollfd The GPollFD.
+ * @param timeout Max time to wait before the callback is called, ignored if 0.
+ * @param cb Callback function to add. Must not be NULL.
+ * @param cb_data Data for the callback function. Can be NULL.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_ARG Invalid argument.
+ * @retval SR_ERR_MALLOC Memory allocation error.
+ *
+ * @since 0.3.0
+ */
+SR_API int sr_session_source_add_pollfd(struct sr_session *session,
+               GPollFD *pollfd, int timeout, sr_receive_data_callback cb,
+               void *cb_data)
+{
+       (void) session;
+
+       return _sr_session_source_add(session, pollfd, timeout, cb,
+                                     cb_data, (gintptr)pollfd);
+}
+
+/**
+ * Add an event source for a GIOChannel.
+ *
+ * @param channel The GIOChannel.
+ * @param events Events to poll on.
+ * @param timeout Max time to wait before the callback is called, ignored if 0.
+ * @param cb Callback function to add. Must not be NULL.
+ * @param cb_data Data for the callback function. Can be NULL.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_ARG Invalid argument.
+ * @retval SR_ERR_MALLOC Memory allocation error.
+ *
+ * @since 0.3.0
+ */
+SR_API int sr_session_source_add_channel(struct sr_session *session,
+               GIOChannel *channel, int events, int timeout,
+               sr_receive_data_callback cb, void *cb_data)
+{
+       GPollFD p;
+
+       (void) session;
+
+#ifdef _WIN32
+       g_io_channel_win32_make_pollfd(channel, events, &p);
+#else
+       p.fd = g_io_channel_unix_get_fd(channel);
+       p.events = events;
+#endif
+
+       return _sr_session_source_add(session, &p, timeout, cb, cb_data, (gintptr)channel);
+}
+
+/**
+ * Remove the source belonging to the specified channel.
+ *
+ * @todo Add more error checks and logging.
+ *
+ * @param poll_object The channel for which the source should be removed.
+ *
+ * @retval SR_OK Success
+ * @retval SR_ERR_ARG Invalid arguments
+ * @retval SR_ERR_MALLOC Memory allocation error
+ * @retval SR_ERR_BUG Internal error
+ */
+static int _sr_session_source_remove(struct sr_session *session, gintptr poll_object)
+{
+       struct source *new_sources;
+       GPollFD *new_pollfds;
+       unsigned int old;
+
+       if (!session->sources || !session->num_sources) {
+               sr_err("%s: sources was NULL", __func__);
+               return SR_ERR_BUG;
+       }
+
+       for (old = 0; old < session->num_sources; old++) {
+               if (session->sources[old].poll_object == poll_object)
+                       break;
+       }
+
+       /* fd not found, nothing to do */
+       if (old == session->num_sources)
+               return SR_OK;
+
+       session->num_sources -= 1;
+
+       if (old != session->num_sources) {
+               memmove(&session->pollfds[old], &session->pollfds[old+1],
+                       (session->num_sources - old) * sizeof(GPollFD));
+               memmove(&session->sources[old], &session->sources[old+1],
+                       (session->num_sources - old) * sizeof(struct source));
+       }
+
+       new_pollfds = g_try_realloc(session->pollfds, sizeof(GPollFD) * session->num_sources);
+       if (!new_pollfds && session->num_sources > 0) {
+               sr_err("%s: new_pollfds malloc failed", __func__);
+               return SR_ERR_MALLOC;
+       }
+
+       new_sources = g_try_realloc(session->sources, sizeof(struct source) * session->num_sources);
+       if (!new_sources && session->num_sources > 0) {
+               sr_err("%s: new_sources malloc failed", __func__);
+               return SR_ERR_MALLOC;
+       }
+
+       session->pollfds = new_pollfds;
+       session->sources = new_sources;
+
+       return SR_OK;
+}
+
+/**
+ * Remove the source belonging to the specified file descriptor.
+ *
+ * @param fd The file descriptor for which the source should be removed.
+ *
+ * @retval SR_OK Success
+ * @retval SR_ERR_ARG Invalid argument
+ * @retval SR_ERR_MALLOC Memory allocation error.
+ * @retval SR_ERR_BUG Internal error.
+ *
+ * @since 0.3.0
+ */
+SR_API int sr_session_source_remove(struct sr_session *session, int fd)
+{
+       (void) session;
+
+       return _sr_session_source_remove(session, (gintptr)fd);
+}
+
+/**
+ * Remove the source belonging to the specified poll descriptor.
+ *
+ * @param pollfd The poll descriptor for which the source should be removed.
+ *
+ * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments, or
+ *         SR_ERR_MALLOC upon memory allocation errors, SR_ERR_BUG upon
+ *         internal errors.
+ *
+ * @since 0.2.0
+ */
+SR_API int sr_session_source_remove_pollfd(struct sr_session *session,
+               GPollFD *pollfd)
+{
+       (void) session;
+
+       return _sr_session_source_remove(session, (gintptr)pollfd);
+}
+
+/**
+ * Remove the source belonging to the specified channel.
+ *
+ * @param channel The channel for which the source should be removed.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_ARG Invalid argument.
+ * @retval SR_ERR_MALLOC Memory allocation error.
+ * @return SR_ERR_BUG Internal error.
+ *
+ * @since 0.2.0
+ */
+SR_API int sr_session_source_remove_channel(struct sr_session *session,
+               GIOChannel *channel)
+{
+       (void) session;
+
+       return _sr_session_source_remove(session, (gintptr)channel);
+}
+
+/** @} */
diff --git a/src/session_driver.c b/src/session_driver.c
new file mode 100644 (file)
index 0000000..9120ea1
--- /dev/null
@@ -0,0 +1,337 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert@biot.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 <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <zip.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "virtual-session"
+
+/* size of payloads sent across the session bus */
+/** @cond PRIVATE */
+#define CHUNKSIZE (512 * 1024)
+/** @endcond */
+
+SR_PRIV struct sr_dev_driver session_driver_info;
+static struct sr_dev_driver *di = &session_driver_info;
+
+struct session_vdev {
+       char *sessionfile;
+       char *capturefile;
+       struct zip *archive;
+       struct zip_file *capfile;
+       int bytes_read;
+       uint64_t samplerate;
+       int unitsize;
+       int num_channels;
+       int cur_chunk;
+       gboolean finished;
+};
+
+static const int hwcaps[] = {
+       SR_CONF_CAPTUREFILE,
+       SR_CONF_CAPTURE_UNITSIZE,
+       SR_CONF_SAMPLERATE,
+};
+
+static int receive_data(int fd, int revents, void *cb_data)
+{
+       struct sr_dev_inst *sdi;
+       struct session_vdev *vdev;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_logic logic;
+       struct zip_stat zs;
+       int ret, got_data;
+       char capturefile[16];
+       void *buf;
+
+       (void)fd;
+       (void)revents;
+
+       sdi = cb_data;
+       got_data = FALSE;
+       vdev = sdi->priv;
+       if (!vdev->finished) {
+               if (!vdev->capfile) {
+                       /* No capture file opened yet, or finished with the last
+                        * chunked one. */
+                       if (vdev->cur_chunk == 0) {
+                               /* capturefile is always the unchunked base name. */
+                               if (zip_stat(vdev->archive, vdev->capturefile, 0, &zs) != -1) {
+                                       /* No chunks, just a single capture file. */
+                                       vdev->cur_chunk = 0;
+                                       if (!(vdev->capfile = zip_fopen(vdev->archive,
+                                                       vdev->capturefile, 0)))
+                                               return FALSE;
+                                               sr_dbg("Opened %s.", vdev->capturefile);
+                               } else {
+                                       /* Try as first chunk filename. */
+                                       snprintf(capturefile, 15, "%s-1", vdev->capturefile);
+                                       if (zip_stat(vdev->archive, capturefile, 0, &zs) != -1) {
+                                               vdev->cur_chunk = 1;
+                                               if (!(vdev->capfile = zip_fopen(vdev->archive,
+                                                               capturefile, 0)))
+                                                       return FALSE;
+                                               sr_dbg("Opened %s.", capturefile);
+                                       } else {
+                                               sr_err("No capture file '%s' in " "session file '%s'.",
+                                                               vdev->capturefile, vdev->sessionfile);
+                                               return FALSE;
+                                       }
+                               }
+                       } else {
+                               /* Capture data is chunked, advance to the next chunk. */
+                               vdev->cur_chunk++;
+                               snprintf(capturefile, 15, "%s-%d", vdev->capturefile,
+                                               vdev->cur_chunk);
+                               if (zip_stat(vdev->archive, capturefile, 0, &zs) != -1) {
+                                       if (!(vdev->capfile = zip_fopen(vdev->archive,
+                                                       capturefile, 0)))
+                                               return FALSE;
+                                       sr_dbg("Opened %s.", capturefile);
+                               } else {
+                                       /* We got all the chunks, finish up. */
+                                       vdev->finished = TRUE;
+                                       return TRUE;
+                               }
+                       }
+               }
+
+               if (!(buf = g_try_malloc(CHUNKSIZE))) {
+                       sr_err("%s: buf malloc failed", __func__);
+                       return FALSE;
+               }
+
+               ret = zip_fread(vdev->capfile, buf,
+                               CHUNKSIZE / vdev->unitsize * vdev->unitsize);
+               if (ret > 0) {
+                       if (ret % vdev->unitsize != 0)
+                               sr_warn("Read size %d not a multiple of the"
+                                       " unit size %d.", ret, vdev->unitsize);
+                       got_data = TRUE;
+                       packet.type = SR_DF_LOGIC;
+                       packet.payload = &logic;
+                       logic.length = ret;
+                       logic.unitsize = vdev->unitsize;
+                       logic.data = buf;
+                       vdev->bytes_read += ret;
+                       sr_session_send(sdi, &packet);
+               } else {
+                       /* done with this capture file */
+                       zip_fclose(vdev->capfile);
+                       vdev->capfile = NULL;
+                       if (vdev->cur_chunk == 0) {
+                               /* It was the only file. */
+                               vdev->finished = TRUE;
+                       } else {
+                               /* There might be more chunks, so don't fall through
+                                * to the SR_DF_END here. */
+                               g_free(buf);
+                               return TRUE;
+                       }
+               }
+               g_free(buf);
+       }
+
+       if (!got_data) {
+               packet.type = SR_DF_END;
+               sr_session_send(sdi, &packet);
+               sr_session_source_remove(sdi->session, -1);
+       }
+
+       return TRUE;
+}
+
+/* driver callbacks */
+
+static int init(struct sr_context *sr_ctx)
+{
+       return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static int dev_clear(void)
+{
+       struct drv_context *drvc;
+       GSList *l;
+
+       drvc = di->priv;
+       for (l = drvc->instances; l; l = l->next)
+               sr_dev_inst_free(l->data);
+       g_slist_free(drvc->instances);
+       drvc->instances = NULL;
+
+       return SR_OK;
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+       struct drv_context *drvc;
+       struct session_vdev *vdev;
+
+       drvc = di->priv;
+       vdev = g_malloc0(sizeof(struct session_vdev));
+       sdi->priv = vdev;
+       drvc->instances = g_slist_append(drvc->instances, sdi);
+
+       return SR_OK;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+       const struct session_vdev *const vdev = sdi->priv;
+       g_free(vdev->sessionfile);
+       g_free(vdev->capturefile);
+
+       g_free(sdi->priv);
+       sdi->priv = NULL;
+
+       return SR_OK;
+}
+
+static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct session_vdev *vdev;
+
+       (void)cg;
+
+       switch (id) {
+       case SR_CONF_SAMPLERATE:
+               if (sdi) {
+                       vdev = sdi->priv;
+                       *data = g_variant_new_uint64(vdev->samplerate);
+               } else
+                       return SR_ERR;
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       struct session_vdev *vdev;
+
+       (void)cg;
+
+       vdev = sdi->priv;
+
+       switch (id) {
+       case SR_CONF_SAMPLERATE:
+               vdev->samplerate = g_variant_get_uint64(data);
+               sr_info("Setting samplerate to %" PRIu64 ".", vdev->samplerate);
+               break;
+       case SR_CONF_SESSIONFILE:
+               g_free(vdev->sessionfile);
+               vdev->sessionfile = g_strdup(g_variant_get_string(data, NULL));
+               sr_info("Setting sessionfile to '%s'.", vdev->sessionfile);
+               break;
+       case SR_CONF_CAPTUREFILE:
+               g_free(vdev->capturefile);
+               vdev->capturefile = g_strdup(g_variant_get_string(data, NULL));
+               sr_info("Setting capturefile to '%s'.", vdev->capturefile);
+               break;
+       case SR_CONF_CAPTURE_UNITSIZE:
+               vdev->unitsize = g_variant_get_uint64(data);
+               break;
+       case SR_CONF_NUM_LOGIC_CHANNELS:
+               vdev->num_channels = g_variant_get_uint64(data);
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+               const struct sr_channel_group *cg)
+{
+       (void)sdi;
+       (void)cg;
+
+       switch (key) {
+       case SR_CONF_DEVICE_OPTIONS:
+               *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+                               hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+               break;
+       default:
+               return SR_ERR_NA;
+       }
+
+       return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+       struct session_vdev *vdev;
+       int ret;
+
+       (void)cb_data;
+
+       vdev = sdi->priv;
+       vdev->bytes_read = 0;
+       vdev->cur_chunk = 0;
+       vdev->finished = FALSE;
+
+       sr_info("Opening archive %s file %s", vdev->sessionfile,
+               vdev->capturefile);
+
+       if (!(vdev->archive = zip_open(vdev->sessionfile, 0, &ret))) {
+               sr_err("Failed to open session file '%s': "
+                      "zip error %d.", vdev->sessionfile, ret);
+               return SR_ERR;
+       }
+
+       /* Send header packet to the session bus. */
+       std_session_send_df_header(sdi, LOG_PREFIX);
+
+       /* freewheeling source */
+       sr_session_source_add(sdi->session, -1, 0, 0, receive_data, (void *)sdi);
+
+       return SR_OK;
+}
+
+/** @private */
+SR_PRIV struct sr_dev_driver session_driver = {
+       .name = "virtual-session",
+       .longname = "Session-emulating driver",
+       .api_version = 1,
+       .init = init,
+       .cleanup = dev_clear,
+       .scan = NULL,
+       .dev_list = NULL,
+       .dev_clear = dev_clear,
+       .config_get = config_get,
+       .config_set = config_set,
+       .config_list = config_list,
+       .dev_open = dev_open,
+       .dev_close = dev_close,
+       .dev_acquisition_start = dev_acquisition_start,
+       .dev_acquisition_stop = NULL,
+       .priv = NULL,
+};
diff --git a/src/session_file.c b/src/session_file.c
new file mode 100644 (file)
index 0000000..1c1cee5
--- /dev/null
@@ -0,0 +1,508 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert@biot.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 <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <zip.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+#include "config.h" /* Needed for PACKAGE_VERSION and others. */
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+/** @cond PRIVATE */
+#define LOG_PREFIX "session-file"
+/** @endcond */
+
+/**
+ * @file
+ *
+ * Loading and saving libsigrok session files.
+ */
+
+/**
+ * @addtogroup grp_session
+ *
+ * @{
+ */
+
+extern struct sr_session *session;
+extern SR_PRIV struct sr_dev_driver session_driver;
+
+/** @private */
+SR_PRIV int sr_sessionfile_check(const char *filename)
+{
+       struct stat st;
+       struct zip *archive;
+       struct zip_file *zf;
+       struct zip_stat zs;
+       int version, ret;
+       char s[11];
+
+       if (!filename)
+               return SR_ERR_ARG;
+
+       if (stat(filename, &st) == -1) {
+               sr_err("Couldn't stat %s: %s", filename, strerror(errno));
+               return SR_ERR;
+       }
+
+       if (!(archive = zip_open(filename, 0, &ret)))
+               /* No logging: this can be used just to check if it's
+                * a sigrok session file or not. */
+               return SR_ERR;
+
+       /* check "version" */
+       version = 0;
+       if (!(zf = zip_fopen(archive, "version", 0))) {
+               sr_dbg("Not a sigrok session file: no version found.");
+               return SR_ERR;
+       }
+       if ((ret = zip_fread(zf, s, 10)) == -1)
+               return SR_ERR;
+       zip_fclose(zf);
+       s[ret] = 0;
+       version = strtoull(s, NULL, 10);
+       if (version > 2) {
+               sr_dbg("Cannot handle sigrok session file version %d.", version);
+               return SR_ERR;
+       }
+       sr_spew("Detected sigrok session file version %d.", version);
+
+       /* read "metadata" */
+       if (zip_stat(archive, "metadata", 0, &zs) == -1) {
+               sr_dbg("Not a valid sigrok session file.");
+               return SR_ERR;
+       }
+
+       return SR_OK;
+}
+
+/**
+ * Load the session from the specified filename.
+ *
+ * @param filename The name of the session file to load. Must not be NULL.
+ *
+ * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments,
+ *         SR_ERR_MALLOC upon memory allocation errors, or SR_ERR upon
+ *         other errors.
+ */
+SR_API int sr_session_load(const char *filename, struct sr_session **session)
+{
+       GKeyFile *kf;
+       GPtrArray *capturefiles;
+       struct zip *archive;
+       struct zip_file *zf;
+       struct zip_stat zs;
+       struct sr_dev_inst *sdi;
+       struct sr_channel *ch;
+       int devcnt, ret, i, j;
+       uint64_t tmp_u64, total_channels, enabled_channels, p;
+       char **sections, **keys, *metafile, *val;
+       char channelname[SR_MAX_CHANNELNAME_LEN + 1];
+
+       if ((ret = sr_sessionfile_check(filename)) != SR_OK)
+               return ret;
+
+       if (!(archive = zip_open(filename, 0, &ret)))
+               return SR_ERR;
+
+       if (zip_stat(archive, "metadata", 0, &zs) == -1)
+               return SR_ERR;
+
+       if (!(metafile = g_try_malloc(zs.size))) {
+               sr_err("%s: metafile malloc failed", __func__);
+               return SR_ERR_MALLOC;
+       }
+
+       zf = zip_fopen_index(archive, zs.index, 0);
+       zip_fread(zf, metafile, zs.size);
+       zip_fclose(zf);
+
+       kf = g_key_file_new();
+       if (!g_key_file_load_from_data(kf, metafile, zs.size, 0, NULL)) {
+               sr_dbg("Failed to parse metadata.");
+               return SR_ERR;
+       }
+
+       if ((ret = sr_session_new(session)) != SR_OK)
+               return ret;
+
+       devcnt = 0;
+       capturefiles = g_ptr_array_new_with_free_func(g_free);
+       sections = g_key_file_get_groups(kf, NULL);
+       for (i = 0; sections[i]; i++) {
+               if (!strcmp(sections[i], "global"))
+                       /* nothing really interesting in here yet */
+                       continue;
+               if (!strncmp(sections[i], "device ", 7)) {
+                       /* device section */
+                       sdi = NULL;
+                       enabled_channels = total_channels = 0;
+                       keys = g_key_file_get_keys(kf, sections[i], NULL, NULL);
+                       for (j = 0; keys[j]; j++) {
+                               val = g_key_file_get_string(kf, sections[i], keys[j], NULL);
+                               if (!strcmp(keys[j], "capturefile")) {
+                                       sdi = sr_dev_inst_new(devcnt, SR_ST_ACTIVE, NULL, NULL, NULL);
+                                       sdi->driver = &session_driver;
+                                       if (devcnt == 0)
+                                               /* first device, init the driver */
+                                               sdi->driver->init(NULL);
+                                       sr_dev_open(sdi);
+                                       sr_session_dev_add(*session, sdi);
+                                       sdi->driver->config_set(SR_CONF_SESSIONFILE,
+                                                       g_variant_new_string(filename), sdi, NULL);
+                                       sdi->driver->config_set(SR_CONF_CAPTUREFILE,
+                                                       g_variant_new_string(val), sdi, NULL);
+                                       g_ptr_array_add(capturefiles, val);
+                               } else if (!strcmp(keys[j], "samplerate")) {
+                                       sr_parse_sizestring(val, &tmp_u64);
+                                       sdi->driver->config_set(SR_CONF_SAMPLERATE,
+                                                       g_variant_new_uint64(tmp_u64), sdi, NULL);
+                               } else if (!strcmp(keys[j], "unitsize")) {
+                                       tmp_u64 = strtoull(val, NULL, 10);
+                                       sdi->driver->config_set(SR_CONF_CAPTURE_UNITSIZE,
+                                                       g_variant_new_uint64(tmp_u64), sdi, NULL);
+                               } else if (!strcmp(keys[j], "total probes")) {
+                                       total_channels = strtoull(val, NULL, 10);
+                                       sdi->driver->config_set(SR_CONF_NUM_LOGIC_CHANNELS,
+                                                       g_variant_new_uint64(total_channels), sdi, NULL);
+                                       for (p = 0; p < total_channels; p++) {
+                                               snprintf(channelname, SR_MAX_CHANNELNAME_LEN, "%" PRIu64, p);
+                                               if (!(ch = sr_channel_new(p, SR_CHANNEL_LOGIC, TRUE,
+                                                               channelname)))
+                                                       return SR_ERR;
+                                               sdi->channels = g_slist_append(sdi->channels, ch);
+                                       }
+                               } else if (!strncmp(keys[j], "probe", 5)) {
+                                       if (!sdi)
+                                               continue;
+                                       enabled_channels++;
+                                       tmp_u64 = strtoul(keys[j]+5, NULL, 10);
+                                       /* sr_session_save() */
+                                       sr_dev_channel_name_set(sdi, tmp_u64 - 1, val);
+                               }
+                       }
+                       g_strfreev(keys);
+                       /* Disable channels not specifically listed. */
+                       if (total_channels)
+                               for (p = enabled_channels; p < total_channels; p++)
+                                       sr_dev_channel_enable(sdi, p, FALSE);
+               }
+               devcnt++;
+       }
+       g_strfreev(sections);
+       g_key_file_free(kf);
+
+       return SR_OK;
+}
+
+/**
+ * Save a session to the specified file.
+ *
+ * @param filename The name of the filename to save the session as.
+ *                 Must not be NULL.
+ * @param sdi The device instance from which the data was captured.
+ * @param buf The data to be saved.
+ * @param unitsize The number of bytes per sample.
+ * @param units The number of samples.
+ *
+ * @retval SR_OK Success
+ * @retval SR_ERR_ARG Invalid arguments
+ * @retval SR_ERR Other errors
+ *
+ * @since 0.2.0
+ */
+SR_API int sr_session_save(struct sr_session *session, const char *filename,
+               const struct sr_dev_inst *sdi, unsigned char *buf, int unitsize,
+               int units)
+{
+       struct sr_channel *ch;
+       GSList *l;
+       GVariant *gvar;
+       uint64_t samplerate;
+       int cnt, ret;
+       char **channel_names;
+
+       samplerate = 0;
+       if (sr_dev_has_option(sdi, SR_CONF_SAMPLERATE)) {
+               if (sr_config_get(sdi->driver, sdi, NULL,
+                                       SR_CONF_SAMPLERATE, &gvar) == SR_OK) {
+                       samplerate = g_variant_get_uint64(gvar);
+                       g_variant_unref(gvar);
+               }
+       }
+
+       channel_names = g_malloc0(sizeof(char *) * (g_slist_length(sdi->channels) + 1));
+       cnt = 0;
+       for (l = sdi->channels; l; l = l->next) {
+               ch = l->data;
+               if (ch->type != SR_CHANNEL_LOGIC)
+                       continue;
+               if (ch->enabled != TRUE)
+                       continue;
+               if (!ch->name)
+                       continue;
+               /* Just borrowing the ptr. */
+               channel_names[cnt++] = ch->name;
+       }
+
+       if ((ret = sr_session_save_init(session, filename, samplerate,
+                       channel_names)) != SR_OK)
+               return ret;
+
+       ret = sr_session_append(session, filename, buf, unitsize, units);
+
+       return ret;
+}
+
+/**
+ * Initialize a saved session file.
+ *
+ * @param filename The name of the filename to save the session as.
+ *                 Must not be NULL.
+ * @param samplerate The samplerate to store for this session.
+ * @param channels A NULL-terminated array of strings containing the names
+ * of all the channels active in this session.
+ *
+ * @retval SR_OK Success
+ * @retval SR_ERR_ARG Invalid arguments
+ * @retval SR_ERR Other errors
+ *
+ * @since 0.3.0
+ */
+SR_API int sr_session_save_init(struct sr_session *session,
+               const char *filename, uint64_t samplerate, char **channels)
+{
+       FILE *meta;
+       struct zip *zipfile;
+       struct zip_source *versrc, *metasrc;
+       int tmpfile, cnt, ret, i;
+       char version[1], metafile[32], *s;
+
+       (void) session;
+
+       if (!filename) {
+               sr_err("%s: filename was NULL", __func__);
+               return SR_ERR_ARG;
+       }
+
+       /* Quietly delete it first, libzip wants replace ops otherwise. */
+       unlink(filename);
+       if (!(zipfile = zip_open(filename, ZIP_CREATE, &ret)))
+               return SR_ERR;
+
+       /* "version" */
+       version[0] = '2';
+       if (!(versrc = zip_source_buffer(zipfile, version, 1, 0)))
+               return SR_ERR;
+       if (zip_add(zipfile, "version", versrc) == -1) {
+               sr_info("error saving version into zipfile: %s",
+                       zip_strerror(zipfile));
+               return SR_ERR;
+       }
+
+       /* init "metadata" */
+       strcpy(metafile, "sigrok-meta-XXXXXX");
+       if ((tmpfile = g_mkstemp(metafile)) == -1)
+               return SR_ERR;
+       close(tmpfile);
+       meta = g_fopen(metafile, "wb");
+       fprintf(meta, "[global]\n");
+       fprintf(meta, "sigrok version = %s\n", PACKAGE_VERSION);
+
+       /* metadata */
+       fprintf(meta, "[device 1]\n");
+
+       /* metadata */
+       fprintf(meta, "capturefile = logic-1\n");
+       cnt = 0;
+       for (i = 0; channels[i]; i++)
+               cnt++;
+       fprintf(meta, "total probes = %d\n", cnt);
+       s = sr_samplerate_string(samplerate);
+       fprintf(meta, "samplerate = %s\n", s);
+       g_free(s);
+
+       for (i = 0; channels[i]; i++)
+               fprintf(meta, "probe%d = %s\n", i + 1, channels[i]);
+
+       fclose(meta);
+
+       if (!(metasrc = zip_source_file(zipfile, metafile, 0, -1))) {
+               unlink(metafile);
+               return SR_ERR;
+       }
+       if (zip_add(zipfile, "metadata", metasrc) == -1) {
+               unlink(metafile);
+               return SR_ERR;
+       }
+
+       if ((ret = zip_close(zipfile)) == -1) {
+               sr_info("error saving zipfile: %s", zip_strerror(zipfile));
+               unlink(metafile);
+               return SR_ERR;
+       }
+
+       unlink(metafile);
+
+       return SR_OK;
+}
+
+/**
+ * Append data to an existing session file.
+ *
+ * The session file must have been created with sr_session_save_init()
+ * or sr_session_save() beforehand.
+ *
+ * @param filename The name of the filename to append to. Must not be NULL.
+ * @param buf The data to be appended.
+ * @param unitsize The number of bytes per sample.
+ * @param units The number of samples.
+ *
+ * @retval SR_OK Success
+ * @retval SR_ERR_ARG Invalid arguments
+ * @retval SR_ERR Other errors
+ *
+ * @since 0.3.0
+ */
+SR_API int sr_session_append(struct sr_session *session, const char *filename,
+               unsigned char *buf, int unitsize, int units)
+{
+       struct zip *archive;
+       struct zip_source *logicsrc;
+       zip_int64_t num_files;
+       struct zip_file *zf;
+       struct zip_stat zs;
+       struct zip_source *metasrc;
+       GKeyFile *kf;
+       GError *error;
+       gsize len;
+       int chunk_num, next_chunk_num, tmpfile, ret, i;
+       const char *entry_name;
+       char *metafile, tmpname[32], chunkname[16];
+
+       (void) session;
+
+       if ((ret = sr_sessionfile_check(filename)) != SR_OK)
+               return ret;
+
+       if (!(archive = zip_open(filename, 0, &ret)))
+               return SR_ERR;
+
+       if (zip_stat(archive, "metadata", 0, &zs) == -1)
+               return SR_ERR;
+
+       metafile = g_malloc(zs.size);
+       zf = zip_fopen_index(archive, zs.index, 0);
+       zip_fread(zf, metafile, zs.size);
+       zip_fclose(zf);
+
+       /*
+        * If the file was only initialized but doesn't yet have any
+        * data it in, it won't have a unitsize field in metadata yet.
+        */
+       error = NULL;
+       kf = g_key_file_new();
+       if (!g_key_file_load_from_data(kf, metafile, zs.size, 0, &error)) {
+               sr_err("Failed to parse metadata: %s.", error->message);
+               return SR_ERR;
+       }
+       g_free(metafile);
+       tmpname[0] = '\0';
+       if (!g_key_file_has_key(kf, "device 1", "unitsize", &error)) {
+               if (error && error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND) {
+                       sr_err("Failed to check unitsize key: %s", error ? error->message : "?");
+                       return SR_ERR;
+               }
+               /* Add unitsize field. */
+               g_key_file_set_integer(kf, "device 1", "unitsize", unitsize);
+               metafile = g_key_file_to_data(kf, &len, &error);
+               strcpy(tmpname, "sigrok-meta-XXXXXX");
+               if ((tmpfile = g_mkstemp(tmpname)) == -1)
+                       return SR_ERR;
+               if (write(tmpfile, metafile, len) < 0) {
+                       sr_dbg("Failed to create new metadata: %s", strerror(errno));
+                       g_free(metafile);
+                       unlink(tmpname);
+                       return SR_ERR;
+               }
+               close(tmpfile);
+               if (!(metasrc = zip_source_file(archive, tmpname, 0, -1))) {
+                       sr_err("Failed to create zip source for metadata.");
+                       g_free(metafile);
+                       unlink(tmpname);
+                       return SR_ERR;
+               }
+               if (zip_replace(archive, zs.index, metasrc) == -1) {
+                       sr_err("Failed to replace metadata file.");
+                       g_free(metafile);
+                       unlink(tmpname);
+                       return SR_ERR;
+               }
+               g_free(metafile);
+       }
+       g_key_file_free(kf);
+
+       next_chunk_num = 1;
+       num_files = zip_get_num_entries(archive, 0);
+       for (i = 0; i < num_files; i++) {
+               entry_name = zip_get_name(archive, i, 0);
+               if (strncmp(entry_name, "logic-1", 7))
+                       continue;
+               if (strlen(entry_name) == 7) {
+                       /* This file has no extra chunks, just a single "logic-1".
+                        * Rename it to "logic-1-1" * and continue with chunk 2. */
+                       if (zip_rename(archive, i, "logic-1-1") == -1) {
+                               sr_err("Failed to rename 'logic-1' to 'logic-1-1'.");
+                               unlink(tmpname);
+                               return SR_ERR;
+                       }
+                       next_chunk_num = 2;
+                       break;
+               } else if (strlen(entry_name) > 8 && entry_name[7] == '-') {
+                       chunk_num = strtoull(entry_name + 8, NULL, 10);
+                       if (chunk_num >= next_chunk_num)
+                               next_chunk_num = chunk_num + 1;
+               }
+       }
+       snprintf(chunkname, 15, "logic-1-%d", next_chunk_num);
+       if (!(logicsrc = zip_source_buffer(archive, buf, units * unitsize, FALSE))) {
+               unlink(tmpname);
+               return SR_ERR;
+       }
+       if (zip_add(archive, chunkname, logicsrc) == -1) {
+               unlink(tmpname);
+               return SR_ERR;
+       }
+       if ((ret = zip_close(archive)) == -1) {
+               sr_info("error saving session file: %s", zip_strerror(archive));
+               unlink(tmpname);
+               return SR_ERR;
+       }
+       unlink(tmpname);
+
+       return SR_OK;
+}
+
+/** @} */
diff --git a/src/soft-trigger.c b/src/soft-trigger.c
new file mode 100644 (file)
index 0000000..386f8cc
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Bert Vermeulen <bert@biot.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 <string.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+/* @cond PRIVATE */
+#define LOG_PREFIX "soft-trigger"
+/* @endcond */
+
+SR_PRIV struct soft_trigger_logic *soft_trigger_logic_new(
+               const struct sr_dev_inst *sdi, struct sr_trigger *trigger)
+{
+       struct soft_trigger_logic *stl;
+
+       stl = g_malloc0(sizeof(struct soft_trigger_logic));
+       stl->sdi = sdi;
+       stl->trigger = trigger;
+       stl->unitsize = (g_slist_length(sdi->channels) + 7) / 8;
+       stl->prev_sample = g_malloc0(stl->unitsize);
+
+       return stl;
+}
+
+SR_PRIV void soft_trigger_logic_free(struct soft_trigger_logic *stl)
+{
+       g_free(stl->prev_sample);
+       g_free(stl);
+}
+
+static gboolean logic_check_match(struct soft_trigger_logic *stl,
+               uint8_t *sample, struct sr_trigger_match *match)
+{
+       int bit, prev_bit;
+       gboolean result;
+
+       stl->count++;
+       result = FALSE;
+       bit = *(sample + match->channel->index / 8)
+                       & (1 << (match->channel->index % 8));
+       if (match->match == SR_TRIGGER_ZERO)
+               result = bit == 0;
+       else if (match->match == SR_TRIGGER_ONE)
+               result = bit != 0;
+       else {
+               /* Edge matches. */
+               if (stl->count == 1)
+                       /* First sample, don't have enough for an edge match yet. */
+                       return FALSE;
+               prev_bit = *(stl->prev_sample + match->channel->index / 8)
+                               & (1 << (match->channel->index % 8));
+               if (match->match == SR_TRIGGER_RISING)
+                       result = prev_bit == 0 && bit != 0;
+               else if (match->match == SR_TRIGGER_FALLING)
+                       result = prev_bit != 0 && bit == 0;
+               else if (match->match == SR_TRIGGER_EDGE)
+                       result = prev_bit != bit;
+       }
+
+       return result;
+}
+
+/* Returns the offset (in samples) within buf of where the trigger
+ * occurred, or -1 if not triggered. */
+SR_PRIV int soft_trigger_logic_check(struct soft_trigger_logic *stl,
+               uint8_t *buf, int len)
+{
+       struct sr_datafeed_packet packet;
+       struct sr_trigger_stage *stage;
+       struct sr_trigger_match *match;
+       GSList *l, *l_stage;
+       int offset;
+       int i;
+       gboolean match_found;
+
+       offset = -1;
+       for (i = 0; i < len; i += stl->unitsize) {
+               l_stage = g_slist_nth(stl->trigger->stages, stl->cur_stage);
+               stage = l_stage->data;
+               if (!stage->matches)
+                       /* No matches supplied, client error. */
+                       return SR_ERR_ARG;
+
+               match_found = TRUE;
+               for (l = stage->matches; l; l = l->next) {
+                       match = l->data;
+                       if (!match->channel->enabled)
+                               /* Ignore disabled channels with a trigger. */
+                               continue;
+                       if (!logic_check_match(stl, buf + i, match)) {
+                               match_found = FALSE;
+                               break;
+                       }
+               }
+               memcpy(stl->prev_sample, buf + i, stl->unitsize);
+               if (match_found) {
+                       /* Matched on the current stage. */
+                       if (l_stage->next) {
+                               /* Advance to next stage. */
+                               stl->cur_stage++;
+                       } else {
+                               /* Matched on last stage, fire trigger. */
+                               offset = i / stl->unitsize;
+
+                               packet.type = SR_DF_TRIGGER;
+                               packet.payload = NULL;
+                               sr_session_send(stl->sdi, &packet);
+                               break;
+                       }
+               } else if (stl->cur_stage > 0) {
+                       /*
+                        * We had a match at an earlier stage, but failed on the
+                        * current stage. However, we may have a match on this
+                        * stage in the next bit -- trigger on 0001 will fail on
+                        * seeing 00001, so we need to go back to stage 0 -- but
+                        * at the next sample from the one that matched originally,
+                        * which the counter increment at the end of the loop
+                        * takes care of.
+                        */
+                       i -= stl->cur_stage * stl->unitsize;
+                       if (i < -1)
+                               i = -1; /* Oops, went back past this buffer. */
+                       /* Reset trigger stage. */
+                       stl->cur_stage = 0;
+               }
+       }
+
+       return offset;
+}
+
diff --git a/src/std.c b/src/std.c
new file mode 100644 (file)
index 0000000..2319dfe
--- /dev/null
+++ b/src/std.c
@@ -0,0 +1,291 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/** @file
+  * Standard API helper functions.
+  * @internal
+  */
+
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "std"
+
+/**
+ * Standard sr_driver_init() API helper.
+ *
+ * This function can be used to simplify most driver's init() API callback.
+ *
+ * It creates a new 'struct drv_context' (drvc), assigns sr_ctx to it, and
+ * then 'drvc' is assigned to the 'struct sr_dev_driver' (di) that is passed.
+ *
+ * @param sr_ctx The libsigrok context to assign.
+ * @param di The driver instance to use.
+ * @param[in] prefix A driver-specific prefix string used for log messages.
+ *
+ * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments, or
+ *         SR_ERR_MALLOC upon memory allocation errors.
+ */
+SR_PRIV int std_init(struct sr_context *sr_ctx, struct sr_dev_driver *di,
+                    const char *prefix)
+{
+       struct drv_context *drvc;
+
+       if (!di) {
+               sr_err("%s: Invalid driver, cannot initialize.", prefix);
+               return SR_ERR_ARG;
+       }
+
+       if (!(drvc = g_try_malloc(sizeof(struct drv_context)))) {
+               sr_err("%s: Driver context malloc failed.", prefix);
+               return SR_ERR_MALLOC;
+       }
+
+       drvc->sr_ctx = sr_ctx;
+       drvc->instances = NULL;
+       di->priv = drvc;
+
+       return SR_OK;
+}
+
+/**
+ * Standard API helper for sending an SR_DF_HEADER packet.
+ *
+ * This function can be used to simplify most driver's
+ * dev_acquisition_start() API callback.
+ *
+ * @param sdi The device instance to use.
+ * @param prefix A driver-specific prefix string used for log messages.
+ *              Must not be NULL. An empty string is allowed.
+ *
+ * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments, or
+ *         SR_ERR upon other errors.
+ */
+SR_PRIV int std_session_send_df_header(const struct sr_dev_inst *sdi,
+                                      const char *prefix)
+{
+       int ret;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_header header;
+
+       if (!prefix) {
+               sr_err("Invalid prefix.");
+               return SR_ERR_ARG;
+       }
+
+       sr_dbg("%s: Starting acquisition.", prefix);
+
+       /* Send header packet to the session bus. */
+       sr_dbg("%s: Sending SR_DF_HEADER packet.", prefix);
+       packet.type = SR_DF_HEADER;
+       packet.payload = (uint8_t *)&header;
+       header.feed_version = 1;
+       gettimeofday(&header.starttime, NULL);
+
+       if ((ret = sr_session_send(sdi, &packet)) < 0) {
+               sr_err("%s: Failed to send header packet: %d.", prefix, ret);
+               return ret;
+       }
+
+       return SR_OK;
+}
+
+#ifdef HAVE_LIBSERIALPORT
+
+/**
+ * Standard serial driver dev_open() helper.
+ *
+ * This function can be used to implement the dev_open() driver API
+ * callback in drivers that use a serial port. The port is opened
+ * with the SERIAL_RDWR and SERIAL_NONBLOCK flags.
+ *
+ * If the open succeeded, the status field of the given sdi is set
+ * to SR_ST_ACTIVE.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR Serial port open failed.
+ */
+SR_PRIV int std_serial_dev_open(struct sr_dev_inst *sdi)
+{
+       struct sr_serial_dev_inst *serial;
+
+       serial = sdi->conn;
+       if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
+               return SR_ERR;
+
+       sdi->status = SR_ST_ACTIVE;
+
+       return SR_OK;
+}
+
+/**
+ * Standard serial driver dev_close() helper.
+ *
+ * This function can be used to implement the dev_close() driver API
+ * callback in drivers that use a serial port.
+ *
+ * After closing the port, the status field of the given sdi is set
+ * to SR_ST_INACTIVE.
+ *
+ * @retval SR_OK Success.
+ */
+SR_PRIV int std_serial_dev_close(struct sr_dev_inst *sdi)
+{
+       struct sr_serial_dev_inst *serial;
+
+       serial = sdi->conn;
+       if (serial && sdi->status == SR_ST_ACTIVE) {
+               serial_close(serial);
+               sdi->status = SR_ST_INACTIVE;
+       }
+
+       return SR_OK;
+}
+
+/**
+ * Standard sr_session_stop() API helper.
+ *
+ * This function can be used to simplify most (serial port based) driver's
+ * dev_acquisition_stop() API callback.
+ *
+ * @param sdi The device instance for which acquisition should stop.
+ *            Must not be NULL.
+ * @param cb_data Opaque 'cb_data' pointer. Must not be NULL.
+ * @param dev_close_fn Function pointer to the driver's dev_close().
+ *                       Must not be NULL.
+ * @param serial The serial device instance (struct serial_dev_inst *).
+ *               Must not be NULL.
+ * @param[in] prefix A driver-specific prefix string used for log messages.
+ *               Must not be NULL. An empty string is allowed.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_ARG Invalid arguments.
+ * @retval SR_ERR_DEV_CLOSED Device is closed.
+ * @retval SR_ERR Other errors.
+ */
+SR_PRIV int std_serial_dev_acquisition_stop(struct sr_dev_inst *sdi,
+                       void *cb_data, dev_close_callback dev_close_fn,
+                       struct sr_serial_dev_inst *serial, const char *prefix)
+{
+       int ret;
+       struct sr_datafeed_packet packet;
+
+       if (!prefix) {
+               sr_err("Invalid prefix.");
+               return SR_ERR_ARG;
+       }
+
+       if (sdi->status != SR_ST_ACTIVE) {
+               sr_err("%s: Device inactive, can't stop acquisition.", prefix);
+               return SR_ERR_DEV_CLOSED;
+       }
+
+       sr_dbg("%s: Stopping acquisition.", prefix);
+
+       if ((ret = serial_source_remove(sdi->session, serial)) < 0) {
+               sr_err("%s: Failed to remove source: %d.", prefix, ret);
+               return ret;
+       }
+
+       if ((ret = dev_close_fn(sdi)) < 0) {
+               sr_err("%s: Failed to close device: %d.", prefix, ret);
+               return ret;
+       }
+
+       /* Send SR_DF_END packet to the session bus. */
+       sr_dbg("%s: Sending SR_DF_END packet.", prefix);
+       packet.type = SR_DF_END;
+       packet.payload = NULL;
+       if ((ret = sr_session_send(cb_data, &packet)) < 0) {
+               sr_err("%s: Failed to send SR_DF_END packet: %d.", prefix, ret);
+               return ret;
+       }
+
+       return SR_OK;
+}
+
+#endif
+
+/**
+ * Standard driver dev_clear() helper.
+ *
+ * Clear driver, this means, close all instances.
+ *
+ * This function can be used to implement the dev_clear() driver API
+ * callback. dev_close() is called before every sr_dev_inst is cleared.
+ *
+ * The only limitation is driver-specific device contexts (sdi->priv).
+ * These are freed, but any dynamic allocation within structs stored
+ * there cannot be freed.
+ *
+ * @param driver The driver which will have its instances released.
+ * @param clear_private If not NULL, this points to a function called
+ * with sdi->priv as argument. The function can then clear any device
+ * instance-specific resources kept there. It must also clear the struct
+ * pointed to by sdi->priv.
+ *
+ * @return SR_OK on success.
+ */
+SR_PRIV int std_dev_clear(const struct sr_dev_driver *driver,
+               std_dev_clear_callback clear_private)
+{
+       struct drv_context *drvc;
+       struct sr_dev_inst *sdi;
+       GSList *l;
+       int ret;
+
+       if (!(drvc = driver->priv))
+               /* Driver was never initialized, nothing to do. */
+               return SR_OK;
+
+       ret = SR_OK;
+       for (l = drvc->instances; l; l = l->next) {
+               if (!(sdi = l->data)) {
+                       ret = SR_ERR_BUG;
+                       continue;
+               }
+               if (driver->dev_close)
+                       driver->dev_close(sdi);
+
+               if (sdi->conn) {
+#ifdef HAVE_LIBSERIALPORT
+                       if (sdi->inst_type == SR_INST_SERIAL)
+                               sr_serial_dev_inst_free(sdi->conn);
+#endif
+#ifdef HAVE_LIBUSB_1_0
+                       if (sdi->inst_type == SR_INST_USB)
+                               sr_usb_dev_inst_free(sdi->conn);
+#endif
+                       if (sdi->inst_type == SR_INST_SCPI)
+                               sr_scpi_free(sdi->conn);
+               }
+               if (clear_private)
+                       clear_private(sdi->priv);
+               else
+                       g_free(sdi->priv);
+               sr_dev_inst_free(sdi);
+       }
+
+       g_slist_free(drvc->instances);
+       drvc->instances = NULL;
+
+       return ret;
+}
diff --git a/src/strutil.c b/src/strutil.c
new file mode 100644 (file)
index 0000000..54dc1f3
--- /dev/null
@@ -0,0 +1,553 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+/** @cond PRIVATE */
+#define LOG_PREFIX "strutil"
+/** @endcond */
+
+/**
+ * @file
+ *
+ * Helper functions for handling or converting libsigrok-related strings.
+ */
+
+/**
+ * @defgroup grp_strutil String utilities
+ *
+ * Helper functions for handling or converting libsigrok-related strings.
+ *
+ * @{
+ */
+
+/**
+ * @private
+ *
+ * Convert a string representation of a numeric value (base 10) to a long integer. The
+ * conversion is strict and will fail if the complete string does not represent
+ * a valid long integer. The function sets errno according to the details of the
+ * failure.
+ *
+ * @param str The string representation to convert.
+ * @param ret Pointer to long where the result of the conversion will be stored.
+ *
+ * @retval SR_OK Conversion successful.
+ * @retval SR_ERR Failure.
+ *
+ * @since 0.3.0
+ */
+SR_PRIV int sr_atol(const char *str, long *ret)
+{
+       long tmp;
+       char *endptr = NULL;
+
+       errno = 0;
+       tmp = strtol(str, &endptr, 10);
+
+       if (!endptr || *endptr || errno) {
+               if (!errno)
+                       errno = EINVAL;
+               return SR_ERR;
+       }
+
+       *ret = tmp;
+       return SR_OK;
+}
+
+/**
+ * @private
+ *
+ * Convert a string representation of a numeric value (base 10) to an integer. The
+ * conversion is strict and will fail if the complete string does not represent
+ * a valid integer. The function sets errno according to the details of the
+ * failure.
+ *
+ * @param str The string representation to convert.
+ * @param ret Pointer to int where the result of the conversion will be stored.
+ *
+ * @retval SR_OK Conversion successful.
+ * @retval SR_ERR Failure.
+ *
+ * @since 0.3.0
+ */
+SR_PRIV int sr_atoi(const char *str, int *ret)
+{
+       long tmp;
+
+       if (sr_atol(str, &tmp) != SR_OK)
+               return SR_ERR;
+
+       if ((int) tmp != tmp) {
+               errno = ERANGE;
+               return SR_ERR;
+       }
+
+       *ret = (int) tmp;
+       return SR_OK;
+}
+
+/**
+ * @private
+ *
+ * Convert a string representation of a numeric value to a double. The
+ * conversion is strict and will fail if the complete string does not represent
+ * a valid double. The function sets errno according to the details of the
+ * failure.
+ *
+ * @param str The string representation to convert.
+ * @param ret Pointer to double where the result of the conversion will be stored.
+ *
+ * @retval SR_OK Conversion successful.
+ * @retval SR_ERR Failure.
+ *
+ * @since 0.3.0
+ */
+SR_PRIV int sr_atod(const char *str, double *ret)
+{
+       double tmp;
+       char *endptr = NULL;
+
+       errno = 0;
+       tmp = strtof(str, &endptr);
+
+       if (!endptr || *endptr || errno) {
+               if (!errno)
+                       errno = EINVAL;
+               return SR_ERR;
+       }
+
+       *ret = tmp;
+       return SR_OK;
+}
+
+/**
+ * @private
+ *
+ * Convert a string representation of a numeric value to a float. The
+ * conversion is strict and will fail if the complete string does not represent
+ * a valid float. The function sets errno according to the details of the
+ * failure.
+ *
+ * @param str The string representation to convert.
+ * @param ret Pointer to float where the result of the conversion will be stored.
+ *
+ * @retval SR_OK Conversion successful.
+ * @retval SR_ERR Failure.
+ *
+ * @since 0.3.0
+ */
+SR_PRIV int sr_atof(const char *str, float *ret)
+{
+       double tmp;
+
+       if (sr_atod(str, &tmp) != SR_OK)
+               return SR_ERR;
+
+       if ((float) tmp != tmp) {
+               errno = ERANGE;
+               return SR_ERR;
+       }
+
+       *ret = (float) tmp;
+       return SR_OK;
+}
+
+/**
+ * @private
+ *
+ * Convert a string representation of a numeric value to a float. The
+ * conversion is strict and will fail if the complete string does not represent
+ * a valid float. The function sets errno according to the details of the
+ * failure. This version ignores the locale.
+ *
+ * @param str The string representation to convert.
+ * @param ret Pointer to float where the result of the conversion will be stored.
+ *
+ * @retval SR_OK Conversion successful.
+ * @retval SR_ERR Failure.
+ *
+ * @since 0.3.0
+ */
+SR_PRIV int sr_atof_ascii(const char *str, float *ret)
+{
+       double tmp;
+       char *endptr = NULL;
+
+       errno = 0;
+       tmp = g_ascii_strtod(str, &endptr);
+
+       if (!endptr || *endptr || errno) {
+               if (!errno)
+                       errno = EINVAL;
+               return SR_ERR;
+       }
+
+       /* FIXME This fails unexpectedly. Some other method to safel downcast
+        * needs to be found. Checking against FLT_MAX doesn't work as well. */
+       /*
+       if ((float) tmp != tmp) {
+               errno = ERANGE;
+               sr_dbg("ERANGEEEE %e != %e", (float) tmp, tmp);
+               return SR_ERR;
+       }
+       */
+
+       *ret = (float) tmp;
+       return SR_OK;
+}
+
+/**
+ * Convert a numeric value value to its "natural" string representation
+ * in SI units.
+ *
+ * E.g. a value of 3000000, with units set to "W", would be converted
+ * to "3 MW", 20000 to "20 kW", 31500 would become "31.5 kW".
+ *
+ * @param x The value to convert.
+ * @param unit The unit to append to the string, or NULL if the string
+ *             has no units.
+ *
+ * @return A g_try_malloc()ed string representation of the samplerate value,
+ *         or NULL upon errors. The caller is responsible to g_free() the
+ *         memory.
+ *
+ * @since 0.2.0
+ */
+SR_API char *sr_si_string_u64(uint64_t x, const char *unit)
+{
+       uint8_t i;
+       uint64_t quot, divisor[] = {
+               SR_HZ(1), SR_KHZ(1), SR_MHZ(1), SR_GHZ(1),
+               SR_GHZ(1000), SR_GHZ(1000 * 1000), SR_GHZ(1000 * 1000 * 1000),
+       };
+       const char *p, prefix[] = "\0kMGTPE";
+       char fmt[16], fract[20] = "", *f;
+
+       if (unit == NULL)
+               unit = "";
+
+       for (i = 0; (quot = x / divisor[i]) >= 1000; i++);
+
+       if (i) {
+               sprintf(fmt, ".%%0%d"PRIu64, i * 3);
+               f = fract + sprintf(fract, fmt, x % divisor[i]) - 1;
+
+               while (f >= fract && strchr("0.", *f))
+                       *f-- = 0;
+       }
+
+       p = prefix + i;
+
+       return g_strdup_printf("%" PRIu64 "%s %.1s%s", quot, fract, p, unit);
+}
+
+/**
+ * Convert a numeric samplerate value to its "natural" string representation.
+ *
+ * E.g. a value of 3000000 would be converted to "3 MHz", 20000 to "20 kHz",
+ * 31500 would become "31.5 kHz".
+ *
+ * @param samplerate The samplerate in Hz.
+ *
+ * @return A g_try_malloc()ed string representation of the samplerate value,
+ *         or NULL upon errors. The caller is responsible to g_free() the
+ *         memory.
+ *
+ * @since 0.1.0
+ */
+SR_API char *sr_samplerate_string(uint64_t samplerate)
+{
+       return sr_si_string_u64(samplerate, "Hz");
+}
+
+/**
+ * Convert a numeric frequency value to the "natural" string representation
+ * of its period.
+ *
+ * E.g. a value of 3000000 would be converted to "3 us", 20000 to "50 ms".
+ *
+ * @param frequency The frequency in Hz.
+ *
+ * @return A g_try_malloc()ed string representation of the frequency value,
+ *         or NULL upon errors. The caller is responsible to g_free() the
+ *         memory.
+ *
+ * @since 0.1.0
+ */
+SR_API char *sr_period_string(uint64_t frequency)
+{
+       char *o;
+       int r;
+
+       /* Allocate enough for a uint64_t as string + " ms". */
+       if (!(o = g_try_malloc0(30 + 1))) {
+               sr_err("%s: o malloc failed", __func__);
+               return NULL;
+       }
+
+       if (frequency >= SR_GHZ(1))
+               r = snprintf(o, 30, "%" PRIu64 " ns", frequency / 1000000000);
+       else if (frequency >= SR_MHZ(1))
+               r = snprintf(o, 30, "%" PRIu64 " us", frequency / 1000000);
+       else if (frequency >= SR_KHZ(1))
+               r = snprintf(o, 30, "%" PRIu64 " ms", frequency / 1000);
+       else
+               r = snprintf(o, 30, "%" PRIu64 " s", frequency);
+
+       if (r < 0) {
+               /* Something went wrong... */
+               g_free(o);
+               return NULL;
+       }
+
+       return o;
+}
+
+/**
+ * Convert a numeric voltage value to the "natural" string representation
+ * of its voltage value. The voltage is specified as a rational number's
+ * numerator and denominator.
+ *
+ * E.g. a value of 300000 would be converted to "300mV", 2 to "2V".
+ *
+ * @param v_p The voltage numerator.
+ * @param v_q The voltage denominator.
+ *
+ * @return A g_try_malloc()ed string representation of the voltage value,
+ *         or NULL upon errors. The caller is responsible to g_free() the
+ *         memory.
+ *
+ * @since 0.2.0
+ */
+SR_API char *sr_voltage_string(uint64_t v_p, uint64_t v_q)
+{
+       int r;
+       char *o;
+
+       if (!(o = g_try_malloc0(30 + 1))) {
+               sr_err("%s: o malloc failed", __func__);
+               return NULL;
+       }
+
+       if (v_q == 1000)
+               r = snprintf(o, 30, "%" PRIu64 "mV", v_p);
+       else if (v_q == 1)
+               r = snprintf(o, 30, "%" PRIu64 "V", v_p);
+       else
+               r = snprintf(o, 30, "%gV", (float)v_p / (float)v_q);
+
+       if (r < 0) {
+               /* Something went wrong... */
+               g_free(o);
+               return NULL;
+       }
+
+       return o;
+}
+
+/**
+ * Convert a "natural" string representation of a size value to uint64_t.
+ *
+ * E.g. a value of "3k" or "3 K" would be converted to 3000, a value
+ * of "15M" would be converted to 15000000.
+ *
+ * Value representations other than decimal (such as hex or octal) are not
+ * supported. Only 'k' (kilo), 'm' (mega), 'g' (giga) suffixes are supported.
+ * Spaces (but not other whitespace) between value and suffix are allowed.
+ *
+ * @param sizestring A string containing a (decimal) size value.
+ * @param size Pointer to uint64_t which will contain the string's size value.
+ *
+ * @return SR_OK upon success, SR_ERR upon errors.
+ *
+ * @since 0.1.0
+ */
+SR_API int sr_parse_sizestring(const char *sizestring, uint64_t *size)
+{
+       int multiplier, done;
+       double frac_part;
+       char *s;
+
+       *size = strtoull(sizestring, &s, 10);
+       multiplier = 0;
+       frac_part = 0;
+       done = FALSE;
+       while (s && *s && multiplier == 0 && !done) {
+               switch (*s) {
+               case ' ':
+                       break;
+               case '.':
+                       frac_part = g_ascii_strtod(s, &s);
+                       break;
+               case 'k':
+               case 'K':
+                       multiplier = SR_KHZ(1);
+                       break;
+               case 'm':
+               case 'M':
+                       multiplier = SR_MHZ(1);
+                       break;
+               case 'g':
+               case 'G':
+                       multiplier = SR_GHZ(1);
+                       break;
+               default:
+                       done = TRUE;
+                       s--;
+               }
+               s++;
+       }
+       if (multiplier > 0) {
+               *size *= multiplier;
+               *size += frac_part * multiplier;
+       } else
+               *size += frac_part;
+
+       if (*s && strcasecmp(s, "Hz"))
+               return SR_ERR;
+
+       return SR_OK;
+}
+
+/**
+ * Convert a "natural" string representation of a time value to an
+ * uint64_t value in milliseconds.
+ *
+ * E.g. a value of "3s" or "3 s" would be converted to 3000, a value
+ * of "15ms" would be converted to 15.
+ *
+ * Value representations other than decimal (such as hex or octal) are not
+ * supported. Only lower-case "s" and "ms" time suffixes are supported.
+ * Spaces (but not other whitespace) between value and suffix are allowed.
+ *
+ * @param timestring A string containing a (decimal) time value.
+ * @return The string's time value as uint64_t, in milliseconds.
+ *
+ * @todo Add support for "m" (minutes) and others.
+ * @todo Add support for picoseconds?
+ * @todo Allow both lower-case and upper-case? If no, document it.
+ *
+ * @since 0.1.0
+ */
+SR_API uint64_t sr_parse_timestring(const char *timestring)
+{
+       uint64_t time_msec;
+       char *s;
+
+       /* TODO: Error handling, logging. */
+
+       time_msec = strtoull(timestring, &s, 10);
+       if (time_msec == 0 && s == timestring)
+               return 0;
+
+       if (s && *s) {
+               while (*s == ' ')
+                       s++;
+               if (!strcmp(s, "s"))
+                       time_msec *= 1000;
+               else if (!strcmp(s, "ms"))
+                       ; /* redundant */
+               else
+                       return 0;
+       }
+
+       return time_msec;
+}
+
+/** @since 0.1.0 */
+SR_API gboolean sr_parse_boolstring(const char *boolstr)
+{
+       if (!boolstr)
+               return FALSE;
+
+       if (!g_ascii_strncasecmp(boolstr, "true", 4) ||
+           !g_ascii_strncasecmp(boolstr, "yes", 3) ||
+           !g_ascii_strncasecmp(boolstr, "on", 2) ||
+           !g_ascii_strncasecmp(boolstr, "1", 1))
+               return TRUE;
+
+       return FALSE;
+}
+
+/** @since 0.2.0 */
+SR_API int sr_parse_period(const char *periodstr, uint64_t *p, uint64_t *q)
+{
+       char *s;
+
+       *p = strtoull(periodstr, &s, 10);
+       if (*p == 0 && s == periodstr)
+               /* No digits found. */
+               return SR_ERR_ARG;
+
+       if (s && *s) {
+               while (*s == ' ')
+                       s++;
+               if (!strcmp(s, "fs"))
+                       *q = 1000000000000000ULL;
+               else if (!strcmp(s, "ps"))
+                       *q = 1000000000000ULL;
+               else if (!strcmp(s, "ns"))
+                       *q = 1000000000ULL;
+               else if (!strcmp(s, "us"))
+                       *q = 1000000;
+               else if (!strcmp(s, "ms"))
+                       *q = 1000;
+               else if (!strcmp(s, "s"))
+                       *q = 1;
+               else
+                       /* Must have a time suffix. */
+                       return SR_ERR_ARG;
+       }
+
+       return SR_OK;
+}
+
+/** @since 0.2.0 */
+SR_API int sr_parse_voltage(const char *voltstr, uint64_t *p, uint64_t *q)
+{
+       char *s;
+
+       *p = strtoull(voltstr, &s, 10);
+       if (*p == 0 && s == voltstr)
+               /* No digits found. */
+               return SR_ERR_ARG;
+
+       if (s && *s) {
+               while (*s == ' ')
+                       s++;
+               if (!strcasecmp(s, "mv"))
+                       *q = 1000L;
+               else if (!strcasecmp(s, "v"))
+                       *q = 1;
+               else
+                       /* Must have a base suffix. */
+                       return SR_ERR_ARG;
+       }
+
+       return SR_OK;
+}
+
+/** @} */
diff --git a/src/trigger.c b/src/trigger.c
new file mode 100644 (file)
index 0000000..0783bb2
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Bert Vermeulen <bert@biot.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 "libsigrok.h"
+#include "libsigrok-internal.h"
+
+/* * @cond PRIVATE */
+#define LOG_PREFIX "trigger"
+/* * @endcond */
+   
+SR_API struct sr_trigger *sr_trigger_new(const char *name)
+{
+       struct sr_trigger *trig;
+
+       trig = g_malloc0(sizeof(struct sr_trigger));
+       if (name)
+               trig->name = g_strdup(name);
+
+       return trig;
+}
+
+SR_API void sr_trigger_free(struct sr_trigger *trig)
+{
+       struct sr_trigger_stage *stage;
+       GSList *l;
+
+       for (l = trig->stages; l; l = l->next) {
+               stage = l->data;
+               g_slist_free_full(stage->matches, g_free);
+       }
+       g_slist_free_full(trig->stages, g_free);
+
+       g_free(trig->name);
+       g_free(trig);
+}
+
+SR_API struct sr_trigger_stage *sr_trigger_stage_add(struct sr_trigger *trig)
+{
+       struct sr_trigger_stage *stage;
+
+       stage = g_malloc0(sizeof(struct sr_trigger_stage));
+       stage->stage = g_slist_length(trig->stages);
+       trig->stages = g_slist_append(trig->stages, stage);
+
+       return stage;
+}
+
+SR_API int sr_trigger_match_add(struct sr_trigger_stage *stage,
+               struct sr_channel *ch, int trigger_match, float value)
+{
+       struct sr_trigger_match *match;
+
+       if (ch->type == SR_CHANNEL_LOGIC) {
+               if (trigger_match != SR_TRIGGER_ZERO &&
+                               trigger_match != SR_TRIGGER_ONE &&
+                               trigger_match != SR_TRIGGER_RISING &&
+                               trigger_match != SR_TRIGGER_FALLING &&
+                               trigger_match != SR_TRIGGER_EDGE) {
+                       sr_err("Invalid trigger match for a logic channel.");
+                       return SR_ERR_ARG;
+               }
+
+
+       } else if (ch->type == SR_CHANNEL_ANALOG) {
+               if (trigger_match != SR_TRIGGER_FALLING &&
+                               trigger_match != SR_TRIGGER_OVER &&
+                               trigger_match != SR_TRIGGER_UNDER) {
+                       sr_err("Invalid trigger match for an analog channel.");
+                       return SR_ERR_ARG;
+               }
+       }
+
+       match = g_malloc0(sizeof(struct sr_trigger_match));
+       match->channel = ch;
+       match->match = trigger_match;
+       match->value = value;
+       stage->matches = g_slist_append(stage->matches, match);
+
+       return SR_OK;
+}
diff --git a/src/usb.c b/src/usb.c
new file mode 100644 (file)
index 0000000..c3279d0
--- /dev/null
+++ b/src/usb.c
@@ -0,0 +1,271 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Uwe Hermann <uwe@hermann-uwe.de>
+ * Copyright (C) 2012 Bert Vermeulen <bert@biot.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 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <glib.h>
+#include <libusb.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+/* SR_CONF_CONN takes one of these: */
+#define CONN_USB_VIDPID  "^([0-9a-z]{4})\\.([0-9a-z]{4})$"
+#define CONN_USB_BUSADDR "^(\\d+)\\.(\\d+)$"
+
+#define LOG_PREFIX "usb"
+
+/**
+ * Find USB devices according to a connection string.
+ *
+ * @param usb_ctx libusb context to use while scanning.
+ * @param conn Connection string specifying the device(s) to match. This
+ * can be of the form "<bus>.<address>", or "<vendorid>.<productid>".
+ *
+ * @return A GSList of struct sr_usb_dev_inst, with bus and address fields
+ * matching the device that matched the connection string. The GSList and
+ * its contents must be freed by the caller.
+ */
+SR_PRIV GSList *sr_usb_find(libusb_context *usb_ctx, const char *conn)
+{
+       struct sr_usb_dev_inst *usb;
+       struct libusb_device **devlist;
+       struct libusb_device_descriptor des;
+       GSList *devices;
+       GRegex *reg;
+       GMatchInfo *match;
+       int vid, pid, bus, addr, b, a, ret, i;
+       char *mstr;
+
+       vid = pid = bus = addr = 0;
+       reg = g_regex_new(CONN_USB_VIDPID, 0, 0, NULL);
+       if (g_regex_match(reg, conn, 0, &match)) {
+               if ((mstr = g_match_info_fetch(match, 1)))
+                       vid = strtoul(mstr, NULL, 16);
+               g_free(mstr);
+
+               if ((mstr = g_match_info_fetch(match, 2)))
+                       pid = strtoul(mstr, NULL, 16);
+               g_free(mstr);
+               sr_dbg("Trying to find USB device with VID:PID = %04x:%04x.",
+                      vid, pid);
+       } else {
+               g_match_info_unref(match);
+               g_regex_unref(reg);
+               reg = g_regex_new(CONN_USB_BUSADDR, 0, 0, NULL);
+               if (g_regex_match(reg, conn, 0, &match)) {
+                       if ((mstr = g_match_info_fetch(match, 1)))
+                               bus = strtoul(mstr, NULL, 10);
+                       g_free(mstr);
+
+                       if ((mstr = g_match_info_fetch(match, 2)))
+                               addr = strtoul(mstr, NULL, 10);
+                       g_free(mstr);
+                       sr_dbg("Trying to find USB device with bus.address = "
+                              "%d.%d.", bus, addr);
+               }
+       }
+       g_match_info_unref(match);
+       g_regex_unref(reg);
+
+       if (vid + pid + bus + addr == 0) {
+               sr_err("Neither VID:PID nor bus.address was specified.");
+               return NULL;
+       }
+
+       if (bus > 64) {
+               sr_err("Invalid bus specified: %d.", bus);
+               return NULL;
+       }
+
+       if (addr > 127) {
+               sr_err("Invalid address specified: %d.", addr);
+               return NULL;
+       }
+
+       /* Looks like a valid USB device specification, but is it connected? */
+       devices = NULL;
+       libusb_get_device_list(usb_ctx, &devlist);
+       for (i = 0; devlist[i]; i++) {
+               if ((ret = libusb_get_device_descriptor(devlist[i], &des))) {
+                       sr_err("Failed to get device descriptor: %s.",
+                              libusb_error_name(ret));
+                       continue;
+               }
+
+               if (vid + pid && (des.idVendor != vid || des.idProduct != pid))
+                       continue;
+
+               b = libusb_get_bus_number(devlist[i]);
+               a = libusb_get_device_address(devlist[i]);
+               if (bus + addr && (b != bus || a != addr))
+                       continue;
+
+               sr_dbg("Found USB device (VID:PID = %04x:%04x, bus.address = "
+                      "%d.%d).", des.idVendor, des.idProduct, b, a);
+
+               usb = sr_usb_dev_inst_new(libusb_get_bus_number(devlist[i]),
+                               libusb_get_device_address(devlist[i]), NULL);
+               devices = g_slist_append(devices, usb);
+       }
+       libusb_free_device_list(devlist, 1);
+
+       sr_dbg("Found %d device(s).", g_slist_length(devices));
+       
+       return devices;
+}
+
+SR_PRIV int sr_usb_open(libusb_context *usb_ctx, struct sr_usb_dev_inst *usb)
+{
+       struct libusb_device **devlist;
+       struct libusb_device_descriptor des;
+       int ret, r, cnt, i, a, b;
+
+       sr_dbg("Trying to open USB device %d.%d.", usb->bus, usb->address);
+
+       if ((cnt = libusb_get_device_list(usb_ctx, &devlist)) < 0) {
+               sr_err("Failed to retrieve device list: %s.",
+                      libusb_error_name(cnt));
+               return SR_ERR;
+       }
+
+       ret = SR_ERR;
+       for (i = 0; i < cnt; i++) {
+               if ((r = libusb_get_device_descriptor(devlist[i], &des)) < 0) {
+                       sr_err("Failed to get device descriptor: %s.",
+                              libusb_error_name(r));
+                       continue;
+               }
+
+               b = libusb_get_bus_number(devlist[i]);
+               a = libusb_get_device_address(devlist[i]);
+               if (b != usb->bus || a != usb->address)
+                       continue;
+
+               if ((r = libusb_open(devlist[i], &usb->devhdl)) < 0) {
+                       sr_err("Failed to open device: %s.",
+                              libusb_error_name(r));
+                       break;
+               }
+
+               sr_dbg("Opened USB device (VID:PID = %04x:%04x, bus.address = "
+                      "%d.%d).", des.idVendor, des.idProduct, b, a);
+
+               ret = SR_OK;
+               break;
+       }
+
+       libusb_free_device_list(devlist, 1);
+
+       return ret;
+}
+
+#ifdef _WIN32
+static gpointer usb_thread(gpointer data)
+{
+       struct sr_context *ctx = data;
+
+       while (ctx->usb_thread_running) {
+               g_mutex_lock(&ctx->usb_mutex);
+               libusb_wait_for_event(ctx->libusb_ctx, NULL);
+               SetEvent(ctx->usb_event);
+               g_mutex_unlock(&ctx->usb_mutex);
+               g_thread_yield();
+       }
+
+       return NULL;
+}
+
+static int usb_callback(int fd, int revents, void *cb_data)
+{
+       struct sr_context *ctx = cb_data;
+       int ret;
+
+       g_mutex_lock(&ctx->usb_mutex);
+       ret = ctx->usb_cb(fd, revents, ctx->usb_cb_data);
+
+       if (ctx->usb_thread_running) {
+               ResetEvent(ctx->usb_event);
+               g_mutex_unlock(&ctx->usb_mutex);
+       }
+
+       return ret;
+}
+#endif
+
+SR_PRIV int usb_source_add(struct sr_session *session, struct sr_context *ctx,
+               int timeout, sr_receive_data_callback cb, void *cb_data)
+{
+       if (ctx->usb_source_present) {
+               sr_err("A USB event source is already present.");
+               return SR_ERR;
+       }
+
+#ifdef _WIN32
+       ctx->usb_event = CreateEvent(NULL, TRUE, FALSE, NULL);
+       g_mutex_init(&ctx->usb_mutex);
+       ctx->usb_thread_running = TRUE;
+       ctx->usb_thread = g_thread_new("usb", usb_thread, ctx);
+       ctx->usb_pollfd.fd = ctx->usb_event;
+       ctx->usb_pollfd.events = G_IO_IN;
+       ctx->usb_cb = cb;
+       ctx->usb_cb_data = cb_data;
+       sr_session_source_add_pollfd(session, &ctx->usb_pollfd, timeout,
+                       usb_callback, ctx);
+#else
+       const struct libusb_pollfd **lupfd;
+       unsigned int i;
+
+       lupfd = libusb_get_pollfds(ctx->libusb_ctx);
+       for (i = 0; lupfd[i]; i++)
+               sr_session_source_add(session, lupfd[i]->fd, lupfd[i]->events,
+                               timeout, cb, cb_data);
+       free(lupfd);
+#endif
+       ctx->usb_source_present = TRUE;
+
+       return SR_OK;
+}
+
+SR_PRIV int usb_source_remove(struct sr_session *session, struct sr_context *ctx)
+{
+       if (!ctx->usb_source_present)
+               return SR_OK;
+
+#ifdef _WIN32
+       ctx->usb_thread_running = FALSE;
+       g_mutex_unlock(&ctx->usb_mutex);
+       libusb_unlock_events(ctx->libusb_ctx);
+       g_thread_join(ctx->usb_thread);
+       g_mutex_clear(&ctx->usb_mutex);
+       sr_session_source_remove_pollfd(session, &ctx->usb_pollfd);
+       CloseHandle(ctx->usb_event);
+#else
+       const struct libusb_pollfd **lupfd;
+       unsigned int i;
+
+       lupfd = libusb_get_pollfds(ctx->libusb_ctx);
+       for (i = 0; lupfd[i]; i++)
+               sr_session_source_remove(session, lupfd[i]->fd);
+       free(lupfd);
+#endif
+       ctx->usb_source_present = FALSE;
+
+       return SR_OK;
+}
diff --git a/src/version.c b/src/version.c
new file mode 100644 (file)
index 0000000..3da0c17
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "libsigrok.h"
+
+/**
+ * @file
+ *
+ * Version number querying functions, definitions, and macros.
+ */
+
+/**
+ * @defgroup grp_versions Versions
+ *
+ * Version number querying functions, definitions, and macros.
+ *
+ * This set of API calls returns two different version numbers related
+ * to libsigrok. The "package version" is the release version number of the
+ * libsigrok tarball in the usual "major.minor.micro" format, e.g. "0.1.0".
+ *
+ * The "library version" is independent of that; it is the libtool version
+ * number in the "current:revision:age" format, e.g. "2:0:0".
+ * See http://www.gnu.org/software/libtool/manual/libtool.html#Libtool-versioning for details.
+ *
+ * Both version numbers (and/or individual components of them) can be
+ * retrieved via the API calls at runtime, and/or they can be checked at
+ * compile/preprocessor time using the respective macros.
+ *
+ * @{
+ */
+
+/**
+ * Get the major libsigrok package version number.
+ *
+ * @return The major package version number.
+ *
+ * @since 0.1.0
+ */
+SR_API int sr_package_version_major_get(void)
+{
+       return SR_PACKAGE_VERSION_MAJOR;
+}
+
+/**
+ * Get the minor libsigrok package version number.
+ *
+ * @return The minor package version number.
+ *
+ * @since 0.1.0
+ */
+SR_API int sr_package_version_minor_get(void)
+{
+       return SR_PACKAGE_VERSION_MINOR;
+}
+
+/**
+ * Get the micro libsigrok package version number.
+ *
+ * @return The micro package version number.
+ *
+ * @since 0.1.0
+ */
+SR_API int sr_package_version_micro_get(void)
+{
+       return SR_PACKAGE_VERSION_MICRO;
+}
+
+/**
+ * Get the libsigrok package version number as a string.
+ *
+ * @return The package version number string. The returned string is
+ *         static and thus should NOT be free'd by the caller.
+ *
+ * @since 0.1.0
+ */
+SR_API const char *sr_package_version_string_get(void)
+{
+       return SR_PACKAGE_VERSION_STRING;
+}
+
+/**
+ * Get the "current" part of the libsigrok library version number.
+ *
+ * @return The "current" library version number.
+ *
+ * @since 0.1.0
+ */
+SR_API int sr_lib_version_current_get(void)
+{
+       return SR_LIB_VERSION_CURRENT;
+}
+
+/**
+ * Get the "revision" part of the libsigrok library version number.
+ *
+ * @return The "revision" library version number.
+ *
+ * @since 0.1.0
+ */
+SR_API int sr_lib_version_revision_get(void)
+{
+       return SR_LIB_VERSION_REVISION;
+}
+
+/**
+ * Get the "age" part of the libsigrok library version number.
+ *
+ * @return The "age" library version number.
+ *
+ * @since 0.1.0
+ */
+SR_API int sr_lib_version_age_get(void)
+{
+       return SR_LIB_VERSION_AGE;
+}
+
+/**
+ * Get the libsigrok library version number as a string.
+ *
+ * @return The library version number string. The returned string is
+ *         static and thus should NOT be free'd by the caller.
+ *
+ * @since 0.1.0
+ */
+SR_API const char *sr_lib_version_string_get(void)
+{
+       return SR_LIB_VERSION_STRING;
+}
+
+/** @} */
diff --git a/std.c b/std.c
deleted file mode 100644 (file)
index 2319dfe..0000000
--- a/std.c
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-/** @file
-  * Standard API helper functions.
-  * @internal
-  */
-
-#include <glib.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-#define LOG_PREFIX "std"
-
-/**
- * Standard sr_driver_init() API helper.
- *
- * This function can be used to simplify most driver's init() API callback.
- *
- * It creates a new 'struct drv_context' (drvc), assigns sr_ctx to it, and
- * then 'drvc' is assigned to the 'struct sr_dev_driver' (di) that is passed.
- *
- * @param sr_ctx The libsigrok context to assign.
- * @param di The driver instance to use.
- * @param[in] prefix A driver-specific prefix string used for log messages.
- *
- * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments, or
- *         SR_ERR_MALLOC upon memory allocation errors.
- */
-SR_PRIV int std_init(struct sr_context *sr_ctx, struct sr_dev_driver *di,
-                    const char *prefix)
-{
-       struct drv_context *drvc;
-
-       if (!di) {
-               sr_err("%s: Invalid driver, cannot initialize.", prefix);
-               return SR_ERR_ARG;
-       }
-
-       if (!(drvc = g_try_malloc(sizeof(struct drv_context)))) {
-               sr_err("%s: Driver context malloc failed.", prefix);
-               return SR_ERR_MALLOC;
-       }
-
-       drvc->sr_ctx = sr_ctx;
-       drvc->instances = NULL;
-       di->priv = drvc;
-
-       return SR_OK;
-}
-
-/**
- * Standard API helper for sending an SR_DF_HEADER packet.
- *
- * This function can be used to simplify most driver's
- * dev_acquisition_start() API callback.
- *
- * @param sdi The device instance to use.
- * @param prefix A driver-specific prefix string used for log messages.
- *              Must not be NULL. An empty string is allowed.
- *
- * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments, or
- *         SR_ERR upon other errors.
- */
-SR_PRIV int std_session_send_df_header(const struct sr_dev_inst *sdi,
-                                      const char *prefix)
-{
-       int ret;
-       struct sr_datafeed_packet packet;
-       struct sr_datafeed_header header;
-
-       if (!prefix) {
-               sr_err("Invalid prefix.");
-               return SR_ERR_ARG;
-       }
-
-       sr_dbg("%s: Starting acquisition.", prefix);
-
-       /* Send header packet to the session bus. */
-       sr_dbg("%s: Sending SR_DF_HEADER packet.", prefix);
-       packet.type = SR_DF_HEADER;
-       packet.payload = (uint8_t *)&header;
-       header.feed_version = 1;
-       gettimeofday(&header.starttime, NULL);
-
-       if ((ret = sr_session_send(sdi, &packet)) < 0) {
-               sr_err("%s: Failed to send header packet: %d.", prefix, ret);
-               return ret;
-       }
-
-       return SR_OK;
-}
-
-#ifdef HAVE_LIBSERIALPORT
-
-/**
- * Standard serial driver dev_open() helper.
- *
- * This function can be used to implement the dev_open() driver API
- * callback in drivers that use a serial port. The port is opened
- * with the SERIAL_RDWR and SERIAL_NONBLOCK flags.
- *
- * If the open succeeded, the status field of the given sdi is set
- * to SR_ST_ACTIVE.
- *
- * @retval SR_OK Success.
- * @retval SR_ERR Serial port open failed.
- */
-SR_PRIV int std_serial_dev_open(struct sr_dev_inst *sdi)
-{
-       struct sr_serial_dev_inst *serial;
-
-       serial = sdi->conn;
-       if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
-               return SR_ERR;
-
-       sdi->status = SR_ST_ACTIVE;
-
-       return SR_OK;
-}
-
-/**
- * Standard serial driver dev_close() helper.
- *
- * This function can be used to implement the dev_close() driver API
- * callback in drivers that use a serial port.
- *
- * After closing the port, the status field of the given sdi is set
- * to SR_ST_INACTIVE.
- *
- * @retval SR_OK Success.
- */
-SR_PRIV int std_serial_dev_close(struct sr_dev_inst *sdi)
-{
-       struct sr_serial_dev_inst *serial;
-
-       serial = sdi->conn;
-       if (serial && sdi->status == SR_ST_ACTIVE) {
-               serial_close(serial);
-               sdi->status = SR_ST_INACTIVE;
-       }
-
-       return SR_OK;
-}
-
-/**
- * Standard sr_session_stop() API helper.
- *
- * This function can be used to simplify most (serial port based) driver's
- * dev_acquisition_stop() API callback.
- *
- * @param sdi The device instance for which acquisition should stop.
- *            Must not be NULL.
- * @param cb_data Opaque 'cb_data' pointer. Must not be NULL.
- * @param dev_close_fn Function pointer to the driver's dev_close().
- *                       Must not be NULL.
- * @param serial The serial device instance (struct serial_dev_inst *).
- *               Must not be NULL.
- * @param[in] prefix A driver-specific prefix string used for log messages.
- *               Must not be NULL. An empty string is allowed.
- *
- * @retval SR_OK Success.
- * @retval SR_ERR_ARG Invalid arguments.
- * @retval SR_ERR_DEV_CLOSED Device is closed.
- * @retval SR_ERR Other errors.
- */
-SR_PRIV int std_serial_dev_acquisition_stop(struct sr_dev_inst *sdi,
-                       void *cb_data, dev_close_callback dev_close_fn,
-                       struct sr_serial_dev_inst *serial, const char *prefix)
-{
-       int ret;
-       struct sr_datafeed_packet packet;
-
-       if (!prefix) {
-               sr_err("Invalid prefix.");
-               return SR_ERR_ARG;
-       }
-
-       if (sdi->status != SR_ST_ACTIVE) {
-               sr_err("%s: Device inactive, can't stop acquisition.", prefix);
-               return SR_ERR_DEV_CLOSED;
-       }
-
-       sr_dbg("%s: Stopping acquisition.", prefix);
-
-       if ((ret = serial_source_remove(sdi->session, serial)) < 0) {
-               sr_err("%s: Failed to remove source: %d.", prefix, ret);
-               return ret;
-       }
-
-       if ((ret = dev_close_fn(sdi)) < 0) {
-               sr_err("%s: Failed to close device: %d.", prefix, ret);
-               return ret;
-       }
-
-       /* Send SR_DF_END packet to the session bus. */
-       sr_dbg("%s: Sending SR_DF_END packet.", prefix);
-       packet.type = SR_DF_END;
-       packet.payload = NULL;
-       if ((ret = sr_session_send(cb_data, &packet)) < 0) {
-               sr_err("%s: Failed to send SR_DF_END packet: %d.", prefix, ret);
-               return ret;
-       }
-
-       return SR_OK;
-}
-
-#endif
-
-/**
- * Standard driver dev_clear() helper.
- *
- * Clear driver, this means, close all instances.
- *
- * This function can be used to implement the dev_clear() driver API
- * callback. dev_close() is called before every sr_dev_inst is cleared.
- *
- * The only limitation is driver-specific device contexts (sdi->priv).
- * These are freed, but any dynamic allocation within structs stored
- * there cannot be freed.
- *
- * @param driver The driver which will have its instances released.
- * @param clear_private If not NULL, this points to a function called
- * with sdi->priv as argument. The function can then clear any device
- * instance-specific resources kept there. It must also clear the struct
- * pointed to by sdi->priv.
- *
- * @return SR_OK on success.
- */
-SR_PRIV int std_dev_clear(const struct sr_dev_driver *driver,
-               std_dev_clear_callback clear_private)
-{
-       struct drv_context *drvc;
-       struct sr_dev_inst *sdi;
-       GSList *l;
-       int ret;
-
-       if (!(drvc = driver->priv))
-               /* Driver was never initialized, nothing to do. */
-               return SR_OK;
-
-       ret = SR_OK;
-       for (l = drvc->instances; l; l = l->next) {
-               if (!(sdi = l->data)) {
-                       ret = SR_ERR_BUG;
-                       continue;
-               }
-               if (driver->dev_close)
-                       driver->dev_close(sdi);
-
-               if (sdi->conn) {
-#ifdef HAVE_LIBSERIALPORT
-                       if (sdi->inst_type == SR_INST_SERIAL)
-                               sr_serial_dev_inst_free(sdi->conn);
-#endif
-#ifdef HAVE_LIBUSB_1_0
-                       if (sdi->inst_type == SR_INST_USB)
-                               sr_usb_dev_inst_free(sdi->conn);
-#endif
-                       if (sdi->inst_type == SR_INST_SCPI)
-                               sr_scpi_free(sdi->conn);
-               }
-               if (clear_private)
-                       clear_private(sdi->priv);
-               else
-                       g_free(sdi->priv);
-               sr_dev_inst_free(sdi);
-       }
-
-       g_slist_free(drvc->instances);
-       drvc->instances = NULL;
-
-       return ret;
-}
diff --git a/strutil.c b/strutil.c
deleted file mode 100644 (file)
index 54dc1f3..0000000
--- a/strutil.c
+++ /dev/null
@@ -1,553 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2010 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include "libsigrok.h"
-#include "libsigrok-internal.h"
-
-/** @cond PRIVATE */
-#define LOG_PREFIX "strutil"
-/** @endcond */
-
-/**
- * @file
- *
- * Helper functions for handling or converting libsigrok-related strings.
- */
-
-/**
- * @defgroup grp_strutil String utilities
- *
- * Helper functions for handling or converting libsigrok-related strings.
- *
- * @{
- */
-
-/**
- * @private
- *
- * Convert a string representation of a numeric value (base 10) to a long integer. The
- * conversion is strict and will fail if the complete string does not represent
- * a valid long integer. The function sets errno according to the details of the
- * failure.
- *
- * @param str The string representation to convert.
- * @param ret Pointer to long where the result of the conversion will be stored.
- *
- * @retval SR_OK Conversion successful.
- * @retval SR_ERR Failure.
- *
- * @since 0.3.0
- */
-SR_PRIV int sr_atol(const char *str, long *ret)
-{
-       long tmp;
-       char *endptr = NULL;
-
-       errno = 0;
-       tmp = strtol(str, &endptr, 10);
-
-       if (!endptr || *endptr || errno) {
-               if (!errno)
-                       errno = EINVAL;
-               return SR_ERR;
-       }
-
-       *ret = tmp;
-       return SR_OK;
-}
-
-/**
- * @private
- *
- * Convert a string representation of a numeric value (base 10) to an integer. The
- * conversion is strict and will fail if the complete string does not represent
- * a valid integer. The function sets errno according to the details of the
- * failure.
- *
- * @param str The string representation to convert.
- * @param ret Pointer to int where the result of the conversion will be stored.
- *
- * @retval SR_OK Conversion successful.
- * @retval SR_ERR Failure.
- *
- * @since 0.3.0
- */
-SR_PRIV int sr_atoi(const char *str, int *ret)
-{
-       long tmp;
-
-       if (sr_atol(str, &tmp) != SR_OK)
-               return SR_ERR;
-
-       if ((int) tmp != tmp) {
-               errno = ERANGE;
-               return SR_ERR;
-       }
-
-       *ret = (int) tmp;
-       return SR_OK;
-}
-
-/**
- * @private
- *
- * Convert a string representation of a numeric value to a double. The
- * conversion is strict and will fail if the complete string does not represent
- * a valid double. The function sets errno according to the details of the
- * failure.
- *
- * @param str The string representation to convert.
- * @param ret Pointer to double where the result of the conversion will be stored.
- *
- * @retval SR_OK Conversion successful.
- * @retval SR_ERR Failure.
- *
- * @since 0.3.0
- */
-SR_PRIV int sr_atod(const char *str, double *ret)
-{
-       double tmp;
-       char *endptr = NULL;
-
-       errno = 0;
-       tmp = strtof(str, &endptr);
-
-       if (!endptr || *endptr || errno) {
-               if (!errno)
-                       errno = EINVAL;
-               return SR_ERR;
-       }
-
-       *ret = tmp;
-       return SR_OK;
-}
-
-/**
- * @private
- *
- * Convert a string representation of a numeric value to a float. The
- * conversion is strict and will fail if the complete string does not represent
- * a valid float. The function sets errno according to the details of the
- * failure.
- *
- * @param str The string representation to convert.
- * @param ret Pointer to float where the result of the conversion will be stored.
- *
- * @retval SR_OK Conversion successful.
- * @retval SR_ERR Failure.
- *
- * @since 0.3.0
- */
-SR_PRIV int sr_atof(const char *str, float *ret)
-{
-       double tmp;
-
-       if (sr_atod(str, &tmp) != SR_OK)
-               return SR_ERR;
-
-       if ((float) tmp != tmp) {
-               errno = ERANGE;
-               return SR_ERR;
-       }
-
-       *ret = (float) tmp;
-       return SR_OK;
-}
-
-/**
- * @private
- *
- * Convert a string representation of a numeric value to a float. The
- * conversion is strict and will fail if the complete string does not represent
- * a valid float. The function sets errno according to the details of the
- * failure. This version ignores the locale.
- *
- * @param str The string representation to convert.
- * @param ret Pointer to float where the result of the conversion will be stored.
- *
- * @retval SR_OK Conversion successful.
- * @retval SR_ERR Failure.
- *
- * @since 0.3.0
- */
-SR_PRIV int sr_atof_ascii(const char *str, float *ret)
-{
-       double tmp;
-       char *endptr = NULL;
-
-       errno = 0;
-       tmp = g_ascii_strtod(str, &endptr);
-
-       if (!endptr || *endptr || errno) {
-               if (!errno)
-                       errno = EINVAL;
-               return SR_ERR;
-       }
-
-       /* FIXME This fails unexpectedly. Some other method to safel downcast
-        * needs to be found. Checking against FLT_MAX doesn't work as well. */
-       /*
-       if ((float) tmp != tmp) {
-               errno = ERANGE;
-               sr_dbg("ERANGEEEE %e != %e", (float) tmp, tmp);
-               return SR_ERR;
-       }
-       */
-
-       *ret = (float) tmp;
-       return SR_OK;
-}
-
-/**
- * Convert a numeric value value to its "natural" string representation
- * in SI units.
- *
- * E.g. a value of 3000000, with units set to "W", would be converted
- * to "3 MW", 20000 to "20 kW", 31500 would become "31.5 kW".
- *
- * @param x The value to convert.
- * @param unit The unit to append to the string, or NULL if the string
- *             has no units.
- *
- * @return A g_try_malloc()ed string representation of the samplerate value,
- *         or NULL upon errors. The caller is responsible to g_free() the
- *         memory.
- *
- * @since 0.2.0
- */
-SR_API char *sr_si_string_u64(uint64_t x, const char *unit)
-{
-       uint8_t i;
-       uint64_t quot, divisor[] = {
-               SR_HZ(1), SR_KHZ(1), SR_MHZ(1), SR_GHZ(1),
-               SR_GHZ(1000), SR_GHZ(1000 * 1000), SR_GHZ(1000 * 1000 * 1000),
-       };
-       const char *p, prefix[] = "\0kMGTPE";
-       char fmt[16], fract[20] = "", *f;
-
-       if (unit == NULL)
-               unit = "";
-
-       for (i = 0; (quot = x / divisor[i]) >= 1000; i++);
-
-       if (i) {
-               sprintf(fmt, ".%%0%d"PRIu64, i * 3);
-               f = fract + sprintf(fract, fmt, x % divisor[i]) - 1;
-
-               while (f >= fract && strchr("0.", *f))
-                       *f-- = 0;
-       }
-
-       p = prefix + i;
-
-       return g_strdup_printf("%" PRIu64 "%s %.1s%s", quot, fract, p, unit);
-}
-
-/**
- * Convert a numeric samplerate value to its "natural" string representation.
- *
- * E.g. a value of 3000000 would be converted to "3 MHz", 20000 to "20 kHz",
- * 31500 would become "31.5 kHz".
- *
- * @param samplerate The samplerate in Hz.
- *
- * @return A g_try_malloc()ed string representation of the samplerate value,
- *         or NULL upon errors. The caller is responsible to g_free() the
- *         memory.
- *
- * @since 0.1.0
- */
-SR_API char *sr_samplerate_string(uint64_t samplerate)
-{
-       return sr_si_string_u64(samplerate, "Hz");
-}
-
-/**
- * Convert a numeric frequency value to the "natural" string representation
- * of its period.
- *
- * E.g. a value of 3000000 would be converted to "3 us", 20000 to "50 ms".
- *
- * @param frequency The frequency in Hz.
- *
- * @return A g_try_malloc()ed string representation of the frequency value,
- *         or NULL upon errors. The caller is responsible to g_free() the
- *         memory.
- *
- * @since 0.1.0
- */
-SR_API char *sr_period_string(uint64_t frequency)
-{
-       char *o;
-       int r;
-
-       /* Allocate enough for a uint64_t as string + " ms". */
-       if (!(o = g_try_malloc0(30 + 1))) {
-               sr_err("%s: o malloc failed", __func__);
-               return NULL;
-       }
-
-       if (frequency >= SR_GHZ(1))
-               r = snprintf(o, 30, "%" PRIu64 " ns", frequency / 1000000000);
-       else if (frequency >= SR_MHZ(1))
-               r = snprintf(o, 30, "%" PRIu64 " us", frequency / 1000000);
-       else if (frequency >= SR_KHZ(1))
-               r = snprintf(o, 30, "%" PRIu64 " ms", frequency / 1000);
-       else
-               r = snprintf(o, 30, "%" PRIu64 " s", frequency);
-
-       if (r < 0) {
-               /* Something went wrong... */
-               g_free(o);
-               return NULL;
-       }
-
-       return o;
-}
-
-/**
- * Convert a numeric voltage value to the "natural" string representation
- * of its voltage value. The voltage is specified as a rational number's
- * numerator and denominator.
- *
- * E.g. a value of 300000 would be converted to "300mV", 2 to "2V".
- *
- * @param v_p The voltage numerator.
- * @param v_q The voltage denominator.
- *
- * @return A g_try_malloc()ed string representation of the voltage value,
- *         or NULL upon errors. The caller is responsible to g_free() the
- *         memory.
- *
- * @since 0.2.0
- */
-SR_API char *sr_voltage_string(uint64_t v_p, uint64_t v_q)
-{
-       int r;
-       char *o;
-
-       if (!(o = g_try_malloc0(30 + 1))) {
-               sr_err("%s: o malloc failed", __func__);
-               return NULL;
-       }
-
-       if (v_q == 1000)
-               r = snprintf(o, 30, "%" PRIu64 "mV", v_p);
-       else if (v_q == 1)
-               r = snprintf(o, 30, "%" PRIu64 "V", v_p);
-       else
-               r = snprintf(o, 30, "%gV", (float)v_p / (float)v_q);
-
-       if (r < 0) {
-               /* Something went wrong... */
-               g_free(o);
-               return NULL;
-       }
-
-       return o;
-}
-
-/**
- * Convert a "natural" string representation of a size value to uint64_t.
- *
- * E.g. a value of "3k" or "3 K" would be converted to 3000, a value
- * of "15M" would be converted to 15000000.
- *
- * Value representations other than decimal (such as hex or octal) are not
- * supported. Only 'k' (kilo), 'm' (mega), 'g' (giga) suffixes are supported.
- * Spaces (but not other whitespace) between value and suffix are allowed.
- *
- * @param sizestring A string containing a (decimal) size value.
- * @param size Pointer to uint64_t which will contain the string's size value.
- *
- * @return SR_OK upon success, SR_ERR upon errors.
- *
- * @since 0.1.0
- */
-SR_API int sr_parse_sizestring(const char *sizestring, uint64_t *size)
-{
-       int multiplier, done;
-       double frac_part;
-       char *s;
-
-       *size = strtoull(sizestring, &s, 10);
-       multiplier = 0;
-       frac_part = 0;
-       done = FALSE;
-       while (s && *s && multiplier == 0 && !done) {
-               switch (*s) {
-               case ' ':
-                       break;
-               case '.':
-                       frac_part = g_ascii_strtod(s, &s);
-                       break;
-               case 'k':
-               case 'K':
-                       multiplier = SR_KHZ(1);
-                       break;
-               case 'm':
-               case 'M':
-                       multiplier = SR_MHZ(1);
-                       break;
-               case 'g':
-               case 'G':
-                       multiplier = SR_GHZ(1);
-                       break;
-               default:
-                       done = TRUE;
-                       s--;
-               }
-               s++;
-       }
-       if (multiplier > 0) {
-               *size *= multiplier;
-               *size += frac_part * multiplier;
-       } else
-               *size += frac_part;
-
-       if (*s && strcasecmp(s, "Hz"))
-               return SR_ERR;
-
-       return SR_OK;
-}
-
-/**
- * Convert a "natural" string representation of a time value to an
- * uint64_t value in milliseconds.
- *
- * E.g. a value of "3s" or "3 s" would be converted to 3000, a value
- * of "15ms" would be converted to 15.
- *
- * Value representations other than decimal (such as hex or octal) are not
- * supported. Only lower-case "s" and "ms" time suffixes are supported.
- * Spaces (but not other whitespace) between value and suffix are allowed.
- *
- * @param timestring A string containing a (decimal) time value.
- * @return The string's time value as uint64_t, in milliseconds.
- *
- * @todo Add support for "m" (minutes) and others.
- * @todo Add support for picoseconds?
- * @todo Allow both lower-case and upper-case? If no, document it.
- *
- * @since 0.1.0
- */
-SR_API uint64_t sr_parse_timestring(const char *timestring)
-{
-       uint64_t time_msec;
-       char *s;
-
-       /* TODO: Error handling, logging. */
-
-       time_msec = strtoull(timestring, &s, 10);
-       if (time_msec == 0 && s == timestring)
-               return 0;
-
-       if (s && *s) {
-               while (*s == ' ')
-                       s++;
-               if (!strcmp(s, "s"))
-                       time_msec *= 1000;
-               else if (!strcmp(s, "ms"))
-                       ; /* redundant */
-               else
-                       return 0;
-       }
-
-       return time_msec;
-}
-
-/** @since 0.1.0 */
-SR_API gboolean sr_parse_boolstring(const char *boolstr)
-{
-       if (!boolstr)
-               return FALSE;
-
-       if (!g_ascii_strncasecmp(boolstr, "true", 4) ||
-           !g_ascii_strncasecmp(boolstr, "yes", 3) ||
-           !g_ascii_strncasecmp(boolstr, "on", 2) ||
-           !g_ascii_strncasecmp(boolstr, "1", 1))
-               return TRUE;
-
-       return FALSE;
-}
-
-/** @since 0.2.0 */
-SR_API int sr_parse_period(const char *periodstr, uint64_t *p, uint64_t *q)
-{
-       char *s;
-
-       *p = strtoull(periodstr, &s, 10);
-       if (*p == 0 && s == periodstr)
-               /* No digits found. */
-               return SR_ERR_ARG;
-
-       if (s && *s) {
-               while (*s == ' ')
-                       s++;
-               if (!strcmp(s, "fs"))
-                       *q = 1000000000000000ULL;
-               else if (!strcmp(s, "ps"))
-                       *q = 1000000000000ULL;
-               else if (!strcmp(s, "ns"))
-                       *q = 1000000000ULL;
-               else if (!strcmp(s, "us"))
-                       *q = 1000000;
-               else if (!strcmp(s, "ms"))
-                       *q = 1000;
-               else if (!strcmp(s, "s"))
-                       *q = 1;
-               else
-                       /* Must have a time suffix. */
-                       return SR_ERR_ARG;
-       }
-
-       return SR_OK;
-}
-
-/** @since 0.2.0 */
-SR_API int sr_parse_voltage(const char *voltstr, uint64_t *p, uint64_t *q)
-{
-       char *s;
-
-       *p = strtoull(voltstr, &s, 10);
-       if (*p == 0 && s == voltstr)
-               /* No digits found. */
-               return SR_ERR_ARG;
-
-       if (s && *s) {
-               while (*s == ' ')
-                       s++;
-               if (!strcasecmp(s, "mv"))
-                       *q = 1000L;
-               else if (!strcasecmp(s, "v"))
-                       *q = 1;
-               else
-                       /* Must have a base suffix. */
-                       return SR_ERR_ARG;
-       }
-
-       return SR_OK;
-}
-
-/** @} */
diff --git a/trigger.c b/trigger.c
deleted file mode 100644 (file)
index 0783bb2..0000000
--- a/trigger.c
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2014 Bert Vermeulen <bert@biot.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 "libsigrok.h"
-#include "libsigrok-internal.h"
-
-/* * @cond PRIVATE */
-#define LOG_PREFIX "trigger"
-/* * @endcond */
-   
-SR_API struct sr_trigger *sr_trigger_new(const char *name)
-{
-       struct sr_trigger *trig;
-
-       trig = g_malloc0(sizeof(struct sr_trigger));
-       if (name)
-               trig->name = g_strdup(name);
-
-       return trig;
-}
-
-SR_API void sr_trigger_free(struct sr_trigger *trig)
-{
-       struct sr_trigger_stage *stage;
-       GSList *l;
-
-       for (l = trig->stages; l; l = l->next) {
-               stage = l->data;
-               g_slist_free_full(stage->matches, g_free);
-       }
-       g_slist_free_full(trig->stages, g_free);
-
-       g_free(trig->name);
-       g_free(trig);
-}
-
-SR_API struct sr_trigger_stage *sr_trigger_stage_add(struct sr_trigger *trig)
-{
-       struct sr_trigger_stage *stage;
-
-       stage = g_malloc0(sizeof(struct sr_trigger_stage));
-       stage->stage = g_slist_length(trig->stages);
-       trig->stages = g_slist_append(trig->stages, stage);
-
-       return stage;
-}
-
-SR_API int sr_trigger_match_add(struct sr_trigger_stage *stage,
-               struct sr_channel *ch, int trigger_match, float value)
-{
-       struct sr_trigger_match *match;
-
-       if (ch->type == SR_CHANNEL_LOGIC) {
-               if (trigger_match != SR_TRIGGER_ZERO &&
-                               trigger_match != SR_TRIGGER_ONE &&
-                               trigger_match != SR_TRIGGER_RISING &&
-                               trigger_match != SR_TRIGGER_FALLING &&
-                               trigger_match != SR_TRIGGER_EDGE) {
-                       sr_err("Invalid trigger match for a logic channel.");
-                       return SR_ERR_ARG;
-               }
-
-
-       } else if (ch->type == SR_CHANNEL_ANALOG) {
-               if (trigger_match != SR_TRIGGER_FALLING &&
-                               trigger_match != SR_TRIGGER_OVER &&
-                               trigger_match != SR_TRIGGER_UNDER) {
-                       sr_err("Invalid trigger match for an analog channel.");
-                       return SR_ERR_ARG;
-               }
-       }
-
-       match = g_malloc0(sizeof(struct sr_trigger_match));
-       match->channel = ch;
-       match->match = trigger_match;
-       match->value = value;
-       stage->matches = g_slist_append(stage->matches, match);
-
-       return SR_OK;
-}
diff --git a/version.c b/version.c
deleted file mode 100644 (file)
index 3da0c17..0000000
--- a/version.c
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include "libsigrok.h"
-
-/**
- * @file
- *
- * Version number querying functions, definitions, and macros.
- */
-
-/**
- * @defgroup grp_versions Versions
- *
- * Version number querying functions, definitions, and macros.
- *
- * This set of API calls returns two different version numbers related
- * to libsigrok. The "package version" is the release version number of the
- * libsigrok tarball in the usual "major.minor.micro" format, e.g. "0.1.0".
- *
- * The "library version" is independent of that; it is the libtool version
- * number in the "current:revision:age" format, e.g. "2:0:0".
- * See http://www.gnu.org/software/libtool/manual/libtool.html#Libtool-versioning for details.
- *
- * Both version numbers (and/or individual components of them) can be
- * retrieved via the API calls at runtime, and/or they can be checked at
- * compile/preprocessor time using the respective macros.
- *
- * @{
- */
-
-/**
- * Get the major libsigrok package version number.
- *
- * @return The major package version number.
- *
- * @since 0.1.0
- */
-SR_API int sr_package_version_major_get(void)
-{
-       return SR_PACKAGE_VERSION_MAJOR;
-}
-
-/**
- * Get the minor libsigrok package version number.
- *
- * @return The minor package version number.
- *
- * @since 0.1.0
- */
-SR_API int sr_package_version_minor_get(void)
-{
-       return SR_PACKAGE_VERSION_MINOR;
-}
-
-/**
- * Get the micro libsigrok package version number.
- *
- * @return The micro package version number.
- *
- * @since 0.1.0
- */
-SR_API int sr_package_version_micro_get(void)
-{
-       return SR_PACKAGE_VERSION_MICRO;
-}
-
-/**
- * Get the libsigrok package version number as a string.
- *
- * @return The package version number string. The returned string is
- *         static and thus should NOT be free'd by the caller.
- *
- * @since 0.1.0
- */
-SR_API const char *sr_package_version_string_get(void)
-{
-       return SR_PACKAGE_VERSION_STRING;
-}
-
-/**
- * Get the "current" part of the libsigrok library version number.
- *
- * @return The "current" library version number.
- *
- * @since 0.1.0
- */
-SR_API int sr_lib_version_current_get(void)
-{
-       return SR_LIB_VERSION_CURRENT;
-}
-
-/**
- * Get the "revision" part of the libsigrok library version number.
- *
- * @return The "revision" library version number.
- *
- * @since 0.1.0
- */
-SR_API int sr_lib_version_revision_get(void)
-{
-       return SR_LIB_VERSION_REVISION;
-}
-
-/**
- * Get the "age" part of the libsigrok library version number.
- *
- * @return The "age" library version number.
- *
- * @since 0.1.0
- */
-SR_API int sr_lib_version_age_get(void)
-{
-       return SR_LIB_VERSION_AGE;
-}
-
-/**
- * Get the libsigrok library version number as a string.
- *
- * @return The library version number string. The returned string is
- *         static and thus should NOT be free'd by the caller.
- *
- * @since 0.1.0
- */
-SR_API const char *sr_lib_version_string_get(void)
-{
-       return SR_LIB_VERSION_STRING;
-}
-
-/** @} */