Backport recent changes from mainline.

This includes all changes from

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

up to

  a7600dc5c7
  Makefile.am: Install MIME info file in $(datadir)/mime/packages.

This is possible since (almost) none of the changes above change or
remove public API calls of the library.
This commit is contained in:
Uwe Hermann 2017-06-15 18:46:14 +02:00
parent 1aba657270
commit 8cd15dd4ce
289 changed files with 24305 additions and 9465 deletions

1
.gitignore vendored
View File

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

View File

@ -50,6 +50,7 @@ lib_LTLIBRARIES = libsigrok.la
# Backend files
libsigrok_la_SOURCES = \
src/backend.c \
src/conversion.c \
src/device.c \
src/session.c \
src/session_file.c \
@ -73,10 +74,12 @@ libsigrok_la_SOURCES += \
src/input/binary.c \
src/input/chronovu_la8.c \
src/input/csv.c \
src/input/logicport.c \
src/input/raw_analog.c \
src/input/trace32_ad.c \
src/input/vcd.c \
src/input/wav.c
src/input/wav.c \
src/input/null.c
# Output modules
libsigrok_la_SOURCES += \
@ -91,7 +94,8 @@ libsigrok_la_SOURCES += \
src/output/hex.c \
src/output/ols.c \
src/output/srzip.c \
src/output/vcd.c
src/output/vcd.c \
src/output/null.c
# Transform modules
libsigrok_la_SOURCES += \
@ -104,7 +108,6 @@ libsigrok_la_SOURCES += \
libsigrok_la_SOURCES += \
src/scpi.h \
src/scpi/scpi.c \
src/scpi/helpers.c \
src/scpi/scpi_tcp.c
if NEED_RPC
libsigrok_la_SOURCES += \
@ -143,18 +146,21 @@ endif
# Hardware (DMM chip parsers)
libsigrok_la_SOURCES += \
src/dmm/asycii.c \
src/dmm/bm25x.c \
src/dmm/dtm0660.c \
src/dmm/eev121gw.c \
src/dmm/es519xx.c \
src/dmm/fs9721.c \
src/dmm/fs9922.c \
src/dmm/m2110.c \
src/dmm/metex14.c \
src/dmm/asycii.c \
src/dmm/ms8250d.c \
src/dmm/rs9lcd.c \
src/dmm/bm25x.c \
src/dmm/ut71x.c \
src/dmm/ut372.c \
src/dmm/ut71x.c \
src/dmm/vc870.c \
src/dmm/dtm0660.c
src/dmm/vc96.c
# Hardware (LCR chip parsers)
if NEED_SERIAL
@ -167,15 +173,22 @@ libsigrok_la_SOURCES += \
src/scale/kern.c
# Hardware drivers
noinst_LTLIBRARIES = src/libdrivers.la
noinst_LTLIBRARIES = src/libdrivers.la \
src/libdrivers_head.la src/libdrivers_tail.la
src/libdrivers.o: src/libdrivers.la
$(AM_V_CCLD)$(LINK) src/libdrivers.la
src/libdrivers.o: src/libdrivers.la \
src/libdrivers_head.la src/libdrivers_tail.la
$(AM_V_CCLD)$(LINK) src/libdrivers_head.la src/libdrivers.la \
src/libdrivers_tail.la
src/libdrivers.lo: src/libdrivers.o
$(AM_V_GEN)echo "# Generated by libtool" > $@
$(AM_V_at)echo "pic_object='libdrivers.o'" >> $@
$(AM_V_at)echo "non_pic_object='libdrivers.o'" >> $@
src_libdrivers_head_la_SOURCES = src/driver_list_start.c
src_libdrivers_tail_la_SOURCES = src/driver_list_stop.c
src_libdrivers_la_SOURCES = src/drivers.c
if HW_AGILENT_DMM
@ -221,7 +234,9 @@ src_libdrivers_la_SOURCES += \
src/hardware/beaglelogic/beaglelogic.h \
src/hardware/beaglelogic/protocol.h \
src/hardware/beaglelogic/protocol.c \
src/hardware/beaglelogic/api.c
src/hardware/beaglelogic/api.c \
src/hardware/beaglelogic/beaglelogic_native.c \
src/hardware/beaglelogic/beaglelogic_tcp.c
endif
if HW_BRYMEN_BM86X
src_libdrivers_la_SOURCES += \
@ -272,6 +287,18 @@ src_libdrivers_la_SOURCES += \
src/hardware/demo/protocol.c \
src/hardware/demo/api.c
endif
if HW_DREAMSOURCELAB_DSLOGIC
src_libdrivers_la_SOURCES += \
src/hardware/dreamsourcelab-dslogic/protocol.h \
src/hardware/dreamsourcelab-dslogic/protocol.c \
src/hardware/dreamsourcelab-dslogic/api.c
endif
if HW_FLUKE_45
src_libdrivers_la_SOURCES += \
src/hardware/fluke-45/protocol.h \
src/hardware/fluke-45/protocol.c \
src/hardware/fluke-45/api.c
endif
if HW_FLUKE_DMM
src_libdrivers_la_SOURCES += \
src/hardware/fluke-dmm/protocol.h \
@ -288,9 +315,7 @@ if HW_FX2LAFW
src_libdrivers_la_SOURCES += \
src/hardware/fx2lafw/protocol.h \
src/hardware/fx2lafw/protocol.c \
src/hardware/fx2lafw/api.c \
src/hardware/fx2lafw/dslogic.c \
src/hardware/fx2lafw/dslogic.h
src/hardware/fx2lafw/api.c
endif
if HW_GMC_MH_1X_2X
src_libdrivers_la_SOURCES += \
@ -304,12 +329,24 @@ src_libdrivers_la_SOURCES += \
src/hardware/gwinstek-gds-800/protocol.c \
src/hardware/gwinstek-gds-800/api.c
endif
if HW_GWINSTEK_GPD
src_libdrivers_la_SOURCES += \
src/hardware/gwinstek-gpd/protocol.h \
src/hardware/gwinstek-gpd/protocol.c \
src/hardware/gwinstek-gpd/api.c
endif
if HW_HAMEG_HMO
src_libdrivers_la_SOURCES += \
src/hardware/hameg-hmo/protocol.h \
src/hardware/hameg-hmo/protocol.c \
src/hardware/hameg-hmo/api.c
endif
if HW_HANTEK_4032L
src_libdrivers_la_SOURCES += \
src/hardware/hantek-4032l/protocol.h \
src/hardware/hantek-4032l/protocol.c \
src/hardware/hantek-4032l/api.c
endif
if HW_HANTEK_6XXX
src_libdrivers_la_SOURCES += \
src/hardware/hantek-6xxx/protocol.h \
@ -328,6 +365,12 @@ src_libdrivers_la_SOURCES += \
src/hardware/hp-3457a/protocol.c \
src/hardware/hp-3457a/api.c
endif
if HW_HP_3478A
src_libdrivers_la_SOURCES += \
src/hardware/hp-3478a/protocol.h \
src/hardware/hp-3478a/protocol.c \
src/hardware/hp-3478a/api.c
endif
if HW_HUNG_CHANG_DSO_2100
src_libdrivers_la_SOURCES += \
src/hardware/hung-chang-dso-2100/protocol.h \
@ -346,6 +389,12 @@ src_libdrivers_la_SOURCES += \
src/hardware/ikalogic-scanaplus/protocol.c \
src/hardware/ikalogic-scanaplus/api.c
endif
if HW_IPDBG_LA
src_libdrivers_la_SOURCES += \
src/hardware/ipdbg-la/protocol.h \
src/hardware/ipdbg-la/protocol.c \
src/hardware/ipdbg-la/api.c
endif
if HW_KECHENG_KC_330B
src_libdrivers_la_SOURCES += \
src/hardware/kecheng-kc-330b/protocol.h \
@ -430,6 +479,12 @@ src_libdrivers_la_SOURCES += \
src/hardware/pipistrello-ols/protocol.c \
src/hardware/pipistrello-ols/api.c
endif
if HW_RDTECH_DPS
src_libdrivers_la_SOURCES += \
src/hardware/rdtech-dps/protocol.h \
src/hardware/rdtech-dps/protocol.c \
src/hardware/rdtech-dps/api.c
endif
if HW_RIGOL_DS
src_libdrivers_la_SOURCES += \
src/hardware/rigol-ds/protocol.h \
@ -448,6 +503,12 @@ src_libdrivers_la_SOURCES += \
src/hardware/saleae-logic16/protocol.c \
src/hardware/saleae-logic16/api.c
endif
if HW_SALEAE_LOGIC_PRO
src_libdrivers_la_SOURCES += \
src/hardware/saleae-logic-pro/protocol.h \
src/hardware/saleae-logic-pro/protocol.c \
src/hardware/saleae-logic-pro/api.c
endif
if HW_SCPI_PPS
src_libdrivers_la_SOURCES += \
src/hardware/scpi-pps/protocol.h \
@ -465,6 +526,12 @@ if HW_SERIAL_LCR
src_libdrivers_la_SOURCES += \
src/hardware/serial-lcr/api.c
endif
if HW_SIGLENT_SDS
src_libdrivers_la_SOURCES += \
src/hardware/siglent-sds/protocol.h \
src/hardware/siglent-sds/protocol.c \
src/hardware/siglent-sds/api.c
endif
if HW_SYSCLK_LWLA
src_libdrivers_la_SOURCES += \
src/hardware/sysclk-lwla/lwla.h \
@ -529,6 +596,12 @@ src_libdrivers_la_SOURCES += \
src/hardware/zeroplus-logic-cube/protocol.c \
src/hardware/zeroplus-logic-cube/api.c
endif
if HW_ZKETECH_EBD_USB
src_libdrivers_la_SOURCES += \
src/hardware/zketech-ebd-usb/protocol.h \
src/hardware/zketech-ebd-usb/protocol.c \
src/hardware/zketech-ebd-usb/api.c
endif
libsigrok_la_LIBADD = src/libdrivers.lo $(SR_EXTRA_LIBS) $(LIBSIGROK_LIBS)
libsigrok_la_LDFLAGS = -version-info $(SR_LIB_VERSION) -no-undefined
@ -544,7 +617,7 @@ noinst_HEADERS = src/libsigrok-internal.h
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libsigrok.pc
mimeappdir = $(datadir)/mime/application
mimeappdir = $(datadir)/mime/packages
mimeapp_DATA = contrib/vnd.sigrok.session.xml
mimeicondir = $(datadir)/icons/hicolor/48x48/mimetypes
@ -581,7 +654,9 @@ EXTRA_DIST = \
contrib/libsigrok.png \
contrib/libsigrok.svg \
contrib/vnd.sigrok.session.xml \
contrib/z60_libsigrok.rules
contrib/60-libsigrok.rules \
contrib/61-libsigrok-plugdev.rules \
contrib/61-libsigrok-uaccess.rules
if HAVE_CHECK
TESTS = tests/main

2
README
View File

@ -41,7 +41,7 @@ Requirements for the C library:
- libserialport >= 0.1.1 (optional, used by some drivers)
- librevisa >= 0.0.20130412 (optional, used by some drivers)
- libusb-1.0 >= 1.0.16 (optional, used by some drivers)
- libftdi >= 0.16 or libftdi1 >= 1.0 (optional, used by some drivers)
- libftdi1 >= 1.0 (optional, used by some drivers)
- libgpib (optional, used by some drivers)
- libieee1284 (optional, used by some drivers)
- check >= 0.9.4 (optional, only needed to run unit tests)

View File

@ -14,6 +14,7 @@ the device is connected to the PC (usually via USB), before it can be used.
The default locations where libsigrok expects the firmware files are:
$SIGROK_FIRMWARE_DIR (environment variable)
$HOME/.local/share/sigrok-firmware
$prefix/share/sigrok-firmware
/usr/local/share/sigrok-firmware
@ -114,6 +115,7 @@ The following drivers/devices do not need any firmware upload:
- scpi-pps
- serial-dmm (including all subdrivers)
- serial-lcr (including all subdrivers)
- siglent-sds
- teleinfo
- testo
- tondaj-sl-814
@ -138,7 +140,8 @@ Example:
$ sigrok-cli --driver <somedriver>:conn=/dev/ttyUSB0 ...
The following drivers/devices require a serial port specification:
The following drivers/devices require a serial port specification. Some of
the drivers implement a default for the connection.
- agilent-dmm
- appa-55ii
@ -183,6 +186,21 @@ The following drivers/devices do not require a serial port specification:
- yokogawa-dlm (USBTMC or TCP)
- zeroplus-logic-cube
Beyond strict serial communication over COM ports (e.g. /dev/ttyUSB0), the
conn= property can also address specific USB devices, as well as specify TCP
or VXI communication parameters. See these examples:
$ sigrok-cli --driver <somedriver>:conn=<vid>.<pid> ...
$ sigrok-cli --driver <somedriver>:conn=tcp-raw/<ipaddr>/<port> ...
$ sigrok-cli --driver <somedriver>:conn=vxi/<ipaddr> ...
The following drivers/devices accept network communication parameters:
- hameg-hmo
- rigol-ds
- siglent-sds
- yokogawa-dlm
Specifying serial port parameters
---------------------------------
@ -212,33 +230,39 @@ For USB-to-serial based devices, we recommended using our udev rules file
(see below for details).
Permissions for USB devices (udev rules file)
---------------------------------------------
Permissions for USB devices (udev rules files)
----------------------------------------------
When using USB-based devices supported by libsigrok, the user running the
libsigrok frontend (e.g. sigrok-cli) has to have (read/write) permissions
for the respective USB device.
On Linux, this is accomplished using either 'chmod' (not recommended) or
using the udev rules file shipped with libsigrok (recommended).
On Linux, this is accomplished using udev rules. libsigrok ships a rules
file containing all supported devices which can be detected reliably
(generic USB-to-serial converters are omitted, as these are used for a wide
range of devices, e.g. GPS receivers, which are not handled by libsigrok).
The file is available in contrib/z60_libsigrok.rules. It contains entries
for all libsigrok-supported (USB-based) devices and changes their group
to 'plugdev' and the permissions to '664'.
The file is available in contrib/60-libsigrok.rules. This file just contains
the list of devices and flags these devices with ID_SIGROK="1". Access is
granted by the 61-libsigrok-plugdev.rules or 61-libsigrok-uaccess.rules files,
allowing access to members of the plugdev group or to currently logged in
users, respectively.
When using a libsigrok package from your favorite Linux distribution, the
packager will have already taken care of properly installing the udev file
in the correct (distro-specific) place, and you don't have to do anything.
The packager might also have adapted 'plugdev' and '664' as needed.
files should already be installed in /usr/lib/udev/rules.d/, i.e.
60-libsigrok.rules and one of the access granting rules files. Use of
61-libsigrok-uaccess.rules is encouraged on systemd distributions.
The access policy can be locally overridden by placing appropriate rules in
/etc/udev/rules.d/, disabling or ammending the default policy. See the
udev documentation, e.g. man 7 udev, for details.
If you're building from source, you need to copy the file to the place
where your distro expects such files. This is beyond the scope of this README,
but generally the location could be e.g. /etc/udev/rules.d, or maybe
/lib/udev/rules.d, or something else. Afterwards you might have to restart
udev, e.g. via '/etc/init.d/udev restart' or similar, and you'll have to
re-attach your device via USB.
where udev will read these rules. Local rules should go to /etc/udev/rules.d.
Keep the file naming, otherwise interaction between the libsigrok rules and
rules shipped by the system will be broken.
Please consult the udev docs of your distro for details.
Please consult the udev docs for details.
Cypress FX2 based devices
@ -349,6 +373,9 @@ a short list for convenience:
'SI232 online' (28-29S) or 'SI232 store' (22-26x). The interface must
be configured to the same baud rate as the host (default 9600).
Multimeter and interface must be configured to the same address.
- Metrix MX56C: Press the PRINT button to have the meter send acquisition
data via IR. Hold the PRINT button to adjust the meter's transmission
interval.
- Norma DM950: If the interface doesn't work (e.g. USB-RS232 converter), power
on the device with "FUNC" pressed (to power the interface from the DMM).
- PCE PCE-DM32: Briefly press the "RS232" button.

View File

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

View File

@ -7,4 +7,5 @@
/** Get configuration key by string identifier. */
static const ConfigKey *get_by_identifier(string identifier);
/** Parse a string argument into the appropriate type for this key. */
static Glib::VariantBase parse_string(string value, enum sr_datatype dt);
Glib::VariantBase parse_string(string value) const;

View File

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

View File

@ -252,6 +252,8 @@ public:
map<string, shared_ptr<Driver> > drivers();
/** Available input formats, indexed by name. */
map<string, shared_ptr<InputFormat> > input_formats();
/** Lookup the responsible input module for an input file. */
shared_ptr<InputFormat> input_format_match(string filename);
/** Available output formats, indexed by name. */
map<string, shared_ptr<OutputFormat> > output_formats();
/** Current log level. */
@ -283,7 +285,7 @@ public:
/** Create an analog packet. */
shared_ptr<Packet> create_analog_packet(
vector<shared_ptr<Channel> > channels,
float *data_pointer, unsigned int num_samples, const Quantity *mq,
const float *data_pointer, unsigned int num_samples, const Quantity *mq,
const Unit *unit, vector<const QuantityFlag *> mqflags);
/** Load a saved session.
* @param filename File name string. */
@ -333,7 +335,7 @@ public:
set<const Capability *> config_capabilities(const ConfigKey *key) const;
/** Check whether a configuration capability is supported for a given key.
* @param key ConfigKey to check.
* @param capability Capability to check for. */
* @param capability Capability to check for. */
bool config_check(const ConfigKey *key, const Capability *capability) const;
protected:
Configurable(
@ -758,6 +760,8 @@ private:
const struct sr_datafeed_logic *_structure;
friend class Packet;
friend class Analog;
friend struct std::default_delete<Logic>;
};
/** Payload of a datafeed packet with analog data */
@ -803,6 +807,34 @@ public:
const Unit *unit() const;
/** Measurement flags associated with the samples in this packet. */
vector<const QuantityFlag *> mq_flags() const;
/**
* Provides a Logic packet that contains a conversion of the analog
* data using a simple threshold.
*
* @param threshold Threshold to use.
* @param data_ptr Pointer to num_samples() bytes where the logic
* samples are stored. When nullptr, memory for
* logic->data_pointer() will be allocated and must
* be freed by the caller.
*/
shared_ptr<Logic> get_logic_via_threshold(float threshold,
uint8_t *data_ptr=nullptr) const;
/**
* Provides a Logic packet that contains a conversion of the analog
* data using a Schmitt-Trigger.
*
* @param lo_thr Low threshold to use (anything below this is low).
* @param hi_thr High threshold to use (anything above this is high).
* @param state Points to a byte that contains the current state of the
* converter. For best results, set to value of logic
* sample n-1.
* @param data_ptr Pointer to num_samples() bytes where the logic
* samples are stored. When nullptr, memory for
* logic->data_pointer() will be allocated and must be
* freed by the caller.
*/
shared_ptr<Logic> get_logic_via_schmitt_trigger(float lo_thr,
float hi_thr, uint8_t *state, uint8_t *data_ptr=nullptr) const;
private:
explicit Analog(const struct sr_datafeed_analog *structure);
~Analog();
@ -845,7 +877,7 @@ public:
/** Description of this input format. */
string description() const;
/** A list of preferred file name extensions for this file format.
* @note This list is a recommendation only. */
* @note This list is a recommendation only. */
vector<string> extensions() const;
/** Options supported by this input format. */
map<string, shared_ptr<Option> > options();
@ -917,6 +949,8 @@ public:
Glib::VariantBase default_value() const;
/** Possible values for this option, if a limited set. */
vector<Glib::VariantBase> values() const;
/** Parse a string argument into the appropriate type for this option. */
Glib::VariantBase parse_string(string value);
private:
Option(const struct sr_option *structure,
shared_ptr<const struct sr_option *> structure_array);
@ -939,7 +973,7 @@ public:
/** Description of this output format. */
string description() const;
/** A list of preferred file name extensions for this file format.
* @note This list is a recommendation only. */
* @note This list is a recommendation only. */
vector<string> extensions() const;
/** Options supported by this output format. */
map<string, shared_ptr<Option> > options();

View File

@ -45,6 +45,8 @@ which provides access to the error code and description."
%module(docstring=DOCSTRING) classes
%{
#include "config.h"
#include <stdio.h>
#include <pygobject.h>
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
@ -53,8 +55,6 @@ which provides access to the error code and description."
PyObject *PyGObject_lib;
PyObject *GLib;
#include "config.h"
#if PYGOBJECT_FLAGS_SIGNED
typedef gint pyg_flags_type;
#else

View File

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

View File

@ -99,8 +99,7 @@ SR_EXTRA_CXX_LIBS=
SR_ARG_OPT_PKG([libserialport], [LIBSERIALPORT], [NEED_SERIAL],
[libserialport >= 0.1.1])
SR_ARG_OPT_PKG([libftdi], [LIBFTDI],,
[libftdi1 >= 1.0], [libftdi >= 0.16])
SR_ARG_OPT_PKG([libftdi], [LIBFTDI], , [libftdi1 >= 1.0])
# FreeBSD comes with an "integrated" libusb-1.0-style USB API.
# This means libusb-1.0 is always available; no need to check for it.
@ -234,18 +233,24 @@ SR_DRIVER([ChronoVu LA], [chronovu-la], [libusb libftdi])
SR_DRIVER([Colead SLM], [colead-slm], [libserialport])
SR_DRIVER([Conrad DIGI 35 CPU], [conrad-digi-35-cpu], [libserialport])
SR_DRIVER([demo], [demo])
SR_DRIVER([DreamSourceLab DSLogic], [dreamsourcelab-dslogic], [libusb])
SR_DRIVER([Fluke 45], [fluke-45])
SR_DRIVER([Fluke DMM], [fluke-dmm], [libserialport])
SR_DRIVER([FTDI LA], [ftdi-la], [libusb libftdi])
SR_DRIVER([fx2lafw], [fx2lafw], [libusb])
SR_DRIVER([GMC MH 1x/2x], [gmc-mh-1x-2x], [libserialport])
SR_DRIVER([GW Instek GDS-800], [gwinstek-gds-800], [libserialport])
SR_DRIVER([GW Instek GPD], [gwinstek-gpd], [libserialport])
SR_DRIVER([Hameg HMO], [hameg-hmo], [libserialport])
SR_DRIVER([Hantek 4032L], [hantek-4032l], [libusb])
SR_DRIVER([Hantek 6xxx], [hantek-6xxx], [libusb])
SR_DRIVER([Hantek DSO], [hantek-dso], [libusb])
SR_DRIVER([HP 3457A], [hp-3457a])
SR_DRIVER([HP 3478A], [hp-3478a], [libgpib])
SR_DRIVER([Hung-Chang DSO-2100], [hung-chang-dso-2100], [libieee1284])
SR_DRIVER([Ikalogic Scanalogic-2], [ikalogic-scanalogic2], [libusb])
SR_DRIVER([Ikalogic Scanaplus], [ikalogic-scanaplus], [libftdi])
SR_DRIVER([IPDBG LA], [ipdbg-la])
SR_DRIVER([Kecheng KC-330B], [kecheng-kc-330b], [libusb])
SR_DRIVER([KERN scale], [kern-scale], [libserialport])
SR_DRIVER([Korad KAxxxxP], [korad-kaxxxxp], [libserialport])
@ -260,12 +265,15 @@ SR_DRIVER([Norma DMM], [norma-dmm], [libserialport])
SR_DRIVER([OpenBench Logic Sniffer], [openbench-logic-sniffer], [libserialport])
SR_DRIVER([PCE PCE-322A], [pce-322a], [libserialport])
SR_DRIVER([Pipistrello-OLS], [pipistrello-ols], [libftdi])
SR_DRIVER([RDTech DPSxxxx/DPHxxxx], [rdtech-dps], [libserialport])
SR_DRIVER([Rigol DS], [rigol-ds])
SR_DRIVER([Rohde&Schwarz SME-0x], [rohde-schwarz-sme-0x], [libserialport])
SR_DRIVER([Saleae Logic16], [saleae-logic16], [libusb])
SR_DRIVER([Saleae Logic Pro], [saleae-logic-pro], [libusb])
SR_DRIVER([SCPI PPS], [scpi-pps])
SR_DRIVER([serial DMM], [serial-dmm], [libserialport])
SR_DRIVER([serial LCR], [serial-lcr], [libserialport])
SR_DRIVER([Siglent SDS], [siglent-sds])
SR_DRIVER([Sysclk LWLA], [sysclk-lwla], [libusb])
SR_DRIVER([Teleinfo], [teleinfo], [libserialport])
SR_DRIVER([Testo], [testo], [libusb])
@ -275,6 +283,7 @@ SR_DRIVER([UNI-T UT32x], [uni-t-ut32x], [libusb])
SR_DRIVER([Victor DMM], [victor-dmm], [libusb])
SR_DRIVER([Yokogawa DL/DLM], [yokogawa-dlm])
SR_DRIVER([ZEROPLUS Logic Cube], [zeroplus-logic-cube], [libusb])
SR_DRIVER([ZKETECH EBD-USB], [zketech-ebd-usb], [libserialport])
###############################
## Language bindings setup ##
@ -604,3 +613,24 @@ Enabled language bindings:
- Java............................ $BINDINGS_JAVA$sr_report_java
_EOF
# Emit a warning if the C++ bindings are not being built.
AM_COND_IF([BINDINGS_CXX], [], [
cat >&AS_MESSAGE_FD <<_EOF
===============================================================================
WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
===============================================================================
=== ===
=== The libsigrok C++ bindings are not being built since you ===
=== are missing one or more dependencies (see above)! ===
=== ===
=== This means you won't be able to compile frontends that require ===
=== the C++ bindings (such as PulseView)! You also won't be able to build ===
=== other bindings and frontends using those (such as sigrok-meter)! ===
=== ===
===============================================================================
WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
===============================================================================
_EOF
])

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

@ -0,0 +1,298 @@
##
## This file is part of the libsigrok project.
##
## Copyright (C) 2010-2013 Uwe Hermann <uwe@hermann-uwe.de>
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; if not, see <http://www.gnu.org/licenses/>.
##
#
# These rules do not grant any permission by itself, but flag devices
# supported by libsigrok.
# The access policy is stored in the 61-libsigrok-plugdev.rules and
# 61-libsigrok-uaccess.rules.
#
# Note: Any syntax changes here will need to be tested against the
# 'update-device-filter' Makefile target in the sigrok-androidutils
# repo, since that parses this file.
#
#
# Please keep this list sorted alphabetically by vendor/device name.
#
ACTION!="add|change", GOTO="libsigrok_rules_end"
SUBSYSTEM!="usb|usbmisc|usb_device", GOTO="libsigrok_rules_end"
# Agilent USBTMC-connected devices
# 34405A
ATTRS{idVendor}=="0957", ATTRS{idProduct}=="0618", ENV{ID_SIGROK}="1"
# 34410A
ATTRS{idVendor}=="0957", ATTRS{idProduct}=="0607", ENV{ID_SIGROK}="1"
# DSO1000 series
ATTRS{idVendor}=="0957", ATTRS{idProduct}=="0588", ENV{ID_SIGROK}="1"
# MSO7000A series
ATTRS{idVendor}=="0957", ATTRS{idProduct}=="1735", ENV{ID_SIGROK}="1"
# ASIX SIGMA
# ASIX SIGMA2
ATTRS{idVendor}=="a600", ATTRS{idProduct}=="a000", ENV{ID_SIGROK}="1"
# Braintechnology USB-LPS
ATTRS{idVendor}=="16d0", ATTRS{idProduct}=="0498", ENV{ID_SIGROK}="1"
# Brymen BU-86X adapter (e.g. for Brymen BM867/BM869 and possibly others).
ATTRS{idVendor}=="0820", ATTRS{idProduct}=="0001", ENV{ID_SIGROK}="1"
# CEM DT-8852
ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", ENV{ID_SIGROK}="1"
# ChronoVu LA8 (new VID/PID)
# ChronoVu LA16 (new VID/PID)
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8867", ENV{ID_SIGROK}="1"
# CWAV USBee AX
# ARMFLY AX-Pro (clone of the CWAV USBee AX)
# ARMFLY Mini-Logic (clone of the CWAV USBee AX)
# EE Electronics ESLA201A (clone of the CWAV USBee AX)
# HT USBee-AxPro (clone of the CWAV USBee AX)
# MCU123 USBee AX Pro clone (clone of the CWAV USBee AX)
# Noname LHT00SU1 (clone of the CWAV USBee AX)
# XZL_Studio AX (clone of the CWAV USBee AX)
ATTRS{idVendor}=="08a9", ATTRS{idProduct}=="0014", ENV{ID_SIGROK}="1"
# CWAV USBee DX
# HT USBee-DxPro (clone of the CWAV USBee DX), not yet supported!
# XZL_Studio DX (clone of the CWAV USBee DX)
ATTRS{idVendor}=="08a9", ATTRS{idProduct}=="0015", ENV{ID_SIGROK}="1"
# CWAV USBee SX
ATTRS{idVendor}=="08a9", ATTRS{idProduct}=="0009", ENV{ID_SIGROK}="1"
# CWAV USBee ZX
ATTRS{idVendor}=="08a9", ATTRS{idProduct}=="0005", ENV{ID_SIGROK}="1"
# Cypress FX2 eval boards without EEPROM:
# Lcsoft Mini Board
# Braintechnology USB Interface V2.x
# fx2grok-tiny
ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="8613", ENV{ID_SIGROK}="1"
# Dangerous Prototypes Buspirate (v3)
# ChronoVu LA8 (old VID/PID)
# ChronoVu LA16 (old VID/PID)
# ftdi-la
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", ENV{ID_SIGROK}="1"
# Dangerous Prototypes Buspirate (v4)
ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="fb00", ENV{ID_SIGROK}="1"
# DreamSourceLab DSLogic
ATTRS{idVendor}=="2a0e", ATTRS{idProduct}=="0001", ENV{ID_SIGROK}="1"
# DreamSourceLab DSLogic Pro
ATTRS{idVendor}=="2a0e", ATTRS{idProduct}=="0003", ENV{ID_SIGROK}="1"
# DreamSourceLab DScope
ATTRS{idVendor}=="2a0e", ATTRS{idProduct}=="0002", ENV{ID_SIGROK}="1"
# DreamSourceLab DSLogic Plus
ATTRS{idVendor}=="2a0e", ATTRS{idProduct}=="0020", ENV{ID_SIGROK}="1"
# DreamSourceLab DSLogic Basic
ATTRS{idVendor}=="2a0e", ATTRS{idProduct}=="0021", ENV{ID_SIGROK}="1"
# HAMEG HO720
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="ed72", ENV{ID_SIGROK}="1"
# HAMEG HO730
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="ed73", ENV{ID_SIGROK}="1"
# Hantek DSO-2090
# lsusb: "04b4:2090 Cypress Semiconductor Corp."
# lsusb after FW upload: "04b5:2090 ROHM LSI Systems USA, LLC"
ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="2090", ENV{ID_SIGROK}="1"
ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="2090", ENV{ID_SIGROK}="1"
# Hantek DSO-2150
# lsusb: "04b4:2150 Cypress Semiconductor Corp."
# lsusb after FW upload: "04b5:2150 ROHM LSI Systems USA, LLC"
ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="2150", ENV{ID_SIGROK}="1"
ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="2150", ENV{ID_SIGROK}="1"
# Hantek DSO-2250
# lsusb: "04b4:2250 Cypress Semiconductor Corp."
# lsusb after FW upload: "04b5:2250 ROHM LSI Systems USA, LLC"
ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="2250", ENV{ID_SIGROK}="1"
ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="2250", ENV{ID_SIGROK}="1"
# Hantek DSO-5200
# lsusb: "04b4:5200 Cypress Semiconductor Corp."
# lsusb after FW upload: "04b5:5200 ROHM LSI Systems USA, LLC"
ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="5200", ENV{ID_SIGROK}="1"
ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="5200", ENV{ID_SIGROK}="1"
# Hantek DSO-5200A
# lsusb: "04b4:520a Cypress Semiconductor Corp."
# lsusb after FW upload: "04b5:520a ROHM LSI Systems USA, LLC"
ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="520a", ENV{ID_SIGROK}="1"
ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="520a", ENV{ID_SIGROK}="1"
# Hantek 6022BE, renumerates as 1d50:608e "sigrok fx2lafw", Serial: Hantek 6022BE
ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="6022", ENV{ID_SIGROK}="1"
# Hantek 6022BL, renumerates as 1d50:608e "sigrok fx2lafw", Serial: Hantek 6022BL
ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="602a", ENV{ID_SIGROK}="1"
# Hantek 4032L
ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="4032", ENV{ID_SIGROK}="1"
# IKALOGIC Scanalogic-2
ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="4123", ENV{ID_SIGROK}="1"
# IKALOGIC ScanaPLUS
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6014", ENV{ID_SIGROK}="1"
# Kecheng KC-330B
ATTRS{idVendor}=="1041", ATTRS{idProduct}=="8101", ENV{ID_SIGROK}="1"
# Lascar Electronics EL-USB-2
# Lascar Electronics EL-USB-CO
# This is actually the generic SiLabs (Cygnal) F32x USBXpress VID:PID.
ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="0002", ENV{ID_SIGROK}="1"
# LeCroy LogicStudio16
ATTRS{idVendor}=="05ff", ATTRS{idProduct}=="a001", ENV{ID_SIGROK}="1"
ATTRS{idVendor}=="05ff", ATTRS{idProduct}=="a002", ENV{ID_SIGROK}="1"
# Link Instruments MSO-19
ATTRS{idVendor}=="3195", ATTRS{idProduct}=="f190", ENV{ID_SIGROK}="1"
# Logic Shrimp
ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="fa95", ENV{ID_SIGROK}="1"
# MiniLA Mockup
# ftdi-la
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6010", ENV{ID_SIGROK}="1"
# MIC 98581
# MIC 98583
# Tondaj SL-814
ATTRS{idVendor}=="067b", ATTRS{idProduct}=="2303", ENV{ID_SIGROK}="1"
# Openbench Logic Sniffer
ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="000a", ENV{ID_SIGROK}="1"
# Rigol DS1000 series
ATTRS{idVendor}=="1ab1", ATTRS{idProduct}=="0588", ENV{ID_SIGROK}="1"
# Rigol 1000Z series
ATTRS{idVendor}=="1ab1", ATTRS{idProduct}=="04ce", ENV{ID_SIGROK}="1"
# Rigol DS2000 series
ATTRS{idVendor}=="1ab1", ATTRS{idProduct}=="04b0", ENV{ID_SIGROK}="1"
# Rigol DS4000 series
ATTRS{idVendor}=="1ab1", ATTRS{idProduct}=="04b1", ENV{ID_SIGROK}="1"
# Rigol DG4000 series
ATTRS{idVendor}=="1ab1", ATTRS{idProduct}=="0641", ENV{ID_SIGROK}="1"
# Rigol DP800 series
ATTRS{idVendor}=="1ab1", ATTRS{idProduct}=="0e11", ENV{ID_SIGROK}="1"
# Rohde&Schwarz HMO1002 Series VCP/USBTMC mode
ATTRS{idVendor}=="0aad", ATTRS{idProduct}=="0118", ENV{ID_SIGROK}="1"
ATTRS{idVendor}=="0aad", ATTRS{idProduct}=="0119", ENV{ID_SIGROK}="1"
# Sainsmart DDS120 / Rocktech BM102, renumerates as 1d50:608e "sigrok fx2lafw", Serial: Sainsmart DDS120
ATTRS{idVendor}=="8102", ATTRS{idProduct}=="8102", ENV{ID_SIGROK}="1"
# Saleae Logic
# EE Electronics ESLA100 (clone of the Saleae Logic)
# Hantek 6022BL in LA mode (clone of the Saleae Logic)
# Instrustar ISDS205X in LA mode (clone of the Saleae Logic)
# Robomotic MiniLogic (clone of the Saleae Logic)
# Robomotic BugLogic 3 (clone of the Saleae Logic)
# MCU123 Saleae Logic clone (clone of the Saleae Logic)
ATTRS{idVendor}=="0925", ATTRS{idProduct}=="3881", ENV{ID_SIGROK}="1"
# Saleae Logic16
ATTRS{idVendor}=="21a9", ATTRS{idProduct}=="1001", ENV{ID_SIGROK}="1"
# Saleae Logic Pro 16
ATTRS{idVendor}=="21a9", ATTRS{idProduct}=="1006", ENV{ID_SIGROK}="1"
# Siglent USBTMC devices.
# f4ec:ee3a: E.g. SDS1052DL+ scope
# f4ed:ee3a: E.g. SDS1202X-E scope or SDG1010 waveform generator
ATTRS{idVendor}=="f4ec", ATTRS{idProduct}=="ee3a", ENV{ID_SIGROK}="1"
ATTRS{idVendor}=="f4ed", ATTRS{idProduct}=="ee3a", ENV{ID_SIGROK}="1"
# sigrok FX2 LA (8ch)
# fx2grok-flat (before and after renumeration)
ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="608c", ENV{ID_SIGROK}="1"
# sigrok FX2 LA (16ch)
ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="608d", ENV{ID_SIGROK}="1"
# sigrok FX2 DSO (2ch)
ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="608e", ENV{ID_SIGROK}="1"
# sigrok usb-c-grok
ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="608f", ENV{ID_SIGROK}="1"
# SysClk LWLA1016
ATTRS{idVendor}=="2961", ATTRS{idProduct}=="6688", ENV{ID_SIGROK}="1"
# SysClk LWLA1034
ATTRS{idVendor}=="2961", ATTRS{idProduct}=="6689", ENV{ID_SIGROK}="1"
# Testo 435
ATTRS{idVendor}=="128d", ATTRS{idProduct}=="0003", ENV{ID_SIGROK}="1"
# UNI-T UT-D04 multimeter cable (for various UNI-T and rebranded DMMs)
# http://sigrok.org/wiki/Device_cables#UNI-T_UT-D04
# UNI-T UT325
ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="e008", ENV{ID_SIGROK}="1"
# V&A VA4000 multimeter cable (for various V&A DMMs)
# http://sigrok.org/wiki/Device_cables#V.26A_VA4000
ATTRS{idVendor}=="04fc", ATTRS{idProduct}=="0201", ENV{ID_SIGROK}="1"
# Victor 70C
# Victor 86C
ATTRS{idVendor}=="1244", ATTRS{idProduct}=="d237", ENV{ID_SIGROK}="1"
# ZEROPLUS Logic Cube LAP-C series
# There are various devices in the ZEROPLUS Logic Cube series:
# 0c12:7002: LAP-16128U
# 0c12:7009: LAP-C(16064)
# 0c12:700a: LAP-C(16128)
# 0c12:700b: LAP-C(32128)
# 0c12:700c: LAP-C(321000)
# 0c12:700d: LAP-C(322000)
# 0c12:700e: LAP-C(16032)
# 0c12:7016: LAP-C(162000)
# 0c12:7025: LAP-C(16128+)
# 0c12:7100: AKIP-9101
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="7002", ENV{ID_SIGROK}="1"
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="7007", ENV{ID_SIGROK}="1"
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="7009", ENV{ID_SIGROK}="1"
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="700a", ENV{ID_SIGROK}="1"
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="700b", ENV{ID_SIGROK}="1"
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="700c", ENV{ID_SIGROK}="1"
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="700d", ENV{ID_SIGROK}="1"
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="700e", ENV{ID_SIGROK}="1"
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="7016", ENV{ID_SIGROK}="1"
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="7025", ENV{ID_SIGROK}="1"
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="7100", ENV{ID_SIGROK}="1"
LABEL="libsigrok_rules_end"

View File

@ -0,0 +1,31 @@
##
## This file is part of the libsigrok project.
##
## Copyright (C) 2017 Stefan Bruens <stefan.bruens@rwth-aachen.de>
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; if not, see <http://www.gnu.org/licenses/>.
##
# Grant access permissions to users who are in the "plugdev" group.
# "plugdev" is typically used on Debian based distributions and may not
# exist elsewhere.
#
# This file, when installed, must be installed with a name lexicographically
# sorted later than the accompanied 60-libsigrok.rules
ACTION!="add|change", GOTO="libsigrok_rules_plugdev_end"
ENV{ID_SIGROK}=="1", MODE="660", GROUP="plugdev"
LABEL="libsigrok_rules_plugdev_end"

View File

@ -0,0 +1,32 @@
##
## This file is part of the libsigrok project.
##
## Copyright (C) 2017 Stefan Bruens <stefan.bruens@rwth-aachen.de>
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; if not, see <http://www.gnu.org/licenses/>.
##
# Grant access permissions to users who are currently logged in locally.
# This is the default policy for systems using systemd-logind (or a
# compatible replacement).
#
# This file, when installed, must be installed with a name lexicographically
# sorted later than the accompanied 60-libsigrok.rules, and earlier than
# the systemd upstream 71-seat.rules.
ACTION!="add|change", GOTO="libsigrok_rules_uaccess_end"
ENV{ID_SIGROK}=="1", TAG+="uaccess"
LABEL="libsigrok_rules_uaccess_end"

View File

@ -1,243 +0,0 @@
##
## This file is part of the libsigrok project.
##
## Copyright (C) 2010-2013 Uwe Hermann <uwe@hermann-uwe.de>
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; if not, see <http://www.gnu.org/licenses/>.
##
# NOTE: On a systemd based system, using tag=uaccess, this file _must_ be
# named/numbered to come before the seat rules are applied in 70-xxx.
##
## Please keep this list sorted alphabetically by vendor/device name.
##
ACTION!="add|change", GOTO="libsigrok_rules_end"
SUBSYSTEM!="usb|usbmisc|usb_device", GOTO="libsigrok_rules_end"
# Agilent USBTMC-connected devices
# 34405A
ATTRS{idVendor}=="0957", ATTRS{idProduct}=="0618", MODE="660", GROUP="plugdev", TAG+="uaccess"
# 34410A
ATTRS{idVendor}=="0957", ATTRS{idProduct}=="0607", MODE="660", GROUP="plugdev", TAG+="uaccess"
# DSO1000 series
ATTRS{idVendor}=="0957", ATTRS{idProduct}=="0588", MODE="660", GROUP="plugdev", TAG+="uaccess"
# ASIX SIGMA
# ASIX SIGMA2
ATTRS{idVendor}=="a600", ATTRS{idProduct}=="a000", MODE="660", GROUP="plugdev", TAG+="uaccess"
# Braintechnology USB-LPS
ATTRS{idVendor}=="16d0", ATTRS{idProduct}=="0498", MODE="660", GROUP="plugdev", TAG+="uaccess"
# CEM DT-8852
ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", MODE="660", GROUP="plugdev", TAG+="uaccess"
# ChronoVu LA8 (new VID/PID)
# ChronoVu LA16 (new VID/PID)
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8867", MODE="660", GROUP="plugdev", TAG+="uaccess"
# CWAV USBee AX
# ARMFLY AX-Pro (clone of the CWAV USBee AX)
# ARMFLY Mini-Logic (clone of the CWAV USBee AX)
# EE Electronics ESLA201A (clone of the CWAV USBee AX)
# MCU123 USBee AX Pro clone (clone of the CWAV USBee AX)
# XZL_Studio AX (clone of the CWAV USBee AX)
ATTRS{idVendor}=="08a9", ATTRS{idProduct}=="0014", MODE="660", GROUP="plugdev", TAG+="uaccess"
# CWAV USBee DX
# XZL_Studio DX (clone of the CWAV USBee DX)
ATTRS{idVendor}=="08a9", ATTRS{idProduct}=="0015", MODE="660", GROUP="plugdev", TAG+="uaccess"
# CWAV USBee SX
ATTRS{idVendor}=="08a9", ATTRS{idProduct}=="0009", MODE="660", GROUP="plugdev", TAG+="uaccess"
# Cypress FX2 eval boards without EEPROM:
# Lcsoft Mini Board
# Braintechnology USB Interface V2.x
ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="8613", MODE="660", GROUP="plugdev", TAG+="uaccess"
# Dangerous Prototypes Buspirate (v3)
# ChronoVu LA8 (old VID/PID)
# ChronoVu LA16 (old VID/PID)
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", MODE="660", GROUP="plugdev", TAG+="uaccess"
# Dangerous Prototypes Buspirate (v4)
ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="fb00", MODE="660", GROUP="plugdev", TAG+="uaccess"
# DreamSourceLab DSLogic
ATTRS{idVendor}=="2a0e", ATTRS{idProduct}=="0001", MODE="660", GROUP="plugdev", TAG+="uaccess"
# DreamSourceLab DSLogic Pro
ATTRS{idVendor}=="2a0e", ATTRS{idProduct}=="0003", MODE="660", GROUP="plugdev", TAG+="uaccess"
# DreamSourceLab DScope
ATTRS{idVendor}=="2a0e", ATTRS{idProduct}=="0002", MODE="660", GROUP="plugdev", TAG+="uaccess"
# HAMEG HO720
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="ed72", MODE="660", GROUP="plugdev", TAG+="uaccess"
# HAMEG HO730
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="ed73", MODE="660", GROUP="plugdev", TAG+="uaccess"
# Hantek DSO-2090
# lsusb: "04b4:2090 Cypress Semiconductor Corp."
# lsusb after FW upload: "04b5:2090 ROHM LSI Systems USA, LLC"
ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="2090", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="2090", MODE="660", GROUP="plugdev", TAG+="uaccess"
# Hantek DSO-2150
# lsusb: "04b4:2150 Cypress Semiconductor Corp."
# lsusb after FW upload: "04b5:2150 ROHM LSI Systems USA, LLC"
ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="2150", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="2150", MODE="660", GROUP="plugdev", TAG+="uaccess"
# Hantek DSO-2250
# lsusb: "04b4:2250 Cypress Semiconductor Corp."
# lsusb after FW upload: "04b5:2250 ROHM LSI Systems USA, LLC"
ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="2250", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="2250", MODE="660", GROUP="plugdev", TAG+="uaccess"
# Hantek DSO-5200
# lsusb: "04b4:5200 Cypress Semiconductor Corp."
# lsusb after FW upload: "04b5:5200 ROHM LSI Systems USA, LLC"
ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="5200", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="5200", MODE="660", GROUP="plugdev", TAG+="uaccess"
# Hantek DSO-5200A
# lsusb: "04b4:520a Cypress Semiconductor Corp."
# lsusb after FW upload: "04b5:520a ROHM LSI Systems USA, LLC"
ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="520a", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="520a", MODE="660", GROUP="plugdev", TAG+="uaccess"
# Hantek 6022BE
ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="6022", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="608e", MODE="660", GROUP="plugdev", TAG+="uaccess"
# Hantek 6022BL
ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="602a", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="608e", MODE="660", GROUP="plugdev", TAG+="uaccess"
# IKALOGIC Scanalogic-2
ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="4123", MODE="660", GROUP="plugdev", TAG+="uaccess"
# IKALOGIC ScanaPLUS
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6014", MODE="660", GROUP="plugdev", TAG+="uaccess"
# Kecheng KC-330B
ATTRS{idVendor}=="1041", ATTRS{idProduct}=="8101", MODE="660", GROUP="plugdev", TAG+="uaccess"
# Lascar Electronics EL-USB-2
# Lascar Electronics EL-USB-CO
# This is actually the generic SiLabs (Cygnal) F32x USBXpress VID:PID.
ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="0002", MODE="660", GROUP="plugdev", TAG+="uaccess"
# LeCroy LogicStudio16
ATTRS{idVendor}=="05ff", ATTRS{idProduct}=="a001", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="05ff", ATTRS{idProduct}=="a002", MODE="660", GROUP="plugdev", TAG+="uaccess"
# Link Instruments MSO-19
ATTRS{idVendor}=="3195", ATTRS{idProduct}=="f190", MODE="660", GROUP="plugdev", TAG+="uaccess"
# Logic Shrimp
ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="fa95", MODE="660", GROUP="plugdev", TAG+="uaccess"
# MiniLA Mockup
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6010", MODE="660", GROUP="plugdev", TAG+="uaccess"
# MIC 98581
# MIC 98583
# Tondaj SL-814
ATTRS{idVendor}=="067b", ATTRS{idProduct}=="2303", MODE="660", GROUP="plugdev", TAG+="uaccess"
# Openbench Logic Sniffer
ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="000a", MODE="660", GROUP="plugdev", TAG+="uaccess"
# Rigol DS1000 series
ATTRS{idVendor}=="1ab1", ATTRS{idProduct}=="0588", MODE="660", GROUP="plugdev", TAG+="uaccess"
# Rigol 1000Z series
ATTRS{idVendor}=="1ab1", ATTRS{idProduct}=="04ce", MODE="660", GROUP="plugdev", TAG+="uaccess"
# Rigol DS2000 series
ATTRS{idVendor}=="1ab1", ATTRS{idProduct}=="04b0", MODE="660", GROUP="plugdev", TAG+="uaccess"
# Rigol DG4000 series
ATTRS{idVendor}=="1ab1", ATTRS{idProduct}=="0641", MODE="660", GROUP="plugdev", TAG+="uaccess"
# Rohde&Schwarz HMO1002 Series VCP/USBTMC mode
ATTRS{idVendor}=="0aad", ATTRS{idProduct}=="0118", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="0aad", ATTRS{idProduct}=="0119", MODE="660", GROUP="plugdev", TAG+="uaccess"
# Sainsmart DDS120 / Rocktech BM102
ATTRS{idVendor}=="8102", ATTRS{idProduct}=="8102", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="608e", MODE="660", GROUP="plugdev", TAG+="uaccess"
# Saleae Logic
# EE Electronics ESLA100 (clone of the Saleae Logic)
# Robomotic MiniLogic (clone of the Saleae Logic)
# Robomotic BugLogic 3 (clone of the Saleae Logic)
# MCU123 Saleae Logic clone (clone of the Saleae Logic)
ATTRS{idVendor}=="0925", ATTRS{idProduct}=="3881", MODE="660", GROUP="plugdev", TAG+="uaccess"
# Saleae Logic16
ATTRS{idVendor}=="21a9", ATTRS{idProduct}=="1001", MODE="660", GROUP="plugdev", TAG+="uaccess"
# sigrok FX2 LA (8ch)
ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="608c", MODE="660", GROUP="plugdev", TAG+="uaccess"
# sigrok FX2 LA (16ch)
ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="608d", MODE="660", GROUP="plugdev", TAG+="uaccess"
# SysClk LWLA1016
ATTRS{idVendor}=="2961", ATTRS{idProduct}=="6688", MODE="660", GROUP="plugdev", TAG+="uaccess"
# SysClk LWLA1034
ATTRS{idVendor}=="2961", ATTRS{idProduct}=="6689", MODE="660", GROUP="plugdev", TAG+="uaccess"
# Testo 435
ATTRS{idVendor}=="128d", ATTRS{idProduct}=="0003", MODE="660", GROUP="plugdev", TAG+="uaccess"
# UNI-T UT-D04 multimeter cable (for various UNI-T and rebranded DMMs)
# http://sigrok.org/wiki/Device_cables#UNI-T_UT-D04
# UNI-T UT325
ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="e008", MODE="660", GROUP="plugdev", TAG+="uaccess"
# V&A VA4000 multimeter cable (for various V&A DMMs)
# http://sigrok.org/wiki/Device_cables#V.26A_VA4000
ATTRS{idVendor}=="04fc", ATTRS{idProduct}=="0201", MODE="660", GROUP="plugdev", TAG+="uaccess"
# Victor 70C
# Victor 86C
ATTRS{idVendor}=="1244", ATTRS{idProduct}=="d237", MODE="660", GROUP="plugdev", TAG+="uaccess"
# ZEROPLUS Logic Cube LAP-C series
# There are various devices in the ZEROPLUS Logic Cube series:
# 0c12:7002: LAP-16128U
# 0c12:7009: LAP-C(16064)
# 0c12:700a: LAP-C(16128)
# 0c12:700b: LAP-C(32128)
# 0c12:700c: LAP-C(321000)
# 0c12:700d: LAP-C(322000)
# 0c12:700e: LAP-C(16032)
# 0c12:7016: LAP-C(162000)
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="7002", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="7009", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="700a", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="700b", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="700c", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="700d", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="700e", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="7016", MODE="660", GROUP="plugdev", TAG+="uaccess"
LABEL="libsigrok_rules_end"

View File

@ -84,11 +84,11 @@ enum sr_error_code {
/* Handy little macros */
#define SR_HZ(n) (n)
#define SR_KHZ(n) ((n) * (uint64_t)(1000ULL))
#define SR_MHZ(n) ((n) * (uint64_t)(1000000ULL))
#define SR_GHZ(n) ((n) * (uint64_t)(1000000000ULL))
#define SR_KHZ(n) ((n) * UINT64_C(1000))
#define SR_MHZ(n) ((n) * UINT64_C(1000000))
#define SR_GHZ(n) ((n) * UINT64_C(1000000000))
#define SR_HZ_TO_NS(n) ((uint64_t)(1000000000ULL) / (n))
#define SR_HZ_TO_NS(n) (UINT64_C(1000000000) / (n))
/** libsigrok loglevels. */
enum sr_loglevel {
@ -650,11 +650,11 @@ struct sr_key_info {
/** Configuration capabilities. */
enum sr_configcap {
/** Value can be read. */
SR_CONF_GET = (1 << 31),
SR_CONF_GET = (1UL << 31),
/** Value can be written. */
SR_CONF_SET = (1 << 30),
SR_CONF_SET = (1UL << 30),
/** Possible values can be enumerated. */
SR_CONF_LIST = (1 << 29),
SR_CONF_LIST = (1UL << 29),
};
/** Configuration keys */
@ -703,6 +703,9 @@ enum sr_configkey {
/** The device can act as a function generator. */
SR_CONF_SIGNAL_GENERATOR,
/** The device can measure power. */
SR_CONF_POWERMETER,
/* Update sr_key_info_config[] (hwdriver.c) upon changes! */
/*--- Driver scan options -------------------------------------------*/
@ -983,6 +986,15 @@ enum sr_configkey {
/** Trigger level. */
SR_CONF_TRIGGER_LEVEL,
/** Under-voltage condition threshold. */
SR_CONF_UNDER_VOLTAGE_CONDITION_THRESHOLD,
/**
* Which external clock source to use if the device supports
* multiple external clock channels.
*/
SR_CONF_EXTERNAL_CLOCK_SOURCE,
/* Update sr_key_info_config[] (hwdriver.c) upon changes! */
/*--- Special stuff -------------------------------------------------*/

View File

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

View File

@ -174,8 +174,7 @@ SR_PRIV int sr_analog_init(struct sr_datafeed_analog *analog,
SR_API int sr_analog_to_float(const struct sr_datafeed_analog *analog,
float *outbuf)
{
float offset;
unsigned int b, i, count;
unsigned int b, count;
gboolean bigendian;
if (!analog || !(analog->data) || !(analog->meaning)
@ -275,7 +274,7 @@ SR_API int sr_analog_to_float(const struct sr_datafeed_analog *analog,
/* The data is already in the right format. */
memcpy(outbuf, analog->data, count * sizeof(float));
} else {
for (i = 0; i < count; i += analog->encoding->unitsize) {
for (unsigned int i = 0; i < count; i += analog->encoding->unitsize) {
for (b = 0; b < analog->encoding->unitsize; b++) {
if (analog->encoding->is_bigendian == bigendian)
((uint8_t *)outbuf)[i + b] =
@ -287,7 +286,7 @@ SR_API int sr_analog_to_float(const struct sr_datafeed_analog *analog,
if (analog->encoding->scale.p != 1
|| analog->encoding->scale.q != 1)
outbuf[i] = (outbuf[i] * analog->encoding->scale.p) / analog->encoding->scale.q;
offset = ((float)analog->encoding->offset.p / (float)analog->encoding->offset.q);
float offset = ((float)analog->encoding->offset.p / (float)analog->encoding->offset.q);
outbuf[i] += offset;
}
}
@ -308,7 +307,7 @@ SR_API int sr_analog_to_float(const struct sr_datafeed_analog *analog,
SR_API const char *sr_analog_si_prefix(float *value, int *digits)
{
/** @cond PRIVATE */
#define NEG_PREFIX_COUNT 5 /* number of prefixes below unity */
#define NEG_PREFIX_COUNT 5 /* number of prefixes below unity */
#define POS_PREFIX_COUNT (int)(ARRAY_SIZE(prefixes) - NEG_PREFIX_COUNT - 1)
/** @endcond */
static const char *prefixes[] = { "f", "p", "n", "µ", "m", "", "k", "M", "G", "T" };
@ -366,12 +365,9 @@ SR_API gboolean sr_analog_si_prefix_friendly(enum sr_unit unit)
for (i = 0; i < ARRAY_SIZE(prefix_friendly_units); i++)
if (unit == prefix_friendly_units[i])
break;
return TRUE;
if (unit != prefix_friendly_units[i])
return FALSE;
return TRUE;
return FALSE;
}
/**
@ -555,8 +551,8 @@ SR_API int sr_rational_mult(struct sr_rational *res, const struct sr_rational *a
return SR_ERR_ARG;
}
res->p = (int64_t)(p);
res->q = (uint64_t)(q);
res->p = (int64_t)p;
res->q = (uint64_t)q;
return SR_OK;

View File

@ -153,8 +153,14 @@ SR_API GSList *sr_buildinfo_libs_get(void)
m = g_slist_append(m, g_strdup_printf("%s", CONF_LIBUSB_1_0_VERSION));
#else
lv = libusb_get_version();
m = g_slist_append(m, g_strdup_printf("%d.%d.%d.%d%s",
lv->major, lv->minor, lv->micro, lv->nano, lv->rc));
m = g_slist_append(m, g_strdup_printf("%d.%d.%d.%d%s API 0x%08x",
lv->major, lv->minor, lv->micro, lv->nano, lv->rc,
#if defined(LIBUSB_API_VERSION)
LIBUSB_API_VERSION
#elif defined(LIBUSBX_API_VERSION)
LIBUSBX_API_VERSION
#endif
));
#endif
l = g_slist_append(l, m);
#endif
@ -255,6 +261,17 @@ static void print_versions(void)
g_free(str);
}
static void print_resourcepaths(void)
{
GSList *l, *l_orig;
sr_dbg("Firmware search paths:");
l_orig = sr_resourcepaths_get(SR_RESOURCE_FIRMWARE);
for (l = l_orig; l; l = l->next)
sr_dbg(" - %s", (const char *)l->data);
g_slist_free_full(l_orig, g_free);
}
/**
* Sanity-check all libsigrok drivers.
*
@ -309,7 +326,10 @@ static int sanity_check_all_drivers(const struct sr_context *ctx)
sr_err("No dev_list in driver %d ('%s').", i, d);
errors++;
}
/* Note: dev_clear() is optional. */
if (!drivers[i]->dev_clear) {
sr_err("No dev_clear in driver %d ('%s').", i, d);
errors++;
}
/* Note: config_get() is optional. */
if (!drivers[i]->config_set) {
sr_err("No config_set in driver %d ('%s').", i, d);
@ -526,6 +546,8 @@ SR_API int sr_init(struct sr_context **ctx)
print_versions();
print_resourcepaths();
if (!ctx) {
sr_err("%s(): libsigrok context was NULL.", __func__);
return SR_ERR;
@ -537,22 +559,22 @@ SR_API int sr_init(struct sr_context **ctx)
if (sanity_check_all_drivers(context) < 0) {
sr_err("Internal driver error(s), aborting.");
return ret;
goto done;
}
if (sanity_check_all_input_modules() < 0) {
sr_err("Internal input module error(s), aborting.");
return ret;
goto done;
}
if (sanity_check_all_output_modules() < 0) {
sr_err("Internal output module error(s), aborting.");
return ret;
goto done;
}
if (sanity_check_all_transform_modules() < 0) {
sr_err("Internal transform module error(s), aborting.");
return ret;
goto done;
}
#ifdef _WIN32
@ -577,9 +599,7 @@ SR_API int sr_init(struct sr_context **ctx)
context = NULL;
ret = SR_OK;
#if defined(HAVE_LIBUSB_1_0) || defined(_WIN32)
done:
#endif
g_free(context);
return ret;
}

107
src/conversion.c Normal file
View File

@ -0,0 +1,107 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2017 Soeren Apel <soeren@apelpie.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file
*
* Conversion helper functions.
*/
#include <libsigrok/libsigrok.h>
#include "libsigrok-internal.h"
#define LOG_PREFIX "conv"
/**
* Convert analog values to logic values by using a fixed threshold.
*
* @param[in] analog The analog input values.
* @param[in] threshold The threshold to use.
* @param[out] output The converted output values; either 0 or 1. Must provide
* space for count bytes.
* @param[in] count The number of samples to process.
*
* @return SR_OK on success or SR_ERR on failure.
*/
SR_API int sr_a2l_threshold(const struct sr_datafeed_analog *analog,
float threshold, uint8_t *output, uint64_t count)
{
float *input;
if (!analog->encoding->is_float) {
input = g_try_malloc(sizeof(float) * count);
if (!input)
return SR_ERR;
sr_analog_to_float(analog, input);
} else
input = analog->data;
for (uint64_t i = 0; i < count; i++)
output[i] = (input[i] >= threshold) ? 1 : 0;
if (!analog->encoding->is_float)
g_free(input);
return SR_OK;
}
/**
* Convert analog values to logic values by using a Schmitt-trigger algorithm.
*
* @param analog The analog input values.
* @param lo_thr The low threshold - result becomes 0 below it.
* @param lo_thr The high threshold - result becomes 1 above it.
* @param state The internal converter state. Must contain the state of logic
* sample n-1, will contain the state of logic sample n+count upon exit.
* @param output The converted output values; either 0 or 1. Must provide
* space for count bytes.
* @param count The number of samples to process.
*
* @return SR_OK on success or SR_ERR on failure.
*/
SR_API int sr_a2l_schmitt_trigger(const struct sr_datafeed_analog *analog,
float lo_thr, float hi_thr, uint8_t *state, uint8_t *output,
uint64_t count)
{
float *input;
if (!analog->encoding->is_float) {
input = g_try_malloc(sizeof(float) * count);
if (!input)
return SR_ERR;
sr_analog_to_float(analog, input);
} else
input = analog->data;
for (uint64_t i = 0; i < count; i++) {
if (input[i] < lo_thr)
*state = 0;
else if (input[i] > hi_thr)
*state = 1;
output[i] = *state;
}
if (!analog->encoding->is_float)
g_free(input);
return SR_OK;
}

View File

@ -18,8 +18,9 @@
*/
#include <config.h>
#include <stdio.h>
#include <glib.h>
#include <stdio.h>
#include <string.h>
#include <libsigrok/libsigrok.h>
#include "libsigrok-internal.h"
@ -73,6 +74,30 @@ SR_PRIV struct sr_channel *sr_channel_new(struct sr_dev_inst *sdi,
return ch;
}
/**
* Release a previously allocated struct sr_channel.
*
* @param[in] ch Pointer to struct sr_channel.
*
* @private
*/
SR_PRIV void sr_channel_free(struct sr_channel *ch)
{
if (!ch)
return;
g_free(ch->name);
g_free(ch->priv);
g_free(ch);
}
/**
* Wrapper around @ref sr_channel_free(), suitable for glib iterators.
*/
SR_PRIV void sr_channel_free_cb(void *p)
{
sr_channel_free(p);
}
/**
* Set the name of the specified channel.
*
@ -135,10 +160,18 @@ SR_API int sr_dev_channel_enable(struct sr_channel *channel, gboolean state)
return SR_OK;
}
/* Returns the next enabled channel, wrapping around if necessary. */
/** @private */
/**
* Returns the next enabled channel, wrapping around if necessary.
*
* @param[in] sdi The device instance the channel is connected to.
* Must not be NULL.
* @param[in] cur_channel The current channel.
*
* @return A pointer to the next enabled channel of this device.
*
* @private
*/
SR_PRIV struct sr_channel *sr_next_enabled_channel(const struct sr_dev_inst *sdi,
struct sr_channel *cur_channel)
{
struct sr_channel *next_channel;
@ -156,6 +189,69 @@ SR_PRIV struct sr_channel *sr_next_enabled_channel(const struct sr_dev_inst *sdi
return next_channel;
}
/**
* Compare two channels, return whether they differ.
*
* The channels' names and types are checked. The enabled state is not
* considered a condition for difference. The test is motivated by the
* desire to detect changes in the configuration of acquisition setups
* between re-reads of an input file.
*
* @param[in] ch1 First channel.
* @param[in] ch2 Second channel.
*
* @return #TRUE upon differences or unexpected input, #FALSE otherwise.
*
* @internal
*/
SR_PRIV gboolean sr_channels_differ(struct sr_channel *ch1, struct sr_channel *ch2)
{
if (!ch1 || !ch2)
return TRUE;
if (ch1->type != ch2->type)
return TRUE;
if (strcmp(ch1->name, ch2->name))
return TRUE;
return FALSE;
}
/**
* Compare two channel lists, return whether they differ.
*
* Listing the same set of channels but in a different order is considered
* a difference in the lists.
*
* @param[in] l1 First channel list.
* @param[in] l2 Second channel list.
*
* @return #TRUE upon differences or unexpected input, #FALSE otherwise.
*
* @internal
*/
SR_PRIV gboolean sr_channel_lists_differ(GSList *l1, GSList *l2)
{
struct sr_channel *ch1, *ch2;
while (l1 && l2) {
ch1 = l1->data;
ch2 = l2->data;
l1 = l1->next;
l2 = l2->next;
if (!ch1 || !ch2)
return TRUE;
if (sr_channels_differ(ch1, ch2))
return TRUE;
if (ch1->index != ch2->index)
return TRUE;
}
if (l1 || l2)
return TRUE;
return FALSE;
}
/**
* Determine whether the specified device instance has the specified
* capability.
@ -356,9 +452,7 @@ SR_PRIV void sr_dev_inst_free(struct sr_dev_inst *sdi)
for (l = sdi->channels; l; l = l->next) {
ch = l->data;
g_free(ch->name);
g_free(ch->priv);
g_free(ch);
sr_channel_free(ch);
}
g_slist_free(sdi->channels);
@ -529,27 +623,40 @@ SR_API GSList *sr_dev_list(const struct sr_dev_driver *driver)
*/
SR_API int sr_dev_clear(const struct sr_dev_driver *driver)
{
int ret;
if (!driver) {
sr_err("Invalid driver.");
return SR_ERR_ARG;
}
if (driver->dev_clear)
ret = driver->dev_clear(driver);
else
ret = std_dev_clear(driver, NULL);
if (!driver->context) {
/*
* Driver was never initialized, nothing to do.
*
* No log message since this usually gets called for all
* drivers, whether they were initialized or not.
*/
return SR_OK;
}
return ret;
/* No log message here, too verbose and not very useful. */
return driver->dev_clear(driver);
}
/**
* Open the specified device.
* Open the specified device instance.
*
* If the device instance is already open (sdi->status == SR_ST_ACTIVE),
* SR_ERR will be returned and no re-opening of the device will be attempted.
*
* If opening was successful, sdi->status is set to SR_ST_ACTIVE, otherwise
* it will be left unchanged.
*
* @param sdi Device instance to use. Must not be NULL.
*
* @return SR_OK upon success, a negative error code upon errors.
* @retval SR_OK Success.
* @retval SR_ERR_ARG Invalid arguments.
* @retval SR_ERR Device instance was already active, or other error.
*
* @since 0.2.0
*/
@ -558,32 +665,59 @@ SR_API int sr_dev_open(struct sr_dev_inst *sdi)
int ret;
if (!sdi || !sdi->driver || !sdi->driver->dev_open)
return SR_ERR_ARG;
if (sdi->status == SR_ST_ACTIVE) {
sr_err("%s: Device instance already active, can't re-open.",
sdi->driver->name);
return SR_ERR;
}
sr_dbg("%s: Opening device instance.", sdi->driver->name);
ret = sdi->driver->dev_open(sdi);
if (ret == SR_OK)
sdi->status = SR_ST_ACTIVE;
return ret;
}
/**
* Close the specified device.
* Close the specified device instance.
*
* If the device instance is not open (sdi->status != SR_ST_ACTIVE),
* SR_ERR_DEV_CLOSED will be returned and no closing will be attempted.
*
* Note: sdi->status will be set to SR_ST_INACTIVE, regardless of whether
* there are any errors during closing of the device instance (any errors
* will be reported via error code and log message, though).
*
* @param sdi Device instance to use. Must not be NULL.
*
* @return SR_OK upon success, a negative error code upon errors.
* @retval SR_OK Success.
* @retval SR_ERR_ARG Invalid arguments.
* @retval SR_ERR_DEV_CLOSED Device instance was not active.
* @retval SR_ERR Other error.
*
* @since 0.2.0
*/
SR_API int sr_dev_close(struct sr_dev_inst *sdi)
{
int ret;
if (!sdi || !sdi->driver || !sdi->driver->dev_close)
return SR_ERR;
return SR_ERR_ARG;
ret = sdi->driver->dev_close(sdi);
if (sdi->status != SR_ST_ACTIVE) {
sr_err("%s: Device instance not active, can't close.",
sdi->driver->name);
return SR_ERR_DEV_CLOSED;
}
return ret;
sdi->status = SR_ST_INACTIVE;
sr_dbg("%s: Closing device instance.", sdi->driver->name);
return sdi->driver->dev_close(sdi);
}
/**
@ -713,7 +847,9 @@ SR_API const char *sr_dev_inst_connid_get(const struct sr_dev_inst *sdi)
if (b != usb->bus || a != usb->address)
continue;
usb_get_port_path(devlist[i], connection_id, sizeof(connection_id));
if (usb_get_port_path(devlist[i], connection_id, sizeof(connection_id)) < 0)
continue;
((struct sr_dev_inst *)sdi)->connection_id = g_strdup(connection_id);
break;
}

View File

@ -379,7 +379,7 @@ static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
if (info->is_dc)
analog->meaning->mqflags |= SR_MQFLAG_DC;
if (info->is_diode)
analog->meaning->mqflags |= SR_MQFLAG_DIODE;
analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
if (info->is_peak_max)
analog->meaning->mqflags |= SR_MQFLAG_MAX;
if (info->is_peak_min)
@ -519,7 +519,7 @@ SR_PRIV int sr_asycii_parse(const uint8_t *buf, float *floatval,
int ret, exponent;
struct asycii_info *info_local;
info_local = (struct asycii_info *)info;
info_local = info;
/* Don't print byte 15. That one contains the carriage return. */
sr_dbg("DMM packet: \"%.15s\"", buf);

View File

@ -173,7 +173,7 @@ SR_PRIV int sr_brymen_bm25x_parse(const uint8_t *buf, float *floatval,
analog->meaning->mq = SR_MQ_VOLTAGE;
analog->meaning->unit = SR_UNIT_VOLT;
if ((analog->meaning->mqflags & (SR_MQFLAG_DC | SR_MQFLAG_AC)) == 0)
analog->meaning->mqflags |= SR_MQFLAG_DIODE;
analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
}
if (buf[14] & 2) {
analog->meaning->mq = SR_MQ_CURRENT;

View File

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

1373
src/dmm/eev121gw.c Normal file

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

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

@ -0,0 +1,389 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2012 Uwe Hermann <uwe@hermann-uwe.de>
* Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@gmail.com>
* Copyright (C) 2018 Stefan Mandl
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
/*
* MASTECH MS8250D protocol parser.
*
* Sends 18 bytes.
* 40 02 32 75 53 33 35 5303 10 00 00 00 00 00 00 10 00
*
* - Communication parameters: Unidirectional, 2400/8n1
* - CP2102 USB to UART bridge controller
*/
#include <config.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <glib.h>
#include <libsigrok/libsigrok.h>
#include "libsigrok-internal.h"
#define LOG_PREFIX "ms8250d"
/*
* Main display (7-segment LCD value): xxDGA xxEF xxxx xxCB
* https://en.wikipedia.org/wiki/Seven-segment_display
*/
static int parse_digit(uint16_t b)
{
switch (b) {
case 0x0: /* 7-segment not active */
return 0;
case 0x430: /* Overflow */
return 0xF;
case 0x533:
return 0;
case 0x003:
return 1;
case 0x721:
return 2;
case 0x703:
return 3;
case 0x213:
return 4;
case 0x712:
return 5;
case 0x732:
return 6;
case 0x103:
return 7;
case 0x733:
return 8;
case 0x713:
return 9;
default:
sr_dbg("Invalid digit word: 0x%04x.", b);
return -1;
}
}
/* Parse second display. */
static int parse_digit2(uint16_t b)
{
switch (b) {
case 0x00:
return 0;
case 0x7D:
return 0;
case 0x05:
return 1;
case 0x1B:
return 2;
case 0x1F:
return 3;
case 0x27:
return 4;
case 0x3E:
return 5;
case 0x7E:
return 6;
case 0x15:
return 7;
case 0x7F:
return 8;
case 0x3F:
return 9;
default:
sr_dbg("Invalid second display digit word: 0x%04x.", b);
return -1;
}
}
static void parse_flags(const uint8_t *buf, struct ms8250d_info *info)
{
info->is_volt = (buf[9] & (1 << 4)) ? 1 : 0;
info->is_ohm = (buf[9] & (1 << 6)) ? 1 : 0;
info->is_ampere = (buf[10] & (1 << 0)) ? 1 : 0;
info->is_hz = (buf[10] & (1 << 2)) ? 1 : 0;
info->is_farad = (buf[10] & (1 << 1)) ? 1 : 0;
/* Micro */
if (!info->is_farad)
info->is_micro = (buf[8] & (1 << 4)) ? 1 : 0;
else
info->is_micro = (buf[9] & (1 << 1)) ? 1 : 0; /* uF */
info->is_nano = (buf[8] & (1 << 5)) ? 1 : 0;
info->is_milli = (buf[9] & (1 << 0)) ? 1 : 0;
info->is_kilo = (buf[9] & (1 << 2)) ? 1 : 0;
info->is_mega = (buf[8] & (1 << 6)) ? 1 : 0;
info->is_autotimer = (buf[1] & (1 << 0)) ? 1 : 0; /* Auto off timer */
info->is_rs232 = (buf[1] & (1 << 1)) ? 1 : 0; /* RS232 via USB */
info->is_ac = (buf[1] & (1 << 4)) ? 1 : 0;
info->is_dc = (buf[2] & (1 << 1)) ? 1 : 0;
info->is_auto = (buf[16] & (1 << 4)) ? 1 : 0;
info->is_bat = (buf[1] & (1 << 5)) ? 1 : 0; /* Low battery */
info->is_min = (buf[16] & (1 << 2)) ? 1 : 0;
info->is_max = (buf[16] & (1 << 1)) ? 1 : 0;
info->is_rel = (buf[15] & (1 << 7)) ? 1 : 0;
info->is_hold = (buf[16] & (1 << 3)) ? 1 : 0;
info->is_diode = (buf[11] & (1 << 0)) ? 1 : 0;
info->is_beep = (buf[11] & (1 << 1)) ? 1 : 0;
info->is_ncv = (buf[0] & (1 << 0)) ? 1 : 0;
}
static gboolean flags_valid(const struct ms8250d_info *info)
{
int count;
/* Does the packet have more than one multiplier? */
count = 0;
count += (info->is_nano) ? 1 : 0;
count += (info->is_micro) ? 1 : 0;
count += (info->is_milli) ? 1 : 0;
count += (info->is_kilo) ? 1 : 0;
count += (info->is_mega) ? 1 : 0;
if (count > 1) {
sr_dbg("More than one multiplier detected in packet.");
return FALSE;
}
/* Does the packet "measure" more than one type of value? */
count = 0;
count += (info->is_hz) ? 1 : 0;
count += (info->is_ohm) ? 1 : 0;
count += (info->is_farad) ? 1 : 0;
count += (info->is_ampere) ? 1 : 0;
count += (info->is_volt) ? 1 : 0;
if (count > 1) {
sr_dbg("More than one measurement type detected in packet.");
return FALSE;
}
/* Both AC and DC set? */
if (info->is_ac && info->is_dc) {
sr_dbg("Both AC and DC flags detected in packet.");
return FALSE;
}
/* RS232 flag set? */
if (!info->is_rs232) {
sr_dbg("No RS232 flag detected in packet.");
return FALSE;
}
return TRUE;
}
static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
int *exponent, const struct ms8250d_info *info)
{
/* Factors */
if (info->is_nano)
*exponent -= 9;
if (info->is_micro)
*exponent -= 6;
if (info->is_milli)
*exponent -= 3;
if (info->is_kilo)
*exponent += 3;
if (info->is_mega)
*exponent += 6;
*floatval *= powf(10, *exponent);
/* Measurement modes */
if (info->is_volt) {
analog->meaning->mq = SR_MQ_VOLTAGE;
analog->meaning->unit = SR_UNIT_VOLT;
}
if (info->is_ampere) {
analog->meaning->mq = SR_MQ_CURRENT;
analog->meaning->unit = SR_UNIT_AMPERE;
}
if (info->is_ohm) {
analog->meaning->mq = SR_MQ_RESISTANCE;
analog->meaning->unit = SR_UNIT_OHM;
}
if (info->is_hz) {
analog->meaning->mq = SR_MQ_FREQUENCY;
analog->meaning->unit = SR_UNIT_HERTZ;
}
if (info->is_farad) {
analog->meaning->mq = SR_MQ_CAPACITANCE;
analog->meaning->unit = SR_UNIT_FARAD;
}
if (info->is_beep) {
analog->meaning->mq = SR_MQ_CONTINUITY;
analog->meaning->unit = SR_UNIT_BOOLEAN;
*floatval = (*floatval == INFINITY) ? 0.0 : 1.0;
}
if (info->is_diode) {
analog->meaning->mq = SR_MQ_VOLTAGE;
analog->meaning->unit = SR_UNIT_VOLT;
}
if (info->is_percent) {
analog->meaning->mq = SR_MQ_DUTY_CYCLE;
analog->meaning->unit = SR_UNIT_PERCENTAGE;
}
/* Measurement related flags */
if (info->is_ac)
analog->meaning->mqflags |= SR_MQFLAG_AC;
if (info->is_dc)
analog->meaning->mqflags |= SR_MQFLAG_DC;
if (info->is_auto)
analog->meaning->mqflags |= SR_MQFLAG_AUTORANGE;
if (info->is_diode)
analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
if (info->is_hold)
analog->meaning->mqflags |= SR_MQFLAG_HOLD;
if (info->is_rel)
analog->meaning->mqflags |= SR_MQFLAG_RELATIVE;
/* Other flags */
if (info->is_rs232)
sr_spew("RS232 enabled.");
if (info->is_bat)
sr_spew("Battery is low.");
if (info->is_beep)
sr_spew("Beep is active");
}
SR_PRIV gboolean sr_ms8250d_packet_valid(const uint8_t *buf)
{
struct ms8250d_info info;
sr_dbg("DMM packet: %02x %02x %02x %02x %02x %02x %02x "
"%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6],
buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13],
buf[14], buf[15], buf[16], buf[17]);
parse_flags(buf, &info);
if ((buf[17] == 0x00) && flags_valid(&info))
return TRUE;
return FALSE;
}
/**
* Parse a protocol packet.
*
* @param buf Buffer containing the 18-byte protocol packet. Must not be NULL.
* @param floatval Pointer to a float variable. That variable will contain the
* result value upon parsing success. Must not be NULL.
* @param analog Pointer to a struct sr_datafeed_analog. The struct will be
* filled with data according to the protocol packet.
* Must not be NULL.
* @param info Pointer to a struct ms8250d_info. The struct will be filled
* with data according to the protocol packet. Must not be NULL.
*
* @return SR_OK upon success, SR_ERR upon failure. Upon errors, the
* 'analog' variable contents are undefined and should not be used.
*/
SR_PRIV int sr_ms8250d_parse(const uint8_t *buf, float *floatval,
struct sr_datafeed_analog *analog, void *info)
{
int exponent = 0, sec_exponent = 0, sign;
float sec_floatval;
/* buf[0] bar display. */
/* buf[1] bar display. */
/* Parse seven segment digit. */
int16_t digit4 = parse_digit(((buf[7] & 0x73) << 4) | (buf[8] & 0x3));
int16_t digit3 = parse_digit(((buf[6] & 0x07) << 8) | (buf[5] & 0x30) \
| ((buf[6] & 0x30) >> 4));
int16_t digit2 = parse_digit(((buf[4] & 0x73) << 4) | (buf[5] & 0x03));
int16_t digit1 = parse_digit(((buf[3] & 0x07) << 8) | (buf[2] & 0x30) \
| ((buf[3] & 0x30) >> 4));
sr_dbg("Digits: %d %d %d %d.", digit1, digit2, digit3, digit4);
/* Decimal point position. */
if ((buf[3] & (1 << 6)) != 0) {
exponent = -3;
sr_spew("Decimal point after first digit.");
} else if ((buf[5] & (1 << 6)) != 0) {
exponent = -2;
sr_spew("Decimal point after second digit.");
} else if ((buf[7] & (1 << 2)) != 0) {
exponent = -1;
sr_spew("Decimal point after third digit.");
} else {
exponent = 0;
sr_spew("No decimal point in the number.");
}
struct ms8250d_info *info_local;
info_local = info;
parse_flags(buf, info_local);
/* Sign */
sign = (buf[0] & (1 << 2)) ? -1 : 1;
/* Parse second display. */
int16_t sec_digit4 = parse_digit2(buf[12] & 0x7F);
int16_t sec_digit3 = parse_digit2(buf[13] & 0x7F);
int16_t sec_digit2 = parse_digit2(buf[14] & 0x7F);
int16_t sec_digit1 = parse_digit2(buf[15] & 0x7F);
sr_dbg("Digits (2nd display): %d %d %d %d.",
sec_digit1, sec_digit2, sec_digit3, sec_digit4);
/* Second display decimal point position. */
if ((buf[14] & (1 << 7)) != 0) {
sec_exponent = -3;
sr_spew("Sec decimal point after first digit.");
} else if ((buf[13] & (1 << 7)) != 0) {
sec_exponent = -2;
sr_spew("Sec decimal point after second digit.");
} else if ((buf[12] & (1 << 7)) != 0) {
sec_exponent = -1;
sr_spew("Sec decimal point after third digit.");
} else {
sec_exponent = 0;
sr_spew("Sec no decimal point in the number.");
}
*floatval = (double)((digit1 * 1000) + (digit2 * 100) + (digit3 * 10) + digit4);
sec_floatval = (double)(sec_digit1 * 1000) + (sec_digit2 * 100) + (sec_digit3 * 10) + sec_digit4;
sec_floatval *= powf(10, sec_exponent);
/* Apply sign. */
*floatval *= sign;
handle_flags(analog, floatval, &exponent, info_local);
/* Check for "OL". */
if (digit3 == 0x0F) {
sr_spew("Over limit.");
*floatval = INFINITY;
return SR_OK;
}
sr_spew("The display value is %f.", (double)*floatval);
sr_spew("The 2nd display value is %f.", sec_floatval);
analog->encoding->digits = -exponent;
analog->spec->spec_digits = -exponent;
return SR_OK;
}

View File

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

View File

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

View File

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

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

@ -0,0 +1,288 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2012-2013 Uwe Hermann <uwe@hermann-uwe.de>
* Copyright (C) 2018 Matthias Schulz <matthschulz@arcor.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
/*
* Voltcraft 13-bytes ASCII protocol parser.
*
* Bytes 1-3 measuring mode, byte 4 '-' for negative,
* bytes 5-9 value, bytes 10-11 unit, bytes 12-13 CRLF 0d 0a.
*/
#include <config.h>
#include <string.h>
#include <strings.h>
#include <ctype.h>
#include <math.h>
#include <glib.h>
#include <libsigrok/libsigrok.h>
#include "libsigrok-internal.h"
#define LOG_PREFIX "vc96"
/** Parse value from buf, byte 3-8. */
static int parse_value(const uint8_t *buf, struct vc96_info *info,
float *result, int *exponent)
{
int i, is_ol, cnt, dot_pos;
char valstr[8 + 1];
(void)info;
/* Strip all spaces from bytes 3-8. */
memset(&valstr, 0, 6 + 1);
for (i = 0, cnt = 0; i < 6; i++) {
if (buf[3 + i] != ' ')
valstr[cnt++] = buf[3 + i];
}
/* Bytes 5-7: Over limit (various forms) */
is_ol = 0;
is_ol += (!g_ascii_strcasecmp((const char *)&valstr, ".OL")) ? 1 : 0;
is_ol += (!g_ascii_strcasecmp((const char *)&valstr, "O.L")) ? 1 : 0;
is_ol += (!g_ascii_strcasecmp((const char *)&valstr, "OL.")) ? 1 : 0;
is_ol += (!g_ascii_strcasecmp((const char *)&valstr, "OL")) ? 1 : 0;
is_ol += (!g_ascii_strcasecmp((const char *)&valstr, "-.OL")) ? 1 : 0;
is_ol += (!g_ascii_strcasecmp((const char *)&valstr, "-O.L")) ? 1 : 0;
is_ol += (!g_ascii_strcasecmp((const char *)&valstr, "-OL.")) ? 1 : 0;
is_ol += (!g_ascii_strcasecmp((const char *)&valstr, "-OL")) ? 1 : 0;
if (is_ol != 0) {
sr_spew("Over limit.");
*result = INFINITY;
return SR_OK;
}
/* Bytes 3-10: Sign, value (up to 5 digits) and decimal point */
sr_atof_ascii((const char *)&valstr, result);
dot_pos = strcspn(valstr, ".");
if (dot_pos < cnt)
*exponent = -(cnt - dot_pos - 1);
else
*exponent = 0;
sr_spew("The display value is %f.", *result);
return SR_OK;
}
static void parse_flags(const char *buf, struct vc96_info *info)
{
int i, cnt;
char unit[4 + 1];
const char *u;
/* Bytes 0-1: Measurement mode AC, DC */
info->is_ac = !strncmp(buf, "AC", 2);
info->is_dc = !strncmp(buf, "DC", 2);
/* Bytes 0-2: Measurement mode DIO, OHM */
info->is_ohm = !strncmp(buf, "OHM", 3);
info->is_diode = !strncmp(buf, "DIO", 3);
info->is_hfe = !strncmp(buf, "hfe", 3);
/* Bytes 3-8: See parse_value(). */
/* Strip all spaces from bytes 9-10. */
memset(&unit, 0, 2 + 1);
for (i = 0, cnt = 0; i < 2; i++) {
if (buf[9 + i] != ' ')
unit[cnt++] = buf[9 + i];
}
sr_spew("Bytes 9..10 without spaces \"%.4s\".", unit);
/* Bytes 9-10: Unit */
u = (const char *)&unit;
if (!g_ascii_strcasecmp(u, "A"))
info->is_ampere = TRUE;
else if (!g_ascii_strcasecmp(u, "mA"))
info->is_milli = info->is_ampere = TRUE;
else if (!g_ascii_strcasecmp(u, "uA"))
info->is_micro = info->is_ampere = TRUE;
else if (!g_ascii_strcasecmp(u, "V"))
info->is_volt = TRUE;
else if (!g_ascii_strcasecmp(u, "mV"))
info->is_milli = info->is_volt = TRUE;
else if (!g_ascii_strcasecmp(u, "K"))
info->is_kilo = TRUE;
else if (!g_ascii_strcasecmp(u, "M"))
info->is_mega = TRUE;
else if (!g_ascii_strcasecmp(u, ""))
info->is_unitless = TRUE;
/* Bytes 0-2: Measurement mode, except AC/DC */
info->is_resistance = !strncmp(buf, "OHM", 3) ||
(!strncmp(buf, " ", 3) && info->is_ohm);
info->is_diode = !strncmp(buf, "DIO", 3) ||
(!strncmp(buf, " ", 3) && info->is_volt && info->is_milli);
info->is_hfe = !strncmp(buf, "hfe", 3) ||
(!strncmp(buf, " ", 3) && !info->is_ampere && !info->is_volt &&
!info->is_resistance && !info->is_diode);
/*
* Note:
* - Protocol doesn't distinguish "resistance" from "beep" mode.
*/
/* Byte 12: Always '\r' (carriage return, 0x0d, 12) */
/* Byte 13: Always '\n' (carriage return, 0x0a, 13) */
}
static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
int *exponent, const struct vc96_info *info)
{
int factor;
(void)exponent;
/* Factors */
factor = 0;
if (info->is_micro)
factor -= 6;
if (info->is_milli)
factor -= 3;
if (info->is_kilo)
factor += 3;
if (info->is_mega)
factor += 6;
*floatval *= powf(10, factor);
/* Measurement modes */
if (info->is_volt) {
analog->meaning->mq = SR_MQ_VOLTAGE;
analog->meaning->unit = SR_UNIT_VOLT;
}
if (info->is_ampere) {
analog->meaning->mq = SR_MQ_CURRENT;
analog->meaning->unit = SR_UNIT_AMPERE;
}
if (info->is_ohm) {
analog->meaning->mq = SR_MQ_RESISTANCE;
analog->meaning->unit = SR_UNIT_OHM;
}
if (info->is_diode) {
analog->meaning->mq = SR_MQ_VOLTAGE;
analog->meaning->unit = SR_UNIT_VOLT;
}
if (info->is_hfe) {
analog->meaning->mq = SR_MQ_GAIN;
analog->meaning->unit = SR_UNIT_UNITLESS;
}
/* Measurement related flags */
if (info->is_ac)
analog->meaning->mqflags |= SR_MQFLAG_AC;
if (info->is_dc)
analog->meaning->mqflags |= SR_MQFLAG_DC;
if (info->is_diode)
analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
}
static gboolean flags_valid(const struct vc96_info *info)
{
int count;
/* Does the packet have more than one multiplier? */
count = 0;
count += (info->is_micro) ? 1 : 0;
count += (info->is_milli) ? 1 : 0;
count += (info->is_kilo) ? 1 : 0;
count += (info->is_mega) ? 1 : 0;
if (count > 1) {
sr_dbg("More than one multiplier detected in packet.");
return FALSE;
}
/* Does the packet "measure" more than one type of value? */
count = 0;
count += (info->is_ac) ? 1 : 0;
count += (info->is_dc) ? 1 : 0;
count += (info->is_resistance) ? 1 : 0;
count += (info->is_diode) ? 1 : 0;
if (count > 1) {
sr_dbg("More than one measurement type detected in packet.");
return FALSE;
}
/* Both AC and DC set? */
if (info->is_ac && info->is_dc) {
sr_dbg("Both AC and DC flags detected in packet.");
return FALSE;
}
return TRUE;
}
SR_PRIV gboolean sr_vc96_packet_valid(const uint8_t *buf)
{
struct vc96_info info;
memset(&info, 0x00, sizeof(struct vc96_info));
parse_flags((const char *)buf, &info);
if (!flags_valid(&info))
return FALSE;
if ((buf[11] != '\r') || (buf[12] != '\n'))
return FALSE;
return TRUE;
}
/**
* Parse a protocol packet.
*
* @param buf Buffer containing the protocol packet. Must not be NULL.
* @param floatval Pointer to a float variable. That variable will be modified
* in-place depending on the protocol packet. Must not be NULL.
* @param analog Pointer to a struct sr_datafeed_analog. The struct will be
* filled with data according to the protocol packet.
* Must not be NULL.
* @param info Pointer to a struct vc96_info. The struct will be filled
* with data according to the protocol packet. Must not be NULL.
*
* @return SR_OK upon success, SR_ERR upon failure. Upon errors, the
* 'analog' variable contents are undefined and should not be used.
*/
SR_PRIV int sr_vc96_parse(const uint8_t *buf, float *floatval,
struct sr_datafeed_analog *analog, void *info)
{
int ret, exponent = 0;
struct vc96_info *info_local;
info_local = info;
/* Don't print byte 12 + 13. Those contain the CR LF. */
sr_dbg("DMM packet: \"%.11s\".", buf);
memset(info_local, 0x00, sizeof(struct vc96_info));
if ((ret = parse_value(buf, info_local, floatval, &exponent)) < 0) {
sr_dbg("Error parsing value: %d.", ret);
return ret;
}
parse_flags((const char *)buf, info_local);
handle_flags(analog, floatval, &exponent, info_local);
analog->encoding->digits = -exponent;
analog->spec->spec_digits = -exponent;
return SR_OK;
}

33
src/driver_list_start.c Normal file
View File

@ -0,0 +1,33 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2017 Marcus Comstedt <marcus@mc.pp.se>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <glib.h>
#include <libsigrok/libsigrok.h>
#include "libsigrok-internal.h"
/*
* This marks the start of the driver list. This file must be linked
* before any actual drivers.
*/
SR_PRIV const struct sr_dev_driver *sr_driver_list__start[]
__attribute__((section (SR_DRIVER_LIST_SECTION),
used, aligned(sizeof(struct sr_dev_driver *))))
= { NULL /* Dummy item, as zero length arrays are not allowed by C99 */ };

33
src/driver_list_stop.c Normal file
View File

@ -0,0 +1,33 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2017 Marcus Comstedt <marcus@mc.pp.se>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <glib.h>
#include <libsigrok/libsigrok.h>
#include "libsigrok-internal.h"
/*
* This marks the end of the driver list. This file must be linked
* after any actual drivers.
*/
SR_PRIV const struct sr_dev_driver *sr_driver_list__stop[]
__attribute__((section (SR_DRIVER_LIST_SECTION),
used, aligned(sizeof(struct sr_dev_driver *))))
= { NULL /* Dummy item, as zero length arrays are not allowed by C99 */ };

View File

@ -3,6 +3,7 @@
*
* Copyright (C) 2016 Lars-Peter Clausen <lars@metafoo.de>
* Copyright (C) 2016 Aurelien Jacobs <aurel@gnuage.org>
* Copyright (C) 2017 Marcus Comstedt <marcus@mc.pp.se>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -26,17 +27,12 @@
/*
* sr_driver_list is a special section contains pointers to all the hardware
* drivers built into the library. The __start and __stop symbols are
* auto-generated by the linker (OSX needs a little help) and point to the start
* and end of the section. They are used to iterate over the list of all
* drivers.
* created from driver_list_start.c and driver_list_stop.c, and point to the
* start and end of the section. They are used to iterate over the list of
* all drivers.
*/
#ifdef __APPLE__
extern struct sr_dev_driver *__start_sr_driver_list __asm("section$start$__DATA$__sr_driver_list");
extern struct sr_dev_driver *__stop_sr_driver_list __asm("section$end$__DATA$__sr_driver_list");
#else
extern struct sr_dev_driver *__start_sr_driver_list;
extern struct sr_dev_driver *__stop_sr_driver_list;
#endif
SR_PRIV extern const struct sr_dev_driver *sr_driver_list__start[];
SR_PRIV extern const struct sr_dev_driver *sr_driver_list__stop[];
/** @private
* Initialize the driver list in a fresh libsigrok context.
@ -49,8 +45,8 @@ SR_API void sr_drivers_init(struct sr_context *ctx)
array = g_array_new(TRUE, FALSE, sizeof(struct sr_dev_driver *));
#ifdef HAVE_DRIVERS
for (struct sr_dev_driver **drivers = &__start_sr_driver_list;
drivers < &__stop_sr_driver_list; drivers++)
for (const struct sr_dev_driver **drivers = sr_driver_list__start + 1;
drivers < sr_driver_list__stop; drivers++)
g_array_append_val(array, *drivers);
#endif
ctx->driver_list = (struct sr_dev_driver **)array->data;

View File

@ -51,11 +51,7 @@ static const uint64_t samplerates[] = {
};
static const char *data_sources[] = {
"Live",
"Log-Hand",
"Log-Trig",
"Log-Auto",
"Log-Export",
"Live", "Log-Hand", "Log-Trig", "Log-Auto", "Log-Export",
};
extern const struct agdmm_job agdmm_jobs_live[];
@ -187,25 +183,22 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
return std_scan_complete(di, devices);
}
static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
static int config_get(uint32_t key, GVariant **data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
struct dev_context *devc;
int ret;
(void)cg;
devc = sdi->priv;
ret = SR_OK;
switch (key) {
case SR_CONF_SAMPLERATE:
*data = g_variant_new_uint64(devc->cur_samplerate);
break;
case SR_CONF_LIMIT_SAMPLES:
case SR_CONF_LIMIT_MSEC:
ret = sr_sw_limits_config_get(&devc->limits, key, data);
break;
return sr_sw_limits_config_get(&devc->limits, key, data);
case SR_CONF_DATA_SOURCE:
*data = g_variant_new_string(data_sources[devc->data_source]);
break;
@ -213,91 +206,54 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s
return SR_ERR_NA;
}
return ret;
return SR_OK;
}
static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
static int config_set(uint32_t key, GVariant *data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
struct dev_context *devc;
uint64_t samplerate;
const char *tmp_str;
unsigned int i;
int ret;
int idx;
(void)cg;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv;
ret = SR_OK;
switch (key) {
case SR_CONF_SAMPLERATE:
samplerate = g_variant_get_uint64(data);
if (samplerate < samplerates[0] || samplerate > samplerates[1])
ret = SR_ERR_ARG;
else
devc->cur_samplerate = g_variant_get_uint64(data);
return SR_ERR_ARG;
devc->cur_samplerate = g_variant_get_uint64(data);
break;
case SR_CONF_LIMIT_SAMPLES:
case SR_CONF_LIMIT_MSEC:
ret = sr_sw_limits_config_set(&devc->limits, key, data);
return sr_sw_limits_config_set(&devc->limits, key, data);
case SR_CONF_DATA_SOURCE:
if ((idx = std_str_idx(data, ARRAY_AND_SIZE(data_sources))) < 0)
return SR_ERR_ARG;
devc->data_source = idx;
break;
case SR_CONF_DATA_SOURCE: {
tmp_str = g_variant_get_string(data, NULL);
for (i = 0; i < ARRAY_SIZE(data_sources); i++)
if (!strcmp(tmp_str, data_sources[i])) {
devc->data_source = i;
break;
}
if (i == ARRAY_SIZE(data_sources))
return SR_ERR;
break;
}
default:
ret = SR_ERR_NA;
return SR_ERR_NA;
}
return ret;
return SR_OK;
}
static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
static int config_list(uint32_t key, GVariant **data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
GVariant *gvar;
GVariantBuilder gvb;
if (key == SR_CONF_SCAN_OPTIONS) {
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
return SR_OK;
}
if (key == SR_CONF_DEVICE_OPTIONS && !sdi) {
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
drvopts, ARRAY_SIZE(drvopts), sizeof(uint32_t));
return SR_OK;
}
if (!sdi || cg)
return SR_ERR_ARG;
switch (key) {
case SR_CONF_SCAN_OPTIONS:
case SR_CONF_DEVICE_OPTIONS:
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
break;
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
case SR_CONF_SAMPLERATE:
g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), samplerates,
ARRAY_SIZE(samplerates), sizeof(uint64_t));
g_variant_builder_add(&gvb, "{sv}", "samplerate-steps", gvar);
*data = g_variant_builder_end(&gvb);
*data = std_gvar_samplerates_steps(ARRAY_AND_SIZE(samplerates));
break;
case SR_CONF_DATA_SOURCE:
*data = g_variant_new_strv(data_sources, ARRAY_SIZE(data_sources));
*data = g_variant_new_strv(ARRAY_AND_SIZE(data_sources));
break;
default:
return SR_ERR_NA;
@ -311,9 +267,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
struct dev_context *devc = sdi->priv;
struct sr_serial_dev_inst *serial;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc->cur_channel = sr_next_enabled_channel(sdi, NULL);
devc->cur_conf = sr_next_enabled_channel(sdi, NULL);
devc->cur_sample = 1;
@ -338,7 +291,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
sr_sw_limits_acquisition_start(&devc->limits);
std_session_send_df_header(sdi);
/* Poll every 10ms, or whenever some data comes in. */
serial = sdi->conn;
serial_source_add(sdi->session, serial, G_IO_IN, 10,
agdmm_receive_data, (void *)sdi);
@ -354,7 +306,7 @@ static struct sr_dev_driver agdmm_driver_info = {
.cleanup = std_cleanup,
.scan = scan,
.dev_list = std_dev_list,
.dev_clear = NULL,
.dev_clear = std_dev_clear,
.config_get = config_get,
.config_set = config_set,
.config_list = config_list,

View File

@ -77,7 +77,7 @@ static const struct agdmm_job *job_next(struct dev_context *devc)
devc->current_job++;
if (!job_current(devc)->send)
devc->current_job = 0;
} while(job_in_interval(devc) && devc->current_job != current_job);
} while (job_in_interval(devc) && devc->current_job != current_job);
return job_current(devc);
}
@ -200,7 +200,7 @@ SR_PRIV int agdmm_receive_data(int fd, int revents, void *cb_data)
}
if (sr_sw_limits_check(&devc->limits) || stop)
sdi->driver->dev_acquisition_stop(sdi);
sr_dev_acquisition_stop(sdi);
else
dispatch(sdi);
@ -600,7 +600,7 @@ static int recv_conf_u123x(const struct sr_dev_inst *sdi, GMatchInfo *match)
} else if (!strcmp(mstr, "DIOD")) {
devc->cur_mq[i] = SR_MQ_VOLTAGE;
devc->cur_unit[i] = SR_UNIT_VOLT;
devc->cur_mqflags[i] = SR_MQFLAG_DIODE;
devc->cur_mqflags[i] = SR_MQFLAG_DIODE | SR_MQFLAG_DC;
devc->cur_exponent[i] = 0;
devc->cur_digits[i] = 3;
} else if (!strcmp(mstr, "CAP")) {
@ -626,7 +626,7 @@ static int recv_conf_u123x(const struct sr_dev_inst *sdi, GMatchInfo *match)
} else if (!strcmp(mstr, "DC")) {
devc->cur_mqflags[i] |= SR_MQFLAG_DC;
} else {
sr_dbg("Unknown first argument '%s'.", mstr);
sr_dbg("Unknown first argument '%s'.", mstr);
}
g_free(mstr);
} else
@ -738,7 +738,7 @@ static int recv_conf_u124x_5x(const struct sr_dev_inst *sdi, GMatchInfo *match)
} else if (!strcmp(mstr, "DIOD")) {
devc->cur_mq[i] = SR_MQ_VOLTAGE;
devc->cur_unit[i] = SR_UNIT_VOLT;
devc->cur_mqflags[i] = SR_MQFLAG_DIODE;
devc->cur_mqflags[i] = SR_MQFLAG_DIODE | SR_MQFLAG_DC;
devc->cur_exponent[i] = 0;
if (devc->profile->model == KEYSIGHT_U1281 ||
devc->profile->model == KEYSIGHT_U1282) {
@ -871,7 +871,7 @@ static int recv_log(const struct sr_dev_inst *sdi, GMatchInfo *match,
if (mstr[12] & 1) mqflags |= SR_MQFLAG_AVG;
if (mstr[12] & 2) mqflags |= SR_MQFLAG_MIN;
if (mstr[12] & 4) mqflags |= SR_MQFLAG_MAX;
if (function == 5) mqflags |= SR_MQFLAG_DIODE;
if (function == 5) mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
g_free(mstr);
mq = mqs[function];

View File

@ -68,13 +68,11 @@ struct agdmm_profile {
const struct agdmm_recv *recvs;
};
/* Private, per-device-instance driver context. */
struct dev_context {
const struct agdmm_profile *profile;
struct sr_sw_limits limits;
int data_source;
/* Runtime. */
const struct agdmm_job *jobs;
int current_job;
gboolean job_running;

View File

@ -109,8 +109,8 @@ scan_cleanup:
return std_scan_complete(di, devices);
}
static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
static int config_get(uint32_t key, GVariant **data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
struct dev_context *devc = sdi->priv;
@ -130,35 +130,25 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s
return SR_OK;
}
static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
static int config_set(uint32_t key, GVariant *data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
struct dev_context *devc;
const char *tmp_str;
unsigned int i;
int idx;
(void)cg;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv;
switch (key) {
case SR_CONF_LIMIT_SAMPLES:
case SR_CONF_LIMIT_MSEC:
return sr_sw_limits_config_set(&devc->limits, key, data);
case SR_CONF_DATA_SOURCE: {
tmp_str = g_variant_get_string(data, NULL);
for (i = 0; i < ARRAY_SIZE(data_sources); i++)
if (!strcmp(tmp_str, data_sources[i])) {
devc->data_source = i;
break;
}
if (i == ARRAY_SIZE(data_sources))
return SR_ERR;
case SR_CONF_DATA_SOURCE:
if ((idx = std_str_idx(data, ARRAY_AND_SIZE(data_sources))) < 0)
return SR_ERR_ARG;
devc->data_source = idx;
break;
}
default:
return SR_ERR_NA;
}
@ -166,26 +156,15 @@ static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sd
return SR_OK;
}
static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
static int config_list(uint32_t key, GVariant **data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
(void)cg;
switch (key) {
case SR_CONF_SCAN_OPTIONS:
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
break;
case SR_CONF_DEVICE_OPTIONS:
if (!sdi)
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
drvopts, ARRAY_SIZE(drvopts), sizeof(uint32_t));
else
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
break;
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
case SR_CONF_DATA_SOURCE:
*data = g_variant_new_strv(data_sources, ARRAY_SIZE(data_sources));
*data = g_variant_new_strv(ARRAY_AND_SIZE(data_sources));
break;
default:
return SR_ERR_NA;
@ -200,16 +179,12 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
struct dev_context *devc;
serial = sdi->conn;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv;
sr_sw_limits_acquisition_start(&devc->limits);
std_session_send_df_header(sdi);
/* Poll every 50ms, or whenever some data comes in. */
serial_source_add(sdi->session, serial, G_IO_IN, 50,
appa_55ii_receive_data, (void *)sdi);
@ -224,7 +199,7 @@ static struct sr_dev_driver appa_55ii_driver_info = {
.cleanup = std_cleanup,
.scan = scan,
.dev_list = std_dev_list,
.dev_clear = NULL,
.dev_clear = std_dev_clear,
.config_get = config_get,
.config_set = config_set,
.config_list = config_list,

View File

@ -224,7 +224,7 @@ static void appa_55ii_log_end(struct sr_dev_inst *sdi)
if (devc->data_source != DATA_SOURCE_MEMORY)
return;
sdi->driver->dev_acquisition_stop(sdi);
sr_dev_acquisition_stop(sdi);
}
static const uint8_t *appa_55ii_parse_data(struct sr_dev_inst *sdi,
@ -309,7 +309,7 @@ SR_PRIV int appa_55ii_receive_data(int fd, int revents, void *cb_data)
}
if (sr_sw_limits_check(&devc->limits)) {
sdi->driver->dev_acquisition_stop(sdi);
sr_dev_acquisition_stop(sdi);
return TRUE;
}

View File

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

View File

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

View File

@ -18,18 +18,21 @@
*/
#include <config.h>
#include <math.h>
#include <string.h>
#include "protocol.h"
#define READ_TIMEOUT_MS 1000
#define READ_TIMEOUT_MS 500
static int send_cmd(const struct sr_dev_inst *sdi, const char *cmd,
char *replybuf, int replybufsize)
{
char *bufptr;
int len, ret;
struct dev_context *devc;
struct sr_serial_dev_inst *serial;
devc = sdi->priv;
serial = sdi->conn;
/* Send the command (blocking, with timeout). */
@ -40,82 +43,182 @@ static int send_cmd(const struct sr_dev_inst *sdi, const char *cmd,
return SR_ERR;
}
/* Read the reply (blocking, with timeout). */
memset(replybuf, 0, replybufsize);
bufptr = replybuf;
len = replybufsize;
ret = serial_readline(serial, &bufptr, &len, READ_TIMEOUT_MS);
/* If we got 0 characters (possibly one \r or \n), retry once. */
if (len == 0) {
if (!devc->acquisition_running) {
/* Read the reply (blocking, with timeout). */
memset(replybuf, 0, replybufsize);
bufptr = replybuf;
len = replybufsize;
ret = serial_readline(serial, &bufptr, &len, READ_TIMEOUT_MS);
}
if (g_str_has_prefix((const char *)&bufptr, "err ")) {
sr_err("Device replied with an error: '%s'.", bufptr);
return SR_ERR;
/* If we got 0 characters (possibly one \r or \n), retry once. */
if (len == 0) {
len = replybufsize;
ret = serial_readline(serial, &bufptr, &len, READ_TIMEOUT_MS);
}
if (g_str_has_prefix((const char *)&bufptr, "err ")) {
sr_err("Device replied with an error: '%s'.", bufptr);
return SR_ERR;
}
}
return ret;
}
SR_PRIV int reloadpro_set_current_limit(const struct sr_dev_inst *sdi,
float current)
float current_limit)
{
struct dev_context *devc;
int ret, ma;
char buf[100];
char *cmd;
if (current < 0 || current > 6) {
sr_err("The current limit must be 0-6 A (was %f A).", current);
devc = sdi->priv;
if (current_limit < 0 || current_limit > 6) {
sr_err("The current limit must be 0-6 A (was %f A).", current_limit);
return SR_ERR_ARG;
}
/* Hardware expects current in mA, integer (0..6000). */
ma = (int)(current * 1000);
sr_err("Setting current limit to %f A (%d mA).", current, ma);
/* Hardware expects current limit in mA, integer (0..6000). */
ma = (int)round(current_limit * 1000);
cmd = g_strdup_printf("set %d\n", ma);
if ((ret = send_cmd(sdi, cmd, (char *)&buf, sizeof(buf))) < 0) {
sr_err("Error sending current limit command: %d.", ret);
g_free(cmd);
return SR_ERR;
}
g_mutex_lock(&devc->acquisition_mutex);
ret = send_cmd(sdi, cmd, (char *)&buf, sizeof(buf));
g_mutex_unlock(&devc->acquisition_mutex);
g_free(cmd);
if (ret < 0) {
sr_err("Error sending current limit command: %d.", ret);
return SR_ERR;
}
return SR_OK;
}
SR_PRIV int reloadpro_set_on_off(const struct sr_dev_inst *sdi, gboolean on)
{
struct dev_context *devc;
int ret;
char buf[100];
const char *cmd;
devc = sdi->priv;
cmd = (on) ? "on\n" : "off\n";
if ((ret = send_cmd(sdi, cmd, (char *)&buf, sizeof(buf))) < 0) {
g_mutex_lock(&devc->acquisition_mutex);
ret = send_cmd(sdi, cmd, (char *)&buf, sizeof(buf));
g_mutex_unlock(&devc->acquisition_mutex);
if (ret < 0) {
sr_err("Error sending on/off command: %d.", ret);
return SR_ERR;
}
return SR_OK;
}
SR_PRIV int reloadpro_set_under_voltage_threshold(const struct sr_dev_inst *sdi,
float voltage)
{
struct dev_context *devc;
int ret, mv;
char buf[100];
char *cmd;
devc = sdi->priv;
if (voltage < 0 || voltage > 60) {
sr_err("The under voltage threshold must be 0-60 V (was %f V).",
voltage);
return SR_ERR_ARG;
}
/* Hardware expects voltage in mV, integer (0..60000). */
mv = (int)round(voltage * 1000);
sr_spew("Setting under voltage threshold to %f V (%d mV).", voltage, mv);
cmd = g_strdup_printf("uvlo %d\n", mv);
g_mutex_lock(&devc->acquisition_mutex);
ret = send_cmd(sdi, cmd, (char *)&buf, sizeof(buf));
g_mutex_unlock(&devc->acquisition_mutex);
g_free(cmd);
if (ret < 0) {
sr_err("Error sending under voltage threshold command: %d.", ret);
return SR_ERR;
}
return SR_OK;
}
SR_PRIV int reloadpro_get_current_limit(const struct sr_dev_inst *sdi,
float *current)
float *current_limit)
{
struct dev_context *devc;
int ret;
char buf[100];
gint64 end_time;
devc = sdi->priv;
g_mutex_lock(&devc->acquisition_mutex);
if ((ret = send_cmd(sdi, "set\n", (char *)&buf, sizeof(buf))) < 0) {
sr_err("Error sending current limit query: %d.", ret);
return SR_ERR;
}
/* Hardware sends current in mA, integer (0..6000). */
*current = g_ascii_strtod(buf + 4, NULL) / 1000;
if (devc->acquisition_running) {
end_time = g_get_monotonic_time () + 5 * G_TIME_SPAN_SECOND;
if (!g_cond_wait_until(&devc->current_limit_cond,
&devc->acquisition_mutex, end_time)) {
/* Timeout has passed. */
g_mutex_unlock(&devc->acquisition_mutex);
return SR_ERR;
}
} else {
/* Hardware sends current limit in mA, integer (0..6000). */
devc->current_limit = g_ascii_strtod(buf + 4, NULL) / 1000;
}
g_mutex_unlock(&devc->acquisition_mutex);
if (current_limit)
*current_limit = devc->current_limit;
return SR_OK;
}
SR_PRIV int reloadpro_get_under_voltage_threshold(const struct sr_dev_inst *sdi,
float *uvc_threshold)
{
struct dev_context *devc;
int ret;
char buf[100];
gint64 end_time;
devc = sdi->priv;
g_mutex_lock(&devc->acquisition_mutex);
if ((ret = send_cmd(sdi, "uvlo\n", (char *)&buf, sizeof(buf))) < 0) {
sr_err("Error sending under voltage threshold query: %d.", ret);
return SR_ERR;
}
if (devc->acquisition_running) {
end_time = g_get_monotonic_time () + 5 * G_TIME_SPAN_SECOND;
if (!g_cond_wait_until(&devc->uvc_threshold_cond,
&devc->acquisition_mutex, end_time)) {
/* Timeout has passed. */
g_mutex_unlock(&devc->acquisition_mutex);
return SR_ERR;
}
} else {
/* Hardware sends voltage in mV, integer (0..60000). */
devc->uvc_threshold = g_ascii_strtod(buf + 5, NULL) / 1000;
}
g_mutex_unlock(&devc->acquisition_mutex);
if (uvc_threshold)
*uvc_threshold = devc->uvc_threshold;
return SR_OK;
}
@ -123,29 +226,72 @@ SR_PRIV int reloadpro_get_current_limit(const struct sr_dev_inst *sdi,
SR_PRIV int reloadpro_get_voltage_current(const struct sr_dev_inst *sdi,
float *voltage, float *current)
{
struct dev_context *devc;
int ret;
char buf[100];
char **tokens;
gint64 end_time;
devc = sdi->priv;
g_mutex_lock(&devc->acquisition_mutex);
if ((ret = send_cmd(sdi, "read\n", (char *)&buf, sizeof(buf))) < 0) {
sr_err("Error sending voltage/current query: %d.", ret);
return SR_ERR;
}
/* Reply: "read <current> <voltage>". */
tokens = g_strsplit((const char *)&buf, " ", 3);
if (devc->acquisition_running) {
end_time = g_get_monotonic_time () + 5 * G_TIME_SPAN_SECOND;
if (!g_cond_wait_until(&devc->voltage_cond,
&devc->acquisition_mutex, end_time)) {
/* Timeout has passed. */
g_mutex_unlock(&devc->acquisition_mutex);
return SR_ERR;
}
} else {
/* Reply: "read <current> <voltage>". */
tokens = g_strsplit((const char *)&buf, " ", 3);
devc->voltage = g_ascii_strtod(tokens[2], NULL) / 1000;
devc->current = g_ascii_strtod(tokens[1], NULL) / 1000;
g_strfreev(tokens);
}
g_mutex_unlock(&devc->acquisition_mutex);
if (voltage)
*voltage = g_ascii_strtod(tokens[2], NULL) / 1000;
*voltage = devc->voltage;
if (current)
*current = g_ascii_strtod(tokens[1], NULL) / 1000;
g_strfreev(tokens);
*current = devc->current;
return SR_OK;
}
static int send_config_update_key(const struct sr_dev_inst *sdi,
uint32_t key, GVariant *var)
{
struct sr_config *cfg;
struct sr_datafeed_packet packet;
struct sr_datafeed_meta meta;
int ret;
cfg = sr_config_new(key, var);
if (!cfg)
return SR_ERR;
memset(&meta, 0, sizeof(meta));
packet.type = SR_DF_META;
packet.payload = &meta;
meta.config = g_slist_append(meta.config, cfg);
ret = sr_session_send(sdi, &packet);
sr_config_free(cfg);
return ret;
}
static void handle_packet(const struct sr_dev_inst *sdi)
{
float voltage, current;
struct sr_datafeed_packet packet;
struct sr_datafeed_analog analog;
struct sr_analog_encoding encoding;
@ -160,12 +306,49 @@ static void handle_packet(const struct sr_dev_inst *sdi)
if (g_str_has_prefix((const char *)devc->buf, "overtemp")) {
sr_warn("Overtemperature condition!");
devc->otp_active = TRUE;
send_config_update_key(sdi, SR_CONF_OVER_TEMPERATURE_PROTECTION_ACTIVE,
g_variant_new_boolean(TRUE));
return;
}
if (g_str_has_prefix((const char *)devc->buf, "undervolt")) {
sr_warn("Undervoltage condition!");
devc->uvc_active = TRUE;
send_config_update_key(sdi, SR_CONF_UNDER_VOLTAGE_CONDITION_ACTIVE,
g_variant_new_boolean(TRUE));
return;
}
if (g_str_has_prefix((const char *)devc->buf, "err ")) {
sr_err("Device replied with an error: '%s'.", devc->buf);
return;
}
if (g_str_has_prefix((const char *)devc->buf, "set ")) {
tokens = g_strsplit((const char *)devc->buf, " ", 2);
devc->current_limit = g_ascii_strtod(tokens[1], NULL) / 1000;
g_strfreev(tokens);
g_cond_signal(&devc->current_limit_cond);
send_config_update_key(sdi, SR_CONF_CURRENT_LIMIT,
g_variant_new_double(devc->current_limit));
return;
}
if (g_str_has_prefix((const char *)devc->buf, "uvlo ")) {
tokens = g_strsplit((const char *)devc->buf, " ", 2);
devc->uvc_threshold = g_ascii_strtod(tokens[1], NULL) / 1000;
g_strfreev(tokens);
g_cond_signal(&devc->uvc_threshold_cond);
if (devc->uvc_threshold == .0) {
send_config_update_key(sdi, SR_CONF_UNDER_VOLTAGE_CONDITION,
g_variant_new_boolean(FALSE));
} else {
send_config_update_key(sdi, SR_CONF_UNDER_VOLTAGE_CONDITION,
g_variant_new_boolean(TRUE));
send_config_update_key(sdi,
SR_CONF_UNDER_VOLTAGE_CONDITION_THRESHOLD,
g_variant_new_double(devc->uvc_threshold));
}
return;
}
@ -175,8 +358,8 @@ static void handle_packet(const struct sr_dev_inst *sdi)
}
tokens = g_strsplit((const char *)devc->buf, " ", 3);
voltage = g_ascii_strtod(tokens[2], NULL) / 1000;
current = g_ascii_strtod(tokens[1], NULL) / 1000;
devc->voltage = g_ascii_strtod(tokens[2], NULL) / 1000;
devc->current = g_ascii_strtod(tokens[1], NULL) / 1000;
g_strfreev(tokens);
/* Begin frame. */
@ -197,7 +380,8 @@ static void handle_packet(const struct sr_dev_inst *sdi)
meaning.mq = SR_MQ_VOLTAGE;
meaning.mqflags = SR_MQFLAG_DC;
meaning.unit = SR_UNIT_VOLT;
analog.data = &voltage;
encoding.digits = 3;
analog.data = &devc->voltage;
sr_session_send(sdi, &packet);
g_slist_free(l);
@ -208,7 +392,8 @@ static void handle_packet(const struct sr_dev_inst *sdi)
meaning.mq = SR_MQ_CURRENT;
meaning.mqflags = SR_MQFLAG_DC;
meaning.unit = SR_UNIT_AMPERE;
analog.data = &current;
encoding.digits = 3;
analog.data = &devc->current;
sr_session_send(sdi, &packet);
g_slist_free(l);
@ -225,26 +410,34 @@ static void handle_new_data(const struct sr_dev_inst *sdi)
int len;
struct dev_context *devc;
struct sr_serial_dev_inst *serial;
char *buf;
devc = sdi->priv;
serial = sdi->conn;
/* Try to get as much data as the buffer can hold. */
len = RELOADPRO_BUFSIZE - devc->buflen;
len = serial_read_nonblocking(serial, devc->buf + devc->buflen, len);
if (len == 0)
buf = devc->buf;
g_mutex_lock(&devc->acquisition_mutex);
if (serial_readline(serial, &buf, &len, 250) != SR_OK) {
g_mutex_unlock(&devc->acquisition_mutex);
return;
}
if (len == 0) {
g_mutex_unlock(&devc->acquisition_mutex);
return; /* No new bytes, nothing to do. */
}
if (len < 0) {
sr_err("Serial port read error: %d.", len);
g_mutex_unlock(&devc->acquisition_mutex);
return;
}
devc->buflen += len;
if (g_str_has_suffix((const char *)devc->buf, "\n")) {
handle_packet(sdi);
memset(devc->buf, 0, RELOADPRO_BUFSIZE);
devc->buflen = 0;
}
handle_packet(sdi);
g_mutex_unlock(&devc->acquisition_mutex);
memset(devc->buf, 0, RELOADPRO_BUFSIZE);
devc->buflen = 0;
}
SR_PRIV int reloadpro_receive_data(int fd, int revents, void *cb_data)
@ -263,7 +456,7 @@ SR_PRIV int reloadpro_receive_data(int fd, int revents, void *cb_data)
handle_new_data(sdi);
if (sr_sw_limits_check(&devc->limits))
sdi->driver->dev_acquisition_stop(sdi);
sr_dev_acquisition_stop(sdi);
return TRUE;
}

View File

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

View File

@ -19,10 +19,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* ASIX SIGMA/SIGMA2 logic analyzer driver
*/
#include <config.h>
#include "protocol.h"
@ -59,9 +55,14 @@ static const int32_t trigger_matches[] = {
};
#endif
static void clear_helper(struct dev_context *devc)
{
ftdi_deinit(&devc->ftdic);
}
static int dev_clear(const struct sr_dev_driver *di)
{
return std_dev_clear(di, sigma_clear_helper);
return std_dev_clear_with_callback(di, (std_dev_clear_callback)clear_helper);
}
static GSList *scan(struct sr_dev_driver *di, GSList *options)
@ -80,8 +81,6 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
ftdi_init(&devc->ftdic);
/* Look for SIGMAs. */
if ((ret = ftdi_usb_find_all(&devc->ftdic, &devlist,
USB_VENDOR, USB_PRODUCT)) <= 0) {
if (ret < 0)
@ -111,18 +110,16 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
devc->capture_ratio = 50;
devc->use_triggers = 0;
/* Register SIGMA device. */
sdi = g_malloc0(sizeof(struct sr_dev_inst));
sdi->status = SR_ST_INITIALIZING;
sdi->vendor = g_strdup(USB_VENDOR_NAME);
sdi->model = g_strdup(USB_MODEL_NAME);
sdi->vendor = g_strdup("ASIX");
sdi->model = g_strdup("SIGMA");
for (i = 0; i < ARRAY_SIZE(channel_names); i++)
sr_channel_new(sdi, i, SR_CHANNEL_LOGIC, TRUE, channel_names[i]);
sdi->priv = devc;
/* We will open the device again when we need it. */
ftdi_list_free(&devlist);
return std_scan_complete(di, g_slist_append(NULL, sdi));
@ -140,18 +137,13 @@ static int dev_open(struct sr_dev_inst *sdi)
devc = sdi->priv;
/* Make sure it's an ASIX SIGMA. */
if ((ret = ftdi_usb_open_desc(&devc->ftdic,
USB_VENDOR, USB_PRODUCT, USB_DESCRIPTION, NULL)) < 0) {
sr_err("ftdi_usb_open failed: %s",
ftdi_get_error_string(&devc->ftdic));
return 0;
USB_VENDOR, USB_PRODUCT, USB_DESCRIPTION, NULL)) < 0) {
sr_err("Failed to open device (%d): %s.",
ret, ftdi_get_error_string(&devc->ftdic));
return SR_ERR;
}
sdi->status = SR_ST_ACTIVE;
return SR_OK;
}
@ -161,17 +153,11 @@ static int dev_close(struct sr_dev_inst *sdi)
devc = sdi->priv;
/* TODO */
if (sdi->status == SR_ST_ACTIVE)
ftdi_usb_close(&devc->ftdic);
sdi->status = SR_ST_INACTIVE;
return SR_OK;
return (ftdi_usb_close(&devc->ftdic) == 0) ? SR_OK : SR_ERR;
}
static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
static int config_get(uint32_t key, GVariant **data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
struct dev_context *devc;
@ -203,81 +189,50 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s
return SR_OK;
}
static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
static int config_set(uint32_t key, GVariant *data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
struct dev_context *devc;
uint64_t tmp;
int ret;
(void)cg;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv;
ret = SR_OK;
switch (key) {
case SR_CONF_SAMPLERATE:
ret = sigma_set_samplerate(sdi, g_variant_get_uint64(data));
break;
return sigma_set_samplerate(sdi, g_variant_get_uint64(data));
case SR_CONF_LIMIT_MSEC:
tmp = g_variant_get_uint64(data);
if (tmp > 0)
devc->limit_msec = g_variant_get_uint64(data);
else
ret = SR_ERR;
devc->limit_msec = g_variant_get_uint64(data);
break;
case SR_CONF_LIMIT_SAMPLES:
tmp = g_variant_get_uint64(data);
devc->limit_samples = tmp;
devc->limit_msec = sigma_limit_samples_to_msec(devc, tmp);
devc->limit_samples = g_variant_get_uint64(data);
devc->limit_msec = sigma_limit_samples_to_msec(devc,
devc->limit_samples);
break;
#if ASIX_SIGMA_WITH_TRIGGER
case SR_CONF_CAPTURE_RATIO:
tmp = g_variant_get_uint64(data);
if (tmp > 100)
return SR_ERR;
devc->capture_ratio = tmp;
devc->capture_ratio = g_variant_get_uint64(data);
break;
#endif
default:
ret = SR_ERR_NA;
return SR_ERR_NA;
}
return ret;
return SR_OK;
}
static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
static int config_list(uint32_t key, GVariant **data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
GVariant *gvar;
GVariantBuilder gvb;
(void)cg;
switch (key) {
case SR_CONF_DEVICE_OPTIONS:
if (!sdi)
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
drvopts, ARRAY_SIZE(drvopts), sizeof(uint32_t));
else
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
break;
return STD_CONFIG_LIST(key, data, sdi, cg, NO_OPTS, drvopts, devopts);
case SR_CONF_SAMPLERATE:
g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), samplerates,
samplerates_count, sizeof(samplerates[0]));
g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar);
*data = g_variant_builder_end(&gvb);
*data = std_gvar_samplerates(samplerates, samplerates_count);
break;
#if ASIX_SIGMA_WITH_TRIGGER
case SR_CONF_TRIGGER_MATCH:
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
trigger_matches, ARRAY_SIZE(trigger_matches),
sizeof(int32_t));
*data = std_gvar_array_i32(ARRAY_AND_SIZE(trigger_matches));
break;
#endif
default:
@ -299,9 +254,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
uint8_t clock_bytes[sizeof(clockselect)];
size_t clock_idx;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv;
if (sigma_convert_trigger(sdi) != SR_OK) {
@ -411,9 +363,20 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi)
struct dev_context *devc;
devc = sdi->priv;
devc->state.state = SIGMA_IDLE;
sr_session_source_remove(sdi->session, -1);
/*
* When acquisition is currently running, keep the receive
* routine registered and have it stop the acquisition upon the
* next invocation. Else unregister the receive routine here
* already. The detour is required to have sample data retrieved
* for forced acquisition stops.
*/
if (devc->state.state == SIGMA_CAPTURE) {
devc->state.state = SIGMA_STOPPING;
} else {
devc->state.state = SIGMA_IDLE;
sr_session_source_remove(sdi->session, -1);
}
return SR_OK;
}

View File

@ -47,7 +47,7 @@ SR_PRIV const uint64_t samplerates[] = {
SR_PRIV const size_t samplerates_count = ARRAY_SIZE(samplerates);
static const char sigma_firmware_files[][24] = {
static const char firmware_files[][24] = {
/* 50 MHz, supports 8 bit fractions */
"asix-sigma-50.fw",
/* 100 MHz */
@ -78,12 +78,11 @@ static int sigma_write(void *buf, size_t size, struct dev_context *devc)
int ret;
ret = ftdi_write_data(&devc->ftdic, (unsigned char *)buf, size);
if (ret < 0) {
if (ret < 0)
sr_err("ftdi_write_data failed: %s",
ftdi_get_error_string(&devc->ftdic));
} else if ((size_t) ret != size) {
else if ((size_t) ret != size)
sr_err("ftdi_write_data did not complete write.");
}
return ret;
}
@ -272,15 +271,6 @@ SR_PRIV int sigma_write_trigger_lut(struct triggerlut *lut, struct dev_context *
return SR_OK;
}
SR_PRIV void sigma_clear_helper(void *priv)
{
struct dev_context *devc;
devc = priv;
ftdi_deinit(&devc->ftdic);
}
/*
* Configure the FPGA for bitbang mode.
* This sequence is documented in section 2. of the ASIX Sigma programming
@ -446,38 +436,27 @@ static int upload_firmware(struct sr_context *ctx,
unsigned char pins;
size_t buf_size;
const char *firmware;
struct ftdi_context *ftdic;
/* Avoid downloading the same firmware multiple times. */
firmware = sigma_firmware_files[firmware_idx];
firmware = firmware_files[firmware_idx];
if (devc->cur_firmware == firmware_idx) {
sr_info("Not uploading firmware file '%s' again.", firmware);
return SR_OK;
}
/* Make sure it's an ASIX SIGMA. */
ftdic = &devc->ftdic;
ret = ftdi_usb_open_desc(ftdic, USB_VENDOR, USB_PRODUCT,
USB_DESCRIPTION, NULL);
if (ret < 0) {
sr_err("ftdi_usb_open failed: %s",
ftdi_get_error_string(ftdic));
return 0;
}
ret = ftdi_set_bitmode(ftdic, 0xdf, BITMODE_BITBANG);
ret = ftdi_set_bitmode(&devc->ftdic, 0xdf, BITMODE_BITBANG);
if (ret < 0) {
sr_err("ftdi_set_bitmode failed: %s",
ftdi_get_error_string(ftdic));
return 0;
ftdi_get_error_string(&devc->ftdic));
return SR_ERR;
}
/* Four times the speed of sigmalogan - Works well. */
ret = ftdi_set_baudrate(ftdic, 750 * 1000);
ret = ftdi_set_baudrate(&devc->ftdic, 750 * 1000);
if (ret < 0) {
sr_err("ftdi_set_baudrate failed: %s",
ftdi_get_error_string(ftdic));
return 0;
ftdi_get_error_string(&devc->ftdic));
return SR_ERR;
}
/* Initialize the FPGA for firmware upload. */
@ -499,14 +478,14 @@ static int upload_firmware(struct sr_context *ctx,
g_free(buf);
ret = ftdi_set_bitmode(ftdic, 0x00, BITMODE_RESET);
ret = ftdi_set_bitmode(&devc->ftdic, 0x00, BITMODE_RESET);
if (ret < 0) {
sr_err("ftdi_set_bitmode failed: %s",
ftdi_get_error_string(ftdic));
ftdi_get_error_string(&devc->ftdic));
return SR_ERR;
}
ftdi_usb_purge_buffers(ftdic);
ftdi_usb_purge_buffers(&devc->ftdic);
/* Discard garbage. */
while (sigma_read(&pins, 1, devc) == 1)
@ -554,6 +533,7 @@ SR_PRIV int sigma_set_samplerate(const struct sr_dev_inst *sdi, uint64_t sampler
struct drv_context *drvc;
size_t i;
int ret;
int num_channels;
devc = sdi->priv;
drvc = sdi->driver->context;
@ -572,15 +552,16 @@ SR_PRIV int sigma_set_samplerate(const struct sr_dev_inst *sdi, uint64_t sampler
* firmware is required and higher rates might limit the set
* of available channels.
*/
num_channels = devc->num_channels;
if (samplerate <= SR_MHZ(50)) {
ret = upload_firmware(drvc->sr_ctx, 0, devc);
devc->num_channels = 16;
num_channels = 16;
} else if (samplerate == SR_MHZ(100)) {
ret = upload_firmware(drvc->sr_ctx, 1, devc);
devc->num_channels = 8;
num_channels = 8;
} else if (samplerate == SR_MHZ(200)) {
ret = upload_firmware(drvc->sr_ctx, 2, devc);
devc->num_channels = 4;
num_channels = 4;
}
/*
@ -589,6 +570,7 @@ SR_PRIV int sigma_set_samplerate(const struct sr_dev_inst *sdi, uint64_t sampler
* an "event" (memory organization internal to the device).
*/
if (ret == SR_OK) {
devc->num_channels = num_channels;
devc->cur_samplerate = samplerate;
devc->samples_per_event = 16 / devc->num_channels;
devc->state.state = SIGMA_IDLE;
@ -663,16 +645,13 @@ SR_PRIV int sigma_convert_trigger(const struct sr_dev_inst *sdi)
if (match->match == SR_TRIGGER_ONE) {
devc->trigger.simplevalue |= channelbit;
devc->trigger.simplemask |= channelbit;
}
else if (match->match == SR_TRIGGER_ZERO) {
} else if (match->match == SR_TRIGGER_ZERO) {
devc->trigger.simplevalue &= ~channelbit;
devc->trigger.simplemask |= channelbit;
}
else if (match->match == SR_TRIGGER_FALLING) {
} else if (match->match == SR_TRIGGER_FALLING) {
devc->trigger.fallingmask |= channelbit;
trigger_set++;
}
else if (match->match == SR_TRIGGER_RISING) {
} else if (match->match == SR_TRIGGER_RISING) {
devc->trigger.risingmask |= channelbit;
trigger_set++;
}
@ -694,7 +673,6 @@ SR_PRIV int sigma_convert_trigger(const struct sr_dev_inst *sdi)
return SR_OK;
}
/* Software trigger to determine exact trigger position. */
static int get_trigger_offset(uint8_t *samples, uint16_t last_sample,
struct sigma_trigger *t)
@ -1039,6 +1017,7 @@ static int download_capture(struct sr_dev_inst *sdi)
return FALSE;
sr_info("Downloading sample data.");
devc->state.state = SIGMA_DOWNLOAD;
/*
* Ask the hardware to stop data acquisition. Reception of the
@ -1119,12 +1098,12 @@ static int download_capture(struct sr_dev_inst *sdi)
dl_lines_done += dl_lines_curr;
}
g_free(dram_line);
std_session_send_df_end(sdi);
sdi->driver->dev_acquisition_stop(sdi);
g_free(dram_line);
devc->state.state = SIGMA_IDLE;
sr_dev_acquisition_stop(sdi);
return TRUE;
}
@ -1168,6 +1147,14 @@ SR_PRIV int sigma_receive_data(int fd, int revents, void *cb_data)
if (devc->state.state == SIGMA_IDLE)
return TRUE;
/*
* When the application has requested to stop the acquisition,
* then immediately start downloading sample data. Otherwise
* keep checking configured limits which will terminate the
* acquisition and initiate download.
*/
if (devc->state.state == SIGMA_STOPPING)
return download_capture(sdi);
if (devc->state.state == SIGMA_CAPTURE)
return sigma_capture_mode(sdi);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2014 Kumar Abhishek <abhishek@theembeddedkitchen.net>
* Copyright (C) 2014-2017 Kumar Abhishek <abhishek@theembeddedkitchen.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -47,12 +47,14 @@
#define IOCTL_BL_GET_TRIGGER_FLAGS _IOR('k', 0x23, uint32_t)
#define IOCTL_BL_SET_TRIGGER_FLAGS _IOW('k', 0x23, uint32_t)
#define IOCTL_BL_GET_CUR_INDEX _IOR('k', 0x24, uint32_t)
#define IOCTL_BL_CACHE_INVALIDATE _IO('k', 0x25)
#define IOCTL_BL_GET_BUFFER_SIZE _IOR('k', 0x26, uint32_t)
#define IOCTL_BL_SET_BUFFER_SIZE _IOW('k', 0x26, uint32_t)
#define IOCTL_BL_GET_BUFUNIT_SIZE _IOR('k', 0x27, uint32_t)
#define IOCTL_BL_SET_BUFUNIT_SIZE _IOW('k', 0x27, uint32_t)
#define IOCTL_BL_FILL_TEST_PATTERN _IO('k', 0x28)
@ -90,120 +92,41 @@ enum beaglelogic_sampleunit {
* SR_OK or SR_ERR
*/
SR_PRIV int beaglelogic_open_nonblock(struct dev_context *devc);
SR_PRIV int beaglelogic_close(struct dev_context *devc);
struct beaglelogic_ops {
int (*open)(struct dev_context *devc);
int (*close)(struct dev_context *devc);
SR_PRIV int beaglelogic_get_buffersize(struct dev_context *devc);
SR_PRIV int beaglelogic_set_buffersize(struct dev_context *devc);
int (*get_buffersize)(struct dev_context *devc);
int (*set_buffersize)(struct dev_context *devc);
SR_PRIV int beaglelogic_get_samplerate(struct dev_context *devc);
SR_PRIV int beaglelogic_set_samplerate(struct dev_context *devc);
int (*get_samplerate)(struct dev_context *devc);
int (*set_samplerate)(struct dev_context *devc);
SR_PRIV int beaglelogic_get_sampleunit(struct dev_context *devc);
SR_PRIV int beaglelogic_set_sampleunit(struct dev_context *devc);
int (*get_sampleunit)(struct dev_context *devc);
int (*set_sampleunit)(struct dev_context *devc);
SR_PRIV int beaglelogic_get_triggerflags(struct dev_context *devc);
SR_PRIV int beaglelogic_set_triggerflags(struct dev_context *devc);
int (*get_triggerflags)(struct dev_context *devc);
int (*set_triggerflags)(struct dev_context *devc);
/* Start and stop the capture operation */
SR_PRIV int beaglelogic_start(struct dev_context *devc);
SR_PRIV int beaglelogic_stop(struct dev_context *devc);
/* Start and stop the capture operation */
int (*start)(struct dev_context *devc);
int (*stop)(struct dev_context *devc);
/* Get the last error size */
SR_PRIV int beaglelogic_getlasterror(struct dev_context *devc);
/* Get the last error size */
int (*get_lasterror)(struct dev_context *devc);
/* Gets the unit size of the capture buffer (usually 4 or 8 MB) */
SR_PRIV int beaglelogic_get_bufunitsize(struct dev_context *devc);
/* Gets the unit size of the capture buffer (usually 4 or 8 MB) */
int (*get_bufunitsize)(struct dev_context *devc);
int (*set_bufunitsize)(struct dev_context *devc);
SR_PRIV int beaglelogic_mmap(struct dev_context *devc);
SR_PRIV int beaglelogic_munmap(struct dev_context *devc);
int (*mmap)(struct dev_context *devc);
int (*munmap)(struct dev_context *devc);
};
/* Sources */
SR_PRIV inline int beaglelogic_open_nonblock(struct dev_context *devc) {
devc->fd = open(BEAGLELOGIC_DEV_NODE, O_RDONLY | O_NONBLOCK);
return (devc->fd == -1 ? SR_ERR : SR_OK);
}
SR_PRIV extern const struct beaglelogic_ops beaglelogic_native_ops;
SR_PRIV extern const struct beaglelogic_ops beaglelogic_tcp_ops;
SR_PRIV inline int beaglelogic_close(struct dev_context *devc) {
return close(devc->fd);
}
SR_PRIV inline int beaglelogic_get_buffersize(struct dev_context *devc) {
return ioctl(devc->fd, IOCTL_BL_GET_BUFFER_SIZE, &devc->buffersize);
}
SR_PRIV inline int beaglelogic_set_buffersize(struct dev_context *devc) {
return ioctl(devc->fd, IOCTL_BL_SET_BUFFER_SIZE, devc->buffersize);
}
/* This is treated differently as it gets a uint64_t while a uint32_t is read */
SR_PRIV inline int beaglelogic_get_samplerate(struct dev_context *devc) {
uint32_t arg, err;
err = ioctl(devc->fd, IOCTL_BL_GET_SAMPLE_RATE, &arg);
devc->cur_samplerate = arg;
return err;
}
SR_PRIV inline int beaglelogic_set_samplerate(struct dev_context *devc) {
return ioctl(devc->fd, IOCTL_BL_SET_SAMPLE_RATE,
(uint32_t)devc->cur_samplerate);
}
SR_PRIV inline int beaglelogic_get_sampleunit(struct dev_context *devc) {
return ioctl(devc->fd, IOCTL_BL_GET_SAMPLE_UNIT, &devc->sampleunit);
}
SR_PRIV inline int beaglelogic_set_sampleunit(struct dev_context *devc) {
return ioctl(devc->fd, IOCTL_BL_SET_SAMPLE_UNIT, devc->sampleunit);
}
SR_PRIV inline int beaglelogic_get_triggerflags(struct dev_context *devc) {
return ioctl(devc->fd, IOCTL_BL_GET_TRIGGER_FLAGS, &devc->triggerflags);
}
SR_PRIV inline int beaglelogic_set_triggerflags(struct dev_context *devc) {
return ioctl(devc->fd, IOCTL_BL_SET_TRIGGER_FLAGS, devc->triggerflags);
}
SR_PRIV int beaglelogic_getlasterror(struct dev_context *devc) {
int fd;
char buf[16];
int ret;
if ((fd = open(BEAGLELOGIC_SYSFS_ATTR(lasterror), O_RDONLY)) == -1)
return SR_ERR;
if ((ret = read(fd, buf, 16)) < 0)
return SR_ERR;
close(fd);
devc->last_error = strtoul(buf, NULL, 10);
return SR_OK;
}
SR_PRIV inline int beaglelogic_start(struct dev_context *devc) {
return ioctl(devc->fd, IOCTL_BL_START);
}
SR_PRIV inline int beaglelogic_stop(struct dev_context *devc) {
return ioctl(devc->fd, IOCTL_BL_STOP);
}
SR_PRIV int beaglelogic_get_bufunitsize(struct dev_context *devc) {
return ioctl(devc->fd, IOCTL_BL_GET_BUFUNIT_SIZE, &devc->bufunitsize);
}
SR_PRIV int beaglelogic_mmap(struct dev_context *devc) {
if (!devc->buffersize)
beaglelogic_get_buffersize(devc);
devc->sample_buf = mmap(NULL, devc->buffersize,
PROT_READ, MAP_SHARED, devc->fd, 0);
return (devc->sample_buf == MAP_FAILED ? -1 : SR_OK);
}
SR_PRIV int beaglelogic_munmap(struct dev_context *devc) {
return munmap(devc->sample_buf, devc->buffersize);
}
SR_PRIV int beaglelogic_tcp_detect(struct dev_context *devc);
SR_PRIV int beaglelogic_tcp_drain(struct dev_context *devc);
#endif

View File

@ -0,0 +1,153 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2014-2017 Kumar Abhishek <abhishek@theembeddedkitchen.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "protocol.h"
#include "beaglelogic.h"
static int beaglelogic_open_nonblock(struct dev_context *devc)
{
devc->fd = open(BEAGLELOGIC_DEV_NODE, O_RDONLY | O_NONBLOCK);
return ((devc->fd == -1) ? SR_ERR : SR_OK);
}
static int beaglelogic_close(struct dev_context *devc)
{
return close(devc->fd);
}
static int beaglelogic_get_buffersize(struct dev_context *devc)
{
return ioctl(devc->fd, IOCTL_BL_GET_BUFFER_SIZE, &devc->buffersize);
}
static int beaglelogic_set_buffersize(struct dev_context *devc)
{
return ioctl(devc->fd, IOCTL_BL_SET_BUFFER_SIZE, devc->buffersize);
}
/* This is treated differently as it gets a uint64_t while a uint32_t is read */
static int beaglelogic_get_samplerate(struct dev_context *devc)
{
uint32_t arg, err;
err = ioctl(devc->fd, IOCTL_BL_GET_SAMPLE_RATE, &arg);
devc->cur_samplerate = arg;
return err;
}
static int beaglelogic_set_samplerate(struct dev_context *devc)
{
return ioctl(devc->fd, IOCTL_BL_SET_SAMPLE_RATE,
(uint32_t)devc->cur_samplerate);
}
static int beaglelogic_get_sampleunit(struct dev_context *devc)
{
return ioctl(devc->fd, IOCTL_BL_GET_SAMPLE_UNIT, &devc->sampleunit);
}
static int beaglelogic_set_sampleunit(struct dev_context *devc)
{
return ioctl(devc->fd, IOCTL_BL_SET_SAMPLE_UNIT, devc->sampleunit);
}
static int beaglelogic_get_triggerflags(struct dev_context *devc)
{
return ioctl(devc->fd, IOCTL_BL_GET_TRIGGER_FLAGS, &devc->triggerflags);
}
static int beaglelogic_set_triggerflags(struct dev_context *devc)
{
return ioctl(devc->fd, IOCTL_BL_SET_TRIGGER_FLAGS, devc->triggerflags);
}
static int beaglelogic_get_lasterror(struct dev_context *devc)
{
int fd;
char buf[16];
int ret;
if ((fd = open(BEAGLELOGIC_SYSFS_ATTR(lasterror), O_RDONLY)) == -1)
return SR_ERR;
if ((ret = read(fd, buf, 16)) < 0)
return SR_ERR;
close(fd);
devc->last_error = strtoul(buf, NULL, 10);
return SR_OK;
}
static int beaglelogic_start(struct dev_context *devc)
{
return ioctl(devc->fd, IOCTL_BL_START);
}
static int beaglelogic_stop(struct dev_context *devc)
{
return ioctl(devc->fd, IOCTL_BL_STOP);
}
static int beaglelogic_get_bufunitsize(struct dev_context *devc)
{
return ioctl(devc->fd, IOCTL_BL_GET_BUFUNIT_SIZE, &devc->bufunitsize);
}
static int beaglelogic_set_bufunitsize(struct dev_context *devc)
{
return ioctl(devc->fd, IOCTL_BL_SET_BUFUNIT_SIZE, devc->bufunitsize);
}
static int beaglelogic_mmap(struct dev_context *devc)
{
if (!devc->buffersize)
beaglelogic_get_buffersize(devc);
devc->sample_buf = mmap(NULL, devc->buffersize,
PROT_READ, MAP_SHARED, devc->fd, 0);
return ((devc->sample_buf == MAP_FAILED) ? -1 : SR_OK);
}
static int beaglelogic_munmap(struct dev_context *devc)
{
return munmap(devc->sample_buf, devc->buffersize);
}
SR_PRIV const struct beaglelogic_ops beaglelogic_native_ops = {
.open = beaglelogic_open_nonblock,
.close = beaglelogic_close,
.get_buffersize = beaglelogic_get_buffersize,
.set_buffersize = beaglelogic_set_buffersize,
.get_samplerate = beaglelogic_get_samplerate,
.set_samplerate = beaglelogic_set_samplerate,
.get_sampleunit = beaglelogic_get_sampleunit,
.set_sampleunit = beaglelogic_set_sampleunit,
.get_triggerflags = beaglelogic_get_triggerflags,
.set_triggerflags = beaglelogic_set_triggerflags,
.start = beaglelogic_start,
.stop = beaglelogic_stop,
.get_lasterror = beaglelogic_get_lasterror,
.get_bufunitsize = beaglelogic_get_bufunitsize,
.set_bufunitsize = beaglelogic_set_bufunitsize,
.mmap = beaglelogic_mmap,
.munmap = beaglelogic_munmap,
};

View File

@ -0,0 +1,430 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2017 Kumar Abhishek <abhishek@theembeddedkitchen.net>
* Portions of the code are adapted from scpi_tcp.c and scpi.c, their
* copyright notices are listed below:
*
* Copyright (C) 2013 Martin Ling <martin-sigrok@earth.li>
* Copyright (C) 2013 poljar (Damir Jelić) <poljarinho@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#ifdef _WIN32
#define _WIN32_WINNT 0x0501
#include <winsock2.h>
#include <ws2tcpip.h>
#endif
#include <glib.h>
#include <string.h>
#include <unistd.h>
#ifndef _WIN32
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#endif
#include <errno.h>
#include "protocol.h"
#include "beaglelogic.h"
static int beaglelogic_tcp_open(struct dev_context *devc)
{
struct addrinfo hints;
struct addrinfo *results, *res;
int err;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
err = getaddrinfo(devc->address, devc->port, &hints, &results);
if (err) {
sr_err("Address lookup failed: %s:%s: %s", devc->address,
devc->port, gai_strerror(err));
return SR_ERR;
}
for (res = results; res; res = res->ai_next) {
if ((devc->socket = socket(res->ai_family, res->ai_socktype,
res->ai_protocol)) < 0)
continue;
if (connect(devc->socket, res->ai_addr, res->ai_addrlen) != 0) {
close(devc->socket);
devc->socket = -1;
continue;
}
break;
}
freeaddrinfo(results);
if (devc->socket < 0) {
sr_err("Failed to connect to %s:%s: %s", devc->address,
devc->port, g_strerror(errno));
return SR_ERR;
}
return SR_OK;
}
static int beaglelogic_tcp_send_cmd(struct dev_context *devc,
const char *format, ...)
{
int len, out;
va_list args, args_copy;
char *buf;
va_start(args, format);
va_copy(args_copy, args);
len = vsnprintf(NULL, 0, format, args_copy);
va_end(args_copy);
buf = g_malloc0(len + 2);
vsprintf(buf, format, args);
va_end(args);
if (buf[len - 1] != '\n')
buf[len] = '\n';
out = send(devc->socket, buf, strlen(buf), 0);
if (out < 0) {
sr_err("Send error: %s", g_strerror(errno));
g_free(buf);
return SR_ERR;
}
if (out < (int)strlen(buf)) {
sr_dbg("Only sent %d/%zu bytes of command: '%s'.", out,
strlen(buf), buf);
}
sr_spew("Sent command: '%s'.", buf);
g_free(buf);
return SR_OK;
}
static int beaglelogic_tcp_read_data(struct dev_context *devc, char *buf,
int maxlen)
{
int len;
len = recv(devc->socket, buf, maxlen, 0);
if (len < 0) {
sr_err("Receive error: %s", g_strerror(errno));
return SR_ERR;
}
return len;
}
SR_PRIV int beaglelogic_tcp_drain(struct dev_context *devc)
{
char *buf = g_malloc(1024);
fd_set rset;
int ret, len = 0;
struct timeval tv;
FD_ZERO(&rset);
FD_SET(devc->socket, &rset);
/* 25ms timeout */
tv.tv_sec = 0;
tv.tv_usec = 25 * 1000;
do {
ret = select(devc->socket + 1, &rset, NULL, NULL, &tv);
if (ret > 0)
len += beaglelogic_tcp_read_data(devc, buf, 1024);
} while (ret > 0);
sr_spew("Drained %d bytes of data.", len);
g_free(buf);
return SR_OK;
}
static int beaglelogic_tcp_get_string(struct dev_context *devc, const char *cmd,
char **tcp_resp)
{
GString *response = g_string_sized_new(1024);
int len;
gint64 timeout;
*tcp_resp = NULL;
if (cmd) {
if (beaglelogic_tcp_send_cmd(devc, cmd) != SR_OK)
return SR_ERR;
}
timeout = g_get_monotonic_time() + devc->read_timeout;
len = beaglelogic_tcp_read_data(devc, response->str,
response->allocated_len);
if (len < 0) {
g_string_free(response, TRUE);
return SR_ERR;
}
if (len > 0)
g_string_set_size(response, len);
if (g_get_monotonic_time() > timeout) {
sr_err("Timed out waiting for response.");
g_string_free(response, TRUE);
return SR_ERR_TIMEOUT;
}
/* Remove trailing newline if present */
if (response->len >= 1 && response->str[response->len - 1] == '\n')
g_string_truncate(response, response->len - 1);
/* Remove trailing carriage return if present */
if (response->len >= 1 && response->str[response->len - 1] == '\r')
g_string_truncate(response, response->len - 1);
sr_spew("Got response: '%.70s', length %" G_GSIZE_FORMAT ".",
response->str, response->len);
*tcp_resp = g_string_free(response, FALSE);
return SR_OK;
}
static int beaglelogic_tcp_get_int(struct dev_context *devc,
const char *cmd, int *response)
{
int ret;
char *resp = NULL;
ret = beaglelogic_tcp_get_string(devc, cmd, &resp);
if (!resp && ret != SR_OK)
return ret;
if (sr_atoi(resp, response) == SR_OK)
ret = SR_OK;
else
ret = SR_ERR_DATA;
g_free(resp);
return ret;
}
SR_PRIV int beaglelogic_tcp_detect(struct dev_context *devc)
{
char *resp = NULL;
int ret;
ret = beaglelogic_tcp_get_string(devc, "version", &resp);
if (ret == SR_OK && !g_ascii_strncasecmp(resp, "BeagleLogic", 11))
ret = SR_OK;
else
ret = SR_ERR;
g_free(resp);
return ret;
}
static int beaglelogic_open(struct dev_context *devc)
{
return beaglelogic_tcp_open(devc);
}
static int beaglelogic_close(struct dev_context *devc)
{
if (close(devc->socket) < 0)
return SR_ERR;
return SR_OK;
}
static int beaglelogic_get_buffersize(struct dev_context *devc)
{
return beaglelogic_tcp_get_int(devc, "memalloc",
(int *)&devc->buffersize);
}
static int beaglelogic_set_buffersize(struct dev_context *devc)
{
int ret;
char *resp;
beaglelogic_tcp_send_cmd(devc, "memalloc %lu", devc->buffersize);
ret = beaglelogic_tcp_get_string(devc, NULL, &resp);
if (ret == SR_OK && !g_ascii_strncasecmp(resp, "ok", 2))
ret = SR_OK;
else
ret = SR_ERR;
g_free(resp);
return ret;
}
static int beaglelogic_get_samplerate(struct dev_context *devc)
{
int arg, err;
err = beaglelogic_tcp_get_int(devc, "samplerate", &arg);
if (err)
return err;
devc->cur_samplerate = arg;
return SR_OK;
}
static int beaglelogic_set_samplerate(struct dev_context *devc)
{
int ret;
char *resp;
beaglelogic_tcp_send_cmd(devc, "samplerate %lu",
(uint32_t)devc->cur_samplerate);
ret = beaglelogic_tcp_get_string(devc, NULL, &resp);
if (ret == SR_OK && !g_ascii_strncasecmp(resp, "ok", 2))
ret = SR_OK;
else
ret = SR_ERR;
g_free(resp);
return ret;
}
static int beaglelogic_get_sampleunit(struct dev_context *devc)
{
return beaglelogic_tcp_get_int(devc, "sampleunit",
(int *)&devc->sampleunit);
}
static int beaglelogic_set_sampleunit(struct dev_context *devc)
{
int ret;
char *resp;
beaglelogic_tcp_send_cmd(devc, "sampleunit %lu", devc->sampleunit);
ret = beaglelogic_tcp_get_string(devc, NULL, &resp);
if (ret == SR_OK && !g_ascii_strncasecmp(resp, "ok", 2))
ret = SR_OK;
else
ret = SR_ERR;
g_free(resp);
return ret;
}
static int beaglelogic_get_triggerflags(struct dev_context *devc)
{
return beaglelogic_tcp_get_int(devc, "triggerflags",
(int *)&devc->triggerflags);
}
static int beaglelogic_set_triggerflags(struct dev_context *devc)
{
int ret;
char *resp;
beaglelogic_tcp_send_cmd(devc, "triggerflags %lu", devc->triggerflags);
ret = beaglelogic_tcp_get_string(devc, NULL, &resp);
if (ret == SR_OK && !g_ascii_strncasecmp(resp, "ok", 2))
ret = SR_OK;
else
ret = SR_ERR;
g_free(resp);
return ret;
}
static int beaglelogic_get_lasterror(struct dev_context *devc)
{
devc->last_error = 0;
return SR_OK;
}
static int beaglelogic_start(struct dev_context *devc)
{
beaglelogic_tcp_drain(devc);
return beaglelogic_tcp_send_cmd(devc, "get");
}
static int beaglelogic_stop(struct dev_context *devc)
{
return beaglelogic_tcp_send_cmd(devc, "close");
}
static int beaglelogic_get_bufunitsize(struct dev_context *devc)
{
return beaglelogic_tcp_get_int(devc, "bufunitsize",
(int *)&devc->bufunitsize);
}
static int beaglelogic_set_bufunitsize(struct dev_context *devc)
{
int ret;
char *resp;
beaglelogic_tcp_send_cmd(devc, "bufunitsize %ld", devc->bufunitsize);
ret = beaglelogic_tcp_get_string(devc, NULL, &resp);
if (ret == SR_OK && !g_ascii_strncasecmp(resp, "ok", 2))
ret = SR_OK;
else
ret = SR_ERR;
g_free(resp);
return ret;
}
static int dummy(struct dev_context *devc)
{
(void)devc;
return SR_ERR_NA;
}
SR_PRIV const struct beaglelogic_ops beaglelogic_tcp_ops = {
.open = beaglelogic_open,
.close = beaglelogic_close,
.get_buffersize = beaglelogic_get_buffersize,
.set_buffersize = beaglelogic_set_buffersize,
.get_samplerate = beaglelogic_get_samplerate,
.set_samplerate = beaglelogic_set_samplerate,
.get_sampleunit = beaglelogic_get_sampleunit,
.set_sampleunit = beaglelogic_set_sampleunit,
.get_triggerflags = beaglelogic_get_triggerflags,
.set_triggerflags = beaglelogic_set_triggerflags,
.start = beaglelogic_start,
.stop = beaglelogic_stop,
.get_lasterror = beaglelogic_get_lasterror,
.get_bufunitsize = beaglelogic_get_bufunitsize,
.set_bufunitsize = beaglelogic_set_bufunitsize,
.mmap = dummy,
.munmap = dummy,
};

View File

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

View File

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

View File

@ -26,8 +26,11 @@ static const uint32_t scanopts[] = {
SR_CONF_CONN,
};
static const uint32_t devopts[] = {
static const uint32_t drvopts[] = {
SR_CONF_MULTIMETER,
};
static const uint32_t devopts[] = {
SR_CONF_CONTINUOUS,
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET,
@ -95,12 +98,9 @@ static int dev_open(struct sr_dev_inst *sdi)
usb = sdi->conn;
devc = sdi->priv;
if ((ret = sr_usb_open(drvc->sr_ctx->libusb_ctx, usb)) == SR_OK)
sdi->status = SR_ST_ACTIVE;
else
if ((ret = sr_usb_open(drvc->sr_ctx->libusb_ctx, usb)) < 0)
return SR_ERR;
/* Detach kernel drivers which grabbed this device (if any). */
if (libusb_kernel_driver_active(usb->devhdl, 0) == 1) {
ret = libusb_detach_kernel_driver(usb->devhdl, 0);
if (ret < 0) {
@ -109,20 +109,15 @@ static int dev_open(struct sr_dev_inst *sdi)
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;
return SR_OK;
}
static int dev_close(struct sr_dev_inst *sdi)
@ -131,36 +126,30 @@ static int dev_close(struct sr_dev_inst *sdi)
struct dev_context *devc;
int ret;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
usb = sdi->conn;
devc = sdi->priv;
if (!usb->devhdl)
return SR_OK;
if ((ret = libusb_release_interface(usb->devhdl, 0)))
sr_err("Failed to release interface 0: %s.\n", libusb_error_name(ret));
else
sr_dbg("Successfully released interface 0.\n");
if (!ret && devc->detached_kernel_driver) {
if ((ret = libusb_attach_kernel_driver(usb->devhdl, 0))) {
if ((ret = libusb_attach_kernel_driver(usb->devhdl, 0)))
sr_err("Failed to attach kernel driver: %s.\n",
libusb_error_name(ret));
} else {
else
devc->detached_kernel_driver = 0;
sr_dbg("Successfully attached kernel driver.\n");
}
}
libusb_close(usb->devhdl);
sdi->status = SR_ST_INACTIVE;
return ret;
return (ret == 0) ? SR_OK : SR_ERR;
}
static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
static int config_get(uint32_t key, GVariant **data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
struct dev_context *devc = sdi->priv;
@ -169,50 +158,28 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s
return sr_sw_limits_config_get(&devc->sw_limits, key, data);
}
static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
static int config_set(uint32_t key, GVariant *data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
struct dev_context *devc;
(void)cg;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv;
return sr_sw_limits_config_set(&devc->sw_limits, key, data);
}
static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
static int config_list(uint32_t key, GVariant **data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
(void)sdi;
(void)cg;
switch (key) {
case SR_CONF_SCAN_OPTIONS:
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
break;
case SR_CONF_DEVICE_OPTIONS:
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
break;
default:
return SR_ERR_NA;
}
return SR_OK;
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
}
static int dev_acquisition_start(const struct sr_dev_inst *sdi)
{
struct dev_context *devc;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv;
sr_sw_limits_acquisition_start(&devc->sw_limits);
@ -227,9 +194,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
static int dev_acquisition_stop(struct sr_dev_inst *sdi)
{
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
std_session_send_df_end(sdi);
sr_session_source_remove(sdi->session, -1);
@ -245,7 +209,7 @@ static struct sr_dev_driver brymen_bm86x_driver_info = {
.cleanup = std_cleanup,
.scan = scan,
.dev_list = std_dev_list,
.dev_clear = NULL,
.dev_clear = std_dev_clear,
.config_get = config_get,
.config_set = config_set,
.config_list = config_list,

View File

@ -99,8 +99,10 @@ static void brymen_bm86x_parse(unsigned char *buf, float *floatval,
if (buf[8] & 0x01) {
analog[0].meaning->mq = SR_MQ_VOLTAGE;
analog[0].meaning->unit = SR_UNIT_VOLT;
if (!strcmp(str, "diod"))
if (!strcmp(str, "diod")) {
analog[0].meaning->mqflags |= SR_MQFLAG_DIODE;
analog[0].meaning->mqflags |= SR_MQFLAG_DC;
}
} else if (buf[14] & 0x80) {
analog[0].meaning->mq = SR_MQ_CURRENT;
analog[0].meaning->unit = SR_UNIT_AMPERE;
@ -214,6 +216,8 @@ static void brymen_bm86x_handle_packet(const struct sr_dev_inst *sdi,
struct sr_analog_encoding encoding[2];
struct sr_analog_meaning meaning[2];
struct sr_analog_spec spec[2];
struct sr_channel *channel;
int sent_ch1, sent_ch2;
float floatval[2];
devc = sdi->priv;
@ -223,30 +227,35 @@ static void brymen_bm86x_handle_packet(const struct sr_dev_inst *sdi,
sr_analog_init(&analog[1], &encoding[1], &meaning[1], &spec[1], 0);
brymen_bm86x_parse(buf, floatval, analog);
sent_ch1 = sent_ch2 = 0;
if (analog[0].meaning->mq != 0) {
channel = sdi->channels->data;
if (analog[0].meaning->mq != 0 && channel->enabled) {
/* Got a measurement. */
sent_ch1 = 1;
analog[0].num_samples = 1;
analog[0].data = &floatval[0];
analog[0].meaning->channels = g_slist_append(NULL, sdi->channels->data);
analog[0].meaning->channels = g_slist_append(NULL, channel);
packet.type = SR_DF_ANALOG;
packet.payload = &analog[0];
sr_session_send(sdi, &packet);
g_slist_free(analog[0].meaning->channels);
}
if (analog[1].meaning->mq != 0) {
channel = sdi->channels->next->data;
if (analog[1].meaning->mq != 0 && channel->enabled) {
/* Got a measurement. */
sent_ch2 = 1;
analog[1].num_samples = 1;
analog[1].data = &floatval[1];
analog[1].meaning->channels = g_slist_append(NULL, sdi->channels->next->data);
analog[1].meaning->channels = g_slist_append(NULL, channel);
packet.type = SR_DF_ANALOG;
packet.payload = &analog[1];
sr_session_send(sdi, &packet);
g_slist_free(analog[1].meaning->channels);
}
if (analog[0].meaning->mq != 0 || analog[1].meaning->mq != 0)
if (sent_ch1 || sent_ch2)
sr_sw_limits_update_samples_read(&devc->sw_limits, 1);
}
@ -344,7 +353,7 @@ SR_PRIV int brymen_bm86x_receive_data(int fd, int revents, void *cb_data)
return FALSE;
if (sr_sw_limits_check(&devc->sw_limits))
sdi->driver->dev_acquisition_stop(sdi);
sr_dev_acquisition_stop(sdi);
return TRUE;
}

View File

@ -27,15 +27,9 @@
#define LOG_PREFIX "brymen-bm86x"
/** Private, per-device-instance driver context. */
struct dev_context {
/* Acquisition settings */
struct sr_sw_limits sw_limits;
/* Operational state */
int detached_kernel_driver;/**< Whether kernel driver was detached or not */
/* Temporary state across callbacks */
int detached_kernel_driver; /**< Whether kernel driver was detached or not */
int interrupt_pending;
};

View File

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

View File

@ -276,7 +276,7 @@ SR_PRIV int brymen_parse(const uint8_t *buf, float *floatval,
}
if (flags.is_diode)
analog->meaning->mqflags |= SR_MQFLAG_DIODE;
analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
/* We can have both AC+DC in a single measurement. */
if (flags.is_ac)
analog->meaning->mqflags |= SR_MQFLAG_AC;

View File

@ -143,7 +143,7 @@ SR_PRIV int brymen_dmm_receive_data(int fd, int revents, void *cb_data)
}
if (sr_sw_limits_check(&devc->sw_limits))
sdi->driver->dev_acquisition_stop(sdi);
sr_dev_acquisition_stop(sdi);
return TRUE;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -177,7 +177,7 @@ static gboolean handle_new_data(struct sr_dev_inst *sdi, int idx)
{
struct dev_context *devc;
struct sr_serial_dev_inst *serial;
int len, i, offset = 0, ret = FALSE;
int len, offset, ret = FALSE;
devc = sdi->priv;
serial = sdi->conn;
@ -193,6 +193,7 @@ static gboolean handle_new_data(struct sr_dev_inst *sdi, int idx)
devc->buflen += len;
/* Now look for packets in that data. */
offset = 0;
while ((devc->buflen - offset) >= center_devs[idx].packet_size) {
if (center_devs[idx].packet_valid(devc->buf + offset)) {
handle_packet(devc->buf + offset, sdi, idx);
@ -204,8 +205,8 @@ static gboolean handle_new_data(struct sr_dev_inst *sdi, int idx)
}
/* If we have any data left, move it to the beginning of our buffer. */
for (i = 0; i < devc->buflen - offset; i++)
devc->buf[i] = devc->buf[offset + i];
if (offset < devc->buflen)
memmove(devc->buf, devc->buf + offset, devc->buflen - offset);
devc->buflen -= offset;
return ret;
@ -243,7 +244,7 @@ static int receive_data(int fd, int revents, int idx, void *cb_data)
}
if (sr_sw_limits_check(&devc->sw_limits))
sdi->driver->dev_acquisition_stop(sdi);
sr_dev_acquisition_stop(sdi);
return TRUE;
}

View File

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

View File

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

View File

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

View File

@ -35,8 +35,11 @@ static const uint32_t scanopts[] = {
SR_CONF_SERIALCOMM,
};
static const uint32_t devopts[] = {
static const uint32_t drvopts[] = {
SR_CONF_SOUNDLEVELMETER,
};
static const uint32_t devopts[] = {
SR_CONF_CONTINUOUS,
SR_CONF_LIMIT_SAMPLES | SR_CONF_SET,
SR_CONF_LIMIT_MSEC | SR_CONF_SET,
@ -81,41 +84,22 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
return std_scan_complete(di, g_slist_append(NULL, sdi));
}
static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
static int config_set(uint32_t key, GVariant *data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
struct dev_context *devc;
(void)cg;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv;
return sr_sw_limits_config_set(&devc->limits, key, data);
}
static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
static int config_list(uint32_t key, GVariant **data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
(void)sdi;
(void)cg;
switch (key) {
case SR_CONF_SCAN_OPTIONS:
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
break;
case SR_CONF_DEVICE_OPTIONS:
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
break;
default:
return SR_ERR_NA;
}
return SR_OK;
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
}
static int dev_acquisition_start(const struct sr_dev_inst *sdi)
@ -123,13 +107,9 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
struct dev_context *devc = sdi->priv;
struct sr_serial_dev_inst *serial;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
sr_sw_limits_acquisition_start(&devc->limits);
std_session_send_df_header(sdi);
/* Poll every 150ms, or whenever some data comes in. */
serial = sdi->conn;
serial_source_add(sdi->session, serial, G_IO_IN, 150,
colead_slm_receive_data, (void *)sdi);
@ -145,7 +125,7 @@ static struct sr_dev_driver colead_slm_driver_info = {
.cleanup = std_cleanup,
.scan = scan,
.dev_list = std_dev_list,
.dev_clear = NULL,
.dev_clear = std_dev_clear,
.config_get = NULL,
.config_set = config_set,
.config_list = config_list,

View File

@ -177,7 +177,7 @@ static void process_packet(const struct sr_dev_inst *sdi)
sr_sw_limits_update_samples_read(&devc->limits, 1);
if (sr_sw_limits_check(&devc->limits))
sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi);
sr_dev_acquisition_stop((struct sr_dev_inst *)sdi);
}
SR_PRIV int colead_slm_receive_data(int fd, int revents, void *cb_data)
@ -202,7 +202,7 @@ SR_PRIV int colead_slm_receive_data(int fd, int revents, void *cb_data)
serial = sdi->conn;
if (devc->state == IDLE) {
if (serial_read_nonblocking(serial, buf, 128) != 1 || buf[0] != 0x10)
if (serial_read_nonblocking(serial, buf, sizeof(buf)) != 1 || buf[0] != 0x10)
/* Nothing there, or caught the tail end of a previous packet,
* or some garbage. Unless it's a single "data ready" byte,
* we don't want it. */

View File

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

View File

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

View File

@ -17,12 +17,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file
* <em>Conrad DIGI 35 CPU</em> power supply driver
* @internal
*/
#include <config.h>
#include "protocol.h"

View File

@ -17,14 +17,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file
*
* <em>Conrad DIGI 35 CPU</em> power supply driver
*
* @internal
*/
#ifndef LIBSIGROK_HARDWARE_CONRAD_DIGI_35_CPU_PROTOCOL_H
#define LIBSIGROK_HARDWARE_CONRAD_DIGI_35_CPU_PROTOCOL_H
@ -36,6 +28,10 @@
#define LOG_PREFIX "conrad-digi-35-cpu"
struct dev_context {
struct sr_sw_limits limits;
};
SR_PRIV int send_msg1(const struct sr_dev_inst *sdi, char cmd, int param);
#endif

View File

@ -29,11 +29,9 @@
#include "protocol.h"
#define DEFAULT_NUM_LOGIC_CHANNELS 8
#define DEFAULT_ENABLED_LOGIC_CHANNELS 8
#define DEFAULT_LOGIC_PATTERN PATTERN_SIGROK
#define DEFAULT_NUM_ANALOG_CHANNELS 4
#define DEFAULT_ENABLED_ANALOG_CHANNELS 4
#define DEFAULT_ANALOG_AMPLITUDE 10
/* Note: No spaces allowed because of sigrok-cli. */
@ -46,6 +44,13 @@ static const char *logic_pattern_str[] = {
"all-low",
"all-high",
"squid",
"graycode",
};
static const uint32_t scanopts[] = {
SR_CONF_NUM_LOGIC_CHANNELS,
SR_CONF_NUM_ANALOG_CHANNELS,
SR_CONF_LIMIT_FRAMES,
};
static const uint32_t drvopts[] = {
@ -54,18 +59,16 @@ static const uint32_t drvopts[] = {
SR_CONF_OSCILLOSCOPE,
};
static const uint32_t scanopts[] = {
SR_CONF_NUM_LOGIC_CHANNELS,
SR_CONF_NUM_ANALOG_CHANNELS,
};
static const uint32_t devopts[] = {
SR_CONF_CONTINUOUS,
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET,
SR_CONF_LIMIT_FRAMES | SR_CONF_GET | SR_CONF_SET,
SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
SR_CONF_AVERAGING | SR_CONF_GET | SR_CONF_SET,
SR_CONF_AVG_SAMPLES | SR_CONF_GET | SR_CONF_SET,
SR_CONF_TRIGGER_MATCH | SR_CONF_LIST,
SR_CONF_CAPTURE_RATIO | SR_CONF_GET | SR_CONF_SET,
};
static const uint32_t devopts_cg_logic[] = {
@ -81,6 +84,14 @@ static const uint32_t devopts_cg_analog_channel[] = {
SR_CONF_AMPLITUDE | SR_CONF_GET | SR_CONF_SET,
};
static const int32_t trigger_matches[] = {
SR_TRIGGER_ZERO,
SR_TRIGGER_ONE,
SR_TRIGGER_RISING,
SR_TRIGGER_FALLING,
SR_TRIGGER_EDGE,
};
static const uint64_t samplerates[] = {
SR_HZ(1),
SR_GHZ(1),
@ -97,11 +108,12 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
struct analog_gen *ag;
GSList *l;
int num_logic_channels, num_analog_channels, pattern, i;
uint64_t limit_frames;
char channel_name[16];
gboolean enabled;
num_logic_channels = DEFAULT_NUM_LOGIC_CHANNELS;
num_analog_channels = DEFAULT_NUM_ANALOG_CHANNELS;
limit_frames = DEFAULT_LIMIT_FRAMES;
for (l = options; l; l = l->next) {
src = l->data;
switch (src->key) {
@ -111,6 +123,9 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
case SR_CONF_NUM_ANALOG_CHANNELS:
num_analog_channels = g_variant_get_int32(src->data);
break;
case SR_CONF_LIMIT_FRAMES:
limit_frames = g_variant_get_uint64(src->data);
break;
}
}
@ -122,8 +137,14 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
devc->cur_samplerate = SR_KHZ(200);
devc->num_logic_channels = num_logic_channels;
devc->logic_unitsize = (devc->num_logic_channels + 7) / 8;
devc->all_logic_channels_mask = 1UL << 0;
devc->all_logic_channels_mask <<= devc->num_logic_channels;
devc->all_logic_channels_mask--;
devc->logic_pattern = DEFAULT_LOGIC_PATTERN;
devc->num_analog_channels = num_analog_channels;
devc->limit_frames = limit_frames;
devc->capture_ratio = 20;
devc->stl = NULL;
if (num_logic_channels > 0) {
/* Logic channels, all in one channel group. */
@ -131,14 +152,14 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
cg->name = g_strdup("Logic");
for (i = 0; i < num_logic_channels; i++) {
sprintf(channel_name, "D%d", i);
enabled = (i < DEFAULT_ENABLED_LOGIC_CHANNELS) ? TRUE : FALSE;
ch = sr_channel_new(sdi, i, SR_CHANNEL_LOGIC, enabled, channel_name);
ch = sr_channel_new(sdi, i, SR_CHANNEL_LOGIC, TRUE, channel_name);
cg->channels = g_slist_append(cg->channels, ch);
}
sdi->channel_groups = g_slist_append(NULL, cg);
}
/* Analog channels, channel groups and pattern generators. */
devc->ch_ag = g_hash_table_new(g_direct_hash, g_direct_equal);
if (num_analog_channels > 0) {
pattern = 0;
/* An "Analog" channel group with all analog channels in it. */
@ -146,12 +167,10 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
acg->name = g_strdup("Analog");
sdi->channel_groups = g_slist_append(sdi->channel_groups, acg);
devc->ch_ag = g_hash_table_new(g_direct_hash, g_direct_equal);
for (i = 0; i < num_analog_channels; i++) {
snprintf(channel_name, 16, "A%d", i);
enabled = (i < DEFAULT_ENABLED_ANALOG_CHANNELS) ? TRUE : FALSE;
ch = sr_channel_new(sdi, i + num_logic_channels, SR_CHANNEL_ANALOG,
enabled, channel_name);
TRUE, channel_name);
acg->channels = g_slist_append(acg->channels, ch);
/* Every analog channel gets its own channel group as well. */
@ -162,6 +181,7 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
/* Every channel gets a generator struct. */
ag = g_malloc(sizeof(struct analog_gen));
ag->ch = ch;
ag->amplitude = DEFAULT_ANALOG_AMPLITUDE;
sr_analog_init(&ag->packet, &ag->encoding, &ag->meaning, &ag->spec, 2);
ag->packet.meaning->channels = cg->channels;
@ -184,43 +204,25 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
return std_scan_complete(di, g_slist_append(NULL, sdi));
}
static int dev_open(struct sr_dev_inst *sdi)
static void clear_helper(struct dev_context *devc)
{
sdi->status = SR_ST_ACTIVE;
return SR_OK;
}
static int dev_close(struct sr_dev_inst *sdi)
{
sdi->status = SR_ST_INACTIVE;
return SR_OK;
}
static void clear_helper(void *priv)
{
struct dev_context *devc;
GHashTableIter iter;
void *value;
devc = priv;
/* Analog generators. */
g_hash_table_iter_init(&iter, devc->ch_ag);
while (g_hash_table_iter_next(&iter, NULL, &value))
g_free(value);
g_hash_table_unref(devc->ch_ag);
g_free(devc);
}
static int dev_clear(const struct sr_dev_driver *di)
{
return std_dev_clear(di, clear_helper);
return std_dev_clear_with_callback(di, (std_dev_clear_callback)clear_helper);
}
static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
static int config_get(uint32_t key, GVariant **data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
struct dev_context *devc;
struct sr_channel *ch;
@ -241,6 +243,9 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s
case SR_CONF_LIMIT_MSEC:
*data = g_variant_new_uint64(devc->limit_msec);
break;
case SR_CONF_LIMIT_FRAMES:
*data = g_variant_new_uint64(devc->limit_frames);
break;
case SR_CONF_AVERAGING:
*data = g_variant_new_boolean(devc->avg);
break;
@ -272,6 +277,9 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s
ag = g_hash_table_lookup(devc->ch_ag, ch);
*data = g_variant_new_double(ag->amplitude);
break;
case SR_CONF_CAPTURE_RATIO:
*data = g_variant_new_uint64(devc->capture_ratio);
break;
default:
return SR_ERR_NA;
}
@ -279,23 +287,17 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s
return SR_OK;
}
static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
static int config_set(uint32_t key, GVariant *data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
struct dev_context *devc;
struct analog_gen *ag;
struct sr_channel *ch;
GSList *l;
int logic_pattern, analog_pattern, ret;
unsigned int i;
const char *stropt;
int logic_pattern, analog_pattern;
devc = sdi->priv;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
ret = SR_OK;
switch (key) {
case SR_CONF_SAMPLERATE:
devc->cur_samplerate = g_variant_get_uint64(data);
@ -308,6 +310,9 @@ static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sd
devc->limit_msec = g_variant_get_uint64(data);
devc->limit_samples = 0;
break;
case SR_CONF_LIMIT_FRAMES:
devc->limit_frames = g_variant_get_uint64(data);
break;
case SR_CONF_AVERAGING:
devc->avg = g_variant_get_boolean(data);
sr_dbg("%s averaging", devc->avg ? "Enabling" : "Disabling");
@ -319,21 +324,9 @@ static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sd
case SR_CONF_PATTERN_MODE:
if (!cg)
return SR_ERR_CHANNEL_GROUP;
stropt = g_variant_get_string(data, NULL);
logic_pattern = analog_pattern = -1;
for (i = 0; i < ARRAY_SIZE(logic_pattern_str); i++) {
if (!strcmp(stropt, logic_pattern_str[i])) {
logic_pattern = i;
break;
}
}
for (i = 0; i < ARRAY_SIZE(analog_pattern_str); i++) {
if (!strcmp(stropt, analog_pattern_str[i])) {
analog_pattern = i;
break;
}
}
if (logic_pattern == -1 && analog_pattern == -1)
logic_pattern = std_str_idx(data, ARRAY_AND_SIZE(logic_pattern_str));
analog_pattern = std_str_idx(data, ARRAY_AND_SIZE(analog_pattern_str));
if (logic_pattern < 0 && analog_pattern < 0)
return SR_ERR_ARG;
for (l = cg->channels; l; l = l->next) {
ch = l->data;
@ -370,47 +363,31 @@ static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sd
ag->amplitude = g_variant_get_double(data);
}
break;
case SR_CONF_CAPTURE_RATIO:
devc->capture_ratio = g_variant_get_uint64(data);
break;
default:
ret = SR_ERR_NA;
return SR_ERR_NA;
}
return ret;
return SR_OK;
}
static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
static int config_list(uint32_t key, GVariant **data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
struct sr_channel *ch;
GVariant *gvar;
GVariantBuilder gvb;
if (key == SR_CONF_SCAN_OPTIONS) {
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
return SR_OK;
}
if (key == SR_CONF_DEVICE_OPTIONS && !sdi) {
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
drvopts, ARRAY_SIZE(drvopts), sizeof(uint32_t));
return SR_OK;
}
if (!sdi)
return SR_ERR_ARG;
if (!cg) {
switch (key) {
case SR_CONF_SCAN_OPTIONS:
case SR_CONF_DEVICE_OPTIONS:
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
break;
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
case SR_CONF_SAMPLERATE:
g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), samplerates,
ARRAY_SIZE(samplerates), sizeof(uint64_t));
g_variant_builder_add(&gvb, "{sv}", "samplerate-steps", gvar);
*data = g_variant_builder_end(&gvb);
*data = std_gvar_samplerates_steps(ARRAY_AND_SIZE(samplerates));
break;
case SR_CONF_TRIGGER_MATCH:
*data = std_gvar_array_i32(ARRAY_AND_SIZE(trigger_matches));
break;
default:
return SR_ERR_NA;
@ -420,18 +397,12 @@ static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *
switch (key) {
case SR_CONF_DEVICE_OPTIONS:
if (ch->type == SR_CHANNEL_LOGIC)
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
devopts_cg_logic, ARRAY_SIZE(devopts_cg_logic),
sizeof(uint32_t));
*data = std_gvar_array_u32(ARRAY_AND_SIZE(devopts_cg_logic));
else if (ch->type == SR_CHANNEL_ANALOG) {
if (strcmp(cg->name, "Analog") == 0)
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
devopts_cg_analog_group, ARRAY_SIZE(devopts_cg_analog_group),
sizeof(uint32_t));
*data = std_gvar_array_u32(ARRAY_AND_SIZE(devopts_cg_analog_group));
else
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
devopts_cg_analog_channel, ARRAY_SIZE(devopts_cg_analog_channel),
sizeof(uint32_t));
*data = std_gvar_array_u32(ARRAY_AND_SIZE(devopts_cg_analog_channel));
}
else
return SR_ERR_BUG;
@ -442,11 +413,9 @@ static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *
return SR_ERR_NA;
if (ch->type == SR_CHANNEL_LOGIC)
*data = g_variant_new_strv(logic_pattern_str,
ARRAY_SIZE(logic_pattern_str));
*data = g_variant_new_strv(ARRAY_AND_SIZE(logic_pattern_str));
else if (ch->type == SR_CHANNEL_ANALOG)
*data = g_variant_new_strv(analog_pattern_str,
ARRAY_SIZE(analog_pattern_str));
*data = g_variant_new_strv(ARRAY_AND_SIZE(analog_pattern_str));
else
return SR_ERR_BUG;
break;
@ -461,15 +430,82 @@ static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *
static int dev_acquisition_start(const struct sr_dev_inst *sdi)
{
struct dev_context *devc;
GSList *l;
struct sr_channel *ch;
int bitpos;
uint8_t mask;
GHashTableIter iter;
void *value;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
struct sr_trigger *trigger;
devc = sdi->priv;
devc->sent_samples = 0;
devc->sent_frame_samples = 0;
/* Setup triggers */
if ((trigger = sr_session_trigger_get(sdi->session))) {
int pre_trigger_samples = 0;
if (devc->limit_samples > 0)
pre_trigger_samples = (devc->capture_ratio * devc->limit_samples) / 100;
devc->stl = soft_trigger_logic_new(sdi, trigger, pre_trigger_samples);
if (!devc->stl)
return SR_ERR_MALLOC;
/* Disable all analog channels since using them when there are logic
* triggers set up would require having pre-trigger sample buffers
* for analog sample data.
*/
for (l = sdi->channels; l; l = l->next) {
ch = l->data;
if (ch->type == SR_CHANNEL_ANALOG)
ch->enabled = FALSE;
}
}
devc->trigger_fired = FALSE;
/*
* Determine the numbers of logic and analog channels that are
* involved in the acquisition. Determine an offset and a mask to
* remove excess logic data content before datafeed submission.
*/
devc->enabled_logic_channels = 0;
devc->enabled_analog_channels = 0;
for (l = sdi->channels; l; l = l->next) {
ch = l->data;
if (!ch->enabled)
continue;
if (ch->type == SR_CHANNEL_ANALOG) {
devc->enabled_analog_channels++;
continue;
}
if (ch->type != SR_CHANNEL_LOGIC)
continue;
/*
* TODO: Need we create a channel map here, such that the
* session datafeed packets will have a dense representation
* of the enabled channels' data? For example store channels
* D3 and D5 in bit positions 0 and 1 respectively, when all
* other channels are disabled? The current implementation
* generates a sparse layout, might provide data for logic
* channels that are disabled while it might suppress data
* from enabled channels at the same time.
*/
devc->enabled_logic_channels++;
}
devc->first_partial_logic_index = devc->enabled_logic_channels / 8;
bitpos = devc->enabled_logic_channels % 8;
mask = (1 << bitpos) - 1;
devc->first_partial_logic_mask = mask;
sr_dbg("num logic %zu, partial off %zu, mask 0x%02x.",
devc->enabled_logic_channels,
devc->first_partial_logic_index,
devc->first_partial_logic_mask);
/*
* Have the waveform for analog patterns pre-generated. It's
* supposed to be periodic, so the generator just needs to
* access the prepared sample data (DDS style).
*/
g_hash_table_iter_init(&iter, devc->ch_ag);
while (g_hash_table_iter_next(&iter, NULL, &value))
demo_generate_analog_pattern(value, devc->cur_samplerate);
@ -479,6 +515,9 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
std_session_send_df_header(sdi);
if (devc->limit_frames > 0)
std_session_send_frame_begin(sdi);
/* We use this timestamp to decide how many more samples to send. */
devc->start_us = g_get_monotonic_time();
devc->spent_us = 0;
@ -489,10 +528,21 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
static int dev_acquisition_stop(struct sr_dev_inst *sdi)
{
sr_dbg("Stopping acquisition.");
struct dev_context *devc;
sr_session_source_remove(sdi->session, -1);
devc = sdi->priv;
if (devc->limit_frames > 0)
std_session_send_frame_end(sdi);
std_session_send_df_end(sdi);
if (devc->stl) {
soft_trigger_logic_free(devc->stl);
devc->stl = NULL;
}
return SR_OK;
}
@ -508,8 +558,8 @@ static struct sr_dev_driver demo_driver_info = {
.config_get = config_get,
.config_set = config_set,
.config_list = config_list,
.dev_open = dev_open,
.dev_close = dev_close,
.dev_open = std_dummy_dev_open,
.dev_close = std_dummy_dev_close,
.dev_acquisition_start = dev_acquisition_start,
.dev_acquisition_stop = dev_acquisition_stop,
.context = NULL,

View File

@ -245,6 +245,19 @@ SR_PRIV void demo_generate_analog_pattern(struct analog_gen *ag, uint64_t sample
}
}
static uint64_t encode_number_to_gray(uint64_t nr)
{
return nr ^ (nr >> 1);
}
static void set_logic_data(uint64_t bits, uint8_t *data, size_t len)
{
while (len--) {
*data++ = bits & 0xff;
bits >>= 8;
}
}
static void logic_generator(struct sr_dev_inst *sdi, uint64_t size)
{
struct dev_context *devc;
@ -253,6 +266,7 @@ static void logic_generator(struct sr_dev_inst *sdi, uint64_t size)
uint8_t *sample;
const uint8_t *image_col;
size_t col_count, col_height;
uint64_t gray;
devc = sdi->priv;
@ -273,15 +287,14 @@ static void logic_generator(struct sr_dev_inst *sdi, uint64_t size)
break;
case PATTERN_INC:
for (i = 0; i < size; i++) {
for (j = 0; j < devc->logic_unitsize; j++) {
for (j = 0; j < devc->logic_unitsize; j++)
devc->logic_data[i + j] = devc->step;
}
devc->step++;
}
break;
case PATTERN_WALKING_ONE:
/* j contains the value of the highest bit */
j = 1 << (devc->num_logic_channels - 1);
j = 1 << (devc->num_logic_channels - 1);
for (i = 0; i < size; i++) {
devc->logic_data[i] = devc->step;
if (devc->step == 0)
@ -296,7 +309,7 @@ static void logic_generator(struct sr_dev_inst *sdi, uint64_t size)
case PATTERN_WALKING_ZERO:
/* Same as walking one, only with inverted output */
/* j contains the value of the highest bit */
j = 1 << (devc->num_logic_channels - 1);
j = 1 << (devc->num_logic_channels - 1);
for (i = 0; i < size; i++) {
devc->logic_data[i] = ~devc->step;
if (devc->step == 0)
@ -327,12 +340,49 @@ static void logic_generator(struct sr_dev_inst *sdi, uint64_t size)
devc->step %= col_count;
}
break;
case PATTERN_GRAYCODE:
for (i = 0; i < size; i += devc->logic_unitsize) {
devc->step++;
devc->step &= devc->all_logic_channels_mask;
gray = encode_number_to_gray(devc->step);
gray &= devc->all_logic_channels_mask;
set_logic_data(gray, &devc->logic_data[i], devc->logic_unitsize);
}
break;
default:
sr_err("Unknown pattern: %d.", devc->logic_pattern);
break;
}
}
/*
* Fixup a memory image of generated logic data before it gets sent to
* the session's datafeed. Mask out content from disabled channels.
*
* TODO: Need we apply a channel map, and enforce a dense representation
* of the enabled channels' data?
*/
static void logic_fixup_feed(struct dev_context *devc,
struct sr_datafeed_logic *logic)
{
size_t fp_off;
uint8_t fp_mask;
size_t off, idx;
uint8_t *sample;
fp_off = devc->first_partial_logic_index;
fp_mask = devc->first_partial_logic_mask;
if (fp_off == logic->unitsize)
return;
for (off = 0; off < logic->length; off += logic->unitsize) {
sample = logic->data + off;
sample[fp_off] &= fp_mask;
for (idx = fp_off + 1; idx < logic->unitsize; idx++)
sample[idx] = 0x00;
}
}
static void send_analog_packet(struct analog_gen *ag,
struct sr_dev_inst *sdi, uint64_t *analog_sent,
uint64_t analog_pos, uint64_t analog_todo)
@ -343,13 +393,16 @@ static void send_analog_packet(struct analog_gen *ag,
int ag_pattern_pos;
unsigned int i;
if (!ag->ch || !ag->ch->enabled)
return;
devc = sdi->priv;
packet.type = SR_DF_ANALOG;
packet.payload = &ag->packet;
if (!devc->avg) {
ag_pattern_pos = analog_pos % ag->num_samples;
sending_now = MIN(analog_todo, ag->num_samples-ag_pattern_pos);
sending_now = MIN(analog_todo, ag->num_samples - ag_pattern_pos);
ag->packet.data = ag->pattern_data + ag_pattern_pos;
ag->packet.num_samples = sending_now;
sr_session_send(sdi, &packet);
@ -358,7 +411,7 @@ static void send_analog_packet(struct analog_gen *ag,
*analog_sent = MAX(*analog_sent, sending_now);
} else {
ag_pattern_pos = analog_pos % ag->num_samples;
to_avg = MIN(analog_todo, ag->num_samples-ag_pattern_pos);
to_avg = MIN(analog_todo, ag->num_samples - ag_pattern_pos);
for (i = 0; i < to_avg; i++) {
ag->avg_val = (ag->avg_val +
@ -366,8 +419,7 @@ static void send_analog_packet(struct analog_gen *ag,
ag_pattern_pos + i)) / 2;
ag->num_avgs++;
/* Time to send averaged data? */
if (devc->avg_samples > 0 &&
ag->num_avgs >= devc->avg_samples)
if ((devc->avg_samples > 0) && (ag->num_avgs >= devc->avg_samples))
goto do_send;
}
@ -403,6 +455,8 @@ SR_PRIV int demo_prepare_data(int fd, int revents, void *cb_data)
void *value;
uint64_t samples_todo, logic_done, analog_done, analog_sent, sending_now;
int64_t elapsed_us, limit_us, todo_us;
int64_t trigger_offset;
int pre_trigger_samples;
(void)fd;
(void)revents;
@ -414,7 +468,7 @@ SR_PRIV int demo_prepare_data(int fd, int revents, void *cb_data)
if (devc->cur_samplerate <= 0
|| (devc->num_logic_channels <= 0
&& devc->num_analog_channels <= 0)) {
sdi->driver->dev_acquisition_stop(sdi);
sr_dev_acquisition_stop(sdi);
return G_SOURCE_CONTINUE;
}
@ -429,20 +483,38 @@ SR_PRIV int demo_prepare_data(int fd, int revents, void *cb_data)
/* How many samples are outstanding since the last round? */
samples_todo = (todo_us * devc->cur_samplerate + G_USEC_PER_SEC - 1)
/ G_USEC_PER_SEC;
if (devc->limit_samples > 0) {
if (devc->limit_samples < devc->sent_samples)
samples_todo = 0;
else if (devc->limit_samples - devc->sent_samples < samples_todo)
samples_todo = devc->limit_samples - devc->sent_samples;
}
if (samples_todo == 0)
return G_SOURCE_CONTINUE;
if (devc->limit_frames) {
/* Never send more samples than a frame can fit... */
samples_todo = MIN(samples_todo, SAMPLES_PER_FRAME);
/* ...or than we need to finish the current frame. */
samples_todo = MIN(samples_todo,
SAMPLES_PER_FRAME - devc->sent_frame_samples);
}
/* Calculate the actual time covered by this run back from the sample
* count, rounded towards zero. This avoids getting stuck on a too-low
* time delta with no samples being sent due to round-off.
*/
todo_us = samples_todo * G_USEC_PER_SEC / devc->cur_samplerate;
logic_done = devc->num_logic_channels > 0 ? 0 : samples_todo;
logic_done = devc->num_logic_channels > 0 ? 0 : samples_todo;
if (!devc->enabled_logic_channels)
logic_done = samples_todo;
analog_done = devc->num_analog_channels > 0 ? 0 : samples_todo;
if (!devc->enabled_analog_channels)
analog_done = samples_todo;
while (logic_done < samples_todo || analog_done < samples_todo) {
/* Logic */
@ -450,13 +522,47 @@ SR_PRIV int demo_prepare_data(int fd, int revents, void *cb_data)
sending_now = MIN(samples_todo - logic_done,
LOGIC_BUFSIZE / devc->logic_unitsize);
logic_generator(sdi, sending_now * devc->logic_unitsize);
/* Check for trigger and send pre-trigger data if needed */
if (devc->stl && (!devc->trigger_fired)) {
trigger_offset = soft_trigger_logic_check(devc->stl,
devc->logic_data, sending_now * devc->logic_unitsize,
&pre_trigger_samples);
if (trigger_offset > -1) {
devc->trigger_fired = TRUE;
logic_done = pre_trigger_samples;
}
} else
trigger_offset = 0;
/* Send logic samples if needed */
packet.type = SR_DF_LOGIC;
packet.payload = &logic;
logic.length = sending_now * devc->logic_unitsize;
logic.unitsize = devc->logic_unitsize;
logic.data = devc->logic_data;
sr_session_send(sdi, &packet);
logic_done += sending_now;
if (devc->stl) {
if (devc->trigger_fired && (trigger_offset < (int)sending_now)) {
/* Send after-trigger data */
logic.length = (sending_now - trigger_offset) * devc->logic_unitsize;
logic.data = devc->logic_data + trigger_offset * devc->logic_unitsize;
logic_fixup_feed(devc, &logic);
sr_session_send(sdi, &packet);
logic_done += sending_now - trigger_offset;
/* End acquisition */
sr_dbg("Triggered, stopping acquisition.");
sr_dev_acquisition_stop(sdi);
break;
} else {
/* Send nothing */
logic_done += sending_now;
}
} else if (!devc->stl) {
/* No trigger defined, send logic samples */
logic.length = sending_now * devc->logic_unitsize;
logic.data = devc->logic_data;
logic_fixup_feed(devc, &logic);
sr_session_send(sdi, &packet);
logic_done += sending_now;
}
}
/* Analog, one channel at a time */
@ -472,21 +578,27 @@ SR_PRIV int demo_prepare_data(int fd, int revents, void *cb_data)
analog_done += analog_sent;
}
}
/* At this point, both logic_done and analog_done should be
* exactly equal to samples_todo, or else.
*/
if (logic_done != samples_todo || analog_done != samples_todo) {
sr_err("BUG: Sample count mismatch.");
return G_SOURCE_REMOVE;
}
devc->sent_samples += samples_todo;
uint64_t min = MIN(logic_done, analog_done);
devc->sent_samples += min;
devc->sent_frame_samples += min;
devc->spent_us += todo_us;
if (devc->limit_frames && devc->sent_frame_samples >= SAMPLES_PER_FRAME) {
std_session_send_frame_end(sdi);
devc->sent_frame_samples = 0;
devc->limit_frames--;
if (!devc->limit_frames) {
sr_dbg("Requested number of frames reached.");
sr_dev_acquisition_stop(sdi);
}
}
if ((devc->limit_samples > 0 && devc->sent_samples >= devc->limit_samples)
|| (limit_us > 0 && devc->spent_us >= limit_us)) {
/* If we're averaging everything - now is the time to send data */
if (devc->avg_samples == 0) {
if (devc->avg && devc->avg_samples == 0) {
g_hash_table_iter_init(&iter, devc->ch_ag);
while (g_hash_table_iter_next(&iter, NULL, &value)) {
ag = value;
@ -498,7 +610,10 @@ SR_PRIV int demo_prepare_data(int fd, int revents, void *cb_data)
}
}
sr_dbg("Requested number of samples reached.");
sdi->driver->dev_acquisition_stop(sdi);
sr_dev_acquisition_stop(sdi);
} else if (devc->limit_frames) {
if (devc->sent_frame_samples == 0)
std_session_send_frame_begin(sdi);
}
return G_SOURCE_CONTINUE;

View File

@ -33,31 +33,12 @@
#define LOGIC_BUFSIZE 4096
/* Size of the analog pattern space per channel. */
#define ANALOG_BUFSIZE 4096
/* Private, per-device-instance driver context. */
struct dev_context {
uint64_t cur_samplerate;
uint64_t limit_samples;
uint64_t limit_msec;
uint64_t sent_samples;
int64_t start_us;
int64_t spent_us;
uint64_t step;
/* Logic */
int32_t num_logic_channels;
unsigned int logic_unitsize;
/* There is only ever one logic channel group, so its pattern goes here. */
uint8_t logic_pattern;
unsigned char logic_data[LOGIC_BUFSIZE];
/* Analog */
int32_t num_analog_channels;
GHashTable *ch_ag;
gboolean avg; /* True if averaging is enabled */
uint64_t avg_samples;
};
/* This is a development feature: it starts a new frame every n samples. */
#define SAMPLES_PER_FRAME 1000UL
#define DEFAULT_LIMIT_FRAMES 0
/* Logic patterns we can generate. */
enum {
enum logic_pattern_type {
/**
* Spells "sigrok" across 8 channels using '0's (with '1's as
* "background") when displayed using the 'bits' output format.
@ -97,19 +78,51 @@ enum {
* something that can get recognized.
*/
PATTERN_SQUID,
/** Gray encoded data, like rotary encoder signals. */
PATTERN_GRAYCODE,
};
/* Analog patterns we can generate. */
enum {
/**
* Square wave.
*/
enum analog_pattern_type {
PATTERN_SQUARE,
PATTERN_SINE,
PATTERN_TRIANGLE,
PATTERN_SAWTOOTH,
};
struct dev_context {
uint64_t cur_samplerate;
uint64_t limit_samples;
uint64_t limit_msec;
uint64_t limit_frames;
uint64_t sent_samples;
uint64_t sent_frame_samples; /* Number of samples that were sent for current frame. */
int64_t start_us;
int64_t spent_us;
uint64_t step;
/* Logic */
int32_t num_logic_channels;
size_t logic_unitsize;
uint64_t all_logic_channels_mask;
/* There is only ever one logic channel group, so its pattern goes here. */
enum logic_pattern_type logic_pattern;
uint8_t logic_data[LOGIC_BUFSIZE];
/* Analog */
int32_t num_analog_channels;
GHashTable *ch_ag;
gboolean avg; /* True if averaging is enabled */
uint64_t avg_samples;
size_t enabled_logic_channels;
size_t enabled_analog_channels;
size_t first_partial_logic_index;
uint8_t first_partial_logic_mask;
/* Triggers */
uint64_t capture_ratio;
gboolean trigger_fired;
struct soft_trigger_logic *stl;
};
static const char *analog_pattern_str[] = {
"square",
"sine",
@ -118,7 +131,8 @@ static const char *analog_pattern_str[] = {
};
struct analog_gen {
int pattern;
struct sr_channel *ch;
enum analog_pattern_type pattern;
float amplitude;
float pattern_data[ANALOG_BUFSIZE];
unsigned int num_samples;
@ -127,7 +141,7 @@ struct analog_gen {
struct sr_analog_meaning meaning;
struct sr_analog_spec spec;
float avg_val; /* Average value */
unsigned num_avgs; /* Number of samples averaged */
unsigned int num_avgs; /* Number of samples averaged */
};
SR_PRIV void demo_generate_analog_pattern(struct analog_gen *ag, uint64_t sample_rate);

View File

@ -0,0 +1,565 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
* Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <math.h>
#include "protocol.h"
static const struct dslogic_profile supported_device[] = {
/* DreamSourceLab DSLogic */
{ 0x2a0e, 0x0001, "DreamSourceLab", "DSLogic", NULL,
"dreamsourcelab-dslogic-fx2.fw",
0, "DreamSourceLab", "DSLogic", 256 * 1024 * 1024},
/* DreamSourceLab DSCope */
{ 0x2a0e, 0x0002, "DreamSourceLab", "DSCope", NULL,
"dreamsourcelab-dscope-fx2.fw",
0, "DreamSourceLab", "DSCope", 256 * 1024 * 1024},
/* DreamSourceLab DSLogic Pro */
{ 0x2a0e, 0x0003, "DreamSourceLab", "DSLogic Pro", NULL,
"dreamsourcelab-dslogic-pro-fx2.fw",
0, "DreamSourceLab", "DSLogic", 256 * 1024 * 1024},
/* DreamSourceLab DSLogic Plus */
{ 0x2a0e, 0x0020, "DreamSourceLab", "DSLogic Plus", NULL,
"dreamsourcelab-dslogic-plus-fx2.fw",
0, "DreamSourceLab", "DSLogic", 256 * 1024 * 1024},
/* DreamSourceLab DSLogic Basic */
{ 0x2a0e, 0x0021, "DreamSourceLab", "DSLogic Basic", NULL,
"dreamsourcelab-dslogic-basic-fx2.fw",
0, "DreamSourceLab", "DSLogic", 256 * 1024},
ALL_ZERO
};
static const uint32_t scanopts[] = {
SR_CONF_CONN,
};
static const uint32_t drvopts[] = {
SR_CONF_LOGIC_ANALYZER,
};
static const uint32_t devopts[] = {
SR_CONF_CONTINUOUS | SR_CONF_SET | SR_CONF_GET,
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
SR_CONF_VOLTAGE_THRESHOLD | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
SR_CONF_CONN | SR_CONF_GET,
SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
SR_CONF_TRIGGER_MATCH | SR_CONF_LIST,
SR_CONF_CAPTURE_RATIO | SR_CONF_GET | SR_CONF_SET,
SR_CONF_EXTERNAL_CLOCK | SR_CONF_GET | SR_CONF_SET,
SR_CONF_CLOCK_EDGE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
};
static const int32_t trigger_matches[] = {
SR_TRIGGER_ZERO,
SR_TRIGGER_ONE,
SR_TRIGGER_RISING,
SR_TRIGGER_FALLING,
SR_TRIGGER_EDGE,
};
static const char *signal_edges[] = {
[DS_EDGE_RISING] = "rising",
[DS_EDGE_FALLING] = "falling",
};
static const double thresholds[][2] = {
{ 0.7, 1.4 },
{ 1.4, 3.6 },
};
static const uint64_t samplerates[] = {
SR_KHZ(10),
SR_KHZ(20),
SR_KHZ(50),
SR_KHZ(100),
SR_KHZ(200),
SR_KHZ(500),
SR_MHZ(1),
SR_MHZ(2),
SR_MHZ(5),
SR_MHZ(10),
SR_MHZ(20),
SR_MHZ(25),
SR_MHZ(50),
SR_MHZ(100),
SR_MHZ(200),
SR_MHZ(400),
};
static gboolean is_plausible(const struct libusb_device_descriptor *des)
{
int i;
for (i = 0; supported_device[i].vid; i++) {
if (des->idVendor != supported_device[i].vid)
continue;
if (des->idProduct == supported_device[i].pid)
return TRUE;
}
return FALSE;
}
static GSList *scan(struct sr_dev_driver *di, GSList *options)
{
struct drv_context *drvc;
struct dev_context *devc;
struct sr_dev_inst *sdi;
struct sr_usb_dev_inst *usb;
struct sr_channel *ch;
struct sr_channel_group *cg;
struct sr_config *src;
const struct dslogic_profile *prof;
GSList *l, *devices, *conn_devices;
gboolean has_firmware;
struct libusb_device_descriptor des;
libusb_device **devlist;
struct libusb_device_handle *hdl;
int ret, i, j;
const char *conn;
char manufacturer[64], product[64], serial_num[64], connection_id[64];
char channel_name[16];
drvc = di->context;
conn = NULL;
for (l = options; l; l = l->next) {
src = l->data;
switch (src->key) {
case SR_CONF_CONN:
conn = g_variant_get_string(src->data, NULL);
break;
}
}
if (conn)
conn_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn);
else
conn_devices = NULL;
/* Find all DSLogic compatible devices and upload firmware to them. */
devices = NULL;
libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
for (i = 0; devlist[i]; i++) {
if (conn) {
usb = NULL;
for (l = conn_devices; l; l = l->next) {
usb = l->data;
if (usb->bus == libusb_get_bus_number(devlist[i])
&& usb->address == libusb_get_device_address(devlist[i]))
break;
}
if (!l)
/* This device matched none of the ones that
* matched the conn specification. */
continue;
}
libusb_get_device_descriptor(devlist[i], &des);
if (!is_plausible(&des))
continue;
if ((ret = libusb_open(devlist[i], &hdl)) < 0) {
sr_warn("Failed to open potential device with "
"VID:PID %04x:%04x: %s.", des.idVendor,
des.idProduct, libusb_error_name(ret));
continue;
}
if (des.iManufacturer == 0) {
manufacturer[0] = '\0';
} else if ((ret = libusb_get_string_descriptor_ascii(hdl,
des.iManufacturer, (unsigned char *) manufacturer,
sizeof(manufacturer))) < 0) {
sr_warn("Failed to get manufacturer string descriptor: %s.",
libusb_error_name(ret));
continue;
}
if (des.iProduct == 0) {
product[0] = '\0';
} else if ((ret = libusb_get_string_descriptor_ascii(hdl,
des.iProduct, (unsigned char *) product,
sizeof(product))) < 0) {
sr_warn("Failed to get product string descriptor: %s.",
libusb_error_name(ret));
continue;
}
if (des.iSerialNumber == 0) {
serial_num[0] = '\0';
} else if ((ret = libusb_get_string_descriptor_ascii(hdl,
des.iSerialNumber, (unsigned char *) serial_num,
sizeof(serial_num))) < 0) {
sr_warn("Failed to get serial number string descriptor: %s.",
libusb_error_name(ret));
continue;
}
libusb_close(hdl);
if (usb_get_port_path(devlist[i], connection_id, sizeof(connection_id)) < 0)
continue;
prof = NULL;
for (j = 0; supported_device[j].vid; j++) {
if (des.idVendor == supported_device[j].vid &&
des.idProduct == supported_device[j].pid) {
prof = &supported_device[j];
break;
}
}
if (!prof)
continue;
sdi = g_malloc0(sizeof(struct sr_dev_inst));
sdi->status = SR_ST_INITIALIZING;
sdi->vendor = g_strdup(prof->vendor);
sdi->model = g_strdup(prof->model);
sdi->version = g_strdup(prof->model_version);
sdi->serial_num = g_strdup(serial_num);
sdi->connection_id = g_strdup(connection_id);
/* Logic channels, all in one channel group. */
cg = g_malloc0(sizeof(struct sr_channel_group));
cg->name = g_strdup("Logic");
for (j = 0; j < NUM_CHANNELS; j++) {
sprintf(channel_name, "%d", j);
ch = sr_channel_new(sdi, j, SR_CHANNEL_LOGIC,
TRUE, channel_name);
cg->channels = g_slist_append(cg->channels, ch);
}
sdi->channel_groups = g_slist_append(NULL, cg);
devc = dslogic_dev_new();
devc->profile = prof;
sdi->priv = devc;
devices = g_slist_append(devices, sdi);
devc->samplerates = samplerates;
devc->num_samplerates = ARRAY_SIZE(samplerates);
has_firmware = usb_match_manuf_prod(devlist[i], "DreamSourceLab", "USB-based Instrument");
if (has_firmware) {
/* Already has the firmware, so fix the new address. */
sr_dbg("Found a DSLogic device.");
sdi->status = SR_ST_INACTIVE;
sdi->inst_type = SR_INST_USB;
sdi->conn = sr_usb_dev_inst_new(libusb_get_bus_number(devlist[i]),
libusb_get_device_address(devlist[i]), NULL);
} else {
if (ezusb_upload_firmware(drvc->sr_ctx, devlist[i],
USB_CONFIGURATION, prof->firmware) == SR_OK) {
/* Store when this device's FW was updated. */
devc->fw_updated = g_get_monotonic_time();
} else {
sr_err("Firmware upload failed for "
"device %d.%d (logical), name %s.",
libusb_get_bus_number(devlist[i]),
libusb_get_device_address(devlist[i]),
prof->firmware);
}
sdi->inst_type = SR_INST_USB;
sdi->conn = sr_usb_dev_inst_new(libusb_get_bus_number(devlist[i]),
0xff, NULL);
}
}
libusb_free_device_list(devlist, 1);
g_slist_free_full(conn_devices, (GDestroyNotify)sr_usb_dev_inst_free);
return std_scan_complete(di, devices);
}
static int dev_open(struct sr_dev_inst *sdi)
{
struct sr_dev_driver *di = sdi->driver;
struct sr_usb_dev_inst *usb;
struct dev_context *devc;
int ret;
int64_t timediff_us, timediff_ms;
devc = sdi->priv;
usb = sdi->conn;
/*
* If the firmware was recently uploaded, wait up to MAX_RENUM_DELAY_MS
* milliseconds for the FX2 to renumerate.
*/
ret = SR_ERR;
if (devc->fw_updated > 0) {
sr_info("Waiting for device to reset.");
/* Takes >= 300ms for the FX2 to be gone from the USB bus. */
g_usleep(300 * 1000);
timediff_ms = 0;
while (timediff_ms < MAX_RENUM_DELAY_MS) {
if ((ret = dslogic_dev_open(sdi, di)) == SR_OK)
break;
g_usleep(100 * 1000);
timediff_us = g_get_monotonic_time() - devc->fw_updated;
timediff_ms = timediff_us / 1000;
sr_spew("Waited %" PRIi64 "ms.", timediff_ms);
}
if (ret != SR_OK) {
sr_err("Device failed to renumerate.");
return SR_ERR;
}
sr_info("Device came back after %" PRIi64 "ms.", timediff_ms);
} else {
sr_info("Firmware upload was not needed.");
ret = dslogic_dev_open(sdi, di);
}
if (ret != SR_OK) {
sr_err("Unable to open device.");
return SR_ERR;
}
ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE);
if (ret != 0) {
switch (ret) {
case LIBUSB_ERROR_BUSY:
sr_err("Unable to claim USB interface. Another "
"program or driver has already claimed it.");
break;
case LIBUSB_ERROR_NO_DEVICE:
sr_err("Device has been disconnected.");
break;
default:
sr_err("Unable to claim interface: %s.",
libusb_error_name(ret));
break;
}
return SR_ERR;
}
if ((ret = dslogic_fpga_firmware_upload(sdi)) != SR_OK)
return ret;
if (devc->cur_samplerate == 0) {
/* Samplerate hasn't been set; default to the slowest one. */
devc->cur_samplerate = devc->samplerates[0];
}
if (devc->cur_threshold == 0.0) {
devc->cur_threshold = thresholds[1][0];
return dslogic_set_voltage_threshold(sdi, devc->cur_threshold);
}
return SR_OK;
}
static int dev_close(struct sr_dev_inst *sdi)
{
struct sr_usb_dev_inst *usb;
usb = sdi->conn;
if (!usb->devhdl)
return SR_ERR_BUG;
sr_info("Closing device on %d.%d (logical) / %s (physical) interface %d.",
usb->bus, usb->address, sdi->connection_id, USB_INTERFACE);
libusb_release_interface(usb->devhdl, USB_INTERFACE);
libusb_close(usb->devhdl);
usb->devhdl = NULL;
return SR_OK;
}
static int config_get(uint32_t key, GVariant **data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
struct dev_context *devc;
struct sr_usb_dev_inst *usb;
int idx;
(void)cg;
if (!sdi)
return SR_ERR_ARG;
devc = sdi->priv;
switch (key) {
case SR_CONF_CONN:
if (!sdi->conn)
return SR_ERR_ARG;
usb = sdi->conn;
if (usb->address == 255)
/* Device still needs to re-enumerate after firmware
* upload, so we don't know its (future) address. */
return SR_ERR;
*data = g_variant_new_printf("%d.%d", usb->bus, usb->address);
break;
case SR_CONF_VOLTAGE_THRESHOLD:
if (!strcmp(devc->profile->model, "DSLogic")) {
if ((idx = std_double_tuple_idx_d0(devc->cur_threshold,
ARRAY_AND_SIZE(thresholds))) < 0)
return SR_ERR_BUG;
*data = std_gvar_tuple_double(thresholds[idx][0],
thresholds[idx][1]);
} else {
*data = std_gvar_tuple_double(devc->cur_threshold, devc->cur_threshold);
}
break;
case SR_CONF_LIMIT_SAMPLES:
*data = g_variant_new_uint64(devc->limit_samples);
break;
case SR_CONF_SAMPLERATE:
*data = g_variant_new_uint64(devc->cur_samplerate);
break;
case SR_CONF_CAPTURE_RATIO:
*data = g_variant_new_uint64(devc->capture_ratio);
break;
case SR_CONF_EXTERNAL_CLOCK:
*data = g_variant_new_boolean(devc->external_clock);
break;
case SR_CONF_CONTINUOUS:
*data = g_variant_new_boolean(devc->continuous_mode);
break;
case SR_CONF_CLOCK_EDGE:
idx = devc->clock_edge;
if (idx >= (int)ARRAY_SIZE(signal_edges))
return SR_ERR_BUG;
*data = g_variant_new_string(signal_edges[0]);
break;
default:
return SR_ERR_NA;
}
return SR_OK;
}
static int config_set(uint32_t key, GVariant *data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
struct dev_context *devc;
int idx;
gdouble low, high;
(void)cg;
if (!sdi)
return SR_ERR_ARG;
devc = sdi->priv;
switch (key) {
case SR_CONF_SAMPLERATE:
if ((idx = std_u64_idx(data, devc->samplerates, devc->num_samplerates)) < 0)
return SR_ERR_ARG;
devc->cur_samplerate = devc->samplerates[idx];
break;
case SR_CONF_LIMIT_SAMPLES:
devc->limit_samples = g_variant_get_uint64(data);
break;
case SR_CONF_CAPTURE_RATIO:
devc->capture_ratio = g_variant_get_uint64(data);
break;
case SR_CONF_VOLTAGE_THRESHOLD:
if (!strcmp(devc->profile->model, "DSLogic")) {
if ((idx = std_double_tuple_idx(data, ARRAY_AND_SIZE(thresholds))) < 0)
return SR_ERR_ARG;
devc->cur_threshold = thresholds[idx][0];
return dslogic_fpga_firmware_upload(sdi);
} else {
g_variant_get(data, "(dd)", &low, &high);
return dslogic_set_voltage_threshold(sdi, (low + high) / 2.0);
}
break;
case SR_CONF_EXTERNAL_CLOCK:
devc->external_clock = g_variant_get_boolean(data);
break;
case SR_CONF_CONTINUOUS:
devc->continuous_mode = g_variant_get_boolean(data);
break;
case SR_CONF_CLOCK_EDGE:
if ((idx = std_str_idx(data, ARRAY_AND_SIZE(signal_edges))) < 0)
return SR_ERR_ARG;
devc->clock_edge = idx;
break;
default:
return SR_ERR_NA;
}
return SR_OK;
}
static int config_list(uint32_t key, GVariant **data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
struct dev_context *devc;
devc = (sdi) ? sdi->priv : NULL;
switch (key) {
case SR_CONF_SCAN_OPTIONS:
case SR_CONF_DEVICE_OPTIONS:
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
case SR_CONF_VOLTAGE_THRESHOLD:
if (!devc || !devc->profile)
return SR_ERR_ARG;
if (!strcmp(devc->profile->model, "DSLogic"))
*data = std_gvar_thresholds(ARRAY_AND_SIZE(thresholds));
else
*data = std_gvar_min_max_step_thresholds(0.0, 5.0, 0.1);
break;
case SR_CONF_SAMPLERATE:
if (!devc)
return SR_ERR_ARG;
*data = std_gvar_samplerates(devc->samplerates, devc->num_samplerates);
break;
case SR_CONF_TRIGGER_MATCH:
*data = std_gvar_array_i32(ARRAY_AND_SIZE(trigger_matches));
break;
case SR_CONF_CLOCK_EDGE:
*data = g_variant_new_strv(ARRAY_AND_SIZE(signal_edges));
break;
default:
return SR_ERR_NA;
}
return SR_OK;
}
static struct sr_dev_driver dreamsourcelab_dslogic_driver_info = {
.name = "dreamsourcelab-dslogic",
.longname = "DreamSourceLab DSLogic",
.api_version = 1,
.init = std_init,
.cleanup = std_cleanup,
.scan = scan,
.dev_list = std_dev_list,
.dev_clear = std_dev_clear,
.config_get = config_get,
.config_set = config_set,
.config_list = config_list,
.dev_open = dev_open,
.dev_close = dev_close,
.dev_acquisition_start = dslogic_acquisition_start,
.dev_acquisition_stop = dslogic_acquisition_stop,
.context = NULL,
};
SR_REGISTER_DEV_DRIVER(dreamsourcelab_dslogic_driver_info);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,152 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
* Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBSIGROK_HARDWARE_DREAMSOURCELAB_DSLOGIC_PROTOCOL_H
#define LIBSIGROK_HARDWARE_DREAMSOURCELAB_DSLOGIC_PROTOCOL_H
#include <glib.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <libusb.h>
#include <libsigrok/libsigrok.h>
#include "libsigrok-internal.h"
#define LOG_PREFIX "dreamsourcelab-dslogic"
#define USB_INTERFACE 0
#define USB_CONFIGURATION 1
#define MAX_RENUM_DELAY_MS 3000
#define NUM_SIMUL_TRANSFERS 32
#define MAX_EMPTY_TRANSFERS (NUM_SIMUL_TRANSFERS * 2)
#define NUM_CHANNELS 16
#define NUM_TRIGGER_STAGES 16
#define DSLOGIC_REQUIRED_VERSION_MAJOR 1
/* 6 delay states of up to 256 clock ticks */
#define MAX_SAMPLE_DELAY (6 * 256)
#define DSLOGIC_FPGA_FIRMWARE_5V "dreamsourcelab-dslogic-fpga-5v.fw"
#define DSLOGIC_FPGA_FIRMWARE_3V3 "dreamsourcelab-dslogic-fpga-3v3.fw"
#define DSCOPE_FPGA_FIRMWARE "dreamsourcelab-dscope-fpga.fw"
#define DSLOGIC_PRO_FPGA_FIRMWARE "dreamsourcelab-dslogic-pro-fpga.fw"
#define DSLOGIC_PLUS_FPGA_FIRMWARE "dreamsourcelab-dslogic-plus-fpga.fw"
#define DSLOGIC_BASIC_FPGA_FIRMWARE "dreamsourcelab-dslogic-basic-fpga.fw"
enum dslogic_operation_modes {
DS_OP_NORMAL,
DS_OP_INTERNAL_TEST,
DS_OP_EXTERNAL_TEST,
DS_OP_LOOPBACK_TEST,
};
enum dslogic_edge_modes {
DS_EDGE_RISING,
DS_EDGE_FALLING,
};
struct dslogic_version {
uint8_t major;
uint8_t minor;
};
struct dslogic_mode {
uint8_t flags;
uint8_t sample_delay_h;
uint8_t sample_delay_l;
};
struct dslogic_trigger_pos {
uint32_t check_id;
uint32_t real_pos;
uint32_t ram_saddr;
uint32_t remain_cnt_l;
uint32_t remain_cnt_h;
uint32_t status;
uint8_t first_block[488];
};
struct dslogic_profile {
uint16_t vid;
uint16_t pid;
const char *vendor;
const char *model;
const char *model_version;
const char *firmware;
uint32_t dev_caps;
const char *usb_manufacturer;
const char *usb_product;
/* Memory depth in bits. */
uint64_t mem_depth;
};
struct dev_context {
const struct dslogic_profile *profile;
/*
* Since we can't keep track of a DSLogic device after upgrading
* the firmware (it renumerates into a different device address
* after the upgrade) this is like a global lock. No device will open
* until a proper delay after the last device was upgraded.
*/
int64_t fw_updated;
const uint64_t *samplerates;
int num_samplerates;
uint64_t cur_samplerate;
uint64_t limit_samples;
uint64_t capture_ratio;
gboolean acq_aborted;
unsigned int sent_samples;
int submitted_transfers;
int empty_transfer_count;
unsigned int num_transfers;
struct libusb_transfer **transfers;
struct sr_context *ctx;
uint16_t *deinterleave_buffer;
uint16_t mode;
uint32_t trigger_pos;
gboolean external_clock;
gboolean continuous_mode;
int clock_edge;
double cur_threshold;
};
SR_PRIV int dslogic_fpga_firmware_upload(const struct sr_dev_inst *sdi);
SR_PRIV int dslogic_set_voltage_threshold(const struct sr_dev_inst *sdi, double threshold);
SR_PRIV int dslogic_dev_open(struct sr_dev_inst *sdi, struct sr_dev_driver *di);
SR_PRIV struct dev_context *dslogic_dev_new(void);
SR_PRIV int dslogic_acquisition_start(const struct sr_dev_inst *sdi);
SR_PRIV int dslogic_acquisition_stop(struct sr_dev_inst *sdi);
#endif

243
src/hardware/fluke-45/api.c Normal file
View File

@ -0,0 +1,243 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2012 Bert Vermeulen <bert@biot.com>
* Copyright (C) 2017 John Chajecki <subs@qcontinuum.plus.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <glib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <libsigrok/libsigrok.h>
#include "libsigrok-internal.h"
#include "scpi.h"
#include "protocol.h"
static const uint32_t scanopts[] = {
SR_CONF_CONN,
SR_CONF_SERIALCOMM,
};
static const uint32_t drvopts[] = {
SR_CONF_MULTIMETER,
};
static const uint32_t devopts[] = {
SR_CONF_CONTINUOUS,
SR_CONF_LIMIT_SAMPLES | SR_CONF_SET,
SR_CONF_LIMIT_MSEC | SR_CONF_SET,
};
/* Vendor, model, number of channels, poll period */
static const struct fluke_scpi_dmm_model supported_models[] = {
{ "FLUKE", "45", 2, 0 },
};
static struct sr_dev_driver fluke_45_driver_info;
static struct sr_dev_inst *probe_device(struct sr_scpi_dev_inst *scpi)
{
struct dev_context *devc;
struct sr_dev_inst *sdi;
struct sr_scpi_hw_info *hw_info;
const struct scpi_command *cmdset = fluke_45_cmdset;
unsigned int i;
const struct fluke_scpi_dmm_model *model = NULL;
gchar *channel_name;
char *response;
sdi = g_malloc0(sizeof(struct sr_dev_inst));
sdi->conn = scpi;
/* Test for serial port ECHO enabled. */
sr_scpi_get_string(scpi, "ECHO-TEST", &response);
if (strcmp(response, "ECHO-TEST") == 0) {
sr_err("Serial port ECHO is ON. Please turn it OFF!");
return NULL;
}
/* Get device IDN. */
if (sr_scpi_get_hw_id(scpi, &hw_info) != SR_OK) {
sr_info("Couldn't get IDN response, retrying.");
sr_scpi_close(scpi);
sr_scpi_open(scpi);
if (sr_scpi_get_hw_id(scpi, &hw_info) != SR_OK) {
sr_info("Couldn't get IDN response.");
return NULL;
}
}
/* Check IDN. */
for (i = 0; i < ARRAY_SIZE(supported_models); i++) {
if (!g_ascii_strcasecmp(hw_info->manufacturer,
supported_models[i].vendor) &&
!strcmp(hw_info->model, supported_models[i].model)) {
model = &supported_models[i];
break;
}
}
if (!model) {
sr_scpi_hw_info_free(hw_info);
return NULL;
}
/* Set up device parameters. */
sdi->vendor = g_strdup(model->vendor);
sdi->model = g_strdup(model->model);
sdi->version = g_strdup(hw_info->firmware_version);
sdi->serial_num = g_strdup(hw_info->serial_number);
sdi->conn = scpi;
sdi->driver = &fluke_45_driver_info;
sdi->inst_type = SR_INST_SCPI;
devc = g_malloc0(sizeof(struct dev_context));
devc->num_channels = model->num_channels;
devc->cmdset = cmdset;
/* Create channels. */
for (i = 0; i < devc->num_channels; i++) {
channel_name = g_strdup_printf("P%d", i + 1);
sr_channel_new(sdi, 0, SR_CHANNEL_ANALOG, TRUE, channel_name);
}
sdi->priv = devc;
return sdi;
}
static GSList *scan(struct sr_dev_driver *di, GSList *options)
{
return sr_scpi_scan(di->context, options, probe_device);
}
static int dev_open(struct sr_dev_inst *sdi)
{
struct sr_scpi_dev_inst *scpi;
int ret;
scpi = sdi->conn;
if ((ret = sr_scpi_open(scpi) < 0)) {
sr_err("Failed to open SCPI device: %s.", sr_strerror(ret));
return SR_ERR;
}
return SR_OK;
}
static int dev_close(struct sr_dev_inst *sdi)
{
struct sr_scpi_dev_inst *scpi;
scpi = sdi->conn;
if (!scpi)
return SR_ERR_BUG;
return sr_scpi_close(scpi);
}
static int config_set(uint32_t key, GVariant *data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
struct dev_context *devc;
(void)cg;
devc = sdi->priv;
return sr_sw_limits_config_set(&devc->limits, key, data);
}
static int config_list(uint32_t key, GVariant **data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
}
static int config_get(uint32_t key, GVariant **data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
struct dev_context *devc = sdi->priv;
(void)cg;
return sr_sw_limits_config_get(&devc->limits, key, data);
}
static int dev_acquisition_start(const struct sr_dev_inst *sdi)
{
struct sr_scpi_dev_inst *scpi;
struct dev_context *devc;
int ret;
scpi = sdi->conn;
devc = sdi->priv;
sr_sw_limits_acquisition_start(&devc->limits);
std_session_send_df_header(sdi);
if ((ret = sr_scpi_source_add(sdi->session, scpi, G_IO_IN, 10,
fl45_scpi_receive_data, (void *)sdi)) != SR_OK)
return ret;
return SR_OK;
}
static int dev_acquisition_stop(struct sr_dev_inst *sdi)
{
struct sr_scpi_dev_inst *scpi;
double d;
scpi = sdi->conn;
/*
* A requested value is certainly on the way. Retrieve it now,
* to avoid leaving the device in a state where it's not expecting
* commands.
*/
sr_scpi_get_double(scpi, NULL, &d);
sr_scpi_source_remove(sdi->session, scpi);
std_session_send_df_end(sdi);
return SR_OK;
}
static struct sr_dev_driver fluke_45_driver_info = {
.name = "fluke-45",
.longname = "Fluke 45",
.api_version = 1,
.init = std_init,
.cleanup = std_cleanup,
.scan = scan,
.dev_list = std_dev_list,
.dev_clear = std_dev_clear,
.config_get = config_get,
.config_set = config_set,
.config_list = config_list,
.dev_open = dev_open,
.dev_close = dev_close,
.dev_acquisition_start = dev_acquisition_start,
.dev_acquisition_stop = dev_acquisition_stop,
.context = NULL,
};
SR_REGISTER_DEV_DRIVER(fluke_45_driver_info);

View File

@ -0,0 +1,349 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2012 Bert Vermeulen <bert@biot.com>
* Copyright (C) 2017 John Chajecki <subs@qcontinuum.plus.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <config.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <glib.h>
#include <errno.h>
#include <scpi.h>
#include <libsigrok/libsigrok.h>
#include "libsigrok-internal.h"
#include "protocol.h"
/* Get the current state of the meter and sets analog object parameters. */
SR_PRIV int fl45_get_status(const struct sr_dev_inst *sdi,
struct sr_datafeed_analog *analog, int idx)
{
struct dev_context *devc;
char *cmd, *func;
int res;
res = 0;
/* Command string to read current function. */
cmd = g_strdup_printf("FUNC%d?", idx + 1);
sr_dbg("Sent command: %s.", cmd);
if (!(devc = sdi->priv))
return TRUE;
/* Default settings. */
analog[idx].meaning->mq = 0;
analog[idx].meaning->unit = 0;
analog[idx].meaning->mqflags = 0;
/* Get a response to the FUNC? command. */
res = fl45_scpi_get_response(sdi, cmd);
if (res == SR_ERR)
return res;
sr_dbg("Response to FUNC: %s.", devc->response);
/* Set up analog mq, unit and flags. */
if (res == SR_OK && devc->response != NULL) {
func = devc->response;
if (strcmp(func, "AAC") == 0) {
analog[idx].meaning->mq = SR_MQ_CURRENT;
analog[idx].meaning->unit = SR_UNIT_AMPERE;
analog[idx].meaning->mqflags = SR_MQFLAG_AC;
} else if (strcmp(func, "AACDC") == 0) {
analog[idx].meaning->mq = SR_MQ_CURRENT;
analog[idx].meaning->unit = SR_UNIT_AMPERE;
analog[idx].meaning->mqflags = SR_MQFLAG_AC;
} else if (strcmp(func, "ADC") == 0) {
analog[idx].meaning->mq = SR_MQ_CURRENT;
analog[idx].meaning->unit = SR_UNIT_AMPERE;
analog[idx].meaning->mqflags = SR_MQFLAG_DC;
} else if (strcmp(func, "CONT") == 0) {
analog[idx].meaning->mq = SR_MQ_CONTINUITY;
analog->meaning->unit = SR_UNIT_BOOLEAN;
} else if (strcmp(func, "DIODE") == 0) {
analog[idx].meaning->mq = SR_MQ_VOLTAGE;
analog[idx].meaning->unit = SR_UNIT_VOLT;
analog[idx].meaning->mqflags = SR_MQFLAG_DIODE;
} else if (strcmp(func, "FREQ") == 0) {
analog[idx].meaning->mq = SR_MQ_FREQUENCY;
analog[idx].meaning->unit = SR_UNIT_HERTZ;
} else if (strcmp(func, "OHMS") == 0) {
analog[idx].meaning->mq = SR_MQ_RESISTANCE;
analog[idx].meaning->unit = SR_UNIT_OHM;
} else if (strcmp(func, "VAC") == 0) {
analog[idx].meaning->mq = SR_MQ_VOLTAGE;
analog[idx].meaning->unit = SR_UNIT_VOLT;
analog[idx].meaning->mqflags = SR_MQFLAG_AC;
} else if (strcmp(func, "VACDC") == 0) {
analog[idx].meaning->mq = SR_MQ_VOLTAGE;
analog[idx].meaning->unit = SR_UNIT_VOLT;
analog[idx].meaning->mqflags |= SR_MQFLAG_AC;
analog[idx].meaning->mqflags |= SR_MQFLAG_DC;
} else if (strcmp(func, "VDC") == 0) {
analog[idx].meaning->mq = SR_MQ_VOLTAGE;
analog[idx].meaning->unit = SR_UNIT_VOLT;
analog[idx].meaning->mqflags = SR_MQFLAG_DC;
}
}
/* Is the meter in autorange mode? */
res = fl45_scpi_get_response(sdi, "AUTO?");
if (res == SR_ERR)
return res;
sr_dbg("Response to AUTO: %s.", devc->response);
if (res == SR_OK && devc->response != NULL) {
if (strcmp(devc->response, "1") == 0)
analog[idx].meaning->mqflags |= SR_MQFLAG_AUTORANGE;
}
return SR_OK;
}
SR_PRIV int fl45_get_modifiers(const struct sr_dev_inst *sdi,
struct sr_datafeed_analog *analog, int idx)
{
struct dev_context *devc;
int res, mod;
if (!(devc = sdi->priv))
return TRUE;
/* Get modifier value. */
res = fl45_scpi_get_response(sdi, "MOD?");
if (res == SR_ERR)
return res;
sr_dbg("Response to MOD: %s.", devc->response);
if (res == SR_OK && devc->response != NULL) {
mod = atoi(devc->response);
if (mod & 0x01) {
analog[idx].meaning->mqflags |= SR_MQFLAG_MIN;
sr_dbg("MIN bit set: %s.", "1");
}
if (mod & 0x02) {
analog[idx].meaning->mqflags |= SR_MQFLAG_MAX;
sr_dbg("MAX bit set: %s.", "2");
}
if (mod & 0x04) {
analog[idx].meaning->mqflags |= SR_MQFLAG_HOLD;
sr_dbg("HOLD bit set: %s.", "4");
}
if (mod & 0x08) {
sr_dbg("dB bit set: %s.", "8");
analog[idx].meaning->mq = SR_MQ_POWER_FACTOR;
analog[idx].meaning->unit = SR_UNIT_DECIBEL_MW;
analog[idx].meaning->mqflags = 0;
analog[idx].encoding->digits = 2;
analog[idx].spec->spec_digits = 2;
}
if (mod & 0x10) {
sr_dbg("dB Power mod bit set: %s.", "16");
analog[idx].meaning->mq = SR_MQ_POWER;
analog[idx].meaning->unit = SR_UNIT_DECIBEL_SPL;
analog[idx].meaning->mqflags = 0;
analog[idx].encoding->digits = 2;
analog[idx].spec->spec_digits = 2;
}
if (mod & 0x20) {
sr_dbg("REL bit set: %s.", "32");
analog[idx].meaning->mqflags |= SR_MQFLAG_HOLD;
}
}
return SR_OK;
}
int get_reading_dd(char *reading, size_t size)
{
int pe, pd, digits;
unsigned int i;
char expstr[3];
char *eptr;
long exp;
/* Calculate required precision. */
pe = pd = digits = 0;
/* Get positions for '.' end 'E'. */
for (i = 0; i < size; i++) {
if (reading[i] == '.')
pd = i;
if (reading[i] == 'E') {
pe = i;
break;
}
}
digits = (pe - pd) - 1;
/* Get exponent element. */
expstr[0] = reading[pe + 1];
expstr[1] = reading[pe + 2];
expstr[2] = '\0';
errno = 0;
exp = strtol(expstr, &eptr, 10);
if (errno != 0)
return 2;
/* A negative exponent increses digits, a positive one reduces. */
exp = exp * (-1);
/* Adjust digits taking into account exponent. */
digits = digits + exp;
return digits;
}
SR_PRIV int fl45_scpi_receive_data(int fd, int revents, void *cb_data)
{
struct sr_dev_inst *sdi;
struct dev_context *devc;
struct sr_datafeed_packet packet;
struct sr_datafeed_analog analog[2];
struct sr_analog_encoding encoding[2];
struct sr_analog_meaning meaning[2];
struct sr_analog_spec spec[2];
struct sr_channel *channel;
char *reading;
float fv;
int res, digits;
unsigned int i;
int sent_ch[2];
(void)fd;
(void)revents;
if (!(sdi = cb_data))
return TRUE;
if (!(devc = sdi->priv))
return TRUE;
res = 0;
sent_ch[0] = sent_ch[1] = 0;
/* Process the list of channels. */
for (i = 0; i < devc->num_channels; i++) {
/* Note: digits/spec_digits will be overridden later. */
sr_analog_init(&analog[i], &encoding[i], &meaning[i], &spec[i], 0);
/* Detect current meter function. */
res = fl45_get_status(sdi, analog, i);
/* Get channel data. */
if (i == 0)
channel = sdi->channels->data;
else
channel = sdi->channels->next->data;
/* Is channel enabled? */
if (analog[i].meaning->mq != 0 && channel->enabled) {
/* Then get a reading from it. */
if (i == 0)
res = fl45_scpi_get_response(sdi, "VAL1?");
if (i == 1)
res = fl45_scpi_get_response(sdi, "VAL2?");
/* Note: Fluke 45 sends all data in text strings. */
reading = devc->response;
/* Deal with OL reading. */
if (strcmp(reading, "+1E+9") == 0) {
fv = INFINITY;
sr_dbg("Reading OL (infinity): %s.",
devc->response);
} else if (res == SR_OK && reading != NULL) {
/* Convert reading to float. */
sr_dbg("Meter reading string: %s.", reading);
res = sr_atof_ascii(reading, &fv);
digits = get_reading_dd(reading, strlen(reading));
analog[i].encoding->digits = digits;
analog[i].spec->spec_digits = digits;
} else {
sr_dbg("Invalid float string: '%s'.", reading);
return SR_ERR;
}
/* Are we on a little or big endian system? */
#ifdef WORDS_BIGENDIAN
analog[i].encoding->is_bigendian = TRUE;
#else
analog[i].encoding->is_bigendian = FALSE;
#endif
/* Apply any modifiers. */
res = fl45_get_modifiers(sdi, analog, i);
/* Channal flag. */
sent_ch[i] = 1;
/* Set up analog object. */
analog[i].num_samples = 1;
analog[i].data = &fv;
analog[i].meaning->channels = g_slist_append(NULL, channel);
packet.type = SR_DF_ANALOG;
packet.payload = &analog[i];
sr_session_send(sdi, &packet);
g_slist_free(analog[i].meaning->channels);
}
}
/* Update appropriate channel limits. */
if (sent_ch[0] || sent_ch[1])
sr_sw_limits_update_samples_read(&devc->limits, 1);
/* Are we done collecting samples? */
if (sr_sw_limits_check(&devc->limits))
sr_dev_acquisition_stop(sdi);
return TRUE;
}
SR_PRIV int fl45_scpi_get_response(const struct sr_dev_inst *sdi, char *cmd)
{
struct dev_context *devc;
devc = sdi->priv;
/* Attempt to get a SCPI reponse. */
if (sr_scpi_get_string(sdi->conn, cmd, &devc->response) != SR_OK)
return SR_ERR;
/* Deal with RS232 '=>' prompt. */
if (strcmp(devc->response, "=>") == 0) {
/*
* If the response is a prompt then ignore and read the next
* response in the buffer.
*/
devc->response = NULL;
/* Now attempt to read again. */
if (sr_scpi_get_string(sdi->conn, NULL, &devc->response) != SR_OK)
return SR_ERR;
}
/* NULL RS232 error prompts. */
if (strcmp(devc->response, "!>") == 0
|| (strcmp(devc->response, "?>") == 0)) {
/* Unable to execute CMD. */
devc->response = NULL;
}
return SR_OK;
}

View File

@ -0,0 +1,200 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2012 Bert Vermeulen <bert@biot.com>
* Copyright (C) 2017 John Chajecki <subs@qcontinuum.plus.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBSIGROK_HARDWARE_FLUKE_45_PROTOCOL_H
#define LIBSIGROK_HARDWARE_FLUKE_45_PROTOCOL_H
#include <stdint.h>
#include <stdbool.h>
#include <scpi.h>
#define LOG_PREFIX "fluke-45"
#define FLUKEDMM_BUFSIZE 256
/* Always USB-serial, 1ms is plenty. */
#define SERIAL_WRITE_TIMEOUT_MS 1
enum data_format {
/* Fluke 45 uses IEEE488v2. */
FORMAT_IEEE488_2,
};
enum dmm_scpi_cmds {
SCPI_CMD_CLS,
SCPI_CMD_RST,
SCPI_CMD_REMS,
SCPI_CMD_RWLS,
SCPI_CMD_LOCS,
SCPI_CMD_LWLS,
SCPI_CMD_REMOTE,
SCPI_CMD_LOCAL,
SCPI_CMD_SET_ACVOLTAGE,
SCPI_CMD_SET_ACDCVOLTAGE,
SCPI_CMD_SET_DCVOLTAGE,
SCPI_CMD_SET_ACCURRENT,
SCPI_CMD_SET_ACDCCURRENT,
SCPI_CMD_SET_DCCURRENT,
SCPI_CMD_SET_FREQUENCY,
SCPI_CMD_SET_RESISTANCE,
SCPI_CMD_SET_CONTINUITY,
SCPI_CMD_SET_DIODE,
SCPI_CMD_SET_AUTO,
SCPI_CMD_GET_AUTO,
SCPI_CMD_SET_FIXED,
SCPI_CMD_SET_RANGE,
SCPI_CMD_GET_RANGE_D1,
SCPI_CMD_GET_RANGE_D2,
SCPI_CMD_SET_DB,
SCPI_CMD_SET_DBCLR,
SCPI_CMD_SET_DBPOWER,
SCPI_CMD_SET_DBREF,
SCPI_CMD_GET_DBREF,
SCPI_CMD_SET_HOLD,
SCPI_CMD_SET_HOLDCLR,
SCPI_CMD_SET_MAX,
SCPI_CMD_SET_MIN,
SCPI_CMD_SET_MMCLR,
SCPI_CMD_SET_REL,
SCPI_CMD_SET_RELCLR,
SCPI_CMD_GET_MEAS_DD,
SCPI_CMD_GET_MEAS_D1,
SCPI_CMD_GET_MEAS_D2,
SCPI_CMD_GET_RATE,
SCPI_CMD_SET_RATE,
SCPI_CMD_SET_TRIGGER,
SCPI_CMD_GET_TRIGGER,
};
static const struct scpi_command fluke_45_cmdset[] = {
{ SCPI_CMD_CLS, "*CLS" },
{ SCPI_CMD_RST, "*RST" },
{ SCPI_CMD_REMS, "*REMS" },
{ SCPI_CMD_RWLS, "*RWLS" },
{ SCPI_CMD_LOCS, "LOCS" },
{ SCPI_CMD_LWLS, "LWLS" },
{ SCPI_CMD_REMOTE, "REMS" },
{ SCPI_CMD_LOCAL, "LOCS" },
{ SCPI_CMD_SET_ACVOLTAGE, "VAC" },
{ SCPI_CMD_SET_ACDCVOLTAGE, "VACDC" },
{ SCPI_CMD_SET_DCVOLTAGE, "VDC" },
{ SCPI_CMD_SET_ACCURRENT, "AAC" },
{ SCPI_CMD_SET_ACDCCURRENT, "AACDC" },
{ SCPI_CMD_SET_DCCURRENT, "ADC" },
{ SCPI_CMD_SET_FREQUENCY, "FREQ" },
{ SCPI_CMD_SET_RESISTANCE, "OHMS" },
{ SCPI_CMD_SET_CONTINUITY, "CONT" },
{ SCPI_CMD_SET_DIODE, "DIODE" },
{ SCPI_CMD_SET_AUTO, "AUTO" },
{ SCPI_CMD_GET_AUTO, "AUTO?" },
{ SCPI_CMD_SET_FIXED, "FIXED" },
{ SCPI_CMD_SET_RANGE, "RANGE" },
{ SCPI_CMD_GET_RANGE_D1, "RANGE1?" },
{ SCPI_CMD_GET_RANGE_D2, "RANGE2?" },
{ SCPI_CMD_SET_DB, "DB" },
{ SCPI_CMD_SET_DBCLR, "DBCLR" },
{ SCPI_CMD_SET_DBPOWER, "DBPOWER" },
{ SCPI_CMD_SET_DBREF, "DBREF" },
{ SCPI_CMD_GET_DBREF, "DBREF?" },
{ SCPI_CMD_SET_HOLD, "HOLD" },
{ SCPI_CMD_SET_HOLDCLR, "HOLDCLR" },
{ SCPI_CMD_SET_MAX, "MAX" },
{ SCPI_CMD_SET_MIN, "MIN" },
{ SCPI_CMD_SET_MMCLR, "MMCLR" },
{ SCPI_CMD_SET_REL, "REL" },
{ SCPI_CMD_SET_RELCLR, "RELCLR" },
{ SCPI_CMD_GET_MEAS_DD, "MEAS?" },
{ SCPI_CMD_GET_MEAS_D1, "MEAS1?" },
{ SCPI_CMD_GET_MEAS_D2, "MEAS2?" },
{ SCPI_CMD_SET_RATE, "RATE" },
{ SCPI_CMD_GET_RATE, "RATE?" },
{ SCPI_CMD_SET_TRIGGER, "TRIGGER" },
{ SCPI_CMD_GET_TRIGGER, "TRIGGER?" },
ALL_ZERO
};
struct fluke_scpi_dmm_model {
const char *vendor;
const char *model;
int num_channels;
int poll_period; /* How often to poll, in ms. */
};
struct channel_spec {
const char *name;
/* Min, max, programming resolution, spec digits, encoding digits. */
double voltage[5];
double current[5];
double resistance[5];
double capacitance[5];
double conductance[5];
double diode[5];
};
struct channel_group_spec {
const char *name;
uint64_t channel_index_mask;
uint64_t features;
};
struct dmm_channel {
enum sr_mq mq;
unsigned int hw_output_idx;
const char *hwname;
int digits;
};
struct dmm_channel_instance {
enum sr_mq mq;
int command;
const char *prefix;
};
struct dmm_channel_group {
uint64_t features;
};
struct dev_context {
struct sr_sw_limits limits;
unsigned int num_channels;
const struct scpi_command *cmdset;
char *response;
const char *mode1;
const char *mode2;
long range1;
long range2;
long autorng;
const char *rate;
long modifiers;
long trigmode;
};
int get_reading_dd(char *reading, size_t size);
SR_PRIV extern const struct fluke_scpi_dmm_model dmm_profiles[];
SR_PRIV int fl45_scpi_receive_data(int fd, int revents, void *cb_data);
SR_PRIV int fl45_scpi_get_response(const struct sr_dev_inst *sdi, char *cmd);
SR_PRIV int fl45_get_status(const struct sr_dev_inst *sdi,
struct sr_datafeed_analog *analog, int idx);
SR_PRIV int fl45_get_modifiers(const struct sr_dev_inst *sdi,
struct sr_datafeed_analog *analog, int idx);
#endif

View File

@ -32,8 +32,11 @@ static const uint32_t scanopts[] = {
SR_CONF_SERIALCOMM,
};
static const uint32_t devopts[] = {
static const uint32_t drvopts[] = {
SR_CONF_MULTIMETER,
};
static const uint32_t devopts[] = {
SR_CONF_CONTINUOUS,
SR_CONF_LIMIT_SAMPLES | SR_CONF_SET,
SR_CONF_LIMIT_MSEC | SR_CONF_SET,
@ -87,7 +90,7 @@ static GSList *fluke_scan(struct sr_dev_driver *di, const char *conn,
/* Response is first a CMD_ACK byte (ASCII '0' for OK,
* or '1' to signify an error. */
len = 128;
len = sizeof(buf);
serial_readline(serial, &b, &len, 150);
if (len != 1)
continue;
@ -95,7 +98,7 @@ static GSList *fluke_scan(struct sr_dev_driver *di, const char *conn,
continue;
/* If CMD_ACK was OK, ID string follows. */
len = 128;
len = sizeof(buf);
serial_readline(serial, &b, &len, 850);
if (len < 10)
continue;
@ -179,41 +182,22 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
return devices;
}
static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
static int config_set(uint32_t key, GVariant *data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
struct dev_context *devc;
(void)cg;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv;
return sr_sw_limits_config_set(&devc->limits, key, data);
}
static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
static int config_list(uint32_t key, GVariant **data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
(void)sdi;
(void)cg;
switch (key) {
case SR_CONF_SCAN_OPTIONS:
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
break;
case SR_CONF_DEVICE_OPTIONS:
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
break;
default:
return SR_ERR_NA;
}
return SR_OK;
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
}
static int dev_acquisition_start(const struct sr_dev_inst *sdi)
@ -221,15 +205,11 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
struct dev_context *devc;
struct sr_serial_dev_inst *serial;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv;
sr_sw_limits_acquisition_start(&devc->limits);
std_session_send_df_header(sdi);
/* Poll every 100ms, or whenever some data comes in. */
serial = sdi->conn;
serial_source_add(sdi->session, serial, G_IO_IN, 50,
fluke_receive_data, (void *)sdi);
@ -252,7 +232,7 @@ static struct sr_dev_driver flukedmm_driver_info = {
.cleanup = std_cleanup,
.scan = scan,
.dev_list = std_dev_list,
.dev_clear = NULL,
.dev_clear = std_dev_clear,
.config_get = NULL,
.config_set = config_set,
.config_list = config_list,

View File

@ -324,7 +324,7 @@ static void handle_qm_19x_meta(const struct sr_dev_inst *sdi, char **tokens)
else if (meas_char == 3)
devc->mqflags |= SR_MQFLAG_DC | SR_MQFLAG_AC;
else if (meas_char == 15)
devc->mqflags |= SR_MQFLAG_DIODE;
devc->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
break;
case 2:
devc->mq = SR_MQ_CURRENT;
@ -526,7 +526,7 @@ SR_PRIV int fluke_receive_data(int fd, int revents, void *cb_data)
}
if (sr_sw_limits_check(&devc->limits)) {
sdi->driver->dev_acquisition_stop(sdi);
sr_dev_acquisition_stop(sdi);
return TRUE;
}

View File

@ -46,12 +46,10 @@ struct flukedmm_profile {
int timeout;
};
/* Private, per-device-instance driver context. */
struct dev_context {
const struct flukedmm_profile *profile;
struct sr_sw_limits limits;
/* Runtime. */
char buf[FLUKEDMM_BUFSIZE];
int buflen;
int64_t cmd_sent_at;

View File

@ -28,8 +28,11 @@ static const uint32_t scanopts[] = {
SR_CONF_CONN,
};
static const uint32_t devopts[] = {
static const uint32_t drvopts[] = {
SR_CONF_LOGIC_ANALYZER,
};
static const uint32_t devopts[] = {
SR_CONF_CONTINUOUS,
SR_CONF_LIMIT_SAMPLES | SR_CONF_SET,
SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
@ -47,14 +50,8 @@ static const struct ftdi_chip_desc ft2232h_desc = {
.product = 0x6010,
.samplerate_div = 20,
.channel_names = {
"ADBUS0",
"ADBUS1",
"ADBUS2",
"ADBUS3",
"ADBUS4",
"ADBUS5",
"ADBUS6",
"ADBUS7",
"ADBUS0", "ADBUS1", "ADBUS2", "ADBUS3",
"ADBUS4", "ADBUS5", "ADBUS6", "ADBUS7",
/* TODO: BDBUS[0..7] channels. */
NULL
}
@ -65,14 +62,7 @@ static const struct ftdi_chip_desc ft232r_desc = {
.product = 0x6001,
.samplerate_div = 30,
.channel_names = {
"TXD",
"RXD",
"RTS#",
"CTS#",
"DTR#",
"DSR#",
"DCD#",
"RI#",
"TXD", "RXD", "RTS#", "CTS#", "DTR#", "DSR#", "DCD#", "RI#",
NULL
}
};
@ -108,7 +98,6 @@ static void scan_device(struct ftdi_context *ftdic,
return;
}
/* Allocate memory for our private device context. */
devc = g_malloc0(sizeof(struct dev_context));
/* Allocate memory for the incoming data. */
@ -135,7 +124,6 @@ static void scan_device(struct ftdi_context *ftdic,
}
sr_dbg("Found an FTDI device: %s.", model);
/* Register the device with libsigrok. */
sdi = g_malloc0(sizeof(struct sr_dev_inst));
sdi->status = SR_ST_INACTIVE;
sdi->vendor = vendor;
@ -178,8 +166,6 @@ static GSList *scan_all(struct ftdi_context *ftdic, GSList *options)
return NULL;
}
sr_dbg("Number of FTDI devices found: %d", ret);
curdev = devlist;
while (curdev) {
scan_device(ftdic, curdev->dev, &devices);
@ -213,7 +199,6 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
}
}
/* Allocate memory for the FTDI context (ftdic) and initialize it. */
ftdic = ftdi_new();
if (!ftdic) {
sr_err("Failed to initialize libftdi.");
@ -242,18 +227,14 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
return std_scan_complete(di, devices);
}
static void clear_helper(void *priv)
static void clear_helper(struct dev_context *devc)
{
struct dev_context *devc;
devc = priv;
g_free(devc->data_buf);
g_free(devc);
}
static int dev_clear(const struct sr_dev_driver *di)
{
return std_dev_clear(di, clear_helper);
return std_dev_clear_with_callback(di, (std_dev_clear_callback)clear_helper);
}
static int dev_open(struct sr_dev_inst *sdi)
@ -276,23 +257,19 @@ static int dev_open(struct sr_dev_inst *sdi)
goto err_ftdi_free;
}
/* Purge RX/TX buffers in the FTDI chip. */
ret = ftdi_usb_purge_buffers(devc->ftdic);
if (ret < 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, 0x00, 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.");
ret = ftdi_set_bitmode(devc->ftdic, 0x00, BITMODE_BITBANG);
if (ret < 0) {
@ -300,15 +277,15 @@ static int dev_open(struct sr_dev_inst *sdi)
ret, ftdi_get_error_string(devc->ftdic));
goto err_dev_open_close_ftdic;
}
sr_dbg("FTDI chip bitbang mode entered successfully.");
sdi->status = SR_ST_ACTIVE;
return SR_OK;
err_dev_open_close_ftdic:
ftdi_usb_close(devc->ftdic);
err_ftdi_free:
ftdi_free(devc->ftdic);
return SR_ERR;
}
@ -318,13 +295,12 @@ static int dev_close(struct sr_dev_inst *sdi)
devc = sdi->priv;
if (devc->ftdic) {
ftdi_usb_close(devc->ftdic);
ftdi_free(devc->ftdic);
devc->ftdic = NULL;
}
if (!devc->ftdic)
return SR_ERR_BUG;
sdi->status = SR_ST_INACTIVE;
ftdi_usb_close(devc->ftdic);
ftdi_free(devc->ftdic);
devc->ftdic = NULL;
return SR_OK;
}
@ -332,16 +308,13 @@ static int dev_close(struct sr_dev_inst *sdi)
static int config_get(uint32_t key, GVariant **data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
int ret;
struct dev_context *devc;
struct sr_usb_dev_inst *usb;
char str[128];
(void)cg;
devc = sdi->priv;
ret = SR_OK;
switch (key) {
case SR_CONF_SAMPLERATE:
*data = g_variant_new_uint64(devc->cur_samplerate);
@ -350,40 +323,32 @@ static int config_get(uint32_t key, GVariant **data,
if (!sdi || !sdi->conn)
return SR_ERR_ARG;
usb = sdi->conn;
snprintf(str, 128, "%d.%d", usb->bus, usb->address);
*data = g_variant_new_string(str);
*data = g_variant_new_printf("%d.%d", usb->bus, usb->address);
break;
default:
return SR_ERR_NA;
}
return ret;
return SR_OK;
}
static int config_set(uint32_t key, GVariant *data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
int ret;
struct dev_context *devc;
uint64_t value;
(void)cg;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv;
ret = SR_OK;
switch (key) {
case SR_CONF_LIMIT_MSEC:
value = g_variant_get_uint64(data);
/* TODO: Implement. */
ret = SR_ERR_NA;
break;
(void)value;
return SR_ERR_NA;
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_SAMPLERATE:
@ -393,44 +358,27 @@ static int config_set(uint32_t key, GVariant *data,
devc->cur_samplerate = value;
return ftdi_la_set_samplerate(devc);
default:
ret = SR_ERR_NA;
return SR_ERR_NA;
}
return ret;
return SR_OK;
}
static int config_list(uint32_t key, GVariant **data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
int ret;
GVariant *gvar;
GVariantBuilder gvb;
(void)sdi;
(void)cg;
ret = SR_OK;
switch (key) {
case SR_CONF_SCAN_OPTIONS:
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
break;
case SR_CONF_DEVICE_OPTIONS:
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
break;
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
case SR_CONF_SAMPLERATE:
g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"),
samplerates, ARRAY_SIZE(samplerates), sizeof(uint64_t));
g_variant_builder_add(&gvb, "{sv}", "samplerate-steps", gvar);
*data = g_variant_builder_end(&gvb);
*data = std_gvar_samplerates_steps(ARRAY_AND_SIZE(samplerates));
break;
default:
return SR_ERR_NA;
}
return ret;
return SR_OK;
}
static int dev_acquisition_start(const struct sr_dev_inst *sdi)
@ -439,9 +387,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
devc = sdi->priv;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
if (!devc->ftdic)
return SR_ERR_BUG;
@ -462,10 +407,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
static int dev_acquisition_stop(struct sr_dev_inst *sdi)
{
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
sr_dbg("Stopping acquisition.");
sr_session_source_remove(sdi->session, -1);
std_session_send_df_end(sdi);

View File

@ -17,6 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <ftdi.h>
#include "protocol.h"
@ -79,7 +80,7 @@ SR_PRIV int ftdi_la_receive_data(int fd, int revents, void *cb_data)
if (bytes_read < 0) {
sr_err("Failed to read FTDI data (%d): %s.",
bytes_read, ftdi_get_error_string(devc->ftdic));
sdi->driver->dev_acquisition_stop(sdi);
sr_dev_acquisition_stop(sdi);
return FALSE;
}
if (bytes_read == 0) {
@ -94,7 +95,7 @@ SR_PRIV int ftdi_la_receive_data(int fd, int revents, void *cb_data)
if (devc->limit_samples && (n >= devc->limit_samples)) {
send_samples(sdi, devc->limit_samples - devc->samples_sent);
sr_info("Requested number of samples reached.");
sdi->driver->dev_acquisition_stop(sdi);
sr_dev_acquisition_stop(sdi);
return TRUE;
} else {
send_samples(sdi, devc->bytes_received);

View File

@ -36,7 +36,6 @@ struct ftdi_chip_desc {
char *channel_names[];
};
/** Private, per-device-instance driver context. */
struct dev_context {
struct ftdi_context *ftdic;
const struct ftdi_chip_desc *desc;

View File

@ -20,21 +20,27 @@
#include <config.h>
#include "protocol.h"
#include "dslogic.h"
#include <math.h>
static const struct fx2lafw_profile supported_fx2[] = {
/*
* CWAV USBee AX
* EE Electronics ESLA201A
* ARMFLY AX-Pro
* ARMFLY AX-Pro (clone of the CWAV USBee AX)
* ARMFLY Mini-Logic (clone of the CWAV USBee AX)
* EE Electronics ESLA201A (clone of the CWAV USBee AX)
* HT USBee-AxPro (clone of the CWAV USBee AX)
* MCU123 USBee AX Pro clone (clone of the CWAV USBee AX)
* Noname LHT00SU1 (clone of the CWAV USBee AX)
* XZL_Studio AX (clone of the CWAV USBee AX)
*/
{ 0x08a9, 0x0014, "CWAV", "USBee AX", NULL,
"fx2lafw-cwav-usbeeax.fw",
DEV_CAPS_AX_ANALOG, NULL, NULL},
/*
* CWAV USBee DX
* XZL-Studio DX
* HT USBee-DxPro (clone of the CWAV USBee DX), not yet supported!
* XZL-Studio DX (clone of the CWAV USBee DX)
*/
{ 0x08a9, 0x0015, "CWAV", "USBee DX", NULL,
"fx2lafw-cwav-usbeedx.fw",
@ -54,38 +60,14 @@ static const struct fx2lafw_profile supported_fx2[] = {
"fx2lafw-cwav-usbeezx.fw",
0, NULL, NULL},
/* DreamSourceLab DSLogic (before FW upload) */
{ 0x2a0e, 0x0001, "DreamSourceLab", "DSLogic", NULL,
"dreamsourcelab-dslogic-fx2.fw",
DEV_CAPS_16BIT | DEV_CAPS_DSLOGIC_FW, NULL, NULL},
/* DreamSourceLab DSLogic (after FW upload) */
{ 0x2a0e, 0x0001, "DreamSourceLab", "DSLogic", NULL,
"dreamsourcelab-dslogic-fx2.fw",
DEV_CAPS_16BIT | DEV_CAPS_DSLOGIC_FW, "DreamSourceLab", "DSLogic"},
/* DreamSourceLab DSCope (before FW upload) */
{ 0x2a0e, 0x0002, "DreamSourceLab", "DSCope", NULL,
"dreamsourcelab-dscope-fx2.fw",
DEV_CAPS_16BIT | DEV_CAPS_DSLOGIC_FW, NULL, NULL},
/* DreamSourceLab DSCope (after FW upload) */
{ 0x2a0e, 0x0002, "DreamSourceLab", "DSCope", NULL,
"dreamsourcelab-dscope-fx2.fw",
DEV_CAPS_16BIT | DEV_CAPS_DSLOGIC_FW, "DreamSourceLab", "DSCope"},
/* DreamSourceLab DSLogic Pro (before FW upload) */
{ 0x2a0e, 0x0003, "DreamSourceLab", "DSLogic Pro", NULL,
"dreamsourcelab-dslogic-pro-fx2.fw",
DEV_CAPS_16BIT | DEV_CAPS_DSLOGIC_FW, NULL, NULL},
/* DreamSourceLab DSLogic Pro (after FW upload) */
{ 0x2a0e, 0x0003, "DreamSourceLab", "DSLogic Pro", NULL,
"dreamsourcelab-dslogic-pro-fx2.fw",
DEV_CAPS_16BIT | DEV_CAPS_DSLOGIC_FW, "DreamSourceLab", "DSLogic"},
/*
* Saleae Logic
* EE Electronics ESLA100
* Robomotic MiniLogic
* Robomotic BugLogic 3
* EE Electronics ESLA100 (clone of the Saleae Logic)
* Hantek 6022BL in LA mode (clone of the Saleae Logic)
* Instrustar ISDS205X in LA mode (clone of the Saleae Logic)
* Robomotic MiniLogic (clone of the Saleae Logic)
* Robomotic BugLogic 3 (clone of the Saleae Logic)
* MCU123 Saleae Logic clone (clone of the Saleae Logic)
*/
{ 0x0925, 0x3881, "Saleae", "Logic", NULL,
"fx2lafw-saleae-logic.fw",
@ -95,6 +77,7 @@ static const struct fx2lafw_profile supported_fx2[] = {
* Default Cypress FX2 without EEPROM, e.g.:
* Lcsoft Mini Board
* Braintechnology USB Interface V2.x
* fx2grok-tiny
*/
{ 0x04B4, 0x8613, "Cypress", "FX2", NULL,
"fx2lafw-cypress-fx2.fw",
@ -109,6 +92,7 @@ static const struct fx2lafw_profile supported_fx2[] = {
/*
* sigrok FX2 based 8-channel logic analyzer
* fx2grok-flat (before and after renumeration)
*/
{ 0x1d50, 0x608c, "sigrok", "FX2 LA (8ch)", NULL,
"fx2lafw-sigrok-fx2-8ch.fw",
@ -121,17 +105,24 @@ static const struct fx2lafw_profile supported_fx2[] = {
"fx2lafw-sigrok-fx2-16ch.fw",
DEV_CAPS_16BIT, NULL, NULL },
ALL_ZERO
};
/*
* usb-c-grok
*/
{ 0x1d50, 0x608f, "sigrok", "usb-c-grok", NULL,
"fx2lafw-usb-c-grok.fw",
0, NULL, NULL},
static const uint32_t drvopts[] = {
SR_CONF_LOGIC_ANALYZER,
ALL_ZERO
};
static const uint32_t scanopts[] = {
SR_CONF_CONN,
};
static const uint32_t drvopts[] = {
SR_CONF_LOGIC_ANALYZER,
};
static const uint32_t devopts[] = {
SR_CONF_CONTINUOUS,
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
@ -141,19 +132,7 @@ static const uint32_t devopts[] = {
SR_CONF_CAPTURE_RATIO | SR_CONF_GET | SR_CONF_SET,
};
static const uint32_t dslogic_devopts[] = {
SR_CONF_CONTINUOUS | SR_CONF_SET | SR_CONF_GET,
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
SR_CONF_VOLTAGE_THRESHOLD | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
SR_CONF_CONN | SR_CONF_GET,
SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
SR_CONF_TRIGGER_MATCH | SR_CONF_LIST,
SR_CONF_CAPTURE_RATIO | SR_CONF_GET | SR_CONF_SET,
SR_CONF_EXTERNAL_CLOCK | SR_CONF_GET | SR_CONF_SET,
SR_CONF_CLOCK_EDGE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
};
static const int32_t soft_trigger_matches[] = {
static const int32_t trigger_matches[] = {
SR_TRIGGER_ZERO,
SR_TRIGGER_ONE,
SR_TRIGGER_RISING,
@ -161,21 +140,6 @@ static const int32_t soft_trigger_matches[] = {
SR_TRIGGER_EDGE,
};
/* Names assigned to available edge slope choices. */
static const char *const signal_edge_names[] = {
[DS_EDGE_RISING] = "rising",
[DS_EDGE_FALLING] = "falling",
};
static const struct {
int range;
gdouble low;
gdouble high;
} volt_thresholds[] = {
{ DS_VOLTAGE_RANGE_18_33_V, 0.7, 1.4 },
{ DS_VOLTAGE_RANGE_5_V, 1.4, 3.6 },
};
static const uint64_t samplerates[] = {
SR_KHZ(20),
SR_KHZ(25),
@ -195,25 +159,6 @@ static const uint64_t samplerates[] = {
SR_MHZ(24),
};
static const uint64_t dslogic_samplerates[] = {
SR_KHZ(10),
SR_KHZ(20),
SR_KHZ(50),
SR_KHZ(100),
SR_KHZ(200),
SR_KHZ(500),
SR_MHZ(1),
SR_MHZ(2),
SR_MHZ(5),
SR_MHZ(10),
SR_MHZ(20),
SR_MHZ(25),
SR_MHZ(50),
SR_MHZ(100),
SR_MHZ(200),
SR_MHZ(400),
};
static gboolean is_plausible(const struct libusb_device_descriptor *des)
{
int i;
@ -325,10 +270,11 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
continue;
}
usb_get_port_path(devlist[i], connection_id, sizeof(connection_id));
libusb_close(hdl);
if (usb_get_port_path(devlist[i], connection_id, sizeof(connection_id)) < 0)
continue;
prof = NULL;
for (j = 0; supported_fx2[j].vid; j++) {
if (des.idVendor == supported_fx2[j].vid &&
@ -342,7 +288,6 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
}
}
/* Skip if the device was not found. */
if (!prof)
continue;
@ -386,21 +331,10 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
sdi->priv = devc;
devices = g_slist_append(devices, sdi);
if (!strcmp(prof->model, "DSLogic")
|| !strcmp(prof->model, "DSLogic Pro")
|| !strcmp(prof->model, "DSCope")) {
devc->dslogic = TRUE;
devc->samplerates = dslogic_samplerates;
devc->num_samplerates = ARRAY_SIZE(dslogic_samplerates);
has_firmware = match_manuf_prod(devlist[i], "DreamSourceLab", "DSLogic")
|| match_manuf_prod(devlist[i], "DreamSourceLab", "DSCope");
} else {
devc->dslogic = FALSE;
devc->samplerates = samplerates;
devc->num_samplerates = ARRAY_SIZE(samplerates);
has_firmware = match_manuf_prod(devlist[i],
"sigrok", "fx2lafw");
}
devc->samplerates = samplerates;
devc->num_samplerates = ARRAY_SIZE(samplerates);
has_firmware = usb_match_manuf_prod(devlist[i],
"sigrok", "fx2lafw");
if (has_firmware) {
/* Already has the firmware, so fix the new address. */
@ -411,14 +345,16 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
libusb_get_device_address(devlist[i]), NULL);
} else {
if (ezusb_upload_firmware(drvc->sr_ctx, devlist[i],
USB_CONFIGURATION, prof->firmware) == SR_OK)
USB_CONFIGURATION, prof->firmware) == SR_OK) {
/* Store when this device's FW was updated. */
devc->fw_updated = g_get_monotonic_time();
else
} else {
sr_err("Firmware upload failed for "
"device %d.%d (logical).",
"device %d.%d (logical), name %s.",
libusb_get_bus_number(devlist[i]),
libusb_get_device_address(devlist[i]));
libusb_get_device_address(devlist[i]),
prof->firmware);
}
sdi->inst_type = SR_INST_USB;
sdi->conn = sr_usb_dev_inst_new(libusb_get_bus_number(devlist[i]),
0xff, NULL);
@ -430,18 +366,14 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
return std_scan_complete(di, devices);
}
static void clear_dev_context(void *priv)
static void clear_helper(struct dev_context *devc)
{
struct dev_context *devc;
devc = priv;
g_slist_free(devc->enabled_analog_channels);
g_free(devc);
}
static int dev_clear(const struct sr_dev_driver *di)
{
return std_dev_clear(di, clear_dev_context);
return std_dev_clear_with_callback(di, (std_dev_clear_callback)clear_helper);
}
static int dev_open(struct sr_dev_inst *sdi)
@ -449,7 +381,6 @@ static int dev_open(struct sr_dev_inst *sdi)
struct sr_dev_driver *di = sdi->driver;
struct sr_usb_dev_inst *usb;
struct dev_context *devc;
const char *fpga_firmware = NULL;
int ret;
int64_t timediff_us, timediff_ms;
@ -509,21 +440,6 @@ static int dev_open(struct sr_dev_inst *sdi)
return SR_ERR;
}
if (devc->dslogic) {
if (!strcmp(devc->profile->model, "DSLogic")) {
if (devc->dslogic_voltage_threshold == DS_VOLTAGE_RANGE_18_33_V)
fpga_firmware = DSLOGIC_FPGA_FIRMWARE_3V3;
else
fpga_firmware = DSLOGIC_FPGA_FIRMWARE_5V;
} else if (!strcmp(devc->profile->model, "DSLogic Pro")){
fpga_firmware = DSLOGIC_PRO_FPGA_FIRMWARE;
} else if (!strcmp(devc->profile->model, "DSCope")) {
fpga_firmware = DSCOPE_FPGA_FIRMWARE;
}
if ((ret = dslogic_fpga_firmware_upload(sdi, fpga_firmware)) != SR_OK)
return ret;
}
if (devc->cur_samplerate == 0) {
/* Samplerate hasn't been set; default to the slowest one. */
devc->cur_samplerate = devc->samplerates[0];
@ -539,14 +455,13 @@ static int dev_close(struct sr_dev_inst *sdi)
usb = sdi->conn;
if (!usb->devhdl)
return SR_ERR;
return SR_ERR_BUG;
sr_info("fx2lafw: Closing device on %d.%d (logical) / %s (physical) interface %d.",
sr_info("Closing device on %d.%d (logical) / %s (physical) interface %d.",
usb->bus, usb->address, sdi->connection_id, USB_INTERFACE);
libusb_release_interface(usb->devhdl, USB_INTERFACE);
libusb_close(usb->devhdl);
usb->devhdl = NULL;
sdi->status = SR_ST_INACTIVE;
return SR_OK;
}
@ -556,9 +471,6 @@ static int config_get(uint32_t key, GVariant **data,
{
struct dev_context *devc;
struct sr_usb_dev_inst *usb;
GVariant *range[2];
unsigned int i;
char str[128];
(void)cg;
@ -576,18 +488,7 @@ static int config_get(uint32_t key, GVariant **data,
/* 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_VOLTAGE_THRESHOLD:
for (i = 0; i < ARRAY_SIZE(volt_thresholds); i++) {
if (volt_thresholds[i].range != devc->dslogic_voltage_threshold)
continue;
range[0] = g_variant_new_double(volt_thresholds[i].low);
range[1] = g_variant_new_double(volt_thresholds[i].high);
*data = g_variant_new_tuple(range, 2);
break;
}
*data = g_variant_new_printf("%d.%d", usb->bus, usb->address);
break;
case SR_CONF_LIMIT_SAMPLES:
*data = g_variant_new_uint64(devc->limit_samples);
@ -598,18 +499,6 @@ static int config_get(uint32_t key, GVariant **data,
case SR_CONF_CAPTURE_RATIO:
*data = g_variant_new_uint64(devc->capture_ratio);
break;
case SR_CONF_EXTERNAL_CLOCK:
*data = g_variant_new_boolean(devc->dslogic_external_clock);
break;
case SR_CONF_CONTINUOUS:
*data = g_variant_new_boolean(devc->dslogic_continuous_mode);
break;
case SR_CONF_CLOCK_EDGE:
i = devc->dslogic_clock_edge;
if (i >= ARRAY_SIZE(signal_edge_names))
return SR_ERR_BUG;
*data = g_variant_new_string(signal_edge_names[0]);
break;
default:
return SR_ERR_NA;
}
@ -617,166 +506,30 @@ static int config_get(uint32_t key, GVariant **data,
return SR_OK;
}
/*
* Helper for mapping a string-typed configuration value to an index
* within a table of possible values.
*/
static int lookup_index(GVariant *value, const char *const *table, int len)
{
const char *entry;
int i;
entry = g_variant_get_string(value, NULL);
if (!entry)
return -1;
/* Linear search is fine for very small tables. */
for (i = 0; i < len; i++) {
if (strcmp(entry, table[i]) == 0)
return i;
}
return -1;
}
static int config_set(uint32_t key, GVariant *data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
struct dev_context *devc;
uint64_t arg;
int i, ret;
gdouble low, high;
int idx;
(void)cg;
if (!sdi)
return SR_ERR_ARG;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR;
devc = sdi->priv;
ret = SR_OK;
switch (key) {
case SR_CONF_SAMPLERATE:
arg = g_variant_get_uint64(data);
for (i = 0; i < devc->num_samplerates; i++) {
if (devc->samplerates[i] == arg) {
devc->cur_samplerate = arg;
break;
}
}
if (i == devc->num_samplerates)
ret = SR_ERR_ARG;
if ((idx = std_u64_idx(data, devc->samplerates, devc->num_samplerates)) < 0)
return SR_ERR_ARG;
devc->cur_samplerate = devc->samplerates[idx];
break;
case SR_CONF_LIMIT_SAMPLES:
devc->limit_samples = g_variant_get_uint64(data);
break;
case SR_CONF_CAPTURE_RATIO:
devc->capture_ratio = g_variant_get_uint64(data);
ret = (devc->capture_ratio > 100) ? SR_ERR : SR_OK;
break;
case SR_CONF_VOLTAGE_THRESHOLD:
g_variant_get(data, "(dd)", &low, &high);
ret = SR_ERR_ARG;
for (i = 0; (unsigned int)i < ARRAY_SIZE(volt_thresholds); i++) {
if (fabs(volt_thresholds[i].low - low) < 0.1 &&
fabs(volt_thresholds[i].high - high) < 0.1) {
devc->dslogic_voltage_threshold = volt_thresholds[i].range;
break;
}
}
if (!strcmp(devc->profile->model, "DSLogic")) {
if (devc->dslogic_voltage_threshold == DS_VOLTAGE_RANGE_5_V)
ret = dslogic_fpga_firmware_upload(sdi, DSLOGIC_FPGA_FIRMWARE_5V);
else
ret = dslogic_fpga_firmware_upload(sdi, DSLOGIC_FPGA_FIRMWARE_3V3);
} else if (!strcmp(devc->profile->model, "DSLogic Pro")) {
ret = dslogic_fpga_firmware_upload(sdi, DSLOGIC_PRO_FPGA_FIRMWARE);
}
break;
case SR_CONF_EXTERNAL_CLOCK:
devc->dslogic_external_clock = g_variant_get_boolean(data);
break;
case SR_CONF_CONTINUOUS:
devc->dslogic_continuous_mode = g_variant_get_boolean(data);
break;
case SR_CONF_CLOCK_EDGE:
i = lookup_index(data, signal_edge_names,
ARRAY_SIZE(signal_edge_names));
if (i < 0)
return SR_ERR_ARG;
devc->dslogic_clock_edge = i;
break;
default:
ret = SR_ERR_NA;
}
return ret;
}
static int config_list(uint32_t key, GVariant **data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
struct dev_context *devc;
GVariant *gvar, *range[2];
GVariantBuilder gvb;
unsigned int i;
(void)cg;
switch (key) {
case SR_CONF_SCAN_OPTIONS:
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
break;
case SR_CONF_DEVICE_OPTIONS:
if (!sdi) {
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
drvopts, ARRAY_SIZE(drvopts), sizeof(uint32_t));
} else {
devc = sdi->priv;
if (!devc->dslogic)
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
else
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
dslogic_devopts, ARRAY_SIZE(dslogic_devopts), sizeof(uint32_t));
}
break;
case SR_CONF_VOLTAGE_THRESHOLD:
if (!sdi->priv)
return SR_ERR_ARG;
devc = sdi->priv;
if (!devc->dslogic)
return SR_ERR_NA;
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_SAMPLERATE:
devc = sdi->priv;
g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), devc->samplerates,
devc->num_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;
case SR_CONF_CLOCK_EDGE:
*data = g_variant_new_strv(signal_edge_names,
ARRAY_SIZE(signal_edge_names));
break;
default:
return SR_ERR_NA;
@ -785,280 +538,29 @@ static int config_list(uint32_t key, GVariant **data,
return SR_OK;
}
static int receive_data(int fd, int revents, void *cb_data)
{
struct timeval tv;
struct drv_context *drvc;
(void)fd;
(void)revents;
drvc = (struct drv_context *)cb_data;
tv.tv_sec = tv.tv_usec = 0;
libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
return TRUE;
}
static int start_transfers(const struct sr_dev_inst *sdi)
static int config_list(uint32_t key, GVariant **data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
struct dev_context *devc;
struct sr_usb_dev_inst *usb;
struct sr_trigger *trigger;
struct libusb_transfer *transfer;
unsigned int i, num_transfers;
int endpoint, timeout, ret;
unsigned char *buf;
size_t size;
devc = sdi->priv;
usb = sdi->conn;
devc = (sdi) ? sdi->priv : NULL;
devc->sent_samples = 0;
devc->acq_aborted = FALSE;
devc->empty_transfer_count = 0;
if ((trigger = sr_session_trigger_get(sdi->session)) && !devc->dslogic) {
int pre_trigger_samples = 0;
if (devc->limit_samples > 0)
pre_trigger_samples = devc->capture_ratio * devc->limit_samples/100;
devc->stl = soft_trigger_logic_new(sdi, trigger, pre_trigger_samples);
if (!devc->stl)
return SR_ERR_MALLOC;
devc->trigger_fired = FALSE;
} else
devc->trigger_fired = TRUE;
num_transfers = fx2lafw_get_number_of_transfers(devc);
//if (devc->dslogic)
// num_transfers = dslogic_get_number_of_transfers(devc);
if (devc->dslogic) {
if (devc->cur_samplerate == SR_MHZ(100))
num_transfers = 16;
else if (devc->cur_samplerate == SR_MHZ(200))
num_transfers = 8;
else if (devc->cur_samplerate == SR_MHZ(400))
num_transfers = 4;
}
size = fx2lafw_get_buffer_size(devc);
devc->submitted_transfers = 0;
devc->transfers = g_try_malloc0(sizeof(*devc->transfers) * num_transfers);
if (!devc->transfers) {
sr_err("USB transfers malloc failed.");
return SR_ERR_MALLOC;
}
timeout = fx2lafw_get_timeout(devc);
endpoint = devc->dslogic ? 6 : 2;
devc->num_transfers = num_transfers;
for (i = 0; i < num_transfers; i++) {
if (!(buf = g_try_malloc(size))) {
sr_err("USB transfer buffer malloc failed.");
return SR_ERR_MALLOC;
}
transfer = libusb_alloc_transfer(0);
libusb_fill_bulk_transfer(transfer, usb->devhdl,
endpoint | LIBUSB_ENDPOINT_IN, buf, size,
fx2lafw_receive_transfer, (void *)sdi, timeout);
sr_info("submitting transfer: %d", i);
if ((ret = libusb_submit_transfer(transfer)) != 0) {
sr_err("Failed to submit transfer: %s.",
libusb_error_name(ret));
libusb_free_transfer(transfer);
g_free(buf);
fx2lafw_abort_acquisition(devc);
return SR_ERR;
}
devc->transfers[i] = transfer;
devc->submitted_transfers++;
}
/*
* If this device has analog channels and at least one of them is
* enabled, use mso_send_data_proc() to properly handle the analog
* data. Otherwise use la_send_data_proc().
*/
if (g_slist_length(devc->enabled_analog_channels) > 0)
devc->send_data_proc = mso_send_data_proc;
else
devc->send_data_proc = la_send_data_proc;
std_session_send_df_header(sdi);
return SR_OK;
}
static void LIBUSB_CALL dslogic_trigger_receive(struct libusb_transfer *transfer)
{
const struct sr_dev_inst *sdi;
struct dslogic_trigger_pos *tpos;
struct dev_context *devc;
sdi = transfer->user_data;
devc = sdi->priv;
if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {
sr_dbg("Trigger transfer canceled.");
/* Terminate session. */
std_session_send_df_end(sdi);
usb_source_remove(sdi->session, devc->ctx);
devc->num_transfers = 0;
g_free(devc->transfers);
if (devc->stl) {
soft_trigger_logic_free(devc->stl);
devc->stl = NULL;
}
} else if (transfer->status == LIBUSB_TRANSFER_COMPLETED
&& transfer->actual_length == sizeof(struct dslogic_trigger_pos)) {
tpos = (struct dslogic_trigger_pos *)transfer->buffer;
sr_info("tpos real_pos %d ram_saddr %d cnt %d", tpos->real_pos,
tpos->ram_saddr, tpos->remain_cnt);
devc->trigger_pos = tpos->real_pos;
g_free(tpos);
start_transfers(sdi);
}
libusb_free_transfer(transfer);
}
static int dslogic_trigger_request(const struct sr_dev_inst *sdi)
{
struct sr_usb_dev_inst *usb;
struct libusb_transfer *transfer;
struct dslogic_trigger_pos *tpos;
struct dev_context *devc;
int ret;
usb = sdi->conn;
devc = sdi->priv;
if ((ret = dslogic_stop_acquisition(sdi)) != SR_OK)
return ret;
if ((ret = dslogic_fpga_configure(sdi)) != SR_OK)
return ret;
/* If this is a DSLogic Pro, set the voltage threshold. */
if (!strcmp(devc->profile->model, "DSLogic Pro")){
if (devc->dslogic_voltage_threshold == DS_VOLTAGE_RANGE_18_33_V) {
dslogic_set_vth(sdi, 1.4);
} else {
dslogic_set_vth(sdi, 3.3);
}
}
if ((ret = dslogic_start_acquisition(sdi)) != SR_OK)
return ret;
sr_dbg("Getting trigger.");
tpos = g_malloc(sizeof(struct dslogic_trigger_pos));
transfer = libusb_alloc_transfer(0);
libusb_fill_bulk_transfer(transfer, usb->devhdl, 6 | LIBUSB_ENDPOINT_IN,
(unsigned char *)tpos, sizeof(struct dslogic_trigger_pos),
dslogic_trigger_receive, (void *)sdi, 0);
if ((ret = libusb_submit_transfer(transfer)) < 0) {
sr_err("Failed to request trigger: %s.", libusb_error_name(ret));
libusb_free_transfer(transfer);
g_free(tpos);
return SR_ERR;
}
devc->transfers = g_try_malloc0(sizeof(*devc->transfers));
if (!devc->transfers) {
sr_err("USB trigger_pos transfer malloc failed.");
return SR_ERR_MALLOC;
}
devc->num_transfers = 1;
devc->submitted_transfers++;
devc->transfers[0] = transfer;
return ret;
}
static int configure_channels(const struct sr_dev_inst *sdi)
{
struct dev_context *devc;
const GSList *l;
int p;
struct sr_channel *ch;
uint32_t channel_mask = 0, num_analog = 0;
devc = sdi->priv;
g_slist_free(devc->enabled_analog_channels);
devc->enabled_analog_channels = NULL;
for (l = sdi->channels, p = 0; l; l = l->next, p++) {
ch = l->data;
if ((p <= NUM_CHANNELS) && (ch->type == SR_CHANNEL_ANALOG)
&& (ch->enabled)) {
num_analog++;
devc->enabled_analog_channels =
g_slist_append(devc->enabled_analog_channels, ch);
} else {
channel_mask |= ch->enabled << p;
}
}
/*
* Use wide sampling if either any of the LA channels 8..15 is enabled,
* and/or at least one analog channel is enabled, and/or the device
* is running DSLogic firmware (not fx2lafw).
*/
devc->sample_wide = (channel_mask > 0xff
|| num_analog > 0
|| (devc->profile->dev_caps & DEV_CAPS_DSLOGIC_FW));
return SR_OK;
}
static int dev_acquisition_start(const struct sr_dev_inst *sdi)
{
struct sr_dev_driver *di;
struct drv_context *drvc;
struct dev_context *devc;
int timeout, ret;
size_t size;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
di = sdi->driver;
drvc = di->context;
devc = sdi->priv;
devc->ctx = drvc->sr_ctx;
devc->sent_samples = 0;
devc->empty_transfer_count = 0;
devc->acq_aborted = FALSE;
if (configure_channels(sdi) != SR_OK) {
sr_err("Failed to configure channels.");
return SR_ERR;
}
timeout = fx2lafw_get_timeout(devc);
usb_source_add(sdi->session, devc->ctx, timeout, receive_data, drvc);
if (devc->dslogic) {
dslogic_trigger_request(sdi);
} else {
size = fx2lafw_get_buffer_size(devc);
/* Prepare for analog sampling. */
if (g_slist_length(devc->enabled_analog_channels) > 0) {
/* We need a buffer half the size of a transfer. */
devc->logic_buffer = g_try_malloc(size / 2);
devc->analog_buffer = g_try_malloc(
sizeof(float) * size / 2);
}
start_transfers(sdi);
if ((ret = fx2lafw_command_start_acquisition(sdi)) != SR_OK) {
fx2lafw_abort_acquisition(devc);
return ret;
}
switch (key) {
case SR_CONF_SCAN_OPTIONS:
case SR_CONF_DEVICE_OPTIONS:
if (cg)
return SR_ERR_NA;
return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
case SR_CONF_SAMPLERATE:
if (!devc)
return SR_ERR_NA;
*data = std_gvar_samplerates(devc->samplerates, devc->num_samplerates);
break;
case SR_CONF_TRIGGER_MATCH:
*data = std_gvar_array_i32(ARRAY_AND_SIZE(trigger_matches));
break;
default:
return SR_ERR_NA;
}
return SR_OK;
@ -1066,13 +568,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
static int dev_acquisition_stop(struct sr_dev_inst *sdi)
{
struct dev_context *devc;
devc = sdi->priv;
if (devc->dslogic)
dslogic_stop_acquisition(sdi);
fx2lafw_abort_acquisition(sdi->priv);
return SR_OK;
@ -1092,7 +587,7 @@ static struct sr_dev_driver fx2lafw_driver_info = {
.config_list = config_list,
.dev_open = dev_open,
.dev_close = dev_close,
.dev_acquisition_start = dev_acquisition_start,
.dev_acquisition_start = fx2lafw_start_acquisition,
.dev_acquisition_stop = dev_acquisition_stop,
.context = NULL,
};

View File

@ -1,425 +0,0 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
* Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <math.h>
#include <glib.h>
#include <glib/gstdio.h>
#include "protocol.h"
#include "dslogic.h"
/*
* This should be larger than the FPGA bitstream image so that it'll get
* uploaded in one big operation. There seem to be issues when uploading
* it in chunks.
*/
#define FW_BUFSIZE (1024 * 1024)
#define FPGA_UPLOAD_DELAY (10 * 1000)
#define USB_TIMEOUT (3 * 1000)
SR_PRIV int dslogic_set_vth(const struct sr_dev_inst *sdi, double vth)
{
struct sr_usb_dev_inst *usb;
int ret;
uint8_t cmd;
usb = sdi->conn;
cmd = (vth / 5.0) * 255;
/* Send the control command. */
ret = libusb_control_transfer(usb->devhdl, LIBUSB_REQUEST_TYPE_VENDOR |
LIBUSB_ENDPOINT_OUT, DS_CMD_VTH, 0x0000, 0x0000,
(unsigned char *)&cmd, sizeof(cmd), 3000);
if (ret < 0) {
sr_err("Unable to send VTH command: %s.",
libusb_error_name(ret));
return SR_ERR;
}
return SR_OK;
}
SR_PRIV int dslogic_fpga_firmware_upload(const struct sr_dev_inst *sdi,
const char *name)
{
uint64_t sum;
struct sr_resource bitstream;
struct drv_context *drvc;
struct sr_usb_dev_inst *usb;
unsigned char *buf;
ssize_t chunksize;
int transferred;
int result, ret;
uint8_t cmd[3];
drvc = sdi->driver->context;
usb = sdi->conn;
sr_dbg("Uploading FPGA firmware '%s'.", name);
result = sr_resource_open(drvc->sr_ctx, &bitstream,
SR_RESOURCE_FIRMWARE, name);
if (result != SR_OK)
return result;
/* Tell the device firmware is coming. */
memset(cmd, 0, sizeof(cmd));
if ((ret = libusb_control_transfer(usb->devhdl, LIBUSB_REQUEST_TYPE_VENDOR |
LIBUSB_ENDPOINT_OUT, DS_CMD_FPGA_FW, 0x0000, 0x0000,
(unsigned char *)&cmd, sizeof(cmd), USB_TIMEOUT)) < 0) {
sr_err("Failed to upload FPGA firmware: %s.", libusb_error_name(ret));
sr_resource_close(drvc->sr_ctx, &bitstream);
return SR_ERR;
}
/* Give the FX2 time to get ready for FPGA firmware upload. */
g_usleep(FPGA_UPLOAD_DELAY);
buf = g_malloc(FW_BUFSIZE);
sum = 0;
result = SR_OK;
while (1) {
chunksize = sr_resource_read(drvc->sr_ctx, &bitstream,
buf, FW_BUFSIZE);
if (chunksize < 0)
result = SR_ERR;
if (chunksize <= 0)
break;
if ((ret = libusb_bulk_transfer(usb->devhdl, 2 | LIBUSB_ENDPOINT_OUT,
buf, chunksize, &transferred, USB_TIMEOUT)) < 0) {
sr_err("Unable to configure FPGA firmware: %s.",
libusb_error_name(ret));
result = SR_ERR;
break;
}
sum += transferred;
sr_spew("Uploaded %" PRIu64 "/%" PRIu64 " bytes.",
sum, bitstream.size);
if (transferred != chunksize) {
sr_err("Short transfer while uploading FPGA firmware.");
result = SR_ERR;
break;
}
}
g_free(buf);
sr_resource_close(drvc->sr_ctx, &bitstream);
if (result == SR_OK)
sr_dbg("FPGA firmware upload done.");
return result;
}
SR_PRIV int dslogic_start_acquisition(const struct sr_dev_inst *sdi)
{
struct dev_context *devc;
struct sr_usb_dev_inst *usb;
struct dslogic_mode mode;
int ret;
devc = sdi->priv;
mode.flags = DS_START_FLAGS_MODE_LA;
mode.sample_delay_h = mode.sample_delay_l = 0;
if (devc->sample_wide)
mode.flags |= DS_START_FLAGS_SAMPLE_WIDE;
usb = sdi->conn;
ret = libusb_control_transfer(usb->devhdl, LIBUSB_REQUEST_TYPE_VENDOR |
LIBUSB_ENDPOINT_OUT, DS_CMD_START, 0x0000, 0x0000,
(unsigned char *)&mode, sizeof(mode), USB_TIMEOUT);
if (ret < 0) {
sr_err("Failed to send start command: %s.", libusb_error_name(ret));
return SR_ERR;
}
return SR_OK;
}
SR_PRIV int dslogic_stop_acquisition(const struct sr_dev_inst *sdi)
{
struct sr_usb_dev_inst *usb;
struct dslogic_mode mode;
int ret;
mode.flags = DS_START_FLAGS_STOP;
mode.sample_delay_h = mode.sample_delay_l = 0;
usb = sdi->conn;
ret = libusb_control_transfer(usb->devhdl, LIBUSB_REQUEST_TYPE_VENDOR |
LIBUSB_ENDPOINT_OUT, DS_CMD_START, 0x0000, 0x0000,
(unsigned char *)&mode, sizeof(struct dslogic_mode), USB_TIMEOUT);
if (ret < 0) {
sr_err("Failed to send stop command: %s.", libusb_error_name(ret));
return SR_ERR;
}
return SR_OK;
}
/*
* Get the session trigger and configure the FPGA structure
* accordingly.
*/
static int dslogic_set_trigger(const struct sr_dev_inst *sdi,
struct dslogic_fpga_config *cfg)
{
struct sr_trigger *trigger;
struct sr_trigger_stage *stage;
struct sr_trigger_match *match;
struct dev_context *devc;
const GSList *l, *m;
int channelbit, i = 0;
uint16_t v16;
devc = sdi->priv;
cfg->trig_mask0[0] = 0xffff;
cfg->trig_mask1[0] = 0xffff;
cfg->trig_value0[0] = 0;
cfg->trig_value1[0] = 0;
cfg->trig_edge0[0] = 0;
cfg->trig_edge1[0] = 0;
cfg->trig_logic0[0] = 0;
cfg->trig_logic1[0] = 0;
cfg->trig_count0[0] = 0;
cfg->trig_count1[0] = 0;
cfg->trig_pos = 0;
cfg->trig_sda = 0;
cfg->trig_glb = 0;
cfg->trig_adp = cfg->count - cfg->trig_pos - 1;
for (i = 1; i < 16; i++) {
cfg->trig_mask0[i] = 0xff;
cfg->trig_mask1[i] = 0xff;
cfg->trig_value0[i] = 0;
cfg->trig_value1[i] = 0;
cfg->trig_edge0[i] = 0;
cfg->trig_edge1[i] = 0;
cfg->trig_count0[i] = 0;
cfg->trig_count1[i] = 0;
cfg->trig_logic0[i] = 2;
cfg->trig_logic1[i] = 2;
}
cfg->trig_pos = (uint32_t)(devc->capture_ratio / 100.0 * devc->limit_samples);
sr_dbg("pos: %d", cfg->trig_pos);
sr_dbg("configuring trigger");
if (!(trigger = sr_session_trigger_get(sdi->session))) {
sr_dbg("No session trigger found");
return SR_OK;
}
for (l = trigger->stages; l; l = l->next) {
stage = l->data;
for (m = stage->matches; m; m = m->next) {
match = m->data;
if (!match->channel->enabled)
/* Ignore disabled channels with a trigger. */
continue;
channelbit = 1 << (match->channel->index);
/* Simple trigger support (event). */
if (match->match == SR_TRIGGER_ONE) {
cfg->trig_mask0[0] &= ~channelbit;
cfg->trig_mask1[0] &= ~channelbit;
cfg->trig_value0[0] |= channelbit;
cfg->trig_value1[0] |= channelbit;
} else if (match->match == SR_TRIGGER_ZERO) {
cfg->trig_mask0[0] &= ~channelbit;
cfg->trig_mask1[0] &= ~channelbit;
} else if (match->match == SR_TRIGGER_FALLING) {
cfg->trig_mask0[0] &= ~channelbit;
cfg->trig_mask1[0] &= ~channelbit;
cfg->trig_edge0[0] |= channelbit;
cfg->trig_edge1[0] |= channelbit;
} else if (match->match == SR_TRIGGER_RISING) {
cfg->trig_mask0[0] &= ~channelbit;
cfg->trig_mask1[0] &= ~channelbit;
cfg->trig_value0[0] |= channelbit;
cfg->trig_value1[0] |= channelbit;
cfg->trig_edge0[0] |= channelbit;
cfg->trig_edge1[0] |= channelbit;
} else if (match->match == SR_TRIGGER_EDGE) {
cfg->trig_edge0[0] |= channelbit;
cfg->trig_edge1[0] |= channelbit;
}
}
}
v16 = RL16(&cfg->mode);
v16 |= 1 << 0;
WL16(&cfg->mode, v16);
return SR_OK;
}
SR_PRIV int dslogic_fpga_configure(const struct sr_dev_inst *sdi)
{
struct dev_context *devc;
struct sr_usb_dev_inst *usb;
uint8_t c[3];
struct dslogic_fpga_config cfg;
uint16_t v16;
uint32_t v32;
int transferred, len, ret;
sr_dbg("Configuring FPGA.");
usb = sdi->conn;
devc = sdi->priv;
WL32(&cfg.sync, DS_CFG_START);
WL16(&cfg.mode_header, DS_CFG_MODE);
WL32(&cfg.divider_header, DS_CFG_DIVIDER);
WL32(&cfg.count_header, DS_CFG_COUNT);
WL32(&cfg.trig_pos_header, DS_CFG_TRIG_POS);
WL16(&cfg.trig_glb_header, DS_CFG_TRIG_GLB);
WL32(&cfg.trig_adp_header, DS_CFG_TRIG_ADP);
WL32(&cfg.trig_sda_header, DS_CFG_TRIG_SDA);
WL32(&cfg.trig_mask0_header, DS_CFG_TRIG_MASK0);
WL32(&cfg.trig_mask1_header, DS_CFG_TRIG_MASK1);
WL32(&cfg.trig_value0_header, DS_CFG_TRIG_VALUE0);
WL32(&cfg.trig_value1_header, DS_CFG_TRIG_VALUE1);
WL32(&cfg.trig_edge0_header, DS_CFG_TRIG_EDGE0);
WL32(&cfg.trig_edge1_header, DS_CFG_TRIG_EDGE1);
WL32(&cfg.trig_count0_header, DS_CFG_TRIG_COUNT0);
WL32(&cfg.trig_count1_header, DS_CFG_TRIG_COUNT1);
WL32(&cfg.trig_logic0_header, DS_CFG_TRIG_LOGIC0);
WL32(&cfg.trig_logic1_header, DS_CFG_TRIG_LOGIC1);
WL32(&cfg.end_sync, DS_CFG_END);
/* Pass in the length of a fixed-size struct. Really. */
len = sizeof(struct dslogic_fpga_config) / 2;
c[0] = len & 0xff;
c[1] = (len >> 8) & 0xff;
c[2] = (len >> 16) & 0xff;
ret = libusb_control_transfer(usb->devhdl, LIBUSB_REQUEST_TYPE_VENDOR |
LIBUSB_ENDPOINT_OUT, DS_CMD_CONFIG, 0x0000, 0x0000,
c, 3, USB_TIMEOUT);
if (ret < 0) {
sr_err("Failed to send FPGA configure command: %s.",
libusb_error_name(ret));
return SR_ERR;
}
/*
* 15 1 = internal test mode
* 14 1 = external test mode
* 13 1 = loopback test mode
* 12 1 = stream mode
* 11 1 = serial trigger
* 8-10 unused
* 7 1 = analog mode
* 6 1 = samplerate 400MHz
* 5 1 = samplerate 200MHz or analog mode
* 4 0 = logic, 1 = dso or analog
* 3 1 = RLE encoding (enable for more than 16 Megasamples)
* 1-2 00 = internal clock,
* 01 = external clock rising,
* 11 = external clock falling
* 0 1 = trigger enabled
*/
v16 = 0x0000;
if (devc->dslogic_mode == DS_OP_INTERNAL_TEST)
v16 = 1 << 15;
else if (devc->dslogic_mode == DS_OP_EXTERNAL_TEST)
v16 = 1 << 14;
else if (devc->dslogic_mode == DS_OP_LOOPBACK_TEST)
v16 = 1 << 13;
if (devc->dslogic_continuous_mode)
v16 |= 1 << 12;
if (devc->dslogic_external_clock) {
v16 |= 1 << 1;
if (devc->dslogic_clock_edge == DS_EDGE_FALLING)
v16 |= 1 << 2;
}
if (devc->limit_samples > DS_MAX_LOGIC_DEPTH *
ceil(devc->cur_samplerate * 1.0 / DS_MAX_LOGIC_SAMPLERATE)
&& !devc->dslogic_continuous_mode) {
/* Enable RLE for long captures.
* Without this, captured data present errors.
*/
v16 |= 1 << 3;
}
WL16(&cfg.mode, v16);
v32 = ceil(DS_MAX_LOGIC_SAMPLERATE * 1.0 / devc->cur_samplerate);
WL32(&cfg.divider, v32);
WL32(&cfg.count, devc->limit_samples);
dslogic_set_trigger(sdi, &cfg);
len = sizeof(struct dslogic_fpga_config);
ret = libusb_bulk_transfer(usb->devhdl, 2 | LIBUSB_ENDPOINT_OUT,
(unsigned char *)&cfg, len, &transferred, USB_TIMEOUT);
if (ret < 0 || transferred != len) {
sr_err("Failed to send FPGA configuration: %s.", libusb_error_name(ret));
return SR_ERR;
}
return SR_OK;
}
static int to_bytes_per_ms(struct dev_context *devc)
{
if (devc->cur_samplerate > SR_MHZ(100))
return SR_MHZ(100) / 1000 * (devc->sample_wide ? 2 : 1);
return devc->cur_samplerate / 1000 * (devc->sample_wide ? 2 : 1);
}
static size_t get_buffer_size(struct dev_context *devc)
{
size_t s;
/*
* The buffer should be large enough to hold 10ms of data and
* a multiple of 512.
*/
s = 10 * to_bytes_per_ms(devc);
// s = to_bytes_per_ms(devc->cur_samplerate);
return (s + 511) & ~511;
}
SR_PRIV int dslogic_get_number_of_transfers(struct dev_context *devc)
{
unsigned int n;
/* Total buffer size should be able to hold about 100ms of data. */
n = (100 * to_bytes_per_ms(devc) / get_buffer_size(devc));
sr_info("New calculation: %d", n);
if (n > NUM_SIMUL_TRANSFERS)
return NUM_SIMUL_TRANSFERS;
return n;
}

View File

@ -1,150 +0,0 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
* Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBSIGROK_HARDWARE_FX2LAFW_DSLOGIC_H
#define LIBSIGROK_HARDWARE_FX2LAFW_DSLOGIC_H
/* Modified protocol commands & flags used by DSLogic */
#define DS_CMD_GET_FW_VERSION 0xb0
#define DS_CMD_GET_REVID_VERSION 0xb1
#define DS_CMD_START 0xb2
#define DS_CMD_FPGA_FW 0xb3
#define DS_CMD_CONFIG 0xb4
#define DS_CMD_VTH 0xb8
#define DS_NUM_TRIGGER_STAGES 16
#define DS_START_FLAGS_STOP (1 << 7)
#define DS_START_FLAGS_CLK_48MHZ (1 << 6)
#define DS_START_FLAGS_SAMPLE_WIDE (1 << 5)
#define DS_START_FLAGS_MODE_LA (1 << 4)
#define DS_MAX_LOGIC_DEPTH SR_MHZ(16)
#define DS_MAX_LOGIC_SAMPLERATE SR_MHZ(100)
enum dslogic_operation_modes {
DS_OP_NORMAL,
DS_OP_INTERNAL_TEST,
DS_OP_EXTERNAL_TEST,
DS_OP_LOOPBACK_TEST,
};
enum {
DS_VOLTAGE_RANGE_18_33_V, /* 1.8V and 3.3V logic */
DS_VOLTAGE_RANGE_5_V, /* 5V logic */
};
enum {
DS_EDGE_RISING,
DS_EDGE_FALLING,
};
struct dslogic_version {
uint8_t major;
uint8_t minor;
};
struct dslogic_mode {
uint8_t flags;
uint8_t sample_delay_h;
uint8_t sample_delay_l;
};
struct dslogic_trigger_pos {
uint32_t real_pos;
uint32_t ram_saddr;
uint32_t remain_cnt;
uint8_t first_block[500];
};
/*
* The FPGA is configured with TLV tuples. Length is specified as the
* number of 16-bit words, and the (type, length) header is in some
* cases padded with 0xffff.
*/
#define _DS_CFG(variable, wordcnt) ((variable << 8) | wordcnt)
#define _DS_CFG_PAD(variable, wordcnt) ((_DS_CFG(variable, wordcnt) << 16) | 0xffff)
#define DS_CFG_START 0xf5a5f5a5
#define DS_CFG_MODE _DS_CFG(0, 1)
#define DS_CFG_DIVIDER _DS_CFG_PAD(1, 2)
#define DS_CFG_COUNT _DS_CFG_PAD(3, 2)
#define DS_CFG_TRIG_POS _DS_CFG_PAD(5, 2)
#define DS_CFG_TRIG_GLB _DS_CFG(7, 1)
#define DS_CFG_TRIG_ADP _DS_CFG_PAD(10, 2)
#define DS_CFG_TRIG_SDA _DS_CFG_PAD(12, 2)
#define DS_CFG_TRIG_MASK0 _DS_CFG_PAD(16, 16)
#define DS_CFG_TRIG_MASK1 _DS_CFG_PAD(17, 16)
#define DS_CFG_TRIG_VALUE0 _DS_CFG_PAD(20, 16)
#define DS_CFG_TRIG_VALUE1 _DS_CFG_PAD(21, 16)
#define DS_CFG_TRIG_EDGE0 _DS_CFG_PAD(24, 16)
#define DS_CFG_TRIG_EDGE1 _DS_CFG_PAD(25, 16)
#define DS_CFG_TRIG_COUNT0 _DS_CFG_PAD(28, 16)
#define DS_CFG_TRIG_COUNT1 _DS_CFG_PAD(29, 16)
#define DS_CFG_TRIG_LOGIC0 _DS_CFG_PAD(32, 16)
#define DS_CFG_TRIG_LOGIC1 _DS_CFG_PAD(33, 16)
#define DS_CFG_END 0xfa5afa5a
struct dslogic_fpga_config {
uint32_t sync;
uint16_t mode_header;
uint16_t mode;
uint32_t divider_header;
uint32_t divider;
uint32_t count_header;
uint32_t count;
uint32_t trig_pos_header;
uint32_t trig_pos;
uint16_t trig_glb_header;
uint16_t trig_glb;
uint32_t trig_adp_header;
uint32_t trig_adp;
uint32_t trig_sda_header;
uint32_t trig_sda;
uint32_t trig_mask0_header;
uint16_t trig_mask0[DS_NUM_TRIGGER_STAGES];
uint32_t trig_mask1_header;
uint16_t trig_mask1[DS_NUM_TRIGGER_STAGES];
uint32_t trig_value0_header;
uint16_t trig_value0[DS_NUM_TRIGGER_STAGES];
uint32_t trig_value1_header;
uint16_t trig_value1[DS_NUM_TRIGGER_STAGES];
uint32_t trig_edge0_header;
uint16_t trig_edge0[DS_NUM_TRIGGER_STAGES];
uint32_t trig_edge1_header;
uint16_t trig_edge1[DS_NUM_TRIGGER_STAGES];
uint32_t trig_count0_header;
uint16_t trig_count0[DS_NUM_TRIGGER_STAGES];
uint32_t trig_count1_header;
uint16_t trig_count1[DS_NUM_TRIGGER_STAGES];
uint32_t trig_logic0_header;
uint16_t trig_logic0[DS_NUM_TRIGGER_STAGES];
uint32_t trig_logic1_header;
uint16_t trig_logic1[DS_NUM_TRIGGER_STAGES];
uint32_t end_sync;
};
SR_PRIV int dslogic_fpga_firmware_upload(const struct sr_dev_inst *sdi,
const char *name);
SR_PRIV int dslogic_start_acquisition(const struct sr_dev_inst *sdi);
SR_PRIV int dslogic_stop_acquisition(const struct sr_dev_inst *sdi);
SR_PRIV int dslogic_fpga_configure(const struct sr_dev_inst *sdi);
SR_PRIV int dslogic_set_vth(const struct sr_dev_inst *sdi, double vth);
SR_PRIV int dslogic_get_number_of_transfers(struct dev_context *devc);
#endif

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