Compare commits

..

1330 Commits

Author SHA1 Message Date
Triss b244ed5246 clean up code & comments a bit 2021-08-03 23:50:01 +02:00
Triss 19a7aa375a basic config options (WIP) 2021-08-03 23:50:01 +02:00
Triss 243b525727 fixed waiting for capture result status thing 2021-08-03 23:50:01 +02:00
Triss 192cb0d897 bleh 2021-08-03 23:50:01 +02:00
Triss 2a815b8a5f acquisition working a bit more now? 2021-08-03 23:50:01 +02:00
Triss acad3c2123 fix use of deprecated libftdi functions 2021-08-03 23:50:01 +02:00
Triss 78cf266f90 it runs now 2021-08-03 23:50:01 +02:00
Triss 32817ebeaa link to hw docs 2021-08-03 23:50:01 +02:00
Triss 33758a51e7 finish up acquisition, also it compiles now 2021-08-03 23:50:01 +02:00
Triss d70c0bc625 config (partial) 2021-08-03 23:50:01 +02:00
Triss 638bdaec16 ikalogic-scanaquad: device init stuff 2021-08-03 23:50:01 +02:00
Triss d1074befa3 bleh 2021-08-03 23:50:01 +02:00
Triss d8f08acdc3 ikalogic-scanaquad: low-level protocol stuff 2021-08-03 23:50:01 +02:00
Triss 012becda49 ikalogic-scanaquad: Initial driver skeleton. 2021-08-03 23:50:01 +02:00
Frank Stettner b96051a507 conrad-digi-35-cpu: Remove CH1 from device.
This device is write only and does not transmit any measurement data.
Therefore a channel is not necessary.
2021-07-23 19:58:46 +02:00
Gerhard Sittig 8e5dbaf6e9 dcttech-usbrelay: support conn=vid.pid specs in addition to paths
Extend the scan code path, accept user provided conn= specs in the
"vid.pid" format. Everything else is assumed to be a hidapi compatible
"path" and may suffer from conn= parser limitations. Unfortunately the
hidapi API won't let us lookup paths from bus.addr specs which would
work when multiple cards need to be told apart.
2021-07-23 19:58:46 +02:00
Gerhard Sittig 0498ef4e42 dcttech-usbrelay: accept conn= spec different from hidapi enum details
Rework the scan and probe routines. Skip the USB enumeration's result
set when the user provided a conn= spec, instead exclusively open the
specified device. It's acceptable when this user spec does not match
the details which the hidapi enumeration would yield. [ This version
prepares but does not implement yet support for "funny" hidapi(3) paths
on platforms beyond Linux. ]

This also weakens the logic which determines the relay count from the
USB product string. Any trailing number is accepted. Which allows to use
compatible devices with differing vendor/product strings when conn= is
specified. The previous "USBRelay" prefix check remains in place for
automatic enumeration.

Beautify diagnostics, even phrase debug and spew level messages such
that they can be presented to users. Makes -l 5 look more consistent.
2021-07-23 19:58:46 +02:00
Gerhard Sittig 996331ce9b dcttech-usbrelay: rework scan (enumeration) and probe (identification)
Move all of the sdi creation into the probe routine which communicates
to the relay card. Extend diagnostics in that code path. Which leaves
pure USB enumeration in the scan routine.
2021-07-22 07:59:34 +02:00
Gerhard Sittig e333a40c1c dcttech-usbrelay: adjust serial number and connection string logic
Store the USB relay card's serial number such that users can tell apart
multiple connected cards. Hold the HIDAPI path in the 'connection_id'
member because 'conn' is something internal, not for display purposes.
2021-07-22 07:09:48 +02:00
Gerhard Sittig 59f6765508 contrib: add udev rule for V-USB based HID devices (USB relay card)
Add the USB identification of the dcttech.com USBRelay<n> card. Which
happens to be shared with other V-USB based firmware projects. Thus is
rather generic. The USB relay card is just the first supported device
of that kind.
2021-07-21 22:03:59 +02:00
Gerhard Sittig 321f85fb07 dcttech-usbrelay: implement multiplexer driver for USB relay card
Implement support for the "www.dcttech.com USBRelay<n>" card. This V-USB
based HID device communicates HID reports to control up to 8 relays. The
driver depends on the HIDAPI external dependency for maximum portability.

Support for the conn= parameters is limited. A path that HIDAPI can open
is expected, which depends on the platform and HIDAPI implementation,
and may not always be expressed by means of sigrok command line options.
See README.devices for a discussion.

The USB serial number is not considered. This is an implementation
detail of the relay card's firmware. HID reports carry a five character
identifier for the board.

Relay state is cached in the driver. It's assumed that relay state won't
change outside of libsigrok control as long as the device is opened. The
single request to activate/deactivate all relays at once is supported.
2021-07-21 22:03:18 +02:00
Gerhard Sittig 64d54a719a dcttech-usbrelay: Initial driver skeleton. 2021-07-21 20:41:16 +02:00
Frank Stettner 569165c0e4 hp-3478a: Fix switching from 4-wire to 2-wire measurement.
The measured quantity flags for the measurement mode can only contain one flag
at maximum. Therefore the quantity flags handling can be simplified, which also
fixes a bug when switching from 4-wire resistance measurement to 2-wire mode.
2021-07-03 18:04:40 +02:00
Frank Stettner 8ef4fb3347 hp-3478a: Only match when conn= is given to avoid false probe positives.
The HP 3478A device would not reliably identify by means of SCPI queries. The
previous scan() implementation would have matched any connected SCPI device,
then upset these devices by emitting non-SCPI requests.

Tighten the scope of the hp-3478a probe, only scan for devices when a conn=
spec was provided. This avoids false positives and malfunction of other
devices, and still lets users address the problematic device. This is similar
to serial-dmm and unspecific cables and has proven to work there.
2021-06-30 20:34:21 +02:00
Frank Stettner 0e3c3c80b8 scpi_vxi: Unbreak MacOS build (vxi.h inclusion order).
Undo the #include statement order change of commit 7414fb55cb. It's
essential on MacOS to include vxi.h early to keep related u_long et al
data types available. See commit d40b8557a9 for a discussion.

Also drop the inclusion of rpc/rpc.h from scpi_vxi.c because it is not
used in that source file, instead is a vxi.h dependency and is included
there.

[ gsi: rephrase commit message ]
2021-06-30 06:56:06 +02:00
Gerhard Sittig 020df861e0 hp-3478a: avoid NULL dereference in config API routines
The 'sdi' parameter to config API calls can be NULL. Only dereference
after checking its validity.

Reported-By: Alexandre Ferreira <alexandref75@hotmail.com>
2021-06-28 07:34:23 +02:00
Gerhard Sittig 1e91a90f2a doc: update IRC reference to Libera.Chat 2021-06-16 20:52:01 +02:00
Ralf 73c575cf9e rigol-ds: fix use-after-free
This amends commit 4fad41a8a4 which fixed a leak but introduced the
use after free.
2021-06-07 07:48:44 +02:00
Daniel Anselmi ed78768225 scpi_vxi: fix memory leak for SCPI response data in VXI support code
Routine scpi_vxi_read_data() invokes device_read_1(), which provides a
static buffer where dynamically allocated memory for SCPI response data
is kept. Release this memory after getting a copy of the response data,
before the next device_read_1() call loses the reference.

Valgrind stats without the fix:

  ==238825== LEAK SUMMARY:
  ==238825== definitely lost: 45,547,737 bytes in 18,331 blocks
  ==238825== indirectly lost: 0 bytes in 0 blocks
  ==238825== possibly lost: 48,154 bytes in 14 blocks
  ==238825== still reachable: 42,859 bytes in 288 blocks
  ==238825== suppressed: 0 bytes in 0 blocks

Valgrind stats with the fix:

  ==239413== LEAK SUMMARY:
  ==239413== definitely lost: 40 bytes in 2 blocks
  ==239413== indirectly lost: 0 bytes in 0 blocks
  ==239413== possibly lost: 0 bytes in 0 blocks
  ==239413== still reachable: 38,613 bytes in 287 blocks
  ==239413== suppressed: 0 bytes in 0 blocks

Remaining leaks in scpi_vxi_open() are of lesser severity because they
don't accumulate during execution.

[ gsi: rebase to recent master, reword commit message ]
2021-06-07 07:44:18 +02:00
Gerhard Sittig 7414fb55cb scpi_vxi: readability nits in the SCPI via VXI source code
Address style nits to improve readablity and future maintenance.
Move system header includes before application level includes. Move
assignments out of variable declaration blocks. Separate function calls
and assignments from error checks and flow control. Break a long line.
Add braces around conditional multi line statements.

All these adjustments are cosmetical. Behaviour does not change.
2021-06-07 07:44:18 +02:00
Sylvain Pelissier 1b7d49db64 contrib: add udev rule for Agilent 34460A USBTMC 2021-06-01 08:20:59 +02:00
Sylvain Pelissier d8064712ce scpi-dmm: Add support for Agilent 34460A
[ gsi: rebase and squash, specify delays like Keysight 34465A ]
2021-06-01 08:20:59 +02:00
Gerhard Sittig 18426d1c0e scpi-dmm: add short measurement delay for 34465A
With Keysight 34465A the VOLT:AC and FREQ functions keep suffering from
USB timeouts and pipe errors. Add a 10ms delay between initiating the
acquisition and checking for completion before fetching the result.

The weird thing is that when successful responses are seen after
temporary failure, enlarging the delay does not make them go away.
Instead the USB errors keep moving to a different spot. Measurements do
arrive though, so this is just annyoing but not a blocker.

  sr: [00:00.134038] scpi_usbtmc: Successfully sent SCPI command: 'CONF?'.
  sr: [00:00.136043] scpi: Got response: '"FREQ +3.00000000E+00,+3.00000000E-06"', length 38.
  sr: [00:00.136119] scpi-dmm: dev_acquisition_start: Precision: '"FREQ +3.00000000E+00,+3.00000000E-06"'
  sr: [00:00.136251] scpi_usbtmc: Successfully sent SCPI command: '*OPC?'.
  sr: [00:00.184211] scpi: Got response: '1', length 1.
  sr: [00:00.184481] scpi_usbtmc: Successfully sent SCPI command: 'INIT'.
  sr: [00:00.234800] session: bus: Received SR_DF_HEADER packet.
  cli: Received SR_DF_HEADER.
  sr: [00:00.245597] scpi_usbtmc: Successfully sent SCPI command: '*OPC?'.
  sr: [00:01.246050] scpi_usbtmc: USBTMC bulk in transfer error: LIBUSB_ERROR_TIMEOUT.
  sr: [00:01.256495] scpi_usbtmc: Successfully sent SCPI command: '*OPC?'.
  sr: [00:01.291871] scpi_usbtmc: USBTMC invalid bulk in header.
  sr: [00:01.302392] scpi_usbtmc: Successfully sent SCPI command: '*OPC?'.
  sr: [00:01.401959] scpi: Got response: '1', length 1.
  sr: [00:01.402135] scpi_usbtmc: Successfully sent SCPI command: '*OPC?'.
  sr: [00:01.403392] scpi: Got response: '1', length 1.
  sr: [00:01.403566] scpi_usbtmc: Successfully sent SCPI command: 'CONF?'.
  sr: [00:01.405769] scpi: Got response: '"FREQ +3.00000000E+00,+3.00000000E-06"', length 38.
  sr: [00:01.406020] scpi_usbtmc: Successfully sent SCPI command: '*OPC?'.
  sr: [00:01.407500] scpi: Got response: '1', length 1.
  sr: [00:01.407674] scpi_usbtmc: Successfully sent SCPI command: 'FETCH?'.
  sr: [00:01.409107] scpi: Got response: '+9.00555531E+01', length 15.

Experimentation suggests that 200ms timeouts reduce the probability of
these USB communication errors. But if functions tend to respond that
differently, are delay time specs per MQ required? The implementation of
the driver currently assumes a single delay spec.
2021-06-01 08:20:59 +02:00
Gerhard Sittig e90551c3f8 scpi-dmm: model and MQ dependent delay before measurement
Some models are slow to start a measurement acquisition in specific MQs
(meter functions). An "*OPC?" query went unanswered after "INIT" was
sent. This was observed on 34405A in temperature, frequency, resistance,
AC voltage and current mode.

Add an optional per-model measurement delay that is used when the MQ
specifies that the delay is applicable. Because functions are changed
rarely but measurements are taken many times, only the first reading
is delayed while later readings are seen at the expected interval. Not
delaying the first reading will result in device errors.

  sr: [00:00.875162] scpi_usbtmc: Successfully sent SCPI command: 'CONF?'.
  sr: [00:00.881666] scpi: Got response: '"FREQ +1.00000E+00,+1.00000E-05"', length 32.
  sr: [00:00.881700] scpi-dmm: dev_acquisition_start: Precision: '"FREQ +1.00000E+00,+1.00000E-05"'
  sr: [00:00.881840] scpi_usbtmc: Successfully sent SCPI command: '*OPC?'.
  sr: [00:00.883966] scpi: Got response: '1', length 1.
  sr: [00:00.884139] scpi_usbtmc: Successfully sent SCPI command: 'INIT'.
  sr: [00:01.884420] session: bus: Received SR_DF_HEADER packet.
  cli: Received SR_DF_HEADER.
  sr: [00:01.895260] scpi_usbtmc: Successfully sent SCPI command: '*OPC?'.
  sr: [00:02.895766] scpi_usbtmc: USBTMC bulk in transfer error: LIBUSB_ERROR_TIMEOUT.
  sr: [00:02.906302] scpi_usbtmc: Successfully sent SCPI command: '*OPC?'.
  sr: [00:02.910703] scpi_usbtmc: USBTMC invalid bulk in header.
  sr: [00:02.921244] scpi_usbtmc: USBTMC bulk out transfer error: LIBUSB_ERROR_PIPE.
  sr: [00:02.931802] scpi_usbtmc: Successfully sent SCPI command: '*OPC?'.
  sr: [00:02.932276] scpi: Got response: '1', length 1.
  sr: [00:02.932425] scpi_usbtmc: Successfully sent SCPI command: '*OPC?'.
  sr: [00:02.934790] scpi: Got response: '1', length 1.
  sr: [00:02.935155] scpi_usbtmc: Successfully sent SCPI command: 'CONF?'.
  sr: [00:02.941564] scpi: Got response: '"FREQ +1.00000E+00,+1.00000E-05"', length 32.

  sr: [00:00.173408] hwdriver: scpi-dmm: Starting acquisition.
  sr: [00:00.173569] scpi_usbtmc: Successfully sent SCPI command: '*OPC?'.
  sr: [00:00.334312] scpi: Got response: '1', length 1.
  sr: [00:00.334544] scpi_usbtmc: Successfully sent SCPI command: 'CONF?'.
  sr: [00:00.341070] scpi: Got response: '"RES +1.00000E+02,+1.00000E-03"', length 31.
  sr: [00:00.341307] scpi_usbtmc: Successfully sent SCPI command: '*OPC?'.
  sr: [00:00.343636] scpi: Got response: '1', length 1.
  sr: [00:00.343872] scpi_usbtmc: Successfully sent SCPI command: 'CONF?'.
  sr: [00:00.350093] scpi: Got response: '"RES +1.00000E+02,+1.00000E-03"', length 31.
  sr: [00:00.350157] scpi-dmm: dev_acquisition_start: Precision: '"RES +1.00000E+02,+1.00000E-03"'
  sr: [00:00.350342] scpi_usbtmc: Successfully sent SCPI command: '*OPC?'.
  sr: [00:00.352524] scpi: Got response: '1', length 1.
  sr: [00:00.352832] scpi_usbtmc: Successfully sent SCPI command: 'INIT'.
  sr: [00:00.352901] session: bus: Received SR_DF_HEADER packet.
  cli: Received SR_DF_HEADER.
  sr: [00:00.363675] scpi_usbtmc: Successfully sent SCPI command: '*OPC?'.
  sr: [00:01.364363] scpi_usbtmc: USBTMC bulk in transfer error: LIBUSB_ERROR_TIMEOUT.
  sr: [00:01.374904] scpi_usbtmc: Successfully sent SCPI command: '*OPC?'.
  sr: [00:02.375380] scpi_usbtmc: USBTMC bulk in transfer error: LIBUSB_ERROR_TIMEOUT.
  sr: [00:02.385872] scpi_usbtmc: Successfully sent SCPI command: '*OPC?'.
  sr: [00:03.232457] scpi_usbtmc: USBTMC invalid bulk in header.
  sr: [00:03.243003] scpi_usbtmc: USBTMC bulk out transfer error: LIBUSB_ERROR_PIPE.
  sr: [00:03.253464] scpi_usbtmc: Successfully sent SCPI command: '*OPC?'.
  sr: [00:03.256568] scpi: Got response: '1', length 1.
  sr: [00:03.256902] scpi_usbtmc: Successfully sent SCPI command: '*OPC?'.
  sr: [00:03.259440] scpi: Got response: '1', length 1.
  sr: [00:03.259713] scpi_usbtmc: Successfully sent SCPI command: 'CONF?'.
  sr: [00:03.266070] scpi: Got response: '"RES +1.00000E+08,+1.00000E+3"', length 30.
  sr: [00:03.266456] scpi_usbtmc: Successfully sent SCPI command: '*OPC?'.
  sr: [00:03.268501] scpi: Got response: '1', length 1.
  sr: [00:03.268961] scpi_usbtmc: Successfully sent SCPI command: 'READ?'.
  sr: [00:03.353589] scpi: Got response: '+9.90000000E+37 ', length 16.

Declare a 2500ms measurement initiation delay for 34405A which was found
by experimentation. This is huge but was found to be necessary.

Of course all other meter functions are unaffected by this commit. As
are the meters which specify no delay.
2021-06-01 08:20:59 +02:00
Gerhard Sittig 08f023fe97 scpi-dmm: model and MQ dependent delay when switching functions
Some models are slow to switch meter functions to specific MQs. This was
observed with 34405A and AC V/I modes, where USB connections timed out
and suffered from pipe errors.

Add an optional delay after "CONF:<mode> [<range>]" SCPI requests. The
duration of the delay is per model, the use of the delay is per MQ on
that model. The 200ms delay for 34405A was found by experimentation.

Speaking about 34405A: Only the "INIT" request in temperature mode
remains as an issue, which is not covered by this commit's approach.
2021-06-01 08:20:59 +02:00
Gerhard Sittig b74cc88d32 scpi-dmm: use different Agilent SCPI command for range and measurment
Don't use the "[SENS:]<mode>:RANGE..." request on Agilent protocol
speaking devices. Use "CONF:<mode> [<range>]" instead. This was tested
with all devices which reference this model.

In theory there is the question whether previously configured ranges
should be re-used when (exclusively) the MQ is switched. It's assumed
that this is not useful, instead users or their applications should
select the function first and optionally pick the range then. Re-use of
e.g. 10k resistance range when switching to capacitance might be seen as
confusing (and results in errors in the device).

Use the combination of INIT and FETCH? to get measurements. The READ?
request is more complex and might "undo" what INIT already initiated.
This improves perception of the 34405A meter's operation.
2021-06-01 08:20:59 +02:00
Gerhard Sittig bf03e06d57 scpi-dmm: rephrase read timeout decls, put "unit" after "ms value"
Rephrase the SCPI read timeouts in scpi-dmm model declarations. Shuffle
the order of product terms such that the milliseconds "unit" goes last,
and the milliseconds value goes first. Assume that "2500 * 1000 [us]"
better reflects the intention than "1000 * 2500" does.
2021-06-01 08:20:59 +02:00
Gerhard Sittig a36b21fb89 fluke-45: drop serial port echo test, was disabled for years
The Fluke 45 driver's ECHO_TEST broke other people's SCPI device
identification and was disabled in 2018-11. Remove the dead code which
is impossible to resurrect. Its purpose was questionable to begin with.

Should users be affected, then the echo would break the identification
phase. The check cannot be done before identification without affecting
other connected devices, cannot be done after the identification either
when that very identification systematically fails. Should a user meet
this condition then applications' logs are available to see why *IDN?
fails, assuming that users are not aware of their serial port or device
configuration. The request's reflection in the place of a response gives
a strong hint.
2021-06-01 08:20:59 +02:00
Gerhard Sittig 69498046f6 hp-3457a: only probe when conn= was specified, to not break SCPI devices
Only scan for hp-3457a devices when the user specified which connection
to use. This avoids breaking SCPI devices by emitting non-standard
requests before reliable device identification.
2021-06-01 08:20:59 +02:00
Gerhard Sittig 7f0463840a scpi-pps: don't break SCPI devices when scanning for HP-IB devices
Only scan for hpib-pps devices when a user provided conn= specification
was given. This avoids breaking SCPI devices by emitting non-standard
requests before reliable device identification.
2021-06-01 08:20:59 +02:00
Gerhard Sittig d822f54d52 scpi: style nits in sr_scpi_scan(), prefer common helper
Improve readability and simplify maintenance of the sr_scpi_scan()
routine.

Move initial assignment and subsequent update of variables in closer
proximity, don't hide assignments in declaration blocks. Use common
helper code where available. Split complex conditions into individual
terms which are easier to review and reason about. Don't mix calls and
value checks and flow control in the same statement.
2021-06-01 08:20:59 +02:00
Gerhard Sittig 2f464b6c85 siglent-sds: move model dependent request emission to after identification
Device or model or protocol variant specific commands should only be
used after the device reliably got identified. The "CHDR OFF" command
upsets other devices and needs to move after *IDN? and model checks.
2021-06-01 08:20:59 +02:00
Gerhard Sittig d008c0273f hp-59306a: only match when conn= is given to avoid false probe positives
The HP 59306A device was made in 1973 and would not reliably identify
by means of SCPI queries. The previous scan() implementation would have
matched any connected SCPI device, then upset these devices by emitting
non-SCPI requests.

Tighten the scope of the hp-59306a probe, only scan for devices when a
conn= spec was provided. This avoids false positives and malfunction of
other devices, and still lets users address the problematic device. This
is similar to serial-dmm and unspecific cables and has proven to work
there.

How to reproduce the issue:

  (while any auto enumerating SCPI device is connected)
  $ sigrok-cli --scan
2021-06-01 08:20:59 +02:00
Gerhard Sittig 6b4bdfbde8 motech-lps-301: make better use of serial extract options helper
Pre-assign default values before having user specified options scanned.
This avoids the necessity to post-process the result. Move the initial
assignment to where its corresponding update is to improve readability.
2021-06-01 08:20:59 +02:00
Gerhard Sittig 9d6a896014 serial: extend semantics of connection and comm params extraction helper
The sr_serial_extract_options() routine is a hidden gem, has existed for
almost eight years, and is exclusively used by the motech-lps-301 driver
(was also used by hameg-hmo at some point in the past). Being so useful
and doing something to terribly popular, more drivers should use it.

Extend the API to make either of the out parameters genuinely optional,
and guarantee that pre-assigned defaults will survive in the absence of
user specs. Update the Doxygen comment.
2021-06-01 08:20:16 +02:00
Gerhard Sittig 5bf642dbf8 scpi-dmm: avoid get/set range calls for some of the Agilent DMM functions
While queries for the range are supported for voltage, current,
resistence, capacitance, the same queries in temperature, frequency,
diode, continuity modes not only fail but even lose the USB connection
to the device. This was consistently observed with 34405A and 34465A.

Suppress get and set range requests for the known problematic modes of
the Agilent protocol speaking meters.
2021-05-22 08:35:11 +02:00
Gerhard Sittig ce96b696b5 scpi-dmm: add four-wire resistance to list of 34405A MQs
Although the 34405A does not support this function, other Agilent
protocol using meters do (currently 34465A, very probably others which
are about to get added in the future).

It's assumed that announcing the availability of that MQ for a set of
meters while only some of them support it is preferrable over exploding
numbers of copies of tables which only slightly vary among each other.
2021-05-22 08:35:11 +02:00
Gerhard Sittig 1de14d67f1 scpi-dmm: prepare introduction of per-MQ driver flags
This mechanical edit adds a flags field and the initializer element to
make the compiler happy. Behaviour does not change. See a word diff for
improved review experience.
2021-05-22 08:35:11 +02:00
Gerhard Sittig a0418c20d8 scpi-dmm: add support to get/set range on Agilent protocol using meters
Add support to get and set the auto/manual range on Agilent protocol
speaking devices (34405A, 34465A). The range values are mere numbers
without a unit or MQ associated with them. Support to list available
ranges is prepared but not used (not needed on these meters). Common
logic could open code the lists of ranges from the model description
if desired in a future implementation.
2021-05-22 08:35:11 +02:00
Gerhard Sittig 7fcdc35e17 scpi-dmm: use INIT instead of MEAS for Agilent to start acquisition
Though measurement values come in, the 34405A and 34465A meters kept
beeping when acquisition is started. Stopped beeping when the MEAS
keyword was changed to INIT, which is used for other Agilent devices
using the HP protocol variant.

This change is acceptable because it was tested on all DMMs which use
the Agilent protocol (according to scpi-dmm profiles).
2021-05-22 08:35:11 +02:00
Gerhard Sittig e3c852854f scpi-dmm: Keysight 34465A is a 6.5 digit meter, bump digits count
Increase the default digit count in the 34465A model description. Though
most measurements get the precision from the current reading, this data
is used as a fallback when the response won't provide the detail.
2021-05-22 08:35:11 +02:00
Gerhard Sittig cae328b54c scpi-dmm: move OPC availability check to after IDN device identification
Assume that *IDN? requests don't involve expensive processing, and thus
don't require *OPC? before their execution. This makes scpi-dmm follow
the good tradition to only use non-standard or model dependent features
after the device was successfully identified. Which avoids confusion on
unrelated devices.

Exclusively check for *OPC? availability on Owon devices, because these
motivated the introduction of the test in the first place. This avoids
confusion on other devices where short timeouts result in errors because
the response is not retrieved although the command is supported (observed
on Agilent meters connected via USBTMC).
2021-05-22 08:35:11 +02:00
Gerhard Sittig 73816a8d8c contrib: add udev rule for Keysight USBTMC
Add the USB identification of a Keysight 34465A digital multimeter.
2021-05-22 08:35:11 +02:00
Gerhard Sittig 84073e32ef siglent-sds: prefer common glib routine to get vector's length
Replace an open coded loop with a call to common glib code.
2021-05-22 08:06:58 +02:00
Gerhard Sittig 191af3d9ca scpi: readability nits in vector getters, style nit in malloc call
Improve readability of SCPI uint8 and float vector get routines. Move
assignment and use of variables closer together to simplify review.
Allocate the glib array based on the text split result's length. Move
data processing to the "straight" path and handle failed conversion as
an exceptional condition in an error path.

Eliminate a redundant data type reference in a malloc call.
2021-05-22 08:06:58 +02:00
Gerhard Sittig 70158398f3 siglent-sds: free memory that was allocated by SCPI get routines
The SCPI get routines may allocate memory for response data which
callers have to free after use.

The implemented approach is modelled after pull request 114 by
Matti Eiden, to get the leak fixes in while the PR is queued.

This addresses part of bug #1683.

Submitted-By: Matti Eiden <snaipperi@gmail.com>
2021-05-22 08:06:58 +02:00
Gerhard Sittig 4da62209dd hameg-hmo: free memory that was allocated by SCPI get routines
The SCPI get routines may allocate memory for response data which
callers have to free after use.

Move an existing assigment such that the initial assignment, the memory
allocation, use of response data, and resource release are in closer
proximity, and thus are easier to reason about during maintenance.
Behaviour does not change.

This is motivated by bug #1683.
2021-05-22 08:06:58 +02:00
Gerhard Sittig 4fad41a8a4 rigol-ds: free memory that was allocated by SCPI get routines
The SCPI get routines may allocate memory for response data which
callers have to free after use.

The approach to release allocated memory is simlar or identical to the
corresponding parts of pull request 95, in an attempt to get the reported
leak fixes in, yet reduce the potential for conflicts where this commit
deviates from the PR. Most work was done by Ralf. Thank you!

This addresses part of bug #1683.

Submitted-By: Reported-By: Ralf <jr-oss@gmx.net>
Tested-By: Reported-By: Ralf <jr-oss@gmx.net>
2021-05-22 08:06:58 +02:00
Gerhard Sittig 83d38ed90a scpi-dmm: free memory that was allocated by SCPI get routines
The SCPI get routines may allocate memory for response data which
callers have to free after use.

This addresses part of bug #1683.
2021-05-22 08:06:58 +02:00
Gerhard Sittig ff85a7f0ab rigol-dg: free memory that was allocated by SCPI get routines
The SCPI get routines may allocate memory for response data which
callers have to free after use.

Move an existing release call to an earlier location, to avoid leaking
memory when an error path is taken.

This addresses part of bug #1683.
2021-05-22 08:06:58 +02:00
Gerhard Sittig 36165cf0f7 lecroy-xstream: free memory that was allocated by SCPI get routines
The SCPI get routines may allocate memory for response data which
callers have to free after use.

This addresses part of bug #1683.
2021-05-22 08:06:58 +02:00
Gerhard Sittig 9417f26fd4 hp-3457a: style nits in the probe routine
Unobfuscate a string comparison. Eliminate redundant data type specs
in malloc calls.
2021-05-22 08:06:58 +02:00
Gerhard Sittig 1c50255506 hp-3457a: free memory that was allocated by SCPI get routines
The SCPI get routines may allocate memory for response data which
callers have to free after use.

This addresses part of bug #1683.
2021-05-22 08:06:58 +02:00
Gerhard Sittig c9cfcd2591 fluke-45: free memory that was allocated by SCPI get routines
The SCPI get routines may allocate memory for response data which
callers have to free after use.

This implementation is incomplete. The fluke-45 driver's context holds
a "global" copy of the most recently received response. While the data
is freed in the next receive call, one item remains allocated for the
driver's remaining life time. Which is considered non-critical.

Also moves an operator in a complex multi-line expression to a different
location to follow the project's style.

This addresses part of bug #1683.
2021-05-22 08:06:58 +02:00
Gerhard Sittig 9b915e3a41 scpi: document callers' responsibility to free getters' allocated memory
Some of the SCPI getter routines allocate memory for response data which
callers need to free after use. Document this responsibility in more
places, and rephrase existing locations for consistency. See a word-diff
for the essence of the commit.

It's assumed that the separate paragraph in the function description is
better perceived than something that's hidden in the parameter or return
value discussion. Also reference the corresponding free routine by name
for callers' convenience (data types will differ among routines). Some
free routines can be called unconditionally, others require NULL checks
at the caller's.

Reported-By: Ralf <jr-oss@gmx.net>
2021-05-22 08:06:58 +02:00
Gerhard Sittig 4c72966444 scpi: make sure to either return valid SCPI response data or NULL
Assign NULL early in those SCPI get routines which return allocated
memory to their callers. So that the return value is either a valid
pointer to memory or NULL regardless of the routine's exit code. This
simplifies call sites and increases robustness.
2021-05-22 08:06:58 +02:00
Gerhard Sittig ac1866b923 serial_libsp: extend diag in code path which opens serial ports
Opening a serial port involves two libserialport calls, while only the
second call's return value gets inspected. Check the lookup before the
open, too, and provide its details in a diag message.
2021-05-22 07:59:18 +02:00
Rafael G. Martins f5c697bfe6 serial-dmm: Add PeakTech 2025 meter support.
This meter seems to be a rebranded Victor 86D. Vendor procotol
documentation matches FS9922 RS232 protocol.
2021-05-16 12:08:58 +02:00
Frank Stettner 4efd5462c7 rdtech-dps: Add missing devc initialisation. 2021-05-09 19:29:38 +02:00
Gerhard Sittig c899e691f3 contrib/60-libsigrok.rules: add udev rule for Microchip PICkit2 2021-04-25 12:52:20 +02:00
Gerhard Sittig 4b8348941d input/csv: trim surrounding whitespace from header line channel names
When CSV import grabs channel names from the first line in the file then
the text strictly between column separators (a comma) was used. Which
resulted in channel names like " channel 1". Trim leading and trailing
space before unquote, to better fulfill most users' expectation. Users
still can quote the input data for special cases if desired.
2021-04-25 12:51:33 +02:00
Gerhard Sittig 7a78fd56f7 rdtech-dps: research to reduce serial comm transfer volume again
The DPS devices default to a rather low UART communication bitrate. The
generous retrieval of more Modbus registers than strictly necessary for
the periodic acquisition of analog channel values and state tracking may
or may not be an issue.

Instrument all call sites in api.c to the device state gathering calls
such that the protocol.c side transparently can reduce the transfer
volume depending on which level of detail the caller may expect given
its current context. Under optimal circumstances this might cut the
traffic in half, which DPS devices may benefit from.

This commit adds the infrastructure to potentially reduce transfer
volume, but does not change behaviour. The "config" reasons may need
further partitioning if Modbus register access really turns out to be
a severe bottleneck. The API lends itself to that extension easily. The
approach which gets prepared in this commit needs to get runtime tested
by those who got access to the hardware.
2021-04-25 12:10:33 +02:00
Gerhard Sittig 884ae8c021 rdtech-dps: introduce support for RD6006 and other Riden RD models
The RD devices differ from DPS devices in their default communication
bitrate (115200), register content endianess (BE), and register set
layout (addresses for registers). In either case 16bit registers get
accessed by means of Modbus communication over a serial channel. The
interpretation of the registers' values mostly is the same as for DPS
devices once a register with the same meaning got identified. Device
identification includes a 32bit serial number which DPS devices appear
to not provide.

All other product features are the same, and map to identical sigrok
mechanisms. That's why re-using the rdtech-dps driver to add rdtech-rd
support is considered desirable. This implementation shares all code
"above" the raw register addressing and raw value interpretation. All
logical processing, configuration interface, state tracking and data
submission to the session feed, are shared among the different device
types.

Declare support for the RD6006, RD6012, and RD6018 models. Their specs
were taken from the 2020.12.2 instruction manual. The driver was tested
with an RD6006 device (firmware version 1.28). Unfortunately automatic
device detection is not possible or will not be reliable, which is why
users need to specify the respective model by picking one of the two
drivers. Within a driver variant the device identification and use of
the device are automatically dealt with.
2021-04-25 12:10:26 +02:00
Gerhard Sittig d7a4dad881 rdtech-dps: layer separation between API and protocol, style nits
The existing power supply driver for Riden DPS/DPH devices unfortunately
duplicated intimate details of modbus communication and register layout
including interpretation of raw register values across several source
files. Do separate the physical transport and the register layout and
register fields interpretation layers. This brings the driver in line
with the usual api.c and protocol.c arrangement of responsibilities, and
prepares the future addition of other similar devices.

Address a few style nits while we are here. Include <config.h> in all
source files, and alpha-sort include directives. Address minor data type
nits. Reduce indentation in code paths. Propagate more error codes.
Update comments which lagged behind the code, adjust grammer (eliminate
"actual" false friends). Eliminate a few magic numbers and redundancies,
switch to the more recent endianess aware byte stream reader API where
beneficial, to eliminate redundant offset math.

Other nits seem to have gone unnoticed before: The indices of all sigrok
channels were identical (all zero). Signed print formats were used for
unsigned data.

This implementation compiles, but wasn't runtime tested due to lack of
hardware. A rough estimate of transfer volume and transport throughput
suggests that the 10ms cycle time no longer can be kept, may end up
around 25ms (40 cycles per second). This can get avoided by adding more
code to tell the configuration requests, the acquisition start, and the
measurements grabbing during acquisition apart. It's assumed though that
the 10ms glib poll interval did not translate to such fast measurement
gathering. The firmware may typically provide data at lower rates anyway.

The generic source code may look overly complicated or redundant at
first glance, but compilers' generated code will greatly get optimized.
Simplified maintenance because of reduced cognitive load is considered
more important.
2021-04-25 12:10:22 +02:00
Frank Stettner 584269fd2f hp-59306a: Initial HP 59306A driver.
[ gsi: drop libgpib dependency, minor style adjustment ]
2021-04-25 12:04:10 +02:00
Frank Stettner 12e7abe219 hp-59306a: Initial driver skeleton. 2021-04-24 16:47:06 +02:00
Frank Stettner 522381a343 Add device type SR_CONF_MULTIPLEXER. 2021-04-24 16:47:06 +02:00
Soeren Apel 004fd9ffd3 Amend #119 to use vector instead of tuple
This way, we don't need to bump glibmm to 2.54, which we otherwise would
2021-03-28 23:17:17 +02:00
Gerhard Sittig 955ab60455 kingst-la2016: address trivial style nits (whitespace, braces, line length)
Improve readability by addressing the trivial style nits in the driver.

Break the channel list into two times eight instead of nine plus seven
items. Put braces around all branches if one of them has braces. Add
braces to multi line branches despite most of the branch just being a
comment -- it's still many lines. Break extra long text lines, adjust
the position of operators when single expressions span multiple lines.

Drop unnecessary parentheses around single variables and auto
incrementing pointer dereferences. Adjust whitespace especially for
pointer data types, and arith operators.
2021-03-16 21:40:32 +01:00
Helge Kruse c3d4003710 kingst-la2016: Eliminate non-portable packed structs for USB transfer layout
Eliminate packed structs in the construction and in the reception of
USB transfers, since these are rather non-portable. Use common support
for endianess aware access to byte streams instead. This unbreaks the
driver for MinGW builds, and increases portability and maintainability
on all other sigrok supported platforms.

[ gsi: adjust more locations, improve robustness, fixup style, reword message ]
2021-03-16 21:27:24 +01:00
Helge Kruse d9a74e97f4 kingst-la2016: Use common code to send trigger and frame boundary packets
[ gsi: adjust more locations, reword commit message ]
2021-03-16 21:26:35 +01:00
Gerhard Sittig 8f87c5284b tests: extend endianess conversion tests to also cover the 48bit writer
Cover the recently added writer for 48bit little endian data. Prepare a
large bytes pattern buffer that can also serve for future 64bit tests.
2021-03-16 21:26:35 +01:00
Gerhard Sittig 797c8d9034 libsigrok-internal.h: add 48bit endianess aware byte stream helpers 2021-03-16 21:26:35 +01:00
Helge Kruse 40a0b2f466 kingst-la2016: Upload firmware to correct USB configuration 1
The ezusb_upload_firmware() routine opens the USB device and selects the
current configuration. The specified value must match the previously read
configuration descriptor. This commit unbreaks the firmware download for
MinGW builds which link against libusb-1.0.20-rc3-event-abstraction-v4.

[ gsi: reworded commit message ]
2021-03-16 21:25:56 +01:00
Frank Stettner 051d85f28d korad-kaxxxxp: Add support for Korad KD3005P V2.1 2021-03-16 21:04:20 +01:00
Petteri Aimonen 2111d1574b scpi-dmm: Add support for Owon XDM2041 2021-03-06 19:04:32 +01:00
Petteri Aimonen ddeaa49d43 scpi-dmm: Gracefully handle meters that lack OPC command.
The SCPI standard requires OPeration Complete command,
but some Owon meters do not implement it. This commit
makes the probe try OPC once, and if it gets no reply
it assumes it is not supported.
2021-03-06 19:04:19 +01:00
Petteri Aimonen 33306b13ac scpi-dmm: Add infinity limit to model-specific config.
Owon multimeters seem otherwise compatible with gwinstek reader,
except infinity is only 1e9.
2021-03-06 19:04:14 +01:00
Petteri Aimonen 5433907ed9 scpi-pps: Add support for Owon P4000 series.
Tested on P4603 firmware version 1.6.0.
2021-02-28 15:25:21 +02:00
litospain 389acdd991 hantek-6xxx: Add ISDS205B support 2021-02-21 23:26:20 +01:00
waka f5c618e55f hantek-6xxx: Fix for channel coupling not updating on changing
Presumed regression related to fix for bug #836
2021-02-21 23:20:22 +01:00
Florian Ragwitz b41562f6ce zketech-ebd-usb: Don't ignore errors 2021-02-21 23:05:32 +01:00
Florian Ragwitz a99ff45359 beaglelogic: Fix resource leak 2021-02-21 23:05:27 +01:00
Alberto Scotta fe185e4990 hantek-dso: fix 100MS/s
Do not downsample at 100MS/s.
The device actually sampled at (100.0/0x1000)MS/s when 100MS/s was set.
2021-02-21 23:01:58 +01:00
HReimann 0f5dcee6ce rigol-ds: Add DS1102Z-E model variant 2021-02-21 22:55:00 +01:00
Richard Allen a2916ad017 python bindings: Support passing in rational voltages for config_set 2021-02-21 22:21:17 +01:00
Richard Allen 1145ceaa78 gwinstek-gpd: Fix voltage/current measurement 2021-02-21 21:46:08 +01:00
Richard Allen c93c014f47 gwinstek-gpd: Support auto-baud detection
If the user does not specify a serialcomm configuration,
try all three options from the manual.
2021-02-21 21:46:08 +01:00
Richard Allen c329b788d2 gwinstek-gpd: Retry device identification on failure
Try the identification command up to three times
if the device responds with 'Invalid Character.',
which can happen if the device has buffered part
of a command but not executed it.
2021-02-21 21:41:18 +01:00
Richard Allen 10fd326dea gwinstek-gpd: Print serialcomm config 2021-02-21 21:41:18 +01:00
Gerhard Sittig 1c5d5905a4 scpi-pps: add R&S HMP2000 model specs
Re-use HMP4000 options and channel groups, only keep separate channel
specs for HMP2000 devices. HMP2030 has three identical 32V/5A channels.
HMP2020 has one 10A channel and one 5A channel.
2021-02-02 21:09:54 +01:00
Gerhard Sittig 7320ce5ecc scpi-pps: adjust R&S HMP4000 current resolution for 10A channels
Specs published by R&S suggest that 10A channels support 0.2mA resolution,
while only 5A channels resolve to 0.1mA (up to 1A full scale, 1mA above 1A).
2021-02-02 21:07:29 +01:00
v1ne 3cc9e21573 ols: Clean up: Replace hand-rolled byte order conversion with existing macros 2021-01-06 10:45:28 +01:00
v1ne f8fd84208d ols: Refactor: Extract trigger setup into private place
This copies the code verbatim from one place to another in preparation to adding
support for complex triggers.
2021-01-06 10:45:28 +01:00
v1ne 50b15953fe ols: Make external clock setting queriable
... and thus selectable in PulseView.
2021-01-06 10:45:28 +01:00
v1ne f20c39d933 ols: Add option to use the falling edge of the external clock 2021-01-06 10:45:28 +01:00
v1ne c36a7d84ca ols: Clear "disabled groups" flags before setting them
This fixes a bug where the channel group setting would not be overwritten in a
new run, but instead the channel group settings of both runs would be merged
together.
2021-01-06 10:45:28 +01:00
v1ne 29f15d52cb ols: Display actual expanded sample instead of the raw sample
While the raw sample is the actual received data, the expanded sample is the
crucial data I as a developer am interested in seeing. At least if I assume that
the sample expansion works.
2021-01-06 10:45:28 +01:00
v1ne aad6b9de5f ols: Clean up: Prefix private function for consistency 2021-01-06 10:45:28 +01:00
Gerhard Sittig ba1fb5e926 doc: update README.devices for Meterman 38XR (RS232 button) 2021-01-05 18:17:45 +01:00
Peter Skarpetis 4c29bba1f0 dmm/mm38xr: introduce DMM packet parser for Meterman 38XR
Introduce a DMM packet parser in src/dmm/ and register it with the
serial-dmm device driver. This adds support for the Meterman 38XR
multimeter.

[ gsi: style adjustment, raise awareness during maintenance ]
2021-01-05 08:13:23 +01:00
Gerhard Sittig 3fa436bb48 serial-dmm: move Mastek items after Metex in the model database
Keep the alpha-sort order in the list of supported chips and models.
2021-01-05 08:10:21 +01:00
Frank Stettner 8fb9afcacd arachnid-labs-re-load-pro: Fix for get voltage and current while in acquisition.
[ gsi: moved intruction order to unify with other cond signalling code paths ]
2021-01-04 16:02:00 +01:00
Gerhard Sittig f93bf8ba02 dmm/bm52x: unbreak build when serial comm is not available
Make another code path in the Brymen BM52x packet parser optional which
snuck in earlier and broke compilation when serial_comm dependencies are
not met.

Ideally the src/dmm/ parser code would not get built at all in that
case, but building a parser with reduced functionality and not using it
later because its callers are conditional is as good, and is what other
DMM packet parsers did in the past.

How to reproduce:

  $ configure --without-libserialport --without-libhidapi --without-libbluez
  $ make
2020-12-29 18:31:38 +01:00
Ralf 6065d660e0 fx2lafw: Unbreak SR_CONF_LIMIT_SAMPLES for large values (above 2**32)
Capture does not stop for sample count values which exceed the range of
a 32bit type variable. Adjust the data type to 64bit.

How to reproduce: 8MSa/s * 600s -> 4,800,000,000 samples

  $ sigrok-cli -d fx2lafw -o capture.sr --config samplerate=8M --time 600000

[ gsi: rephrased the commit message ]
2020-12-25 13:02:07 +01:00
Gerhard Sittig aa8e4959e2 ftdi-la: work around missing USB strings during device probe
Some FTDI chip based products ship with EEPROM content which makes
libftdi fail to lookup the USB strings, which breaks the scan for the
device's presence. The previous implementation was strict and only
accepted the absence of a serial number. This implementation also copes
when vendor and model cannot be gathered from the device, and provides
fallback values based on VID:PID numbers.

Also factor out a magic number for string lengths. Stick with dynamic
allocation since 3x 32bytes would be rather huge a local stack use, and
future maintenance might bump that string length again.

[ gsi: magic number in one spot, bounded string assignment, style nits ]

Submitted-By: Christo Crause <christo.crause@gmail.com>
2020-12-25 12:47:01 +01:00
Niklas Thorne d7ce5452ac asix-sigma: parse serial numbers as unsigned values
This unbreaks device detection on 32bit platforms.
2020-11-28 08:01:31 +01:00
Niklas Thorne 30903c4043 strutil: introduce sr_atoul_base() conversion helper (non-decimal)
Introduce a text to number conversion routine which supports non-decimal
bases and optional suffixes, but returns unsigned results and thus covers
a larger range of values. This kind of amends commit 97aa41e9b5 which
introduced the sr_atol_base() routine.
2020-11-17 17:51:02 +01:00
Gerhard Sittig 3decd3b1f0 driver_list: unbreak list of builtin drivers for LTO configurations
Check for the availability of the "no_reorder" linker attribute, which
keeps the list of builtin drivers in shape on LTO enabled build setups.
Keep backwards compatibility for platforms which lack support for the
"no_reorder" attribute. Phrase the implementation such that other
keywords as well as user provided external specs are possible.

This resolves bug #1433.

Submitted-By: Ivan Mironov <mironov.ivan@gmail.com>
2020-11-05 05:20:42 +01:00
Gerhard Sittig efce57da32 libsigrok-internal.h: add u64be endianess writer
Add endianess aware writer for uint64_t data in BE format. This is
motivated by the Codethink Interrogizer.
2020-10-26 19:50:33 +01:00
Gerhard Sittig 6bee394dee serial-dmm: add support for the Brymen BM820s family
The BM820s series uses the same 10000 counts protocol as BM520s does,
but lacks the capability of recording measurements. Re-use the bm52x
DMM packet parser, but don't register the config get/set/list and
acquisition start callbacks.

It turns out that the packet request and packet validity check routines
need to be individual, since 0x82 is used instead of 0x52 as a magic
number in some places. Fortunately the complex payload parser is shared
among BM520s and BM820s series. This was tested with a BM829s meter.
2020-10-22 21:25:34 +02:00
Gerhard Sittig 0931639a12 dmm/bm52x: add support for recorded measurements (memory data sets)
Extend the BM52x packet parser, add config get/set/list code to handle
the data source property. Either let the common serial-dmm code run the
acquisition of live readings, or locally retrieve the selected "session
page" and forward its measurements to the session bus. These separate
code paths are required because the protocol differs a lot between these
modes, a totally different set of requests and responses is involved,
response interpretation logic is impossible to share between live and
recorded measurements.
2020-10-22 21:25:34 +02:00
Gerhard Sittig 9a1a7dc283 brymen-dmm: remove obsolete driver (support has moved to serial-dmm)
The DMM support for Brymen BM850s has moved to src/dmm/ and became
part of the serial-dmm driver. Remove the now obsolete brymen-dmm/
source code.
2020-10-22 21:25:34 +02:00
Gerhard Sittig 27186edacf dmm/bm85x: introduce DMM packet parser for Brymen BM850(a/s)
Implement a DMM packet parser for the BM850s protocol. This involves
variable length responses, which recently became a common serial-dmm
feature. Register the new parser under the "brymen-bm85x" device name.
This obsoletes the brymen-dmm driver which announces as "brymen-bm857".
This implementation was tested with the BM859s meter.

The text to number conversion with precision detection resolves the
last remaining issue of bug #1611.
2020-10-22 21:25:34 +02:00
Gerhard Sittig 91ab2f6475 strutil: add text to float conversion which also gets precision from text
Provide a common string helper routine which converts input text to a
double precision floating point number, and also gets its precision in
the process.
2020-10-22 21:25:34 +02:00
Gerhard Sittig 070668a0fd serial-dmm: more DMM parser callbacks (open, var length, config, start)
Extend the serial-dmm driver's common infrastructure to support more
per-parser (per-model) specific extensions. Add support for variable
length packets (motivated by BM85x), and pass the packet length to
parsers which accept it. Add callbacks which run after the COM port got
opened (motivated by BM85x). Add support for additional configuration
get/set/list properties (motivated by BM52x), including a hook into the
acquisition start and a state container which is owned by the parser.

Device specific acquisition start can check its local state which can
store the result of previous config get/set requests, and can arrange
for a different receive routine to execute (motivated by BM52x). The
default code path will execute serial-dmm's receive routine which keeps
invoking the DMM's packet parser for each registered display.

Prefer double precision values in the new parser callbacks. Also fixup
some data type issues: Use unsigned types for length and size specs as
well as timeouts, don't promote false booleans to NULL pointers, reduce
malloc() argument redundancy. Rephrase some instruction grouping and
update comments to simplify future maintenance. Get the current time
just once for improved consistency in the packet re-request code path.
Rename identifiers in the data reception path to improve readability.
2020-10-22 21:25:34 +02:00
Gerhard Sittig 1a7adeac29 serial: extend stream detect for variable length packet checkers
The previous implementation of the packet detection in a serial stream
assumed that all packets are of equal length which is known in advance.
Extend the packet validity check interface such that caller provided
callbacks can either decide that the input is valid or invalid (terminal
decision), or request more receive data before a decision can be made
(deferral, coverring variable length packets, with a minimum size to
cover the header before a length becomes available and the total packet
length is known).

This commit extends the API, and adjusts the call sites to not break the
compilation. Actual variable length checkers are yet to be done. Improve
readability while we are here: Better reflect the purpose and units of
variables in their identifiers. Tweak diagnostics messages, update
inline and doxygen comments.
2020-10-22 21:25:02 +02:00
Gerhard Sittig 2cb4204c6f input/vcd: fix a divide by zero bug in the analog-only case
When the input data exclusively contained analog data, then creation of
the submit buffer for logic data caused a division by zero. Fix the
create_feed() routine.
2020-10-22 19:29:58 +02:00
Gerhard Sittig ec30291701 input/vcd: suggest downsampling to users for reduced resource consumption
Naive creation of VCD files with inappropriately fine timescale specs
results in excessive resource consumption due to libsigrok's assumption
of a constant rate stream of sample data. A workaround is available and
documented, but users need to become much more aware.

Implement a reliable check for wasteful input data situations which
depends on the reception of _all_ input data, and can only alert users
late after potentially spending lots of time and assuming that available
resources allow completion of the import. Users could miss that check's
outcome.

Also implement early checks which (necessarily) are based on weaker
conditions, to already raise user's awareness while data import still is
executing. Phrase these early checks as computationally inexpensive as
possible, to not affect the main task of data import too much. Avoid
false positives by balancing the desire for early emission of messages
and picking appropriate conditions to test for.

This commit implements the foundation for early estimates and reliable
terminal checks, as well as the emission of messages which support users
and allow a more effective use of the file format. The specific limits
and tested conditions still may benefit from more tuning in the future.

The input module logic in this commit emits an information for harmless
cases, and emits warnings for "severe" cases where default option values
or incomplete user specs result in several orders of magnitude higher
resource consumption than necessary. GUI users may not notice, but the
library cannot help that given the current infrastructure -- the library
stricly does as the application tells it to, according to user input.

The best use is to run the CLI's --show feature on VCD files of unknown
content, to get an idea how to most appropriately configure a subsequent
file import. An alternative is to open the VCD file before import, check
the timescale in the header and the last two timestamps, to get an rough
estimate of a useful downsample factor.

This is motivated by but does not resolve bug 1624.
2020-10-18 21:19:27 +02:00
Gerhard Sittig 358105152a input/vcd: unbreak U and - values for single bit input data
The previous implementation already mapped L/H/U/- literals for input
data values to the 0/1/0/0 logic levels which sigrok can handle. But
missed these literals in the condition which dispatches real/integer,
bit vector, and single bit data types. Which made VCD import fail for
some of the files in the SpinalWorkshop repo.

Extend the test condition for single bit values. This unbreaks the
import of the Apb3TimerTester.vcd and ApbPwmTester.vcd files, which
contained phrases like these:

  ...
  $var reg 1 % io_apb_pwrite $end
  ...
  #0
  bUUUUUUUU !
  b0 "
  0#
  1$
  U%

and

  ...
  $var reg 8 # io_apb_paddr[7:0] $end
  $var reg 1 $ io_apb_pwrite $end
  ...
  #0
  b0 !
  0"
  b-------- #
  -$
  b-------------------------------- %
  b00000000000000000000000000000000 &
  1'
2020-10-18 21:19:07 +02:00
Soeren Apel a3fe36d01e configure: Add optional TI-RPC dependency, unbreak VXI communication.
Recent glibc-2.26 no longer provides support for SunRPC, and libsigrok's
build support failed to detect the presence of libtirpc in that case.

  https://wiki.gentoo.org/wiki/Glibc_2.26_porting_notes/RPC_implementation

Extend the check, use either SunRPC or TI-RPC. Which re-enables VXI on
recent setups. This resolves bug #1473.
2020-10-09 18:50:58 +02:00
Timo Kokkonen b1eb94bbef rigol-dg: Add device/firmware specific quirks support.
DG800/DG900 units seems to have issues with counter implementation:
- About 1 second delay is needed after enabling or disabling the counter.
  Otherwise unit stops responding properly (start seeing USB errors).
- Second channel and counter cannot be enabled simultaneously.
2020-10-06 22:04:42 +02:00
Gerhard Sittig 92cd85149a itech-it8500: avoid "new" as a variable identifier
Strictly speaking the "new" identifier is not a reserved word. Still
it's good practice not to use it for variables in C language sources.
Rename variables to "old_bit" and "new_bit" for consistency.
2020-10-06 22:02:20 +02:00
Gerhard Sittig 8c8fff4773 itech-it8500: declaration nits
Rearrange the order of declarations in the protocol.h header. Start with
packet layout, continue with requests (commands), then responses (status),
before the device context and the set of routines.

Rename the status codes to STS_* in contrast to CMD_* codes. Use an enum
for different byte values, leave defines for packet sizes et al. Phrase
bit fields in terms of bit numbers not byte values.

Total nit: Change the breaks in the long list of add_source() args. Keep
event type and timeout together, similar to callback and its data.
2020-10-06 22:02:20 +02:00
Gerhard Sittig 78b07caf11 itech-it8500: rephrase config get/set/list, reflect error paths
Explicitly "break the flow" when internal status gathering fails, to
reflect that an error path is taken and the config call will fail. The
conditional assignment of response data in case of success could be
slightly misleading (it was to me during review).

Eliminate a goto which kind of circumvented the optional transmission of
a request to the device. Instead test whether a command was filled in to
determine whether a command needs to get sent.
2020-10-06 22:02:20 +02:00
Timo Kokkonen f21b6983e8 itech-it8500: ITECH IT8500 series DC electronic load driver.
This driver supports ITECH IT8500 series electronic loads:
 IT8511+, IT8511A+,
 IT8512+, IT8512A+, IT8512B+, IT8512C+, IT8512H+,
 IT8513A+, IT8513B+, IT8513C+, IT8514C+, IT8514B+, IT8516C+

Additionally BK Precision 8500 series loads (models 8500, 8502, 8510,
8512, 8514, 8518, 8520, 8522, 8524 & 8526) should work as well.
As ITECH is the OEM manufacturer for these BK Brecision models.
2020-10-06 22:02:20 +02:00
Timo Kokkonen c16effaedc itech-it8500: Initial driver skeleton. 2020-10-06 22:02:20 +02:00
Timo Kokkonen 34ce5b0439 hwdriver: New entries for DC Load "CW" (Power) and "CR" (Resitance) modes.
Added following new entries:
	- SR_CONF_POWER
	- SR_CONF_POWER_TARGET
	- SR_CONF_RESISTANCE_TARGET
2020-10-06 22:02:20 +02:00
Gerhard Sittig d7838e4804 dmm/metex14: unbreak packet request helper return code
Return SR_OK in case of successful transmission of a packet request. The
previous implementation passed the serial layer's verbatim return value,
which was non-negative non-null (read: above zero) in case of success,
which is none of the expected return codes of a packet request routine.

This amends commit 379e95c587 and completes the adjustment which was
started in commit a4be2b327b. The issue has gone unnoticed in the past
since it took not effect. The serial-dmm caller only tested for negative
return values.
2020-10-06 20:59:27 +02:00
Gerhard Sittig 1f8ef363cb README.devices: add JTAGulator section for Logic Analyzer mode
Manual activity is required to enable the SUMP protocol support on the
JTAGulator. Link to the vendor's wiki article for users' convenience.
2020-10-06 20:32:04 +02:00
Gerhard Sittig cd11e33c5d input/csv: trim cell content before conversion
Trailing whitespace in CSV cells broke the text to number conversion.
Trim the text content of cells before processing it. This is useful and
actually essential for data cells, and does not harm titles in header
lines, neither will it affect column format specs.

How to reproduce:

  $ echo ' 3.14 , 2' | \
    sigrok-cli -i - -I csv:header=false:column_formats=2a
  sr: input/csv: Cannot parse analog text  3.14  in column 1 in line 1.
2020-10-04 20:00:16 +02:00
Timo Kokkonen d999f2b61e rigol-dg: Fix reading current output signal duty cycle value.
Reading output signal duty cycle value didn't always work, since it relied
on old (cached) information about the currently active waveform. Changed to
always query channel status so this won't happen anymore.
2020-10-04 13:00:59 +02:00
Timo Kokkonen 9ce14905cb rigol-dg: Add Rigol DG800 and DG900 series support.
This adds support for all Rigol DG800/DG900 series models.

DG800 series: DG811, DG812, DG821, DG822, DG831, DG832
DG900 series: DG952, DG972, DG992
2020-10-04 13:00:35 +02:00
Timo Kokkonen feeafbc003 udev: Add Rigol DG800 and DG900 series VID/PID. 2020-10-04 13:00:28 +02:00
Gerhard Sittig a4be2b327b pce-322a: unbreak send_command() return code
Data was sent to the serial port, and the non-zero positive write length
was mistaken as an error, since it did not match the SR_OK code's value.
This snuck in with commit 379e95c587 in 2017-08.

Rephrase the check for successful serial writes in the pce-322a driver.
Pass on error codes from the serial layer in verbatim form. Check for
the exact expected write length and derive SR_ERR_IO upon mismatch. Do
return SR_OK upon success.

Reported-By: Michael Ströder <michael@stroeder.com>
Tested-By: Michael Ströder <michael@stroeder.com>
2020-10-03 07:20:00 +02:00
Gerhard Sittig 5a0303474c rigol-dg: reduce redundancy in malloc() calls
No need to duplicate the data type, just allocate enough memory to
hold the variable's value. Shuffle the order of items in the array
size calculation (number of items times the size of an item).
2020-09-28 09:11:02 +02:00
Timo Kokkonen 4c98253dba udev: Add Rigol DG1000z Series VID/PID. 2020-09-28 09:11:02 +02:00
Timo Kokkonen 02feeb30b9 rigol-dg: Initial Rigol DG1000z driver implementation.
This implements support for Rigol DG1000z series digital signal
generators. Driver provides basic control via channel groups
("1", and "2"). Acquisition returns data from the built-in
frequency counter.

Supported models: DG1022Z, DG1032Z, DG1062Z

[ gsi: added some coding style adjustment ]
2020-09-28 09:08:37 +02:00
Timo Kokkonen 068db0fbe6 rigol-dg: Initial driver skeleton. 2020-09-28 09:03:37 +02:00
Timo Kokkonen 63eec38073 hwdriver: Add SR_CONF_DUTY_CYCLE & SR_CONF_PHASE. 2020-09-28 09:02:52 +02:00
Ralf 2dddd5bd5e scpi: accept numbers like 4.0000E3 as integer value
MSO5000 returns memory depth value in that format, e.g.
sr: [04:21.491949] scpi_vxi: Successfully sent SCPI command: 'ACQ:MDEP?'.
sr: [04:21.501463] scpi: Got response: '4.0000E+03', length 10.

[ gsi: drop redundant assignment and parens, amend diag message ]
2020-09-27 12:51:39 +02:00
Gerhard Sittig 0c52026459 serial: lower severity of failed stream detect message
Reduce the message's log level from ERR to INFO when the serial stream
detect routine cannot find a valid packet. Although an error code gets
returned, the condition need not be fatal (can be the result of trying
several peers before success or finally giving up). Let callers decide
on the severity of failure to detect a specific device's presence, and
provide more context in their message which is more helpful to users.
Interested readers still get the message at slightly raised log levels.

This avoids confusing user perceivable situations like these:

  $ sigrok-cli --scan
  sr: serial: Didn't find a valid packet (read 0 bytes).
  sr: serial: Didn't find a valid packet (read 0 bytes).
  The following devices were found:
  demo - Demo device with 13 channels: D0 D1 D2 D3 D4 D5 D6 D7 A0 A1 A2 A3 A4
2020-09-27 12:33:19 +02:00
Gerhard Sittig 7dd1dd9f7d ols: more robust device reset in acquisition stop
Use the existing ols_send_reset() routine because acquisition
termination can get initiated in several code paths. Make sure the
device will cease activity whatever state it happens to be in. This
amends commit 6d8182b643.
2020-09-27 07:53:09 +02:00
Ben Gardiner 6d8182b643 ols: send CMD_RESET on acquisition stop
Sending CMD_RESET will interrupt armed/untriggered acquisitions which is
very useful in Pulseview sessions since, without this, a next 'run' will
hang.

Signed-off-by: Ben Gardiner <ben.l.gardiner@gmail.com>
2020-09-24 12:54:32 +00:00
Gerhard Sittig 8e79890770 brymen-dmm: unbreak dBm reference impedance interpretation
The reference impedance for dBm measurements comes in an unexpected
format. Isolate the 4..1200 Ohms value, ignore the (inappropriate?)
"0." and exponent parts of the response. Clearly reflect that Ohms
values are seen in different contexts (dBm reference, continuity,
resistance).

Reword comments in the BM850 response parser's code path for dBm
measurements. The reference value is shown when the function is entered
(verified here) or when the reference value changes (haven't seen this
here but a comment in the previous implementation said so).
2020-09-21 21:37:06 +02:00
Gerhard Sittig 3f8453b274 brymen-dmm: unbreak temperature response parsing
The BM850s temperature function response includes the C/F unit in an
unexpected position ("0.0272CE+3") which breaks number conversion. Drop
the C/F unit to unbreak the conversion.

This was observed with BM859s. Absence of the C/F unit in the response
is fatal in this implementation. If other meter firmware versions or
models don't suffer from that issue, the removal must be silent and
non-fatal.
2020-09-21 21:29:43 +02:00
Gerhard Sittig 66b349841a brymen-dmm: rephrase bfunc and value text parsing
When the BM850s response packet's payload gets interpreted, the DLE/STX
transport envelope is not of interest. Rephrase the bitfield inspection
to better reflect that 'bfunc' indicators get accessed (match the vendor's
documentation). Rephrase the calling parse routine to unobfuscate the text
field access. Unclutter assignments for the analog feed. Use a shorter
layout in debug messages, reflect raw input data and conversion results.
2020-09-21 21:29:27 +02:00
Gerhard Sittig 56213aa027 brymen-dmm: improve text to number conversion robustness, signed OL
The BM850(a/s) response packets are a mix of binary and text content.
The text part of it is _not_ a regular ASCIIZ string. Enforce the NUL
termination before running standard C library string routines on it.
Rephrase the conversion routine to become more C idiomatic.

Also check the optional sign for overflow conditions, return either
positive or negative infinity as a result.
2020-09-21 19:57:32 +02:00
Gerhard Sittig 11addc897a brymen-dmm: style nits, apply comm param defaults, low battery warning
Rephrase how the default serial communication parameters get applied.
Preset the variable to the default value and let optional user provided
specs override these. This avoids an extra check which is difficult to
read and highly redundant. Add a comment for raised awareness that a
default port spec is undesirable because it's unreliable.

Raise the severity of low battery messages. It's worth warning the user
because measurements could be inaccurate.

Reduce indentation in continuation lines of a long routine signature,
and drop an empty line in a short struct while we are here.
2020-09-20 10:44:20 +02:00
Gerhard Sittig 648f32d119 brymen-dmm: unbreak BM85x communication by pulsing RTS after COM port open
Either the Brymen meters in the BM850s series or their cables require an
RTS pulse to wakeup, without it there won't be a response during scan or
when requesting measurements. Follow the vendor's documented sequence for
a low RTS pulse after opening the serial port and before communication to
the device.

This fixes bug #1595.

Reported-By: Karl Palsson <karlp@tweak.net.au>
2020-09-20 10:44:20 +02:00
Gerhard Sittig 3ad30b4e19 serial: add routine to manipulate handshake state (RTS, DTR)
Introduce a routine in libsigrok's internal serial layer which lets
applications manipulate the state of handshake signals (RTS and DTR)
after the serial port got opened and configured. This allows for timed
pulses which cannot get expressed with static "rts=1" etc phrases in
parameter strings, and allows handshake signal control while leaving
bitrate and frame format untouched. Applications specify which signals
to modify while other signals remain as they are (ternary input).

Do implement the signal manipulation in the libserialport transport,
do nothing and silently pass in the HID and BT transports. These can
get extended later as the need arises, depending on the HID chips' and
RFCOMM peers' capability to control these signals. This extension is
transparent to application code (acquisition device drivers).
2020-09-20 10:44:20 +02:00
Gerhard Sittig b1184024fe serial: rephrase check for speed (bitrate) in parameter string routine
Use positive logic, put the error path for an unavailable value where
the check for its availability is. Do the regular activity on available
values in the straight code path with lesser indentation. Also group the
bitrate, frame format, and handshake params when breaking text lines.
2020-09-20 10:42:54 +02:00
Gerhard Sittig 400bc4ffab dmm/bm52x: introduce support for Brymen BM525s
Introduce a bm52x DMM packet parser which is modelled after the bm86x
implementation, and hook it up to the serial-dmm driver. This supports
the live readings (real-time download) of the Brymen BM525s logging DMM.
The timing follows the vendor documentation (0.5s between requests, and
4.0s absolute timeout after request transmission). Reading previously
recorded data (memory data sets) unfortunately does not fit well into
the serial-dmm approach, and needs to get addressed differently later.
2020-09-19 12:52:41 +02:00
Gerhard Sittig abcb13855f serial-dmm: only do bytes to text conversion at higher log levels
Check the current log level before starting the potentially expensive
bytes to text conversion for a debug message (dump DMM packets).
2020-09-19 12:32:35 +02:00
Gerhard Sittig ce3fe37969 input/csv: provide double precision values to session feed
Common conversion support code accepts double precision input data for
analog packets. Use the 'double' data type in the CSV input module to
feed sample data to the session bus.
2020-09-18 16:42:37 +02:00
Gerhard Sittig e62b284c1c analog.c: rephrase analog feed to float conversion routine
Rephrase the sr_analog_to_float() routine to further reduce redundancy.

Check early for a match of the input data and result format, to grab the
raw data without conversion in that case. Handle optional scale/offset
calculation in that fast code path, too.

Unify the instructions which convert input data from either integer or
floating point presentations to the result format. Use common stream
readers to retrieve input data in several formats, which eliminates
local conversion buffers. Move common sub-expressions (scale/offset) out
of loops. Run more calculations on double precision data before results
get trimmed to single precision.

Add and extend comments to improve future maintenance. Include (terse)
details of unsupported input data presentations in error messages.

This implementation was neither tuned nor measured for performance.
There still is a lot of redundancy among the branches which handle a
specific input data type. Rephrasing that approach interacts with the
yet to be done performance tuning, thus needs to get addressed later.
The current phrases' verbosity is believed to improve readability.
2020-09-18 16:42:37 +02:00
Gerhard Sittig e4bcc63de6 libsigrok-internal.h: add more endianess aware stream reader routines
Add endianess aware readers including address incrementing variants for
those intrinsic data types which were missing in the previous version
yet are needed for sr_analog_to_float() adjustment.

Also move the 24bit reader to its position in the sort order.
2020-09-18 16:42:37 +02:00
Gerhard Sittig 6205515cc8 tests/analog: add more tests for analog feed to float array conversion
Extend test coverage for the sr_analog_to_float() conversion routine.
Pass data which is encoded in native, little and big endian format to
the routine. Pass single and double precision floating point data, and
integer data in different unit sizes and signedness. Cover scale/offset
calculations as well.

Also cover expected failed conversion for unsupported combinations of
input data format details (half/quad precision float, u64 integer).

Adjust the grouping of test cases in the sequence while we are here.
Move SI prefix, unit, and rational number related tests out of the
analog-to-float conversion group.
2020-09-18 16:42:37 +02:00
Timo Kokkonen f37f11ec6b analog.c: sr_analog_to_float(): Support for receiving double values.
Unbreak the conversion of input data in the floating point format when
the input data's format does not match the host's internal presentation,
thus grabbing raw data cannot be done.

Also accept the input data in double precision format which was not
supported before. Check for unsupported unit size values and emit an
error message similar to the integer code path.

This is motivated by bug #779 but does not resolve it. Adjusts common
conversion support, but sticks with single precision return data type
for API compatibility.
2020-09-18 16:42:37 +02:00
Jiri Slaby 505a55f789 tests: strutil, use ck_assert
We pass no message, so use ck_assert instead of ck_assert_msg. This
results in an error with check 0.15:
tests/strutil.c:157:2: error: too few arguments to function '_ck_assert_failed'
  157 |  ck_assert_msg(saved_locale != NULL);
2020-09-15 08:56:21 +02:00
Gerhard Sittig 5208214739 input/saleae: improve L2D undersampling, do provide sample data
The Saleae Logic exported files (Logic2 digital format) don't contain a
samplerate, so users need to specify the value. For values smaller than
the samplerate that was used during the capture undersampling will take
place. An implementation detail of the input module could result in
incorrect timing of sample values in the session feed. In extreme cases
none of the periods between signal edges qualified for submission. In
that case no sample data was sent to the sigrok session at all.

  $ sigrok-cli -i digital_1.bin -I saleae:samplerate=1000

Keep the very timestamp at hand when the last sample data was submitted.
Only advance that timestamp when more sample data was sent. This avoids
the accumulation of timing errors for undersampling scenarios, and does
forward undersampled input data when the user provided sample period has
passed.

This fixes bug #1600.
2020-09-02 19:52:44 +02:00
Gerhard Sittig 565c8c3545 korad-kaxxxxp: remove obsolete code (clear before read, timeout literal)
The korad response read routine clears the receive buffers, so callers
don't have to. This amends commit d2cc60bd45.

The acquisition timeout is handled by common sw_limits support. Remove
the no longer referenced literal. This amends commit 3f9b48ae5f.
2020-09-01 17:15:54 +02:00
Gerhard Sittig d2cc60bd45 korad-kaxxxxp: speed up scan process, rephrase response read routine
The Korad protocol relies on unterminated request and response strings,
which works well enough for fixed length acquisition and status queries.
But the variable length replies to identification requests suffered from
an implementation detail in the receive routine. A large timeout must be
used because supported devices reportedly are slow to respond. There is
no simple yet robust condition to detect the response's completion. The
scan code must prepare for the maximum response length across the set of
supported devices. Unfortunately the maximum amount of time was spent
waiting for the response to occupy the provided response buffer, before
a long total timeout expired.

Rework the korad driver's helper routine which gets a variable length
non-terminated text string. Keep the long initial timeout, and keep
iterating in that initial phase to quickly detect when response data
became available. But terminate the read sequence after a shorter period
without receive data after some initial receive data was seen. Assume
that identification responses get transferred at wire speed and without
additional delays beyond bitrate expectations. Acquisition and status
responses shall not be affected by this change.

This speeds up the scan for devices from roughly 5s to some 0.1s on
newer devices (KA3005P v5.5) and 0.5s on older devices (KA3005P V2.0).

This commit also addresses an issue in the response text termination,
where partial responses contained undefined data. The previous version's
return value was unspecific: Negative for fatal errors, but either zero
or non-zero for successful reads, with no way for callers to learn about
the received amount of data. The rephrased version always returns the
amount of received data, and adds internal documentation which discusses
the implementation's constraints and the motivation for the approach.

This is a modified version of the initial implementation which was
Submitted-By: Karl Palsson <karlp@tweak.net.au>
2020-09-01 17:11:36 +02:00
Gerhard Sittig fcacf532f5 korad-kaxxxxp: style cleanup in device scan, keep serno at hand
Cleanup style in the korad driver's scan() routine. Keep declarations
out of code blocks. Reduce redundancy and improve robustness in the
response buffer length calculation. Reduce clutter and group related
instructions together. Unobfuscate result checks, and keep the result
at hand (for diagnostics, or error propagation). Unobfuscate string
comparisons in the model ID lookups, terminate the search upon match.
Use a not so terse name for data that gets referenced at rather distant
locations.

Keep the optionally available serial number at hand, to present it to
users when desired. This aspect was
Reported-By: Karl Palsson <karlp@tweak.net.au>
2020-08-28 16:28:47 +02:00
Gerhard Sittig 003ad0ab8c input/saleae: keep previous channels across cleanup() call
The previous implementation of the cleanup() routine in the saleae input
module kept user specified options, but lost the previously created list
of sigrok channels. Keep it.

Also make sure that reset() voids the previous copy after grabbing its
value. To not unexpectedly release resources which still get referenced.

This shall unbreak file-reload.
2020-08-26 17:06:15 +02:00
Gerhard Sittig f403cb9de9 scpi-pps: use remote and local modes for HMP4000
Stop using the unusal "mixed" mode (local interface available during
remote operation) for HMP4000, applications may not be prepared for this
use case. Use traditional "remote" and "local" modes instead. This change
also ends remote mode after the application is done using the device.
2020-08-25 21:06:01 +02:00
Gerhard Sittig 22f76e188b scpi-pps: Add more HMP4000 series devices
List both vendor names "HAMEG" and "ROHDE&SCHWARZ" in the scpi-pps
driver, either responses were seen for HMP4000 devices. Unfortunately
vendor names don't support regex matches, so they require individual
profile items. The items also "violate" the alpha sort order in the list
of profiles, but keeping the series' models together is more important.

Add a declaration for the HMP4030 device which re-uses the HMP4040 data
but open codes the smaller channel count. Ideally the .probe_channels()
routine would receive the scpi_pps item as a parameter, and could yield
model specific result data from common information for the series. The
implementation in this commit is the least intrusive approach until
something better becomes available.

This shall cover the whole HMP4000 series:
  https://www.rohde-schwarz.com/product/hmp4000
2020-08-25 20:59:31 +02:00
Florian Schmidt bd5f0a143e scpi-pps: add support for Hameg / Rohde & Schwarz HMP4040
This commit introduces initial support for the HMP4040 power supply by
Rohde & Schwarz. It allows to configure the device and "statically" read
back current state. Automatic status updates with per-channel details
are not available yet (common support is missing).

[ gsi: drop status update remainder, address minor style nits ]
2020-08-25 20:58:54 +02:00
Gerhard Sittig 24a953382c doc: update README.devices for GWInstek VCP (CP210x in disguise)
Reference the vendor's Windows specific "driver" download for the
CP210x chip with a non-default VID:PID. Provide an example how to
assign the Linux driver to that device (interactive, no udev rule).
2020-08-25 19:38:23 +02:00
Gerhard Sittig f91c6940ab scpi_serial: add "GWInstek VCP" (PID 0x0030) as seen in GDM-834x 2020-08-25 19:38:23 +02:00
Gerhard Sittig 395c1850b7 scpi-dmm: factor out some OL detection limits
Prepare the "plus/minus infinity" checks for OL conditions to use
model dependent limits. This commit does not change behaviour.
2020-08-25 19:38:23 +02:00
Gerhard Sittig 7d95afb9be scpi-dmm: add SR_CONF_CONN getter
Add config_get() support for conn= specs. This is a best-effort approach.
Failure to get the SCPI connection text is non-fatal during probe.
2020-08-25 19:38:23 +02:00
v1ne 6f9234e6f3 ols: Detect Demon Core, use its canonic command names
Document Demon Core commands and associated metadata magic numbers.
See http://web.archive.org/web/20190317154112/
http://mygizmos.org/ols/Logic-Sniffer-FPGA-Spec.pdf for documentation.

Detect the Demon Core presence, use more symbolic names in related
code paths to eliminate magic numbers, switch to their canonic names.

Reviewed-By: Wolfram Sang <wsa@kernel.org>
2020-08-24 07:57:13 +02:00
v1ne 2755ab36f3 ols: Refactor, deduplicate logic packet code
Reviewed-By: Wolfram Sang <wsa@kernel.org>
2020-08-24 07:57:06 +02:00
v1ne dcdc2848b7 ols: Use symbolic name for "success" error code.
Reviewed-By: Wolfram Sang <wsa@kernel.org>
2020-08-24 07:43:03 +02:00
v1ne 58a75642e9 ols: Make constant names more precise, clarify comment
Reviewed-By: Wolfram Sang <wsa@kernel.org>
2020-08-24 07:33:13 +02:00
v1ne a80bed7656 ols: Rename "flags" to "capture flags".
In the current implementation the "flags" are exclusively used for
captures. Prepare the introduction of device flags by renaming the
capture related flags which are specific to an operation.

Reviewed-By: Wolfram Sang <wsa@kernel.org>
2020-08-24 07:29:03 +02:00
v1ne a2b1a53bb4 ols: Symbolic name for magic value, reflect units in variable names
Reviewed-By: Wolfram Sang <wsa@kernel.org>
2020-08-24 07:26:43 +02:00
v1ne f1a37f3924 ols: Remove stray command
It's nowhere documented and nowhere used.

Reviewed-By: Wolfram Sang <wsa@kernel.org>
2020-08-24 07:26:01 +02:00
v1ne 0ccc6f7cdf ols: Make use of zero-initialization.
No need to assign zero after gmalloc0(). Move comments to declaration.

Reviewed-By: Wolfram Sang <wsa@kernel.org>
2020-08-24 07:24:27 +02:00
Frank Stettner b54d9b4974 libsigrok.h: Fix comment for unit Joule. 2020-08-23 13:10:00 +02:00
Frank Stettner fe8c5aef1f libsigrok.h: Add Joule, Coulomb, and Ah units.
Also extend a comment on energy in comparison to power.
2020-08-22 21:53:56 +02:00
Frank Stettner 82ff704449 libsigrok.h: Add MQ for electric charge. 2020-08-22 21:53:56 +02:00
Frank Stettner f5247d953f teleinfo: Fix measured quantity (energy, not power). 2020-08-22 21:53:39 +02:00
Gerhard Sittig 98b7b08956 output/csv: always generate text for analog/logic data packets
Unconditionally generate output text when a session packet is received
which carries analog or logic sample data. Even if the data gets queued
and is not shown immediately, in that case the output text remains empty
but needs to be present. Otherwise applications may assume that the CSV
output module had not handled the data at all, which would result in
unexpected "screen output" with fallback data being interleaved with the
CSV output.

This resolves bug #1026 in its strictest sense (the unexpected presence
of fallback data). But leaves all other issues mentioned in comment 1.
2020-08-22 19:04:31 +02:00
Gerhard Sittig ce384e074f output/csv: check unsupported/untested input signal conditions
The current implementation of the CSV output module makes assumptions
which don't hold. Which results in incorrect or incomplete output for
some combinations of logic and analog signals.

Check for some of the known problematic conditions, and warn the user
about potentially unexpected results. This is a workaround until the
issues properly get addressed in the implementation.

This is motivated by but does not resolve bug #1026.
2020-08-22 19:00:05 +02:00
Timo Kokkonen 66665b0932 README.devices: Document enabling GW Instek GDM-397 serial output mode. 2020-08-22 09:10:42 +02:00
Timo Kokkonen a3ec8a9aa1 serial-dmm: Add GW Instek GDM-397 meter support.
This meter appears to be rebranded UNI-T UT61B, but with
improved input protection.
2020-08-22 09:10:42 +02:00
Gerhard Sittig e37e301e26 korad-kaxxxxp: add support for forced "detection" of a given model
Korad PSU models are rather popular. But the successful operation of
currently unsupported model names or firmware versions is hard to verify
by users, because building the library from locally modified sources is
involved.

Introduce support for the "force_detect=" scan option. Warning messages
contain how the device identifies itself. Optional user specs can force
the assignment of the driver to the unsupported model. Which results in
reports that include the identification details as well as the successful
use of the device.

  $ sigrok-cli -d korad-kaxxxxp:conn=...:force_detect=KORADKA3005PV2.0 --show
2020-08-22 09:10:29 +02:00
Gerhard Sittig d643e6bc39 hwdriver: introduce SR_CONF_FORCE_DETECT config key (scan option)
Often previously unsupported models might be covered by existing code,
but would not match against a builtin list of known devices.

Introduce a config key which provides a scan option for users to force
the use of a driver with an unsupported device. This increases the
probability of requests for support of an additional model which are
associated with a successful use of that very device, and eliminates
the necessity to build from source for the trivial cases.

It's up to individual drivers whether they support forced detection,
and how they interpret the value of the scan option.
2020-08-22 09:10:29 +02:00
Gerhard Sittig 048250d0e0 korad-kaxxxxp: add config_get() support for SR_CONF_CONN
Let applications query the device instance's conn= key. This lets users
recognize individual devices if multiple of them are connected.

  $ sigrok-cli -d korad-kaxxxxp:conn=/dev/ttyACM0 --show
  ...
  korad-kaxxxxp:conn=/dev/ttyACM0 - Korad KA3005P with 2 channels: V I
  ...
2020-08-22 09:10:29 +02:00
Timo Kokkonen 860ee00ab1 scpi-dmm: Remove SYST:LOC hack for GWInstek meters.
No need for this hack anymymore as there is now DMM_CMD_SETUP_LOCAL
command that can be used to return unit back to "local" mode properly.
2020-08-20 12:48:13 -07:00
Timo Kokkonen 4c80a27284 scpi-dmm: Add new command DMM_CMD_SETUP_LOCAL.
Add new command DMM_CMD_SETUP_LOCAL for setting device back
to "local" mode. If device implmements this command, it is
sent when driver is closed and after device "scan".

Define DMM_CMD_SETUP_LOCAL for GWInstek meters, so they get
returned to local mode automatically after use.
2020-08-20 12:48:00 -07:00
Gerhard Sittig 25879a34e9 scpi-dmm: alpha-sort the list of supported devices (vendor/model list)
Any order is as arbitrary as any other. The alphabetical order of vendor
and model names might be the most robust during maintenance: easiest to
remember, easiest to use when checking for presence, and easiest to add
to or resolve conflicts during merges. Vendor renames (HP to Agilent to
Keysight, et al) are ugly but can't be helped easily.
2020-08-17 20:32:08 +02:00
Gerhard Sittig 33aa8117e3 scpi-dmm: minor style adjustment (gdm906x, analog init, comments, diag)
Address minor style issues: Need not assign NULL after g_malloc0(), need
not check for NULL before g_free(). Rephrase diagnostics messages which
are user visible by default, remove internal development details. Reword
a few comments, and adjust their grammar for consistency across the code
base. The sr_analog_init() routine executed immediately before getting
measurements, need not (re-)assign endianess or floating point details,
except those which do change after initialization (double vs float).
Rephrase model dependent checks for easier adjustment during maintenance.
Unobfuscate string comparisons.
2020-08-17 20:01:02 +02:00
Gerhard Sittig 72cd558d4a scpi: Raise severity when IDN response lacks the serial number field.
Raise the diagnostics message's severity from debug to warn when the
'*IDN?' response lacks the serial number field. Although it has only
been seen for some GWInstek DMMs, it violates the SCPI spec, and more
or other activity is required in a future implementation. This change
amends commit 47e7a6395e.
2020-08-17 19:07:37 +02:00
Gerhard Sittig 6dc0007c71 scpi_serial: Rephrase NL and NL+CR line termination check.
Rearrange the check for line termination in SCPI receive data, and add a
comment in that spot. Keep related conditions together, avoid line breaks
for complex terms. This shall simplify review, and raise awareness during
maintenance. This change amends commit a0ade2f933.
2020-08-17 18:48:50 +02:00
Timo Kokkonen 4e5ff004d8 scpi_serial: Add GW-Instek GPD-9061 (USBCDC mode) VID/PID. 2020-08-17 18:35:17 +02:00
Timo Kokkonen 7eba792f0d udev: Add GW-Instek GDM-9061 VID/PID. 2020-08-17 18:35:17 +02:00
Timo Kokkonen 868fc65ec3 scpi-dmm: Add support for GW-Instek 906X series bench multimeters.
- Add support for GDM-9060 and GDM-9061 DMMs.
2020-08-17 18:35:17 +02:00
Timo Kokkonen d0b602f00f scpi-dmm: Add support for GW-Instek 8200A series bench multimeters.
- Add support for GDM-8251A and GDM-8255A DMMs.
2020-08-17 18:35:17 +02:00
Timo Kokkonen 47e7a6395e scpi: Support devices that omit serial number in *IDN? command responses. 2020-08-17 18:35:17 +02:00
Timo Kokkonen a0ade2f933 scpi_serial: Add support for (broken) devices sending NL+CR terminator.
This allows SCPI code to work with devices that terminate their responses
with NL+CR (instead of usual NL) like some GW-Instek DMMs.
2020-08-17 18:35:17 +02:00
Gerhard Sittig d7df9dc738 serial_hid: add iokit= prefix for the Mac IOKit special case
Rephrase the logic which turns HIDAPI paths returned from enumerations
into something that can be used with conn= device options. Rearrange
code paths and rename variables to hopefully increase readability, and
to prepare support for more conditions in future implementations.

Replace the "IOService:" prefix on recent Mac versions with the "iokit="
literal, to eliminate the previously unhandled colon in path names. This
resolves bug #1586.

Move the allocation of a writable buffer from the callers to the callee,
to simplify multiple call sites, and most of all because the caller need
not be aware of the buffer's required size (input and output size can
differ in either direction).

Update the conn=hid/ section in README.devices, add the iokit= prefix.
2020-08-09 16:09:04 +02:00
Gerhard Sittig 4feb6ec9a2 output/csv: complete and improve timestamp construction support
Unbreak the timestamp calculation when session data is received in
multiple packets. Avoid a division by zero when the samplerate is not
known yet the time column is requested. Only calculate timestamps when
the time column is requested. Use floating point during the scaling,
only convert to integer immediately before printing. Change line breaks
to not split a complex sub-expression across several lines.
2020-08-05 21:03:11 +02:00
Earle F. Philhower, III 01ac3eedfa output/csv: Avoid accumulated timestamp error for odd samplerates
The conversion of sample rates to sample periods and the repeated
addition of truncated values (integer variables) resulted in the
accumulation of errors in the timestamp column for odd samplerate
values. How to reproduce:

  $ sigrok-cli -d demo:analog_channels=0 \
      -c samplerate=6000000 --samples 1200001 \
      -O csv:time=true | tail

Accept the additional cost to reduce the error. Always get the timestamp
in a new calculation based on the sample number and the sample rate.

This addresses bug #1027.

Signed-off-by: Earle F. Philhower, III <earlephilhower@yahoo.com>
[ gsi: rephrased commit message, how to reprodue ]
2020-08-05 20:53:57 +02:00
Timo Kokkonen b81cfbc349 gwinstek-gpd: Add missing SW limits API calls. 2020-08-03 18:54:33 +02:00
Gerhard Sittig d579755a66 sw_limits: add const for limits param for config_get
The sr_sw_limits_config_get() routine exclusively reads the 'limits'
parameter, need not write to it. Add the 'const' attribute.
2020-08-03 17:53:11 +02:00
Gerhard Sittig 0dc27cd1db serial: make failed flush() in open() non-fatal, CP2110 flush() return
Commit cb828f1b3e introduced an unconditional flush() call in the
open() routine's body, and passed its return value in verbatim form to
open() callers. Some of the transports/cables for serial communication
yield the SR_ERR_NA return value. Consider this a non-fatal condition.

Unbreak the CP2110 HID chip's flush() implementation. Don't expect a
return value of 0 from HID write calls, instead expect to see the number
of written bytes for successful calls.

This was tested with ch9325 (UT-D04), cp2110 (UT-D09) and bu86x.
2020-08-01 14:55:20 +02:00
Timo Kokkonen 13726d30b2 gwinstek-gpd: Add support to old (hardware) revision units.
Manufacturer revised hardware design without changing model numbers at some point.
Old units have firmware that behaves differently. Responses are terminated with \r
instead of \n. And STATUS? command response format is different.
2020-08-01 07:19:49 +02:00
Timo Kokkonen 3b316fdca0 gwinstek-gpd: Add support for GPD-3303S. 2020-07-31 14:28:38 +02:00
Gerhard Sittig dc172c38d2 output/ascii: data type nits, rephrase sample bit access
Use size types for counters, unsigned for bit manipulation. Trigger
position needs to remain a signed int (must be possible to go negative
for "not here", and strictly remains within the output text line length,
so should be good).

Rephrase the nested loop during bit extraction from logic packets, and
how a channel's value at a given sample number gets accessed. Eliminate
redundancy in that spot, to improve readability and simplify maintenance.
2020-07-31 11:25:29 +02:00
Gerhard Sittig 31907b76de output/ascii: style nits in name alignment and trigger flush
Unobfuscate the implementation of the recent channel name alignment and
trigger position flush, address other style nits of earlier versions:

Don't need a GString for runtime constant channel names (which also
suffered from a mismatch of declaration and allocation). Don't need to
"construct space" when printf(3) can align the value. Pre-allocate text
buffers with more appropriate length when known in advance. Drop another
unused variable. Eliminate data type redundancy in malloc(3) calls. Make
sure to get zeroed memory, disabled channels can result in assignment
gaps. Use consistent brace style and separate variable declaration from
use (no RAII here).

Excess text line length remains, there has been a lot of it in the
previous implementation. It is left for another commit.

Tested with:

  $ sigrok-cli -d demo:analog_channels=0:logic_channels=4 --samples 40 -O ascii -t D3=r -w
2020-07-31 10:39:50 +02:00
v1ne cc835205cd output/ascii: Also print trigger marker for "short" data lines
The trigger position would be missing in the output text when the number of
available samples is less than the configured text line length. Do flush the
trigger marker for the last chunk of accumulated samples, too.

How to reproduce:

  $ sigrok-cli -d ... --samples 32 -O ascii:width=128

[ gsi: rephrased commit message ]
2020-07-31 10:30:22 +02:00
v1ne 3b93d3c24b output/ascii: Vertically align logic channel names
This results in vertical alignment of sample data and trigger positions.
The implementation assumes that the channel names' byte count corresponds
to the space which they occupy on screen. Channel names with umlauts still
may suffer from misalignment.

[ gsi: rephrased commit message ]
2020-07-31 10:24:43 +02:00
v1ne f64f51b404 output/ascii: Remove unused variable 2020-07-31 10:24:26 +02:00
milan hauth 588295b8b9 analog: avoid double free in '-O analog' shutdown path
Do void the 'def' and 'values' references for '-O analog' module options
in the shutdown path, to avoid double free calls.
2020-07-28 17:07:22 +02:00
Gerhard Sittig 9dde746023 output/srzip: improve robustness (analog-only acquisition)
For pure analog acquisition without logic data the ZIP creation code
path resulted in a division by zero. Skip the bytes to samples math in
that case. How to reproduce:

  $ sigrok-cli -d demo:logic_channels=0:analog_channels=1 --samples 20 -o file.sr

Avoid a dependency on malloc(0) behaviour while we are here. Add a
warning on data feed submitter implementation issues, to not silently
drop the data, which could surprise users. This ShouldNotHappen(TM) for
correct implementations where channel counts and unit size agree, but
was observed with incomplete out-of-tree implementations. Eliminate
a data type redundancy in another malloc() call.
2020-07-27 19:45:46 +02:00
Mike Walters 85cff5cfba scpi-dmm: Add Agilent 34410A. 2020-07-27 01:10:57 +01:00
Wolfram Sang cb828f1b3e serial: flush() after open() in the serial core.
Quite some drivers flush the serial port after opening it. And quite
some don't although they should. Factor this out, so serial_open() will
always flush the port. The removal in the drivers was done with this
small coccinelle script:

@@
struct sr_serial_dev_inst *serial;
@@

        serial_open(serial, ...)
        ... when != serial
-       serial_flush(serial);

and then the results and the unmatched findings of serial_flush() were
audited.

Signed-off-by: Wolfram Sang <wsa@kernel.org>
2020-07-26 16:06:42 +02:00
Gerhard Sittig 3b13990f7d bt: drop bt_put_le16() dependency (not universally available)
Eliminate the dependency on the non-portable bt_put_le16() routine. It
isn't available in all supported BlueZ versions, and won't be available
in other platform backends. Prefer write_u16le() which is available on
all sigrok supported platforms.
2020-07-26 10:47:59 +02:00
Gerhard Sittig f8a8d4bb70 input: use common support to send samplerate meta packet 2020-07-24 20:15:40 +02:00
Gerhard Sittig 9084c39608 input/saleae: reduce the format match routine's greed
Only return OK from the format match routine when either of the tested
conditions reliably matched. Return an error in all other cases. This
avoids that the Saleae module is "winning a contest" due to even the
weakest condition, and then is not able to handle the input file.
2020-07-24 18:40:38 +02:00
Gerhard Sittig d891892dc0 input/saleae: introduce input module for Saleae Logic exported files
Start the implementation of an input module which covers Saleae Logic's
export files. CSV and VCD are handled by other modules, this one accepts
binary exports for Logic1 digital data (every sample, and when changed),
Logic1 analog data, Logic2 digital data, and Logic2 analog data.

The newer file format versions contain header information and can get
auto-detected, the older formats require a user spec. Some of the file
formats lack essential information in the file content, thus require
another user spec (samplerate for digital data is an example).

The .logicdata file format is unknown, and is not supported. The .sal
format could get added later, but requires local file I/O in the input
module, which current common infrastructure does not provide.
2020-07-24 17:21:13 +02:00
Gerhard Sittig daa895cba3 libsigrok-internal: add endianess helpers for floating point types
Extend the common set of endianess conversion helpers. Cover readers and
writers for little endian single and double precision and 64bit integer
values, including support to advance the read/write position.
2020-07-24 17:02:40 +02:00
Gerhard Sittig dd8bec71c2 input/vcd: unbreak the logic which skips a user specified period
Rephrase the default value for the 'skip' option and the detection of a
user specified value. This is tricky because: Sample numbers are kept in
64bit values. Skip and downsample are fed to formulae so we want them
both to be unsigned. Yet absence of a user spec as well as possible user
values 0 and positive must be told apart. Use all-ones for the default
of "-1" which translates to "first timestamp", users need not be able to
specify that negative value.

Make sure to only downsample 'skip' values when the user specified some.
Which avoids the undesired insertion of huge idle gaps at the start of
the capture. An earlier implementation had to check for -1, this recent
version uses an unsigned number in combination with a boolean flag to
achieve this.

Reword some diagnostics messages, and print the samples count between
timestamps while we are here. Add a check for successful text to number
conversion of timestamp values.

How to reproduce:

  $ pulseview -i file.vcd
  $ pulseview -i file.vcd -I vcd:downsample=5
  $ pulseview -i file.vcd -I vcd:skip=111381600

Example file:

  $timescale 1 ns $end
  $scope module top $end
  $var wire 1 ! d1 $end
  $upscope $end
  $enddefinitions $end
  #111381815
  0!
  #111381905
  1!
  #111381990
  0!
  #111382075
2020-07-24 16:10:55 +02:00
Gerhard Sittig c03aaf342c output/srzip: queue samples before ZIP operation
Accumulate samples from multiple session feed packets before sending
them off to ZIP archive operations. This improves throughput for those
setups where acquisition devices or input modules provide only few
samples per session feed send call.

This version also splits large packets from applications into smaller
ZIP members (if the application's packet size is larger than the output
module's local buffer size). If that is not desired, the implementation
needs adjustment to immediately pass larger blocks to ZIP operations
(after potentially flushing previously queued data) instead of looping.

This fixes bug #974.
2020-07-24 09:13:43 +02:00
Gerhard Sittig 8c5bd3d9c7 output/vcd: support analog data, more channels, minor cleanup
Extend and rephrase the VCD output module, to support mixed signal data,
support higher channel counts, and address other minor issues.

Increase the number of VCD identifiers which can get generated. Bump the
limit from 94 to 18346 channels. Prefer single letter names for backwards
compatibility for the first channels. Use two or three letter identifiers
as needed for higher channel counts.

Add support for analog channels, and carefully organize a queue such
that timestamps and their data only get written after input data for
_all_ channels was received from the session feed. Provide IEEE754
double precision values for maximum compatibility with other VCD aware
software, although sigrok internally passes analog data with single
precision. This makes potential later adjustment transparent to external
software.

Factor out and rephrase code while we are here. This implementation
avoids glib calls where they'd hurt performance. A local pool reduces
malloc() pressure to increase throughput. String manipulation is tuned
for simplicity and reduced cost. Special code paths were added to tune
the use cases where mixed signals are not involved (immediate write to
the output text, bypassing the output module's local queue).

An srzip input implementation detail still makes the VCD output consume
lots of memory during merge sort of channels' data. See bug #1566.

Other nits got addressed in bypassing: Adjust data types. Separate the
gathering of detail information and the construction of the VCD header
text to simplify review and future maintenance. Skip VCD identifiers for
disabled channels. Emit a final timestamp to flush the last sample, and
communicate the total capture length.

Update comments. Update the copyright for recent non-trivial changes.
2020-07-24 09:10:27 +02:00
Gerhard Sittig 0ab36d2f54 input/vcd: rework VCD file import logic (vector, integer, real)
Extend and rework the VCD input module: accept more data types, improve
usability, fix known issues.

Add support for bit vectors (arbitrary width), multi-bit integer values
(absolute 64bit width limit, internal limitation to single precision),
and floating point numbers ('real' in VCD, single precision in sigrok).
Unfortunately sigrok neither has concepts of multi-bit logic channels
nor IEEE-1364 stdlogic values, the input module maps input data to
strict boolean and multiple logic channels. A vector's channels are
named and grouped to reflect their relation. VCD 'integer' types are
mapped to sigrok analog channels. Add support for scoped signal names,
and the re-use of one VCD signal name for multiple variables.

Rework file and text handling. Only skip pointless UTF-8 BOMs before
file content (not between sections). Handle lack of line termination at
the end of the input file. Process individual lines of input chunks,
avoid glib calls when they'd result in malloc pressure, and severely
degrade performance. Avoid expensive string operations in hot loops.

Rearrange the order of parse steps, to simplify maintenance and review:
end of section, new section, timestamp, data values, unsupported. Flush
previously queued values in the absence of a final timestamp. Unbreak
$comment sections in the data part. Apply stricter checks to input data,
and propagate errors. Avoid silent operation (weak warnings can go
unnoticed) which yields results that are unexpected to users. Unbreak
the combination of 'downsample' with 'skip' and 'compress'. Reduce noise
when users limit the number of channels while the input file contains
more data (keep a list of consciously ignored channels). Do warn or
error out for serious and unexpected conditions.

Address minor issues. Use common support for datafeed submission. Keep
user specified options across file re-load. Fixup data type nits, move
complex code blocks into separate routines. Sort the groups of routines,
put helpers first and concentrate public routines at the bottom. Extend
the builtin help text. Update comments, update the copyright for the
non-trivial changes.

Fixes bug #776 by adding support for bit vectors.
Fixes bug #1476 by flushing most recently received sample data.
2020-07-24 09:10:27 +02:00
Gerhard Sittig 47a102f9bb input: introduce helper for buffered submission of sample data
Input modules often find themselves in the situation where sample data
was received and could be sent to the session bus, but submission should
get deferred to reduce the number of send calls and provide larger data
chunks in these calls. Introduce common support code for buffered sample
data submission (both logic and analog), provide a simple alloc, submit,
flush, and free API.
2020-07-24 09:10:27 +02:00
Gerhard Sittig cb0fedd942 input/binary: align sr_session_send() chunks to unit size
The input/binary module chops raw input data into chunks and sends these
to the session feed. The total size of input chunks got aligned to the
unit size, the session feed output didn't. Make sure to align session
packets with the input data's unit size, too.

This fixes bug #1582.
2020-07-23 21:59:29 +02:00
Uwe Hermann 339d12df97 bindings/ruby: Bump minimum requirement to Ruby 2.5.0.
This version is known to work with the current code-base and recent
SWIG versions, whereas e.g. Ruby 2.3.x is known to not work (anymore).

This "fixes" the remaining parts of bug #1526.
2020-07-18 17:37:17 +02:00
Soeren Apel 5f8cf332a6 fx2lafw: Use 1 as default for frame limit and reset num_frames 2020-07-13 23:07:56 +02:00
Valentin Ochs bfc34b9ab0 fx2lafw: Add support for frames
When using a number of frames that is not 1, the driver will read
samples up to its limit and then wait for another trigger. This will be
repeated until the configured number of frames has been finished.
2020-07-13 23:07:56 +02:00
motte f5083435cb Korad-kaxxxxp: Add model Tenma 72-2550 2020-07-13 15:46:06 +02:00
Valentin Ochs 34ce4d8258 Fix #1576 by handling DSO1000B's CHAN#:PROB? responses 2020-07-12 23:30:20 +02:00
Valentin Ochs e434f624ba serial-lcr: Allow retrieving frame limit 2020-07-12 20:38:36 +02:00
Valentin Ochs 1b8a37c688 rigol-ds: Allow retrieving frame limit 2020-06-27 22:57:10 +02:00
Valentin Ochs 50bc52f3a6 hantek-dso: Allow retrieving frame limit 2020-06-27 22:56:57 +02:00
Valentin Ochs 98c7ef378c hameg-hmo: Allow retrieving frame limit 2020-06-27 22:56:39 +02:00
Valentin Ochs 7c48d434f0 gwinstek-gds-800: Allow retrieving frame limit 2020-06-27 22:56:10 +02:00
Andy Lutomirski 025bd56f10 scpi_usbtmc_libusb: Retry if a Bulk-IN request starts with an empty packet
This seems to make the Rigol DS1054Z work.  It's still a bit janky --
on a live capture, sample 688 (zero-based) out of the 1200-sample
frame seems to consistently contain garbage.  I'm not sure what's
going on.
2020-06-25 00:03:24 +02:00
Andy Lutomirski e2283318c1 scpi_usbtmc_libusb: Check that bulk in requests read the entire header
The Rigol DS1054Z sometimes returns zero bytes in response to a bulk in
request.  sigrok ends up reading out of bounds and failing ungracefully
when this happens.  Check that libusb returned a full USBTMC header and
fail gracefully if it did not.
2020-06-25 00:03:24 +02:00
Andy Lutomirski 6999029585 rigol-ds: Improve short block handling
When a short block is received, clean up the header state so that the
next block can be read.

Based on a patch for #1011 by Aleksander Alsekseev.
2020-06-25 00:03:24 +02:00
Valentin Ochs 16e96ca3af rigol-ds: Send some commands on 1st frame only
This can speed up reading of multiple segments by a factor 2 (9s vs 18s
when reading 5 frames with 2 channels and 7 kSa)
2020-06-24 23:58:17 +02:00
Valentin Ochs 06ed999aa4 rigol-ds: Experimental support for segmented data with PROTOCOL_V3 models 2020-06-24 23:56:01 +02:00
Valentin Ochs 19f31c8ace rigol-ds: Experimental support for V5 frame reading 2020-06-24 23:56:01 +02:00
Valentin Ochs 8cbe5339b1 rigol-ds: Add support for reading segmented data for protocol v4 2020-06-24 23:56:01 +02:00
Valentin Ochs 704910e32c rigol-ds: Fix reading data from internal memory
According to the programming manual, one should issue

    :WAV:RES
    :WAV:BEG

before reading data from internal memory. Without this, the wrong data
will be returned.
2020-06-24 23:56:01 +02:00
Valentin Ochs 1cbb3b1cfb rigol-ds: Get correct samplerate for Memory and Segmented sources
Read it at the start of acquisition. This prevents requests for
the SR from interfering with ongoing transfers.

This fixes bug #1217.
2020-06-24 23:56:01 +02:00
Valentin Ochs 418c99248c rigol-ds: Do not stop reading after the first frame 2020-06-24 23:56:01 +02:00
Wolfram Sang 9b09360654 std: avoid doube close
I want to fix this double-close issue I see with my OLS:

First close at the end of a 'scan':

sr: [00:00.045171] openbench-logic-sniffer: Got metadata key 0x00, metadata ends.
sr: [00:00.045178] openbench-logic-sniffer: Disabling demux mode.
sr: [00:00.045186] serial: Closing serial port /dev/ttyACM0.

Second one as part of hwdriver cleanup:

sr: [00:00.046088] hwdriver: Cleaning up all drivers.
sr: [00:00.046108] serial: Closing serial port /dev/ttyACM0.
sr: [00:00.046116] serial-libsp: Cannot close unopened serial port /dev/ttyACM0.

So, before closing a second time, check if the device is not idle.

I am optimistic this could fix bugs #1151 and #1275, too.

Signed-off-by: Wolfram Sang <wsa@kernel.org>
2020-06-24 23:20:41 +02:00
Walter Goossens 8b58a519e4 korad-kaxxxxp: Add KA3005P v5.5
Signed-off-by: Walter Goossens <waltergoossens@creative-embedded.com>
2020-06-20 21:54:07 +02:00
Uwe Hermann 856433b26e Revert "bindings/ruby: Disable Ruby bindings until we have a fix for #1526."
This reverts commit 49d130200d.

The Ruby bindings build has been fixed now.
2020-06-20 18:09:51 +02:00
Anatol Pomozov 2e199405e5 bindings/ruby: Fix ruby SWIG bindings generation
bindings/swig/doc.py generates a swig interface file for ruby bindings
that includes docstrings with comments braces ( /* and */ ) like this:

  %feature("docstring") sigrok::Channel::type "/* Type of this channel. */\n";
  %feature("docstring") sigrok::Channel::enabled "/* Enabled status of this channel. */\n";

SWIG generates *.cxx and adds its own braces to the docstring:

/*/* Document-class: Sigrok::Error
Exception thrown when an error code is returned by any libsigrok call. */
*/

this causes compilation error for Ruby bindings.

To fix the error we should not add extra braces to the docstring.
With this patch libsigrok compiles fine with with ruby 2.7 and swig 4.0.2.

Fixes bug #1526

Signed-off-by: Anatol Pomozov <anatol.pomozov@gmail.com>
2020-06-20 18:09:27 +02:00
Wolfram Sang 35be304ba6 openbench-logic-sniffer: improve error messages when scanning ID
- always say 'ID' when the ID command failed
- print hexdump of a faulty ID because on a stalled device we may get
  0x00 bytes which would terminate the string early.

Signed-off-by: Wolfram Sang <wsa@kernel.org>
2020-06-13 23:55:34 +02:00
Florian Schmidt 3f48ab0282 kingst-la2016: improved bitstream upload and fix for v3.4.2
of vendor's bitstream.
is now tested to work with version 3.4.0 and 3.4.2.

[fixes #1559]
2020-06-08 23:49:29 +02:00
Uwe Hermann 36962abf53 udev: Add Kingst LA2016 VID/PID. 2020-06-07 00:48:29 +02:00
Uwe Hermann b2b6dd55ec kingst-la2016: Use ARRAY_SIZE. 2020-06-07 00:48:29 +02:00
Florian Schmidt f2cd2debf9 kingst-la2016: tested with idVendor=77a1, idProduct=01a2 2020-06-07 00:48:24 +02:00
Andreas Sandberg cae33a5874 rdtech-tc: Add initial support for the RDTech TC66C
This changeset adds support for the RDTech TC66C USB power meter.

Currently, the driver reports the following channels:
  * V: VBus voltage
  * I: VBus current
  * D+: D+ voltage
  * D-: D- voltage
  * E: Energy consumed in threshold-based recording mode.

The number of significant digits shown for each channel has been set
to match the number of digits shown on the device.

Usage example:

sigrok-cli -d rdtech-tc:conn=/dev/ttyACM0 --scan

Known issues:

  * BLE support is currently unimplemented. This uses a different
    command set, but the same poll data format.

Kudos to Ben V. Brown for reverse engineering some of the protocol and
documenting the encryption key used for poll data.

Signed-off-by: Andreas Sandberg <andreas@sandberg.pp.se>
2020-06-05 00:25:26 +02:00
Uwe Hermann 219c63ea1b src/crc.c: Add missing file. 2020-06-05 00:25:26 +02:00
Andreas Sandberg 4ea012bdf5 crc: Factor out CRC16 implementation from Modbus
Being able to calculate a CRC16 is useful in multiple places, factor
this into a new module with CRC implementation. This module currently
only supports ANSI/Modbus/USB flavor of CRC16.

Signed-off-by: Andreas Sandberg <andreas@sandberg.pp.se>
2020-06-05 00:25:26 +02:00
Andreas Sandberg 8b607a24e7 rdtech-um: Add initial support for the RDTech UMxx series
This changeset adds support for the RDTech UMxx series of USB power
meters. The driver has been tested with the RDTech UM24C, but should
support the UM24C, UM25C, and the UM34C.

Currently, the driver reports the following channels:
  * V: VBus voltage
  * I: VBus current
  * D+: D+ voltage
  * D-: D- voltage
  * T: Device temperature
  * E: Energy consumed in threshold-based recording mode.

The number of significant digits shown for each channel has been set
to match the number of digits shown on a UM24C.

Missing features:

  * There is currently no support for configuring threshold-based
    recording from sigrok, but this can be done on the device itself.

  * Fast charging mode currently not logged.

Usage example:

sigrok-cli -d rdtech-um:conn=bt/rfcomm/MAC --scan
sigrok-cli -d rdtech-um:conn=/dev/rfcomm0 --scan

Known issues:

  * When using sigrok's Bluetooth transport implementation, the device
    is disconnected between probing and sampling. Some devices (e.g.,
    the UM24C), dislikes this and can't be reconnected reliably for
    sampling. This is not an issue when setting up a rfcomm device
    manually and using it as a serial port.

Kudos to Sven Slootweg for documenting most of the protocol.

Signed-off-by: Andreas Sandberg <andreas@sandberg.pp.se>
2020-06-05 00:25:26 +02:00
Uwe Hermann ef2196712c binary_helpers: Drop unnecessary malloc check.
(as per HACKING)
2020-06-05 00:25:26 +02:00
Andreas Sandberg 18698b40d1 binary_helpers: Add helper for devices with binary data
Many devices receive a struct with binary values when polled. Many of
these values will correspond channels in sigrok. This
change introduces helper functions for automatically reading and
scaling such values and sending them down a sigrok analog channel.

Signed-off-by: Andreas Sandberg <andreas@sandberg.pp.se>
2020-06-05 00:07:30 +02:00
Andreas Sandberg 0cc3d090b7 libsigrok.h: Add SR_MQ_ENERGY 2020-06-04 23:13:43 +02:00
Gerhard Sittig cbfaf5e073 uni-t-ut181a: comment on how to start a recording
The meter allows remote controlled start of recordings, but requires a
few parameters where it's uncertain how to most appropriately get these
by means of SR_CONF_* keys.

Introduce SR_CONF_SET support for SR_CONF_DATALOG to raise awareness,
but leave the implementation empty for now. Leave a TODO comment which
discusses the meter's commands that one might want to use from here.
2020-06-01 18:35:05 +02:00
Gerhard Sittig ebc5110989 uni-t-ut181a: implement device driver for the UNI-T UT181A multimeter
Extend the previously introduced skeleton driver for UNI-T UT181A. Introduce
support for the full multimeter's protocol as it was documented by the ut181a
project. Which covers the retrieval of live readings, saved measurements, and
recordings, in all of the meter's modes and including relative, min/max, and
peak submodes. This implementation also parses compare mode (limits check)
responses, although it cannot express the result in terms of the session feed.

Announce the device as a multimeter as well as a thermometer, it supports
up to two probes including difference mode. When in doubt, prefer usability
over feature coverage (the driver side reflects all properties of the meter,
but not all features can get controlled by the driver). The probe routine
requires that users specify the serial port, and enable serial communication
on the meter.

Several TODO items remain. Comments in the driver code discuss limitations
of the current implementation, as well as cases where the meter's features
don't map well to sigrok's internal presentation. This implementation also
contains (optional, off by default) diagnostics for research on the serial
protocol.
2020-06-01 18:35:05 +02:00
Gerhard Sittig 3094e9d8ca uni-t-ut181a: Initial driver skeleton. 2020-06-01 18:35:05 +02:00
Gerhard Sittig 5cc292b34a asix-sigma: discuss usability of data pattern trigger specs
When data patterns for trigger specs span multiple bits, users may not
want to specify long lists of "<ch>=<lvl>" conditions for sigrok-cli's
--trigger option, and count channels by hand. Or click a dozen dialogs
to specify one data pattern, or modify a previous specification. Setups
with few traces may accept that, "data heavy" setups like parallel data
or address bus inspection may not.

Add comments which discuss the potential use of SR_CONF_TRIGGER_PATTERN.
Outline a syntax which may be flexible enough _and_ acceptable to users,
support data patterns and edge triggers alike, in several presentations
that serve different use cases.  This commit exclusively adds comments,
does not change behaviour.

Update a comment in the user spec to internal format trigger spec parser
to expand on hardware constraints and implementation limitations. Rename
an identifier which checks the number of edge conditions, not the number
of accepted trigger spec details.
2020-05-31 23:56:40 +02:00
Gerhard Sittig e092671365 asix-sigma: unconditionally re-enable trigger support code
Trigger support became operational again. Drop the compile time switch
which disabled the previously incomplete implementation.

This resolves bug #359.
2020-05-31 23:56:16 +02:00
Gerhard Sittig f14e6f7e1a asix-sigma: complete and extend capture mode supervision
Parse trigger specs early when acquisition starts, timeout calculation
needs to reflect on it. Either immediately start an acquisition timeout
for trigger-less configurations. Or prepare a timeout which spans the
post-trigger period, but only start its active period when the trigger
match was detected by the device's hardware.

Extend mode tracking during acquisition to handle other special cases.
Terminate acquisition when the user specified sample count limit exceeds
the hardware capacity, or when no limits were specified and the device's
memory is exhausted.

There is a slight inaccuracy in this approach, but the implementation
fails on the safe side. When both user specified limits and triggers are
involved, then at least the user specified time or sample count span is
provided. Usually more data is sent to the session feed, and all of the
requested period is covered. This is because of the software poll period
and the potential to start the timeout slightly late. As well as having
added some slack for hardware pipelines in the timeout calculation.
2020-05-31 23:53:42 +02:00
Gerhard Sittig debe1ff66d asix-sigma: download sample memory in multiple receive calls
The previous implementation ran the complete sample memory retrieval
in a single call to the receive callback. Which in combination with
slow USB communication and deep memory could block application logic
for rather long periods of time.

Rephrase the download_capture() routine such that it can spread its
workload across multiple invocations. Run the acquisition stop and
resource allocation for the download, the interpretation of a set of
DRAM lines, and the resource cleanup, as needed. And keep calling the
download routine until completion of the interpretation of the sample
memory region of interest. The workload size per invocation may need
more adjustment.

The previous implementation could stall UI progress for some 20-30s.
This change lets users perceive UI progress while sample memory gets
retrieved and interpreted.

This resolves bug #1005.
2020-05-31 23:52:24 +02:00
Gerhard Sittig 914f8160e7 asix-sigma: drop obsolete "trigger countdown" in sample interpretation
Recent commits added "position tracking" for interesting spots in the
sample stream and the current iteration pointer. Which obsoletes the
counters for remaining items until trigger, the "triggered here" flags,
as well as the unfortunate "rewind a little" workaround which lacked a
comment on its motivation or implementation details.
2020-05-31 23:51:23 +02:00
Gerhard Sittig 8a72362505 asix-sigma: re-enable software check for exact trigger position
The hardware provided trigger match location is inaccurate. Do check
sample values against the initial trigger condition spec for a short
range of the retrieved sample data, to refine the trigger marker's
position which is sent to the session feed.

Temporarily ignore the optional sample count limit for trigger-using
acquisitions, to reduce the diff size and simplify review. Since the
hardware transparently compresses sample data, we cannot reliably
determine where to start the download and interpretation of sample data,
and the submission to the session feed. Starting early in the sample
memory content, and sticking with the strict sample count limit, could
clip submission before the actual trigger position.

This implementation provides _at least_ the requested amount of data,
and does cover the spot of interest (the trigger position). This, and
the trigger support's having become operational again, is considered an
important improvement. The inaccuracy is considered acceptable for now.
Trigger-less acquisition does enforce the exact sample count limit.
2020-05-31 23:49:35 +02:00
Gerhard Sittig 66d1790cc0 asix-sigma: rephrase sample memory iteration position and trigger check
Rephrase how the sample memory iteration position gets tracked, increment
after every event slot already. Update the "last seen sample" status more
often (an event slot can hold several sample items). Arrange for a period
of time where software will check sample data for trigger matches. This
improves the precision of the hardware provided trigger match location.

Do send hardware provided trigger locations to the session feed even if
the software check found no match on the data content. This covers user
initiated button presses (which can unblock the acquisition when the
application provided trigger condition never matches).

Note that this implementation does manage the window of supervision, but
does not yet check the sample values against the trigger condition. This
gets added later.
2020-05-31 23:46:21 +02:00
Gerhard Sittig 16a5d5ac7d asix-sigma: rework outer sample download loop (DRAM lines iteration)
Factor USB data transfer out of the code path which interprets sample
memory content. Keep internal state of sample memory download in the
device context. This eliminates local variables, and ideally allows a
future implementation to spread chunked downloads across several read
callbacks, which would improve UI responsiveness.

Update comments while we are here. Address minor portability nits (ull
suffix vs UINT64_C macro). The inner loops (iterating clusters and their
events which contain individual samples) are not affected by this commit.
2020-05-31 23:45:29 +02:00
Gerhard Sittig 1385f791b0 asix-sigma: more trigger LUT download rephrase, think 16bit entities
Further rephrase the sigma_write_trigger_lut() routine. It's helpful to
"think" in BE16 quantities to improve readability of LUT address and
parameter downloads. Better matches the vendor's documentation. Also use
a better name for the "trigger select 2" register content.
2020-05-31 23:44:56 +02:00
Gerhard Sittig ee5cef7103 asix-sigma: concentrate more sample memory interpretation params
Start moving parameters into the device context which are related to the
interpretation of sample memory content. This can simplify error paths,
allow to release resources late. And ideally sample memory download and
interpretation could spread across several receive callbacks, improving
UI responsiveness. Also makes total and current dimensions available to
deeper nesting levels in the interpretation, which currently don't have
access to these details.
2020-05-31 23:44:29 +02:00
Gerhard Sittig de4c29fa91 asix-sigma: concentrate parameters for sample memory interpretation
Create a sub struct in the device context which keeps those parameters
which are related to sample memory interpretation. Which also obsoletes
the 'state' struct and only leaves the 'state' enum as a remainder.

Use the "samples per event" condition instead of the samplerate when
extracting a number of samples from an event's storage. Rename the
de-interleaving routines to better reflect their purpose.
2020-05-31 23:44:09 +02:00
Gerhard Sittig ea57157d0d asix-sigma: force strict boolen arith in LUT item manipulation
Mechanically adjust the add_trigger_function() routine to address nits,
attempt to improve maintainability.

Raise awareness of the fact that strict binary arithmetics is done (bit
operators are used), the strict 0..1 set of values needs to be enforced,
and mere "logical truthness" is not good enough in this spot. Explicitly
check for bit positions instead of "shifting out" the bit of interest
and have the 0/1 value result nearly by coincidence.

Extend comments. Group related instructions and separate them from other
groups. Reduce the scope of the rather generic i, j, tmp named variables
which are just too easy to get wrong.
2020-05-31 23:43:17 +02:00
Gerhard Sittig 3f5f548410 asix-sigma: use more helpers for bit mask creation
Rename macros to better reflect which of them check a bit position, and
which span a bit field of given width. Adjust more call sites to use the
macros. This takes tedium out of maintenance as well as review. Has the
minor benefit of somewhat shortening text lines, and eliminating nested
parentheses (or getting perceived as if it would).
2020-05-31 23:42:53 +02:00
Gerhard Sittig 156b6879e9 asix-sigma: rephrase limits management, use sub structure
Move the acquisition limits related variables into a sub struct within
the device context. Over time they became numerous, and might grow more
in the future.
2020-05-31 23:42:32 +02:00
Gerhard Sittig fb65ca09b7 asix-sigma: track whether triggers were specified when acquisition started
There are several separate conditions which the driver needs to tell
apart. There is a compile time switch whether trigger support shall be
built in. There is the condition whether acquisition start involved a
user provided trigger spec. And there is the hardware flag whether a
previously configured trigger condition matched and where its position
is.

Only accept user provided trigger specs when trigger support is builtin.
(The get/set/list availability and spec passing is done in applications
outside of the library, we better check just to make sure.) Only setup
the trigger related hardware parameters when a spec was provided. Only
check for trigger positions when the hardware detected a match.
2020-05-31 23:41:40 +02:00
Gerhard Sittig 8a57728d0e asix-sigma: enable trigger support code (development HACK)
Enable the compile time option which builds trigger support code into
the asix-sigma driver. This is a development hack. Trigger support in
the driver is incomplete and currently not operational.
2020-05-31 23:41:23 +02:00
Gerhard Sittig 3d9373af2e asix-sigma: data type nits, minor variable renames
Address remaining data type nits. Use more appropriate types for sizes
and counters and indices, as well as for booleans.

Prefer more verbose variable names in a few spots to avoid the rather
generic 'i' symbol, especially in complex code paths with deeply nested
flow control or with long distances between declaration and use. Re-use
an existing buffer in the acquisition start for command sequences which
setup trigger in/out as well as clock parameters.

Introduce some variables which may seem unnecessary. But these are
useful for research during maintenance.

This is a mechanical adjustment, behaviour does not change.
2020-05-31 23:41:06 +02:00
Gerhard Sittig 53c8a99c41 asix-sigma: prepare configuration re-use across sigrok sessions
Introduce the required infrastructure to store successfully applied
configuration data in hardware registers. This lets the probe phase of
the next sigrok session pick up where the previous session left. Which
improves usability, and increases performance by eliminating delays in
the acquisition start, by not repeating unnecessary firmware uploads.

The vendor documentation suggests there would be FPGA registers that are
available for application use ("plugin configuration"). Unfortunately
experiments show that registers beyond address 0x0f don't hold the data
which was written to them. As do unused registers in the first page. So
the desirable feature is not operational in this implementation. There
could be different netlist versions which I'm not aware of, or there
could be flaws in this driver implementation. This needs more attention.
2020-05-31 23:40:19 +02:00
Gerhard Sittig 8bd4dc8799 asix-sigma: nits in the hardware configuration declaration
Stop assuming that C language variables whould have a specific memory
layout that applications could rely on. Use normal data types in higher
abstraction layers, drop non-portable bit fields. Use existing macros
for the creation of bit masks of a given width.
2020-05-31 23:39:55 +02:00
Gerhard Sittig 17ed72cc44 sw_limits: start msec timeout period only after start() call
When application code used the common SW limits API, the call sequence
of init() then set() then check() already kept expiring, which is rather
unexpected. The timeout period should only start when start() is called,
check() should not signal expiration before the start() call.

The specific use case is the combination of an msecs timeout and capture
ratio when triggers are used. The post-trigger period only starts when
the trigger match was seen, even though its length is already known when
the acquisition starts. It's desirable to run the start() call for the
post-trigger timeout late, and not terminate the acquisition before the
trigger match.
2020-05-31 23:39:28 +02:00
Gerhard Sittig dbb3e2ad3d serial: accept bitrate only serialcomm= spec, default to 8n1 frames
The previous implementation considered both the UART bitrate and the
frame format mandatory, users had to specify "/8n1" as well just to
change the bitrate.

This commit makes the frame format optional, and defaults to 8n1 which
is so popular these days. When specified, the frame format still needs
to preceed the other optional flow and handshake flags, for maximum
backwards compatibility, and equal robustness in the process of parsing
serialcomm= specs.

Unfortunately device drivers cannot specify their preferred or default
UART frame format. Which means that users still need to provide these
when a device does not use 8n1. This is not a regression, the previous
implementation always needed the frame format spec.
2020-05-31 23:39:19 +02:00
Gerhard Sittig 7718f3ca8f asix-sigma: update comment on channel names (vendor doc says "1-16")
Eliminate doubt from a comment on ASIX SIGMA's channel names which was
introduced in commit d261dbbfcc. Publicly available documentation does
agree their names start at "1" and go up to "16".
2020-05-29 08:06:18 +02:00
Gerhard Sittig 2d8a508976 asix-sigma: add support for external clock
The 50MHz netlist supports the use of an external clock. Any of the 16
channels can use any of its edges to have another sample taken from all
the other pins. It's nice that the hardware does track timestamps, which
results in an exact reproduction of the input signals' timing with 20ns
resolution, although the clock is externally provided and need not have
a fixed rate.
2020-05-29 08:06:18 +02:00
Gerhard Sittig 16791da9c9 asix-sigma: more trigger spec to register values conversion sync with doc
Rephrase more parts of sigma_build_basic_trigger() to closer match the
vendor documentation. Use the M3Q name. Be explicit about "parameters"
setup (even if that means to assign zero values, comments help there).
Using three BE16 items for the parameters improves readability.
2020-05-29 08:06:18 +02:00
Gerhard Sittig 7dd766e0aa asix-sigma: rephrase trigger LUT creation (mechanical change)
Rephrase the sigma_build_basic_trigger() and build_lut_entry() routines
to hopefully improve readability. Avoid the use of short and generic
identifiers which are just too easy to confuse with each other and the
1 literal and negation operator in deeply nested loops and complex
expressions that span several text lines. Reduce indentation where
appropriate. Concentrate initialization and use of variables such that
reviewers need less context for verification.

This is a purely mechanical change, the function of triggers remains
untested for now. Setting "selres" in that spot is suspicious, too.
2020-05-29 08:06:18 +02:00
Gerhard Sittig 72ea3b84bd asix-sigma: rephrase trigger LUT upload to hardware for readability
Rephrase the sigma_write_trigger_lut() routine to work on "a higher
level" of abstraction. Avoid short and most of all generic variable
names. Use identifiers that are closer to the vendor documentation.
2020-05-29 08:06:18 +02:00
Gerhard Sittig 0f017b7da9 asix-sigma: rephrase and extend register access for readability
Reduce the probability of errors during maintenance, and also increase
readability. Replace open coded nibble extraction and bit positions by
accessor helpers and symbolic identifiers. Adjust existing math where it
did not match the vendor documentation. Always communicate 8bit register
addresses, don't assume that application use remains within a specific
"page". Provide more FPGA register access primitives so that call sites
need not re-invent FPGA command sequence construction. Remove remaining
open coded endianess conversion in DRAM access.
2020-05-29 08:06:18 +02:00
Gerhard Sittig 419f109505 asix-sigma: rephrase firmware dependent param upload at acquisition start
The 100/200MHz supporting FPGA netlists differ in their register set
from 50MHz netlists. Adjust the parameter download at acquisition start.

Raise awareness of the "TriggerSelect" and "TriggerSelect2" difference
(the former only exists in 50MHz netlists, the latter's meaning differs
between firmware variants). "ClockSelect" semantics also differs between
netlists. Stop sending four bytes to a register that is just one byte
deep, channel selection happened to work by mere coincidence.

Eliminate a few more magic numbers, unobfuscate respective code paths.
Though some questions remain (trigger related, not a blocker for now,
needs to get addressed later).
2020-05-29 08:06:18 +02:00
Gerhard Sittig abcd477196 asix-sigma: keep remaining samplerate handling in protocol.c
Make the list of supported samplerates an internal detail of the
protocol.c source file. Have the api.c source file retrieve the list
as well as the currently configured value by means of query routines.

Ideally the current rate could get retrieved from hardware at runtime.
A future driver implementation could do that. This version sticks with
the lowest supported rate, as in the previous version.
2020-05-29 08:06:18 +02:00
Gerhard Sittig a426f74aca asix-sigma: cosmetics, sort protocol.h function groups
Sort "semi public" routines and "global data" of the asix-sigma driver
in the protocol.h header file by their use. Add comments. This improves
maintenance of the driver source.
2020-05-29 08:06:18 +02:00
Gerhard Sittig 7fe1f91f75 asix-sigma: prepare FTDI open/close for "optional open"
Move all of the FTDI connection handling from api.c to protocol.c, and
prepare "forced" and "optional" open/close. This allows future driver
code to gracefully handle situations where FPGA registers need to get
accessed, while the caller may be inside or outside the "opened" period
of the session. This is motivated by automatic netlist type and sample
rate detection, to avoid the cost of repeated firmware uploads.
2020-05-29 08:06:18 +02:00
Gerhard Sittig 88a5f9eabe asix-sigma: improve error propagation, increase robustness
Detect more error conditions, and unbreak those code paths where wrong
data was forwarded. It's essential to tell the USB communication layer,
sigrok API error codes, and glib mainloop receive callbacks apart. Since
the compiler won't notice, maintainers have to be extra careful.

Rephrase diagnostics messages. The debug and spew levels are intended
for developers, but the error/warn/info levels will get presented to
users, should read more fluently and speak from the application's POV.
Allow long text lines in source code, to not break string literals which
users will report and developers need to search for (this matches Linux
kernel coding style).

This commit also combines the retrieval of sample memory fill level,
trigger position, and status flags. Since these values span an adjacent
set of FPGA registers. Which reduces USB communication overhead, and
simplifies error handling. The helper routine considers the retrieval
of each of these values as optional from the caller's perspective, to
simplify other use cases (mode check during acquisition, before sample
download after acquisition has stopped).

INIT pin sensing after PROG pin pulsing was reworked, to handle the
technicalities of the FTDI chip and its USB communication and the FTDI
library which is an external dependency of this device driver. Captures
of USB traffic suggest that pin state is communicated at arbitrary times.
2020-05-29 08:06:18 +02:00
Gerhard Sittig 5c231fc466 asix-sigma: style nits, expression complexity, information locality
Address minor style nits to improve readability and simplify review. The
sizeof() expressions need not duplicate data type details. Concentrate
the assignment to, update of, and evaluation of variables in closer
proximity to reduce potential for errors during maintenance. Separate
the gathering of input data and the check for their availability from
each other, to simplify expressions and better reflect the logic's flow.
2020-05-29 08:06:18 +02:00
Gerhard Sittig 9334ed6ccd asix-sigma: update copyright notice for recent non-trivial changes 2020-05-29 07:50:33 +02:00
Gerhard Sittig 2a62a9c44e asix-sigma: more u16 sample memory access nits (timestamps, values)
Further "flatten" the DRAM layout's declaration for sample data. Declare
timestamps and sample data as uint16_t, keep accessing them via endianess
aware conversion routines. Accessing a larger integer in smaller quantities
is perfectly fine, the inverse direction would be problematic.
2020-05-29 07:50:33 +02:00
Gerhard Sittig a53b8e4d74 asix-sigma: improve robustness of parameter upload to hardware
Keep application data in its logical presentation in C language struct
fields. Explicitly convert to raw byte streams by means of endianess
aware conversion helpers. Don't assume a specific memory layout for
C language variables any longer. This improves portability, and
reliability of hardware access across compiler versions and build
configurations.

This change also unobfuscates the "disabled channels" arithmetics in
the sample rate dependent logic. Passes read-only pointers to write
routines. Improves buffer size checks. Reduces local buffer size for
DRAM reads. Rewords comments on "decrement then subtract 64" during
trigger/stop position gathering. Unobfuscates access to sample data
after download (timestamps, and values). Covers a few more occurances
of magic numbers for memory organization.

Prefer masks over shift counts for hardware register bit fields, to
improve consistency of the declaration block and code instructions.
Improve maintenability of the LA mode initiation after FPGA netlist
configuration (better match written data and read-back expectation,
eliminate magic literals that are hidden in nibbles).
2020-05-29 07:50:33 +02:00
Gerhard Sittig 9b4d261fab asix-sigma: style nits, devc in routine signatures, long text lines
Move the 'devc' parameter to the front in routine signatures for the
remaining locations which were not adjusted yet. Reduce indentation of
continuation lines, especially in long routine signatures. Try to not
break string literals in diagnostics messages, rephrase some of the
messages. Massage complex formulae for the same reason.

Whitespace changes a lot, word positions move on text lines. See a
corresponding whitespace ignoring and/or word diff for the essence of
the change.
2020-05-29 07:50:23 +02:00
Gerhard Sittig b65649f6b9 asix-sigma: reword list of sample rates, (try to) use 1/2/5 steps
The driver got extended in a previous commit to accept any hardware
supported samplerate in the setter API, although the list call does
suggest a discrete set of rates (a subset of the hardware capabilities).
Update a comment to catch up with the implementation.

Drop the 250kHz item, it's too close to 200kHz. Add a 2MHz item to
achieve a more consistent 1/2/5 sequence in each decade. Unfortunately
50MHz and an integer divider will never result in 20MHz, that's why
25MHz is an exception to this rule (has been before, just "stands out
more perceivably" in this adjusted sequence).
2020-05-29 07:50:18 +02:00
Gerhard Sittig c749d1ca57 asix-sigma: improve robustness of firmware download, delay and retry
Running several firmware uploads in quick repetition sometimes failed.
It's essential to stop the active netlist from preventing the FPGA's
getting reconfigured (FTDI to FPGA pins are so few, and shared). Delays
in a single iteration of the initiation sequence improves reliability.
Retries of the sequence are belt and suspenders on top of that.

Before the change, failure to configure was roughly one in ten. After
the change, several thousand reconfigurations passed without failure.
2020-05-29 07:50:18 +02:00
Gerhard Sittig 80e717b3cf asix-sigma: eliminate magic numbers in firmware file references
Use symbolic identifiers to select firmware images, which eliminates
magic 0/1/2 position numbers in the list of files, improves readability
and also improves robustness. Move 'devc' to 'ctx' and before other
arguments in routine signatures while we are here.
2020-05-29 07:50:18 +02:00
Gerhard Sittig 1bb9dc8217 asix-sigma: mark FPGA config phase in "state" of dev context
FPGA configuration (netlist upload) of ASIX SIGMA devices is rather
special a phase, and deserves its own state in the device context's
"state" tracking. Not only is the logic analyzer not available during
this period, the FTDI cable is also put into bitbanging mode instead
of regular data communication in FIFO mode, and netlist configuration
takes a considerable amount of time (tenths of a second).
2020-05-29 07:50:18 +02:00
Gerhard Sittig 5e78a56481 asix-sigma: rework time/count limits support, accept more samplerates
Use common support for SW limits, and untangle the formerly convoluted
logic for sample count or time limits. Accept user provided samplerate
values when the hardware supports them, also those which are not listed.

The previous implementation mapped sample count limits to timeout specs
which depend on the samplerate. The order of applications' calls into
the config set routines is unspecified, the use of one common storage
space led to an arbitrary resulting value for the msecs limit, and loss
of user specified values for read-back.

Separate the input which was specified by applications, from limits
which were derived from this input and determine the acquisition phase's
duration, from sample count limits which apply to sample data download
and session feed submission after the acquisition finished. This allows
to configure the values in any order, to read back previously configured
values, and to run arbitrary numbers of acquisition and download cycles
without losing input specs.

This commit also concentrates all the limits related computation in a
single location at the start of the acquisition. Moves the submission
buffer's count limit container to the device context where the other
limits are kept as well. Renames the samplerate variable, and drops an
aggressive check for supported rates (now uses hardware constraints as
the only condition). Removes an unused variable in the device context.
2020-05-29 07:50:18 +02:00
Gerhard Sittig 98b43eb3cd asix-sigma: rephrase submission of logic data to session feed
Introduce a 4MiB session feed submission buffer in the device context.
This reduces the number of API calls and improves performance of srzip
archive creation.

This change also eliminates complex logic which manipulates a previously
created buffer's length and data position, to split the queued data when
a trigger position was involed. The changed implementation results in a
data flow from sample memory to the session feed which feels more natural
during review, and better lends itself to future trigger support code.

Use common SW limits support for the optional sample count limit. Move
'sdi' and 'devc' parameters to the front to match conventions. Reduce
indentation in routine signatures while we are here.

This implementation is prepared to handle trigger positions, but for now
disables the specific logic which checks for trigger condition matches
to improve the trigger marker's resolution. This will get re-enabled in
a later commit.
2020-05-29 07:50:18 +02:00
Gerhard Sittig 2c33b09255 asix-sigma: eliminate magic numbers in sample memory access
Add more symbolic identifiers, and rename some of the existing names for
access to SIGMA sample memory. This eliminates magic numbers and reduces
redundancy and potential for errors during maintenance.

This commit also concentrates DRAM layout related declarations in the
header file in a single location, which previously were scattered, and
separated registers from their respective bit fields.

Extend comments on the difference of events versus sample data.
2020-05-29 07:50:18 +02:00
Gerhard Sittig 7c41c420aa asix-sigma: move FPGA commands before register layout declaration
Move the FPGA commands (which can access registers, and sample memory)
declarations before the register layout declaration. Which then no
longer separates the registers declarations from their bit fields.
Update comments on the register set while we are here.
2020-05-29 07:50:18 +02:00
Gerhard Sittig 07411a605e asix-sigma: rephrase some of the FPGA command exchange
Eliminate a few magic numbers in FPGA commands, use symbolic identifiers
for automatic register address increments, and DRAM access bank selects.
Improve grouping of related declarations in the header file.
2020-05-29 07:49:58 +02:00
Gerhard Sittig 9fb4c6324d asix-sigma: sync FPGA register names with documentation
Rename source code identifiers for FPGA registers to closer match the
vendor's documentation.
2020-05-29 07:49:58 +02:00
Gerhard Sittig dc0906e21c asix-sigma: eliminate magic numbers in FPGA configuration
Slightly rephrase and comment on the FPGA configuration of the ASIX
SIGMA logic analyzer. Use symbolic pin names to eliminate magic numbers.
Concentrate FPGA related comments in a single spot, tell the Xilinx FPGA
from FTDI cable (uses bitbang mode for slave serial configuration).

This fixes typos in the PROG pulse and INIT check (tests D5 and comments
on D6). Also removes the most probably undesired 100s timeout in the
worst case (100M us, 10K iterations times 10ms delay). Obsoletes labels
for error paths. Drops a few empty lines to keep related instruction
blocks together. Includes other style nits.
2020-05-29 07:49:58 +02:00
Gerhard Sittig 53a939aba5 asix-sigma: rework scan for USB devices, add support for conn= specs
Stick with the FTDI library for data acquisition, and most of all for
firmware upload (bitbang is needed during FPGA configuration). Removing
this dependency is more complex, and needs to get addressed later.

Re-use common USB support during scan before open, which also allows to
select devices if several of them are connected. Either of "conn=vid.pid"
or "conn=bus.addr" formats are supported and were tested.

This implementation detects and displays SIGMA and SIGMA2 devices. Though
their function is identical, users may want to see the respective device
name. Optionally detect OMEGA devices, too (compile time option, off by
default), though they currently are not supported beyond detection. They
just show up during scans for ASIX logic analyzers, and users may want to
have them listed, too, for awareness.

This implementation also improves robustness when devices get disconnected
between scan and use. The open and close routines now always create the
FTDI contexts after the code has moved out of the scan phase, where common
USB support code is used.

This resolves bug #841.
2020-05-29 07:49:50 +02:00
Gerhard Sittig 742368a2bc asix-sigma: nits in the list of firmware files
Eliminate an unnecessary magic number for the maximum filename length of
SIGMA netlists. Use a more compact source code phrase to "unclutter" the
list of filenames and their features/purpose. Move the filesize limit to
the list of files to simplify future maintenance.
2020-05-29 06:13:41 +02:00
Gerhard Sittig 97aa41e9b5 strutil: introduce sr_atol_base() conversion helper (non-decimal)
Introduce a text to number conversion routine which is more general than
sr_atol() is. It accepts non-decimal numbers, with optional caller given
or automatic base, including 0b for binary. It is not as strict and can
return the position after the number, so that callers can optionally
support suffix notations (units, or scale factors, or multiple separated
numbers in the same text string).
2020-05-29 06:12:50 +02:00
Gerhard Sittig d770bfbbbc tests: extend endianess conversion tests to also cover inline routines
Cover the recently introduced inline routines which back the preprocessor
macros for endianess conversion. Add test sequences for read and write
routines for different data types of different sizes, different endianess
formats and signedness, and include those routines which increment the
read/write position.
2020-05-29 06:12:33 +02:00
Gerhard Sittig 080b6bcf09 libsigrok-internal.h: add 24bit little endian reader helper
Add another endianess conversion helper which reads 24bit values in
little endian format.
2020-05-29 06:11:38 +02:00
Gerhard Sittig f1833600a0 libsigrok-internal.h: rephrase endianess conversion helpers
Address style, robustness, and usability nits in the common endianess
conversion helpers in the libsigrok-internal.h header file. Rephrase
preprocessor macros as static inline C language functions to eliminate
side effects, and improve data type safety. Provide macros under the
previous names for backwards compatibility, so that call sites can
migrate to the routines at their discretion (or not at all).

Performance is not affected. Inline routines are identically accessible
to compiler optimizers as preprocessor macros with their text expansion
are. Resulting machine code should be the same.

Introduce variants which also increment the read or write position in
the byte stream after data transfer. This reduces more redundancy at
call sites.
2020-05-29 06:10:18 +02:00
Gerhard Sittig f2a9a7c2c8 tests: also cover endianess conversion helpers
Introduce a new tests/conv.c source file which exercises the endianess
conversion macros. It's assumed that some use cases may break their
operation, fortunately these edge cases were not seen before, or the
unreliable operation went unnoticed. This test raises awareness of the
implementation's constraints.

This is a start, the test sequence will benefit from adding some more
cases to increase coverage.
2020-05-29 06:09:47 +02:00
Frank Stettner 883db4dad1 hp-3478a: Fix glib variant ref count in SET MQ request. 2020-05-26 21:17:32 +02:00
Frank Stettner 1c8110dbc7 scpi-dmm: Fix coding style. 2020-05-26 21:17:25 +02:00
Tobias Faeth 6d2e307016 serial-dmm: Added support for Metex ME-21 multimeters 2020-05-26 21:11:48 +02:00
Uwe Hermann de4dc45eae udev: Add FTDI FT4232 VID/PID. 2020-05-02 17:01:39 +02:00
Sergey Rzhevsky 9785891436 ftdi-la: Add FT4232H PID:VID. 2020-05-02 17:01:39 +02:00
Richard 77f3c5e51f rigol-ds: Added support for the DS1202Z-E 2020-05-02 17:01:39 +02:00
Gerhard Sittig 8c381a353c hameg-hmo: use common helper to setup description of an analog value
Replace an open coded sequence of assignments to an aggregate of several
related structures. Prefer the common sr_analog_init() routine instead.
2020-05-02 17:01:39 +02:00
Gerhard Sittig 00f3c94386 uni-t-ut32x: drop redundant close and free at end of scan
The UT32x driver requires a user spec for the connection. The device
cannot get identified, that's why successful open/close for the port
will suffice. Lack of an input spec as well as failure in the early
scan phase will terminate the scan routine early.

When we reach the end of the scan which creates the device instance
and registers it with the list of found devices, the port already
is closed and the list of devices will never be empty. Remove the
redundant close call and the dead branch which frees the serial port.
2020-05-02 17:01:39 +02:00
Gerhard Sittig ff5fb18526 scpi-dmm: fix glib variant ref count in SET MQ request 2020-05-02 17:01:39 +02:00
Uwe Hermann 6cfc6c5c7a Fix compiler warnings related to -Wcast-function-type.
This fixes bug #1297.
2020-05-02 17:01:39 +02:00
Uwe Hermann 4c5ac0cf5b siglent-sds: Fix various compiler warnings.
src/hardware/siglent-sds/protocol.c: In function 'siglent_sds_get_digital':
  src/hardware/siglent-sds/protocol.c:382:35: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
          if (data_low_channels->len <= samples_index) {
                                     ^
  src/hardware/siglent-sds/protocol.c:391:36: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
          if (data_high_channels->len <= samples_index) {
                                      ^
  src/hardware/siglent-sds/protocol.c:417:32: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
       for (long index = 0; index < tmp_samplebuf->len; index++) {
                                  ^
  In file included from src/hardware/siglent-sds/protocol.c:37:0:
  src/hardware/siglent-sds/protocol.c: In function 'siglent_sds_receive':
  src/hardware/siglent-sds/protocol.h:28:20: warning: format '%li' expects argument of type 'long int', but argument 3 has type 'uint64_t {aka long long unsigned int}' [-Wformat=]
   #define LOG_PREFIX "siglent-sds"
                      ^
  ./src/libsigrok-internal.h:815:41: note: in expansion of macro 'LOG_PREFIX'
   #define sr_dbg(...) sr_log(SR_LOG_DBG,  LOG_PREFIX ": " __VA_ARGS__)
                                           ^
  src/hardware/siglent-sds/protocol.c:564:6: note: in expansion of macro 'sr_dbg'
        sr_dbg("Requesting: %li bytes.", devc->num_samples - devc->num_block_bytes);
        ^
  src/hardware/siglent-sds/protocol.c: In function 'siglent_sds_get_dev_cfg_horizontal':
  src/hardware/siglent-sds/protocol.h:28:20: warning: format '%lu' expects argument of type 'long unsigned int', but argument 3 has type 'uint64_t {aka long long unsigned int}' [-Wformat=]
   #define LOG_PREFIX "siglent-sds"
                      ^
  ./src/libsigrok-internal.h:815:41: note: in expansion of macro 'LOG_PREFIX'
   #define sr_dbg(...) sr_log(SR_LOG_DBG,  LOG_PREFIX ": " __VA_ARGS__)
                                           ^
  src/hardware/siglent-sds/protocol.c:933:2: note: in expansion of macro 'sr_dbg'
    sr_dbg("Current memory depth: %lu.", devc->memory_depth_analog);
    ^
2020-05-02 15:48:26 +02:00
Andreas Sandberg 4704f64551 bt/bt_bluez: Implement retry if rfcomm sockets are busy
There are cases where the connect() call returns EBUSY when trying to
connect to a device. This has been observed when sampling an RDTech
UM24C. In this case, scanning the device works fine. However, when
sampling the device, Sigrok first scans the device, then closes the
connection and re-opens it to sample the device. If the close/open
calls happen in close successions, the Bluetooth stack sometimes
returns EBUSY.

Work around this issue by retrying if the connect() returns EBUSY.

Signed-off-by: Andreas Sandberg <andreas@sandberg.pp.se>
2020-04-11 16:00:52 +02:00
v1ne 1d657f47be modbus: Close device after scan
Since the device should be closed after the scan, close it in sr_modbus_scan.
Alternatively, every single driver could close the device after calling
sr_modbus_scan. This causes duplicated code, is prone to forgetting it and it
wasn't the calling driver who opened the device in the first place.

This change unbreaks maynuo-m97 and rdtech-dps.
2020-04-11 15:55:35 +02:00
Florian Schmidt 8f3c77db26 scpi-pps: fixed out-of-bounds array access...
when accessing devc->device->channels in config_list().
this array has to be accessed via the "hw_output_idx"

This fixes bug #1533.
2020-04-11 15:52:13 +02:00
Uwe Hermann f0aec55605 center-3xx: Fix incorrect values due to endianness issue.
Replace RL16S with RB16S, the values are big-endian.

This is related to the recently-fixed bug #1463.
2020-04-09 23:51:16 +02:00
Uwe Hermann 4c5f70063a Use std_session_send_df_frame_begin()/_end() where possible. 2020-04-08 23:54:25 +02:00
Uwe Hermann 7f7702b81b std: Rename std_session_send_frame_begin/_end(). 2020-04-08 23:35:44 +02:00
Uwe Hermann 0fa71943e3 Use std_session_send_df_trigger() where possible. 2020-04-08 23:21:39 +02:00
Uwe Hermann 447c4216fc std: Factor out send_df_without_payload() helper. 2020-04-08 23:11:15 +02:00
Uwe Hermann 10cf811385 std: Add std_session_send_df_trigger(). 2020-04-08 23:02:04 +02:00
Uwe Hermann 148cf8bea1 zeroplus-logic-cube: Fix an issue when changing triggers.
Changing triggers (e.g. from low to high) would sometimes cause the
acquisition to seemingly "hang" due to missing variable initializations
(in reality the device would wait for incorrect triggers and/or on
incorrect channels).

This fixes bug #1535.
2020-04-08 22:58:02 +02:00
Jan Metzger 88daa0536c zeroplus-logic-cube: Enable edge-triggering capabilities.
This fixes bug #1334.
2020-04-08 22:57:02 +02:00
Christian Fruth c8dcd3ab72 korad-kaxxxxp: Add support for RND KA3005P V5.5 power supply 2020-04-07 00:54:18 +02:00
Peter van der Perk 082ca8d8bc korad-kaxxxxp: Add support for TENMA 72-2540 V5.2 power supply 2020-04-07 00:54:18 +02:00
Uwe Hermann 78d78afb57 udev: Add TIAO USB Multi Protocol Adapter (TUMPA) VID/PID. 2020-04-07 00:54:18 +02:00
Tom Matthews 3ff6cfeebe ftdi-la: add TUMPA VID:PID and JTAG pin names 2020-04-07 00:54:18 +02:00
v1ne 69c5d959e7 rdtech-dps: Make it work in SmuView
Without the mutex, concurrent reception from the ModBus port leads to CRC
errors.
2020-04-04 23:25:25 +02:00
Gerhard Sittig 56a1bf7b4b center-3xx: use common signed LE16 conversion for temperature value
Prefer the common conversion helper for little endian 16bit signed data.
The previous local implementation only worked for positive values, and
yielded incorrect results for negative temperatures.

This fixes bug #1463.
2020-04-04 23:25:25 +02:00
Elen Eisendle ca7d442692 serial-dmm/uni-t-dmm: Add UNI-T UT804 DMM definitions 2020-04-04 23:25:09 +02:00
Andreas Sandberg 35037b1d8b input/trace32_ad: Fix pod_data uninitialised warning
Signed-off-by: Andreas Sandberg <andreas@sandberg.pp.se>
2020-04-04 22:25:03 +02:00
Andreas Sandberg 5ff772410b gwinstek-gpd: Fix use of uninitialized variable
Signed-off-by: Andreas Sandberg <andreas@sandberg.pp.se>
2020-04-04 22:24:26 +02:00
Juan M. Bello-Rivas 5652085a4e bindings/cxx: Include missing header file
Including the `functional` header is necessary in order to use `std::function` in the definition of `LogCallbackFunction` when compiling with gcc 7.3.0.
2020-04-04 22:24:21 +02:00
Uwe Hermann 49d130200d bindings/ruby: Disable Ruby bindings until we have a fix for #1526.
The Ruby bindings currently don't build (at least with Ruby 2.7
and/or SWIG 4.x). Disable them as a temporary workaround until we
have a more permanent fix.
2020-04-04 22:24:05 +02:00
Uwe Hermann c9901879f6 configure.ac: Also check for "swig4.0". 2020-04-04 22:24:05 +02:00
Uwe Hermann e803574173 bindings/java: Fix build issue with SWIG 4.x.
Tested with SWIG 3.x and SWIG 4.x.

This fixes bug #1527.
2020-04-04 22:24:05 +02:00
Uwe Hermann 6762401d2b Doxygen: Fix various warnings.
src/resource.c:414: warning: unbalanced grouping commands

  conversion.c:81: warning: argument 'lo_thr' from the argument list of sr_a2l_schmitt_trigger has multiple @param documentation sections

  src/analog.c:611: warning: return value 'SR_ERR_ARG' of sr_rational_div has multiple documentation sections

  src/device.c:205: warning: explicit link request to 'TRUE' could not be resolved
  src/device.c:205: warning: explicit link request to 'FALSE' could not be resolved
  src/device.c:231: warning: explicit link request to 'TRUE' could not be resolved
  src/device.c:231: warning: explicit link request to 'FALSE' could not be resolved

  src/serial.c:246: warning: explicit link request to 'NULL' could not be resolved

  src/strutil.c:602: warning: explicit link request to 'NULL' could not be resolved

  src/device.c:94: warning: unable to resolve reference to 'sr_channel_free()' for \ref command

  src/strutil.c:597: warning: unable to resolve reference to 'sr_hexdump_free()' for \ref command
  src/strutil.c:622: warning: unable to resolve reference to 'sr_hexdump_new()' for \ref command

  src/device.c:430: warning: The following parameters of sr_dev_inst_channel_add(struct sr_dev_inst *sdi, int index, int type, const char *name) are not documented: parameter 'sdi'

  src/session.c:163: warning: The following parameters of fd_source_new(struct sr_session *session, void *key, gintptr fd, int events, int timeout_ms) are not documented: parameter 'events'
2020-03-25 20:27:57 +01:00
Uwe Hermann 82b9f3d116 Doxygen: Properly mark a few symbols as private.
(otherwise these end up in the API docs)

Remove all @internal markings, only use @private where needed.
2020-03-25 20:10:24 +01:00
Uwe Hermann deaaebb28d bindings/python/Doxyfile: Set OPTIMIZE_OUTPUT_JAVA to NO. 2020-03-25 19:38:48 +01:00
Uwe Hermann b4066aa80e Doxyfile_internal: Fix various settings and paths. 2020-03-25 19:38:48 +01:00
Uwe Hermann 4e9e767be0 Doxyfile: Predefine HAVE_SERIAL_COMM for serial docs.
Without this, src/serial.c API docs won't be generated.
2020-03-25 19:38:19 +01:00
Uwe Hermann b07a07fec2 Doxyfile: Fix/update path and file references. 2020-03-25 19:35:20 +01:00
Uwe Hermann 2faa1db033 Doxyfile: Bring back the workaround for bug #1422. 2020-03-24 21:15:15 +01:00
Uwe Hermann e2bd01f4a7 All Doxyfile files: Update file template to doxygen 1.8.16.
This is done semi-automatically by running "doxygen -u Doxyfile".
2020-03-24 21:15:15 +01:00
Uwe Hermann d7357ebbb6 All Doxyfile files: Set CREATE_SUBDIRS to NO. 2020-03-24 21:15:15 +01:00
Uwe Hermann 20680f58ff manson-hcs-3xxx: Support device IDs with and without "HCS-" prefix.
Since we've now seen lots of devices in the wild that come with the
"HCS-" prefix in the ID, it's probably safe to assume all of them
could have it.

This fixes bug #1530.
2020-03-24 21:10:27 +01:00
Uwe Hermann bfa79fbdb6 asix-sigma: Drop duplicate error message prefixes.
The sr_err() call automatically adds a prefix to all messages, in
this specific case "asix-sigma: " will be added.
2020-03-24 19:22:11 +01:00
Daniel Trnka 440810958c asix-sigma: move DRAM line buffer allocation closer to its use
Move the allocation of the DRAM line buffer in the sample download code
path closer to the location where that buffer is used and gets released.
2020-03-24 19:20:40 +01:00
Daniel Trnka f73b00b647 asix-sigma: check for successful register access in sample download
The previous implementation got stuck in an infinite loop when data
acquisition started, but the device got disconnected before the data
acquisition terminates. An implementation detail ignored communication
errors, and never saw the expected condition that was required to
continue in the sample download sequence. Unbreak that code path.
2020-03-24 19:20:40 +01:00
Uwe Hermann f5c863e572 korad-kaxxxxp: Fix max. possible current for all devices.
Even though the devices/websites/manuals usually say 0..30V, the
hardware actually accepts up to 31V, both via serial as well as by
simply rotating the knob on the device (and our driver already
reflects that).

The same is true for current, it's usually 0..5A as per docs, but many
(probably all) devices accept 5.1A via serial and knob.

Thus, set the max current of all devices to 5.1A (or 3.1A for 3A
devices). We're assuming they all have this property, and we've seen
this in practice on at least three different versions of the device.
2020-03-22 16:58:54 +01:00
David Sastre Medina 7415217ede korad-kaxxxxp: Add a new ID for KORAD KA3005P V4.2 power supply
On a recently acquired Korad KA3005P power supply, the ID supplied by the
device is not known by libsigrok.

$ sigrok-cli --driver=korad-kaxxxxp:conn=/dev/ttyACM0 --scan
sr: korad-kaxxxxp: Unknown model ID 'KORAD KA3005P V4.2' detected, aborting.

This fixes bug #1522.

Thanks to bitaround@gmail.com for the amperage fix.
2020-03-22 15:52:16 +01:00
jirjirjir c4a46475a6 rigol-ds: Rigol DS1152E-EDU support fix 2020-03-16 23:44:25 +01:00
Soeren Apel 781ae4484d Fix #1509 by providing alternate sample format scales 2020-02-28 23:26:20 +01:00
Martin Ling 8491cf7cad python: Apply typemap for VariantBase to VariantContainerBase.
Fixes #1480.
2020-01-05 18:25:13 +00:00
Uwe Hermann f0362f595a agilent-dmm: Add Agilent U1237AX (completely untested). 2019-12-27 22:08:41 +01:00
Uwe Hermann e47e23355f agilent-dmm: U127x: Fix mode switch event handling.
The DMMs report as an event to which mode the user switched (by turning the
rotary switch): "*0", "*1", etc.

Most other DMMs have few modes, but the U127x DMMs have up to 11 different
modes (i.e., "*10" is a valid event).
2019-12-27 20:59:04 +01:00
Uwe Hermann 4c660b46c1 Makefile.am: Add missing src/serial_hid.h. 2019-12-24 16:39:01 +01:00
Uwe Hermann f0901a5050 src/serial_hid.h: Include guard consistency fix. 2019-12-24 16:38:56 +01:00
Uwe Hermann 31b4a9a236 input/csv: Set default "header" option value to true.
This makes re-opening files that were saved via the libsigrok CSV
output module slightly more convenient.
2019-12-22 23:50:22 +01:00
Uwe Hermann 5a27356705 output/csv: Set default "time" option value to false. 2019-12-22 23:50:11 +01:00
Uwe Hermann d649ff2290 manson-hcs-3xxx: support new HCS-3200 / PPS-13610 model string.
This fixes bug #1441.
2019-12-22 23:19:47 +01:00
Uwe Hermann c810ad60b4 mastech-ms6514: Add missing string.h #include. 2019-12-22 21:06:46 +01:00
Uwe Hermann aca2b460cc README.devices: Document MASTECH MS6514 interface enabling. 2019-12-22 15:52:46 +01:00
Uwe Hermann 9b1101d621 configure.ac: mastech-ms6514: Add serial_comm flag. 2019-12-22 15:33:45 +01:00
Dave Buechi 23669c3df3 Initial support for MASTECH MS6514 thermometer 2019-12-22 15:32:51 +01:00
Uwe Hermann 212769c3b8 input/csv: Consistently use a newline before the last return statement. 2019-12-22 14:42:34 +01:00
Gerhard Sittig 51e60cde09 input/csv: style nits, drop @brief and DIAG in debug output
The @brief keyword is not needed since JAVADOC_AUTOBRIEF is enabled in the
Doxygen configuration. Remove a remaining "DIAG" prefix in a debug
message, the output already is filtered according to the log level, and
prefixed by the module name.
2019-12-22 14:35:41 +01:00
Gerhard Sittig 811dcf7ea9 input/csv: re-calculate samplerate after file re-import
Don't clobber the user provided samplerate (specified by input module
options). This allows to re-determine the samplerate from a potentially
changed file on disk upon reload.
2019-12-21 18:20:04 +01:00
Gerhard Sittig 307b239390 input/csv: expand cleanup (resource release) and unbreak file reload
The list of previously created channels is kept across file reloads. We
also need to keep (or re-create) the list of channels that are used for
datafeed submission of analog data.

Release more allocated resources in the .cleanup() routine, and do reset
internal state such that a .reset() thus .cleanup() then .receive() call
sequence will work. This code path is taken for re-import of files (see
bug #1241, CSV was affected).
2019-12-21 18:20:04 +01:00
Gerhard Sittig fbefa03f58 input/csv: improve reliabilty of text line isolation
Slightly unobfuscate the "end of current input chunk" marker in the data
processing loop. Make the variable's identifier reflect that it's not a
temporary, but instead something worth keeping around until needed again.

Unbreak the calculation of line numbers in those situations where input
chunks (including previously accumulated unprocessed data) happens to
start with a line termination. This covers input files which start with
empty lines, as well as environments with mutli-byte line termination
sequences (CR/LF) and arbitrary distribution of bytes across chunks.

This fixes bug #968.

Accept when there is no line termination in the current input chunk. We
cannot assume that calling applications always provide file content in
large enough chunks to span complete lines. And any arbitrary chunk size
which applications happen to use can get exceeded by input files (e.g.
for generated files with wide data or long comments).
2019-12-21 18:20:04 +01:00
Gerhard Sittig cb3b80512e input/csv: update developer comments and TODO list
Mention the required synchronization of default option values and format
match logic in a prominent location where options are discussed.

Update the TODO list for the CSV input module. Mixed signal handling got
fixed by rearranging channel creation. Samplerate can get determined
from timestamp columns already. The double data type for analog data
remains.
2019-12-21 18:20:04 +01:00
Gerhard Sittig 05719d75aa input/csv: move channel creation to after format parsing
The previous implementation incompletely handled arbitrary data type
oders in mixed signal input files. Rearrange the logic such that all
format specs get parsed first, then all channel creation details get
determined, then all channels get created. It appears to be essential
that all logic channels get created first, resulting in index numbers
starting at 0 and addressing the correct position in bitfields. The
analog channels get created after all logic channels exist. Adjacent
number ranges for channel types also results in more readable logic in
other locations.

This was tested with -I csv:column_formats=t,2a,l,a,x4,a,-,b3 example
data, and works as expected.
2019-12-21 18:20:04 +01:00
Gerhard Sittig cd7c5f9655 input/csv: add automatic format match support
Implement .format_match() support in the CSV input module. Simple
multi-column files will automatically load without an "-I csv" spec.
Non-default option values still do require the module selection before
options can get passed to the module.
2019-12-21 18:20:04 +01:00
Gerhard Sittig 43e1e23a11 input/csv: another stab at option help texts
Try to balance a compact format and completeness/accuracy of content for
builtin help texts for the CSV input module's options. Assume a technical
audience (this is signal analysis software after all).

Rename a few internal identifiers which help organize the list of options
and their help texts. Too short names became obscure.
2019-12-21 18:20:04 +01:00
Gerhard Sittig 7e4e65bf65 input/csv: add support for timestamp columns, auto detect samplerate
Accept 't' format specs for timestamp columns. Automatically derive the
samplerate from input data when timestamps are available and the user
did not provide a rate. Stick with a simple approach for robustness
since automatic detection is easy to override when it fails. This
feature is mostly about convenience.
2019-12-21 18:20:04 +01:00
Gerhard Sittig fc3b42e93a input/csv: robustness nits in column format dispatching
The previous implementation open coded type checks by comparing an enum
value against specific constants. Which was especially ugly since there
are multiple types which all are logic, and future column types neither
get ignored nor have channels associated with them.

Improve readability and robustness by adding helpers which check classes
(ignore, logic, analog) instead of the multitude of -/x/o/b|l/a variants
within the classes.

Also comment on the order of channel creation, and how to improve it.
2019-12-21 18:20:04 +01:00
Gerhard Sittig 08eb955a69 input/csv: update comments/helptext for analog input data
Expand the developer comment that's inline in the source file. There is
enough room to explain things. Try to come up with a "one-line" help text
that is precise yet compact, and does inform the user of available format
choices including modifiers. Chances are that longer descriptions start
reducing the usefulness of the help or the visibility of options when
users are in a hurry. Those who care can access the manual.

Mark more options as obsolete, and mention more default values in the
builtin help text. Also tweak a comment on getting channel names from
header lines.
2019-12-21 18:20:04 +01:00
Gerhard Sittig 3f1f63f007 input/csv: work around undesired logic/analog group "bleeding"
Support for mixed signal CSV input data is desirable and should be
possible. The current implementation just happens to not fully cope with
arbitrary mixes of data types in columns yet. Add a quick workaround,
but also a TODO item to properly address the topic later.
2019-12-21 18:20:04 +01:00
Gerhard Sittig a267bf450c input/csv: accept user provided analog resolution in column formats
Stick with the (arbitrary) default of 3 digits for analog data. Accept
user specified digit counts in the column_formats= option, like "a4".
2019-12-21 18:20:04 +01:00
Gerhard Sittig 43bdef2634 input/csv: add support for analog input data
Extend the CSV input module which was strictly limited to logic data so
far. Add support for analog data types. Implement the 'a' column format,
and feed analog data to the session bus.

This implementation feeds data of individual analog channels to the
session bus in separate packets each. This approach was found to work
most reliably, not all recipients support the submission of multiple
samples for multiple channels in a single packet.

A fixed 'digits' value is used. This needs to get addressed later.

Local experiments suggest that the 'double' data type for analog data
can result in erroneous visual presentation (observed with sigrok-cli).
Use 'float' for now, until the issue is understood and got fixed.
Support for double is prepared internally and is easily enabled.
2019-12-21 18:20:04 +01:00
Gerhard Sittig 5ada72fc0a input/csv: address unassorted nits
Address several minor nits. Eliminate unneeded variables. Update text to
number conversion comments including wildcard handling. Remove empty
lines in init() which used to spill out a set of lines which all do the
same thing (evaluate a set of options) and shall belong together.
2019-12-21 18:20:04 +01:00
Gerhard Sittig 9e7af34eaf input/csv: move channel creation to column processing details creation
Move the creation of logic channels to the location where formats fields
get iterated, and column processing details get derived. This reduces a
lot of redundancy, and simplifies the addition of more data formats.
2019-12-21 18:20:04 +01:00
Gerhard Sittig 5a9711764d input/csv: update TODO comments
Update the list of TODO items at the top of the CSV input module's
source. Text line handling (counting line numbers) got fixed. Adding
support for analog channels was prepared, as are timestamp columns.
2019-12-21 18:20:04 +01:00
Gerhard Sittig 72903e9d55 input/csv: rework user accessible options for consistency
Rename the CSV input module's option keywords. To better reflect their
purpose, and for consistency across the rather complex set of options
and how they interact. Rearrange the list of options (not that the order
matters from the outside, but it's good to have during maintenance).

Update builtin help texts which will show up in applications, as well as
the source code comments which discuss these options in greater detail.
Would be nice to have a "general" help text for input modules which is
not tied to one single option, to provide an overview or use examples.
Arrange the option keys, short and long help texts such that the source
better reflects the applications' screen layout. To better support
future maintenance, again.

Consistently separate multi-work keywords for improved readability.
Prefer underscores over dashes for consistency with common keys in
shared infrastructure in other project sources (device options, MQ
items, etc).
2019-12-21 18:20:04 +01:00
Gerhard Sittig 1a920e33fe input/csv: extend column-formats support for backwards compatibility
Extend the "column-formats" option support in the CSV input module to
also support wildcards and automatic channel count detection. Move the
format string interpretation to the location where the first data line
or the optional header line are seen. Map the simple options (single
column number and channel count, or first column number and optional
channel count) to a format string, to unify internal code paths. Remove
code paths for the previous specific yet limited scenarios.

Rephrase the condition which keeps executing the "initial receive"
phase. The text line termination sequence gets derived from the first
complete text line, but other essential information is only gathered
later, potentially after skipping a large (user specified) amount of
input data. Keep checking for this essential setup data until data or
the header actually were seen, before regular processing of input data
starts.
2019-12-21 18:20:04 +01:00
Gerhard Sittig 2142a79b53 input/csv: introduce column-formats option (flexible logic import)
Extend the CSV input module, introduce support for the "column-formats="
option. This syntax can express the previous single- and multi-column
semantics, as well as any arbitrary order of to-get-ignored, and single-
and multi-bit columns in several formats.

The previous "simple" keywords for single and multi column modes still
are in place, it's yet to get determined whether to axe them. Depends on
whether users can handle the format strings for these simple cases.
2019-12-21 18:20:04 +01:00
Gerhard Sittig ef0b9935cf input/csv: fixup input file line number handling
The previous implementation allowed CSV input files to use any line
termination in either CR only, LF only, or CR/LF format. The first EOL
was searched for and was recorded, but then was not used. Instead any of
CR or LF were considered a line termination. "Raw data processing" still
was correct, but line numbers in diagnostics were way off, and optional
features like skipping first N lines were not effective. Fix that.

Source code inspection suggests the "startline" feature did not work at
all. The user provided number was used in the initial optional search
for the header line (to get signal names) or auto-determination of the
number of columns. But then was not used when the file actually got
processed.
2019-12-21 18:20:04 +01:00
Gerhard Sittig 836fac9cf6 input/csv: unassorted adjustment, mostly "column processing" related
Reduce "state" in the CSV input module's context. Stick with variables
that are local to routines when knowledge of details need not be global.
Really base the processing of a column's input text on the column's
processing information which was gathered in the setup phase.

Rename few identifiers, to explicitly refer to logic channels (the only
currently supported data type of the CSV input module). Cease feeding
logic data to the session bus when there are no logic channels at all
(currently not really an option). Prepare for simpler dispatching of
parse routines should more data types get added in a future version.

Reduce some "clutter" (overly fragmented stuff that should go together
since it forms logical groups and is not really standalone). Address a
few more minor style nits (sizeof() redundancy, "seemingly inverse"
string comparison phrases).
2019-12-21 18:20:04 +01:00
Gerhard Sittig f6dcb3200d input/csv: improve "channel name from header line" logic
Improve the code paths which determine logic channels' names from an
optional CSV file header line. Strip optional quotes from the column's
input text (re-use a SCPI helper routine for that). Also use the channel
name for multi-bit fields, append [0] etc suffixes in that case. Comment
on the manipulation of input data, which is acceptable since that very
data won't get processed another time in another code path.
2019-12-21 18:20:04 +01:00
Gerhard Sittig e53f32d2b8 input/csv: introduce generic "column processing" support
Rephrase the CSV input module's implementation such that generic support
to "process a column" becomes available. All columns of an input file's
text line get inspected, a column can either get ignored, or converted
to logic data. A future version can then remove the current limitations
of single- and multi-column modes (either one single multi-bit cell, or
multiple single-bit cells which must be adjacent).

Combine the bin/oct/hex parse routines into one routine which handles up
to four bits per input number digit with common logic. Availability of
more data than channels (according to user specs) is not fatal.

Drop the counter intuitive "first-channel" option, use "first-column"
instead. Warn when comment leader and column separator are identical
(was silent before, may be unexpected). Extend diagnostics and address
minor readability nits, update comments. Rephrase logic channel name
assignment.

Use simple scalar options to derive generic processing details: Either
'single-column' and 'numchannels' are required, with an optional
'format' spec (resulting in single-column mode). Or 'first-column' with
an optional 'numchannels' (multi-column mode with fixed format, using
all available columns by default). The default is multi-column mode with
one logic channel per column and spanning all columns on a text line.
2019-12-21 18:20:04 +01:00
Gerhard Sittig de8fe3b515 input/csv: improve robustness of "use header for channel names"
Don't clobber the value of the user provided 'header' option. Use a
separate flag to track whether the header line was seen before, or
needs to get skipped when it passes by.
2019-12-21 18:20:04 +01:00
Gerhard Sittig 246aca5f54 input/csv: move samplerate meta packet to logic data feed submission
Move the communication of the samplerate meta packet to the very spot
where logic sample data gets sent. This allows to optionally determine
late the samplerate, potentially from input data instead of user specs.
2019-12-21 18:20:04 +01:00
Gerhard Sittig 626c388abf input/csv: rearrange text to logic data conversion and datafeed
Move the helper routines which arrange for the data feed to an earlier
spot, so that references resolve without forward declarations. Rename
routines to reflect that they deal with logic data.

Slightly unobfuscate column text to logic data conversion, and reduce
redundancy. Move sample data preset to a central location.

Rephrase error messages, provide stronger hints as to why the input text
for a conversion was considered invalid.
2019-12-21 18:20:04 +01:00
Gerhard Sittig dbc38383b2 input/csv: stricter input data test for multi column mode
The previous implementation assumed that in multi-column mode each cell
communicates exactly one bit of input (a logic channel). But only the
first character got tested. Tighten the check, to cover the whole input
text. This rejects fully invalid input, as well as increases robustness
since multi-bit input like "100" was mistaken as a value of 1 before.
2019-12-21 18:20:04 +01:00
Gerhard Sittig 19267272d3 input/csv: slightly shuffle text routines, add bin/hex/oct doc
Add documentation to the bin/hex/oct text parse routines, and move the
bin/hex/oct dispatcher to the location where its invoked routines are.
Stick with a TODO comment for parse_line() to reduce the diff size.
2019-12-21 18:20:04 +01:00
Gerhard Sittig 9eab4435f0 input/csv: unobfuscate text line to column splitting
The parse_line() routine is rather complex, optionally accepts an upper
limit for the number of columns, but unconditionally assumes a first one
and drops preceeding fields. The rather generic n and k identifiers are
not helpful.

Use the 'seen' and 'taken' names instead which better reflect what's
actually happening. Remove empty lines which used to tear apart groups
of instructions which are strictly related. This organization neither
was helpful during maintenance.
2019-12-21 18:20:04 +01:00
Gerhard Sittig b2c4dde226 input/csv: trim whitespace after eliminating comments
Accept when comments are indented, trim the whitespace from text lines
after stripping off the comment. This avoids the processing of lines
which actually are empty, and improves robustness (avoids errors for a
non-fatal situation). Also results in more appropriate diagnostics at
higher log levels.
2019-12-21 18:20:04 +01:00
Gerhard Sittig c6aa9870b4 input/csv: eliminate magic numbers in options declaration
The CSV input module has grown so many options, that counting them by
hand became tedious and error prone. Eliminate the magic numbers in the
associated code paths.

This also has the side effect that the set is easy to re-order just by
adjusting the enum, no other code is affected. Help text and default
values is much easier to verify and adjust with the symbolic references.

[ see 'git diff --word-diff' for the essence of the change ]
2019-12-21 18:20:04 +01:00
Gerhard Sittig ad6a2beec3 input/csv: data type nits (sizes, enums)
Use size_t for things that get counted: column indices, channel numbers
(line numbers already used size_t). De-anonymize an enum to avoid 'int'
where it gets referenced. Adjust printf(3) format strings. Get unsigned
values from option lookups (stick with 32bits, should be acceptable for
spreadsheet columns and channel counts).

Address other minor nits while we are here: Also terminate the last item
in an enum declaration. Add a doxygen comment for parse_line(). Rename a
parameter to achieve tabular doc text layout.
2019-12-21 18:20:04 +01:00
Gerhard Sittig e05f18273d input/csv: include section nits
Rephrase the #include statements in the CSV input module. "config" is
not a system header but is provided by the application source code.
Separate the config and system and application groups (their order is
essential). Alpha-sort the files within their group for simplified
maintenance.
2019-12-21 18:20:04 +01:00
Gerhard Sittig affaf54012 input/csv: add channel list checks for file re-read
Do for the CSV input module what commit 08f8421a9e did for VCD. Check
the channel list for consistency across re-imports of the same file.
This addresses the CSV part of bug #1241.
2019-12-21 18:20:04 +01:00
Gerhard Sittig 539188e524 input/csv: improve cleanup code path, unbreak re-import
The cleanup() routine gets invoked upon shutdown, as well as before
re-importing another file. The cleanup() routine must not release
resources which get allocated in the init() routine, as the init()
routine won't run again in the module's lifetime. The cleanup() routine
must void those context fields which get evaluated in the next receive()
calls.
2019-12-21 18:20:04 +01:00
Gerhard Sittig 17c30d0593 output/vcd: support smaller timescales with higher resolution
The previous implementation inspected the input stream's samplerate, and
simply used the next 1kHz/1MHz/1GHz timescale for VCD export. Re-import
of the exported file might suffer from rather high an overhead, where
users might have to downsample the input stream. Also exported data
might use an "odd" timescale which doesn't represent the input stream's
timing well.

Rephrase the samplerate to VCD timescale conversion such that the lowest
frequency is used which satisfies the file format's constraints as well
as provides high enough a resolution to communicate the input stream's
timing with minimal loss. Do limit this scaling support to at most three
orders above the input samplerate, to most appropriately cope with odd
rates.

As a byproduct the rephrased implementation transparently supports rates
above 1GHz. Input streams with no samplerate now result in 1s timescale
instead of the 1ms timescale of the previous implementation.
2019-12-21 17:19:50 +01:00
Gerhard Sittig 4ddea31451 output/vcd: use larger data type to internally store frequency
The 'period' member of the VCD output module's context is supposed to
hold frequencies that correspond to the timescale used during export.
An 'int' (in combination with VCD's 1/10/100 constraint) thus would
result in a 1GHz limit, use uint64_t instead to support higher rates.
2019-12-21 17:19:50 +01:00
Gerhard Sittig 3895064542 output/wavedrom: rephrase accumulation of output data
Iterate over the received sample set first, before iterating over the
respective sample's number of channels. This avoids redundant extraction
of sampled bits (which saves only little), but also increases locality
of processed data (though string accumulation still may be expensive).

It also adds the future option of RLE compression during accumulation of
output data, which perfectly matches the WaveDrom syntax for repeated
bit patterns.
2019-12-21 13:58:43 +01:00
Gerhard Sittig 7a0d1bdc20 output/wavedrom: separate data processing logic from init/cleanup
Rearrange the order of routines in the wavedrom output module. Keep the
flow of .receive() -> .process_logic() -> .wavedrom_render() in one common
group of routines, which is not disrupted by the .init() and .cleanup()
routines which are kind of boilerplate in the source file. This increases
readability and maintainability.
2019-12-21 13:58:43 +01:00
Gerhard Sittig dd5735c998 output/wavedrom: address style nits
Adjust brace style, use C language comments, drop camel case. Use size_t
for indices and offsets. Unobfuscate the open/close logic of rendered
output. Allocate zero-filled memory, reduce sizeof() redundancy. Don't
SHOUT in the module's .name property.

[ Changes indentation, see 'git diff -w -b' for review. ]
2019-12-21 13:58:43 +01:00
Marc Jacobi 40f812f5dc output/wavedrom: introduce a wavedrom output module
WaveDrom provides a textual description of digital timing diagrams,
using the JSON syntax. See https://wavedrom.com/ for more details.
2019-12-21 13:58:43 +01:00
Frank Stettner 675cb86f15 hp-3478a: Check for overflow. 2019-12-20 23:08:51 +01:00
Frank Stettner 7812a5c802 hp-3478a: Add get/set/list of digits. 2019-12-20 23:08:51 +01:00
Frank Stettner e5137b9343 hp-3478a: Add get/set/list of measurement ranges. 2019-12-20 23:07:25 +01:00
Frank Stettner ccf68765aa Add config key SR_CONF_DIGITS. 2019-12-20 13:02:06 +01:00
Frank Stettner 84b4f9a1ff Add config key SR_CONF_RANGE. 2019-12-20 13:02:06 +01:00
Michał Janiszewski e3f86ef5fc beaglelogic: Fix mismatched printf specifiers. 2019-12-19 22:20:47 +01:00
Uwe Hermann 599f9e1deb README.devices: Various updates.
- Mention missing drivers that require (or not) firmware uploads.

 - Update HID "chip" spec options.

 - Remove rarely useful and hard to maintain lists of drivers requiring
   serial port, HID, Bluetooth, BLE, or network conn specs.
2019-12-19 22:15:43 +01:00
Uwe Hermann 349c5e5432 README: Clarify bluez/libbluetooth name. 2019-12-19 22:13:51 +01:00
Gerhard Sittig dc40081706 asix-sigma: comment on trigger/stop position, silence warning
Add a comment on the logic which skips the upper 64 bytes of a 512 bytes
chunk in the Asix Sigma's sample memory. Move the initial assignment and
the subsequent update from a value which was retrieved from a hardware
register closer together for awareness during maintenance. Pre-setting a
high position value that will never match when the feature is not in use
is very appropriate.

Adjust the sigma_read_pos() routine to handle triggerpos identically to
stoppos. The test condition's intention is to check whether a decrement
of the position ends up in the meta data section of a chunk. The previous
implementation tested whether a pointer to the position variable ended in
0x1ff when decremented -- which is unrelated to the driver's operation.
It's assumed that no harm was done because the trigger feature is
unsupported (see bug #359).

This silences the compiler warning reported in bug #1411.
2019-12-19 21:18:35 +01:00
Adrian Godwin a16198316f scpi-dmm: Added minimal support for HP34401A (PR #36) 2019-12-17 00:08:09 +01:00
Peter Åstrand cf6beeb20d korad-kaxxxxp: Add support for RND 320-KD3005P (PR #35)
Since this model replies with a serial number, truncate before that
2019-12-17 00:08:03 +01:00
Sylvain Pelissier 24931412ee lecroy-xstream: Remove header read (PR #33) 2019-12-16 23:52:50 +01:00
Andreas Sandberg 19ab8e363e fluke-dmm: Fix use-after-free bugs
The handler for fluke 18x and 28x DMMs allocates several data
structures on the stack that are used after they have been freed when
creating a data feed packet.

Restructure the code so that all handlers send their own packets. As a
bonus, this avoid a couple of small heap allocations.
2019-12-16 15:51:07 +01:00
Frank Stettner 253d653d4d korad-kaxxxxp: Reword debug output for the status byte. 2019-12-16 15:42:53 +01:00
Frank Stettner 2e129b8b25 korad-kaxxxxp: Send META packet when states have changed. 2019-12-16 15:42:49 +01:00
Frank Stettner 8da30037cf korad-kaxxxxp: Fix bug when setting values while acquisition is running.
By separating the variables that holds the get and set values, the output
state, OVP and OCP can now be set while the acquisition is running.
Also some variables are named more clearly.
2019-12-16 15:42:36 +01:00
Frank Stettner dfdf4c83ff rdtech-dps: Send META package when states have changed. 2019-12-16 15:38:58 +01:00
Frank Stettner cce6a8a1b7 rdtech-dps: Handle different current/voltage digits for the various models. 2019-12-16 15:38:54 +01:00
Frank Stettner aff2094193 rdtech-dps: Retry sr_modbus_read_holding_registers() up to 3 times.
The communication with the rdtech power supplies is not very reliable,
especially during the start. Because of that, the driver tries to read the
modbus registers up to three times.
Nevertheless there is the chance, that the communication fails.
2019-11-13 10:09:07 +01:00
Frank Stettner c9b187a607 rdtech-dps: Use SR_MQFLAG_DC only for voltage and current channels. 2019-11-12 23:14:33 +01:00
Frank Stettner 7c0891b0b8 rdtech-dps: Synchronize read and write operations. 2019-11-12 23:14:33 +01:00
Sylvain Pelissier ef62ab6c73 Add udev rule for Lecroy WaveRunner oscilloscope 2019-11-09 15:53:29 +01:00
Gerhard Sittig ad4174c1d8 ols: introduce metadata quirks support, unbreak Logic Shrimp
Introduce quirks support for devices which provide incomplete metadata.
Add conservative logic to unbreak the Logic Shrimp. Amend previously
received information when it was incomplete, but don't interfere if a
future firmware version fixes the issue.

Without this change, the device gets detected but "has zero channels"
and would be unusable. Because when a device provides metadata, these
details are used exclusively, no fallbacks apply.
2019-11-07 23:16:06 +01:00
Sylvain Munaut cfdc80151b std: Remove call to sr_dev_close from std_serial_dev_acquisition_stop
There is no reason to close the entire device in acquisition_stop and
this actually breaks pulseview on serial devices using this callback
when running multiple acquisition cycles

This fixes bug #1271.

Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
2019-11-02 16:38:13 +01:00
Marc Schink f216309fd0 demo: Fix memory leak
How to reproduce:

 $ G_SLICE=always-malloc G_DEBUG=gc-friendly valgrind --leak-check=full sigrok-cli --scan --driver demo

Signed-off-by: Marc Schink <dev@zapb.de>
2019-11-02 15:32:22 +01:00
Gerhard Sittig 76dea519e4 mooshimeter-dmm: silence compiler warning (memset() prototypes)
The Mooshimeter driver uses mem*() and str*() library calls. Include the
<string.h> header file to silence compiler warnings.

  ...
  ./src/hardware/mooshimeter-dmm/protocol.c: In function 'lookup_tree_path':
  ./src/hardware/mooshimeter-dmm/protocol.c:275:3: warning: implicit declaration of function 'strchr' [-Wimplicit-function-declaration]
     end = strchr(path, ':');
     ^
  ./src/hardware/mooshimeter-dmm/protocol.c:275:9: warning: incompatible implicit declaration of built-in function 'strchr' [enabled by default]
     end = strchr(path, ':');
           ^
  ...
2019-10-29 17:50:07 +01:00
Gerhard Sittig 113de3a572 bt: apply 20s timeout to BLE connect(2) attempts
Even working BLE devices won't immediately succeed in the first call to
connect(2), which is why the "in progress" phase was added. But absent
peers made the previous implementation try forever, getting stuck in the
sr_bt_connect_ble() call.

Try to balance these two constraints. Do terminate BLE connect attempts
after a generous timeout. When this 20s period passed, there probably is
a configuration error or unresponsive peer. Yet the timeout needs to be
in this ballpark to not erroneously fail for working setups.
2019-10-29 17:42:34 +01:00
Uwe Hermann 0f92d5db03 bt/bt_bluez: Adjust some log levels. 2019-10-26 21:31:51 +02:00
Uwe Hermann f314d87111 bt/bt_bluez: Remove some no longer needed verbose log messages. 2019-10-26 21:31:51 +02:00
Uwe Hermann 2489de3a24 README: Mention new (optional) libgio dependency.
libgio may or may not be part of a larger libglib package, depending on
OS and distro.
2019-10-26 21:31:51 +02:00
Uwe Hermann 59d916fe67 mooshimeter-dmm: Only report successful scan upon working connection. 2019-10-26 21:10:48 +02:00
Derek Hageman ebcd1aba01 Add support for the Mooshimeter DMM
This adds support for the Mooshim Engineering BLE based Mooshimeter.
Because the meter requires raw BLE packets, the driver uses the BLE
layer directly. Since the meter has no physical way of configuring it,
the actual configuration is set entirely with sigrok device options.
2019-10-22 12:21:47 +02:00
Stefan Brüns 02a8c07d89 Fix link errors when compiling with LTO enabled
When libsigrok is compiled with link-time-optimization, the linker
stumbles over the section named the same as the function. Whether this
is a compiler/linker bug or a coding error is unknown.

Renaming the special section (to the same as already used on OS X) avoids
the problem.

This fixes bug #1416.
2019-10-07 00:13:13 +02:00
Gerhard Sittig 2da97803e6 build: unbreak C++ binding compilation with newer Doxygen (1.8.16)
Doxygen version 1.8.16 introduced an issue which breaks the compilation
of sigrok's C++ binding (https://github.com/doxygen/doxygen/issues/7190).
Don't set the FILE_PATTERNS variable at all, instead of assigning an
empty value. This resolves bug #1422.
2019-10-06 10:08:09 +02:00
Kate J. Temkin 1656cd4a4a fx2lafw: allow for sampling at 48MHz, matching a fw change 2019-10-01 23:52:00 +02:00
Jan Luebbe 6d8205ad9a manson-hcs-3xxx: support new firmware for HCS-3202
A recently bought device seems to use a different model string, but
still speaks the same protocol.
2019-09-27 15:35:38 +02:00
Sebastian Reichel f6129c8f0c rigol-ds: Add initial Rigol MSO5000 support.
This adds basic support for the Rigol MSO5000 series. It has
the same problems as the DS4000 series: Live capture provides
one digital channel per byte. Buffered memory returns the data
compressed (one byte has 8 digital channels), but the banks are
read separately. It's not possible to read uint16.
2019-08-21 14:54:12 +02:00
Miklos Marton 4d8338bb96 demo: Add random analog signal generation 2019-07-31 23:15:18 +02:00
Elen Eisendle b1b8a7d079 korad-kaxxxxp: Add Korad KD6005P 2019-07-31 23:15:11 +02:00
Gerhard Sittig b50970a541 lcr/vc4080: introduce LCR packet parser for Voltcraft 4080 (and PeakTech 2165)
Introduce the lcr/vc4080.c source file which implements the parser for
the serial data stream of the Voltcraft 4080 LCR meter. Add the meter to
the list of supported devices in the serial-lcr driver, as well as the
PeakTech 2165 LCR meter which is another compatible device.

This implementation contains a workaround for USB based serial cables
which seem to suffer from incomplete parity handling (observed with the
FT232R based PeakTech cable). Similar approaches were seen in existing
DMM drivers.

This implementation supports the main and secondary displays. The D and Q
"displays" which are communicated in the serial packets appear unreliable
and redundant, users can have the D and Q values shown in the supported
displays.
2019-07-31 22:40:44 +02:00
Gerhard Sittig 66c300c4a6 serial-lcr: also request packets before initial state retrieval
Commit cb5cd1538f introduced packet request support in the serial-lcr
device driver. Calls were added to the detection of the device's
presence, and the periodic acquisition of measurement data. Add another
call to the device configuration retrieval that follows the presence
detection, without it communication timed out with no data received.

Also slightly raise the timeout for this device configuration gathering
phase. With one second sharp, the VC4080 was detected, but getting its
current configuration kept failing. This device's serial communication
is extra slow (1200 bps) and the packets are rather large (39 bytes).
Which made the stream detect's receive routine stop checking for the
availability of more data while a packet was being received.
2019-07-31 15:23:03 +02:00
Gerhard Sittig c4d2e6fa5e serial-lcr: move probe, dev inst creation, data read out of scan
Move the initial device probe (LCR packet validity check), the creation
of the device instance after successful probe, and the subsequent packet
inspection after resource allocation out of the scan routine. This shall
improve readability of the serial-lcr driver's probe logic, and reduces
diffs when handling of multiple connections gets added later.

Add a developer comment, the serial-lcr driver needs to handle multiple
connections when the conn= spec is ambiguous (multiple cables of the
same type, with the same VID:PID).
2019-07-31 15:23:03 +02:00
Gerhard Sittig 0fb4512125 dmm/bm86x.c: reduce verbosity level (packet request)
Remove a debug message from the Brymen BM86x meter's packet request method.
2019-07-31 15:23:03 +02:00
Gerhard Sittig 60117e6e9a serial_hid: reduce verbosity, drop excessive debug messages
The HID transport for serial communication was rather noisy at log
levels of 4 and above. Now that test coverage was increased and
operation is stable, drop a lot of the excessive and redundant debug
messages in regular code paths.
2019-07-31 15:23:03 +02:00
Uwe Hermann ea9e7a3e82 config keys: Revert re-orderings to avoid ABI changes. 2019-07-30 23:53:42 +02:00
Uwe Hermann 1838d9f13f hameg-hmo: Fix two compiler warnings (-Wstringop-truncation).
src/hardware/hameg-hmo/protocol.c: In function ‘hmo_scope_state_get’:
  src/hardware/hameg-hmo/protocol.c:1130:2: warning: ‘strncpy’ specified bound 20 equals destination size [-Wstringop-truncation]
    strncpy(state->trigger_pattern,
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     sr_scpi_unquote_string(tmp_str),
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     MAX_ANALOG_CHANNEL_COUNT + MAX_DIGITAL_CHANNEL_COUNT);
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    CC       src/hardware/hp-3478a/api.lo
    CC       src/hardware/hung-chang-dso-2100/protocol.lo
  src/hardware/hameg-hmo/api.c: In function ‘config_set’:
  src/hardware/hameg-hmo/api.c:388:3: warning: ‘strncpy’ specified bound 20 equals destination size [-Wstringop-truncation]
     strncpy(state->trigger_pattern,
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      tmp_str,
      ~~~~~~~~
      MAX_ANALOG_CHANNEL_COUNT + MAX_DIGITAL_CHANNEL_COUNT);
      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2019-07-30 23:53:42 +02:00
Uwe Hermann c38d69adf4 hameg-hmo: Fix two compiler warnings (-Warray-bounds).
src/hardware/hameg-hmo/protocol.c: In function ‘hmo_scope_state_get’:
  src/hardware/hameg-hmo/protocol.c:1035:31: warning: array subscript 0 is above array bounds of ‘char *[0]’ [-Warray-bounds]
     g_free(logic_threshold_short[i]);
            ~~~~~~~~~~~~~~~~~~~~~^~~
  src/hardware/hameg-hmo/protocol.c:1035:31: warning: array subscript 0 is above array bounds of ‘char *[0]’ [-Warray-bounds]
  src/hardware/hameg-hmo/protocol.c:974:24: warning: array subscript 0 is above array bounds of ‘char *[0]’ [-Warray-bounds]
     logic_threshold_short[i] = g_strdup((*config->logic_threshold)[i]);
     ~~~~~~~~~~~~~~~~~~~~~^~~
  src/hardware/hameg-hmo/protocol.c:974:24: warning: array subscript 0 is above array bounds of ‘char *[0]’ [-Warray-bounds]
2019-07-30 23:53:42 +02:00
Guido Trentalancia 97a000748a hameg-hmo: Add SR_CONF_HIGH_RESOLUTION and SR_CONF_PEAK_DETECTION.
Implement High Resolution mode and Peak Detection settings.

Beautify the code by reordering the Trigger Source settings
definitions.
2019-07-26 01:43:19 +02:00
Guido Trentalancia 29a9b1a0bd hameg-hmo: Get SCPI_CMD_GET_HORIZONTAL_DIV at runtime.
Get the number of horizontal divisions from the device (at runtime)
instead of hardcoding its value in the driver.
2019-07-26 01:43:19 +02:00
Guido Trentalancia a12456f1bb hameg-hmo: Don't hardcode POD/channel numbers.
Don't hardcode the number of PODs or the number of logic (digital)
channels per POD.
2019-07-26 00:55:40 +02:00
Guido Trentalancia 0c96de7223 hameg-hmo: Remove duplicate function call.
This call was inadvertently left around in commit
8cccbac8da.
2019-07-26 00:55:40 +02:00
Guido Trentalancia 66ddc22a1d hameg-hmo: Rename SCPI_CMD_GET_VERTICAL_DIV to *_SCALE.
Fix the name of the SCPI command used to get the vertical scale.
2019-07-26 00:55:40 +02:00
Guido Trentalancia 396af5ad7d hameg-hmo: Beautify trigger pattern.
Beautify the trigger pattern by removing the quotes from the SCPI response
using sr_scpi_unquote_string() and improve the string pattern handling.
2019-07-26 00:55:40 +02:00
Guido Trentalancia a058de0410 hameg-hmo: Add missing 1ns timebase for some models.
Extend the timebase setting down to 1ns from the current limit
of 2ns for all supported series except the HMO Compact.
2019-07-26 00:55:40 +02:00
Guido Trentalancia 0184aca19d hameg-hmo: Add missing quotes for SCPI_CMD_SET_TRIGGER_PATTERN. 2019-07-26 00:11:07 +02:00
Guido Trentalancia b720f16eb5 hameg-hmo: Add RTA4000 MSO support (untested).
According to the latest available version of the manual, as
for the RTB2000 and RTM3000 series, the RTA4000 series also
uses a slightly different dialect than other previously
supported models, in particular when it comes to the POD
(logic channel groups) handling.

I do not have such model available for testing therefore, as
for the RTB2000 and RTM3000 support recently introduced, I do
not know whether or not the RTA4000 also understands the
existing dialect. In doubt, the new official dialect is
implemented by this patch.
2019-07-26 00:11:07 +02:00
Guido Trentalancia aac3063300 hameg-hmo: Add RTB2000 and RTM3000 MSO support (untested).
According to the latest available version of the manual, they
both use a slightly different dialect than currently supported
models, in particular when it comes to the POD (logic channel
groups) handling.

I do not have any of the above models available for testing
therefore I do not know whether or not they also understand
the existing dialect. In doubt, the new official dialect is
implemented by this patch.
2019-07-26 00:11:07 +02:00
Guido Trentalancia 3a247d0359 hameg-hmo: Add SR_CONF_LOGIC_ANALYZER drvopt. 2019-07-26 00:11:07 +02:00
Guido Trentalancia 4f3cb1eaf7 hameg-hmo: Fix the upper limit for the vertical scale. 2019-07-26 00:11:07 +02:00
Guido Trentalancia 1203acc78f hameg-hmo: Only update states after successful SCPI SET.
Update the oscilloscope state with new settings only after
they have been successfully stored in the device to avoid
an inconsistent state in case of SCPI SET command failure.
2019-07-26 00:11:07 +02:00
Guido Trentalancia 39e1972347 hameg-hmo: Fix for an incorrect samplerate being returned.
The hameg-hmo driver returns an incorrect sample rate: to reproduce this
bug, set the maximum sample rate from the ACQUIRE menu.

This patch fixes the driver so that the correct sample rate is returned.
2019-07-26 00:11:07 +02:00
Guido Trentalancia 3883934404 hameg-hmo: Avoid bogus SCPI timeouts.
During the initial configuration phase of the hameg-hmo driver
only send an OPC command if a SCPI command has been previously
sent to the device so that bogus SCPI timeouts are avoided.
2019-07-26 00:11:07 +02:00
Guido Trentalancia 262061ff3d hameg-hmo: Use 1-based (not 0-based) POD numbers.
The current starting index for the POD name is currently wrong as it is zero.

The official POD numbering starts instead at 1 (see device panel, buttons
and manual), so the current index used for message printing and groups
naming in the driver needs to be incremented by one.
2019-07-26 00:11:07 +02:00
Guido Trentalancia 830e24b68f hameg-hmo: SR_CONF_LIMIT_SAMPLES/_FRAMES don't support _GET.
The samples and frame acquisition limits are not stored in the device or
elsewhere. Therefore they should not be read.
2019-07-26 00:11:07 +02:00
Guido Trentalancia 673989692c hameg-hmo: Avoid a double-free.
Avoid double memory freeing leading to segmentation fault in when a SCPI
command fails to get a string due conditions such as a timeout or an invalid
command.
2019-07-26 00:11:07 +02:00
Guido Trentalancia 4fa4db2c79 hameg-hmo: Add SR_CONF_TRIGGER_PATTERN support.
Introduce support for the Pattern Trigger functionality, sometimes also
called Logic Trigger.
2019-07-26 00:11:07 +02:00
Guido Trentalancia c8ecfa6ea4 hameg-hmo: When setting slope, also set trigger type to edge.
When setting the type of slope for the edge trigger function, also set the
trigger type to edge because it is not necessarily configured that way and
therefore such functionality might fail to work properly!

This fixes parts of bug #1328.
2019-07-26 00:11:07 +02:00
Guido Trentalancia a9f3fa0548 hameg-hmo: Remove unused SCPI command enums, sort entries. 2019-07-26 00:11:07 +02:00
Guido Trentalancia 4cf90b8667 hameg-hmo: Add support for the HMO1202 MSO. 2019-07-26 00:11:07 +02:00
Guido Trentalancia e35ebc6aa3 hameg-hmo: Initial R&S RTC1000 MSO support attempt.
(might need testing)
2019-07-26 00:11:07 +02:00
Guido Trentalancia e131be0ac3 hameg-hmo: Add support for SR_CONF_LOGIC_THRESHOLD/_CUSTOM.
Update the Hameg/Rohde&Schwarz HMO driver (hameg-hmo) so that it
is possible to configure the logic threshold for digital signals.

The user can get or set the logic threshold configuration using
the channel group POD0 (and/or POD1 where available), for example:

sigrok-cli --driver hameg-hmo --get logic_threshold -g POD0
sigrok-cli --driver hameg-hmo --config logic_threshold=TTL --set -g POD0

sigrok-cli --driver hameg-hmo --get logic_threshold_custom -g POD0
sigrok-cli --driver hameg-hmo --config logic_threshold_custom=0.7 --set -g POD0
2019-07-26 00:11:07 +02:00
Guido Trentalancia 3308450089 hameg-hmo: Update the default serial port options.
Update the default serial port options for Rohde&Schwarz and
Hameg mixed-signal oscilloscope devices connected through USB.

Also, remove misplaced and unused serial port configuration option.

This patch complements fa3d104f17
in terms of updating the USB PIDs for new devices (HMO series).

This fixes parts of bug #1321.
2019-07-26 00:11:07 +02:00
Guido Trentalancia 232eb33c67 hameg-hmo: Try to find a valid serialcomm if none is supplied.
If no serial port option is specified on the command-line using the
"serialcomm" driver option, but the device is connected through USB
and it requires a known default serial port option, then use it in
order to avoid data corruption or even worse problems.

Note: the easiest way to reproduce data corruption on HMO3000 series
is to start an analog data acquisition (e.g. on channel CH1) after
switching from Ethernet mode to USB VCP mode (HO732 USB/Ethernet interface).

This fixes parts of bug #1321.
2019-07-26 00:11:07 +02:00
Guido Trentalancia bb0665868e hameg-hmo: Avoid getting stuck upon SCPI timeouts.
Correctly set the length of the buffer used to hold the SCPI response
from the device containing the binary acquisition data.

If a timeout occurs, truncate the buffer and send the partial response
from the device instead of getting stuck on timeouts!

Thanks to Stefan Brüns for reviewing the first version of this patch
and spotting out a serious problem with it.

This fixes bug #1323.
2019-07-26 00:11:07 +02:00
Guido Trentalancia d779dcacb7 hameg-hmo: Add SR_CONF_LIMIT_SAMPLES support.
At the moment only the maximum number of frames to be acquired can be
configured for the Hameg/Rohde&Schwarz HMO mixed-signal oscilloscope
series driver (hameg-hmo).

This patch adds support to configure the number of samples to acquire
in both analog and digital (logic) mode.
2019-07-26 00:11:07 +02:00
Guido Trentalancia 6d0f3508f7 hameg-hmo: Add support for 16 digital (logic) channels.
This patch introduces the support for 16 digital (logic) channels for the
following oscilloscope models: HMO3032, HMO3042, HMO3052 and HMO3522
(previously only 8 digital channels were supported, i.e. only 1 POD).
2019-07-26 00:11:07 +02:00
Guido Trentalancia 91525636a6 hameg-hmo: Remove invalid HMO2522, add missing HMO3522.
This patch takes care of removing an invalid product model (HMO2522)
and adds a missing product model (HMO3522) in the hameg-hmo driver,
thus extending the number of supported oscilloscope models.

This fixes bug #1322.
2019-07-26 00:11:07 +02:00
Guido Trentalancia 14cb6aa40a hameg-hmo: Use g_byte_array_free() instead of g_free().
Use the appropriate glib function to free memory (byte array).

This fixes bug #1324.
2019-07-26 00:10:35 +02:00
Guido Trentalancia 4fff7b3c8a Update the pkg-config (.pc) entry for libsigrok. 2019-07-26 00:10:35 +02:00
Guido Trentalancia 1bb348cdbf std: std_gvar_tuple_array/_rational: Fix GVariantBuilder type.
Fix the type of container used to initialize the GVariantBuilder
structure which builds an array of tuples.
2019-07-26 00:10:35 +02:00
Uwe Hermann 80d3497569 hantek-4032l: Fix broken triggering on low signal.
The trigger range/mask "compression" procedure is apparently not
required and breaks triggering on a low line state.

This has been verified to fix the issue on a Hantek 4032L with FPGA
version 0x4303. It is possible that the procedure mentioned above
might be required for other FPGA versions, though that is unknown.

If you experience trigger issues with other FPGA versions, please
contact us for further debugging and testing.

This fixes bug #1402.
2019-07-06 23:22:47 +02:00
Uwe Hermann e6bb2984e9 hantek-4032l: Cosmetics. 2019-07-06 23:21:22 +02:00
Nadav Mavor 744d683ca7 rigol-ds: Add Agilent DSO1000B series IDs 2019-07-06 16:54:26 +02:00
Mike Walters 0b0f40d864 scpi-pps: Support HP 66312a 2019-07-03 12:43:18 +01:00
Daniel Anselmi 6c6dd7328a bindings: Avoid "using namespace" in headers.
This fixes bug #1354.
2019-06-30 19:38:56 +02:00
Uwe Hermann 1ac6436468 udev: Add Siglent SDS1104X-E VID/PID.
This fixes bug #1357.
2019-06-30 19:06:46 +02:00
Uwe Hermann be7c63dcf8 serial_hid: Don't print empty strings, [aaaa.bbbb] VID/PID format. 2019-06-20 18:16:31 +02:00
Uwe Hermann c0aa074eb2 std: Factor out std_dummy_set_params(). 2019-06-20 17:56:29 +02:00
Gerhard Sittig e378e3a2d4 dmm/bm86x: unbreak temperature modes (two probes and no probes)
The Brymen BM86x supports up to two temperature probes. The dual display
can show individual temperatures of the two probes or differences. The
previous implementation "detected" a value of zero degrees when no probe
was attached and the display showed dash lines. When cycling assignments
of probes to displays, some valid combinations did not result in values
shown by the libsigrok driver.

An implementation detail of the formerly separate brymen-bm86x driver
was lost during recent migration of the dmm/bm86x parser into the
serial-dmm driver. When the meter's temperature function is selected,
it's essential to inspect the primary display's flags and digits, to
determine the secondary display's quantity and unit. Previous versions
never bothered to explicitly check for the "----" digits text, but the
combination of the primary's last digit showing C/F as well as the
binary C/F flags before the value provided hints which the secondary
displays group of digits and flags did not.

This fixes bug #1394.
2019-06-20 17:23:48 +02:00
Gerhard Sittig 3775ef8c7a dmm/bm86x: drop local packet dump, already done in serial-dmm 2019-06-20 17:21:47 +02:00
Gerhard Sittig d4f5170c39 doc: update README.devices, victor-dmm has moved into serial-dmm 2019-06-20 17:21:47 +02:00
Gerhard Sittig a1771c26ba serial_hid: make --list-serial output compatible with conn=, print "VID.PID"
When the list of all connections gets created which are supported by the
HID serial transport, items contain a "hid/ch9325/raw=/dev/hidraw3" path
and a "1a86:e008" pair of vendor and product IDs.

Separate the VID/PID pair by a period not a colon, so that --list-serial
output immediately becomes usable with "--driver <name>:conn=<spec>"
invocations. Eliminate the necessity to adjust clipboard context by the
user. This improves usability in cases where not a single connection
gets addressed, but a group of connections gets specified by ambiguous
conn= specs.

$ sigrok-cli -d uni-t-ut32x:conn=1a86.e008 --scan
2019-06-20 17:21:47 +02:00
Gerhard Sittig 87307940f1 serial_hid: address constness nits 2019-06-20 17:21:47 +02:00
Gerhard Sittig cb5cd1538f serial-lcr: add support for packet request
Some meters require the reception of a request before they provide
acquisition data. Add support for the chip driver's .packet_request()
routine, and timeout handling in the serial-lcr driver. This follows
the serial-dmm model.
2019-06-20 16:45:36 +02:00
Gerhard Sittig 3f5473dde2 serial-lcr: add support for chip specific channel names
Allow LCR chip drivers to specify custom printf() formats for their
channel names. Default to "P1" etc in the absence of format specs.
This implementation is similar to serial-dmm.
2019-06-20 16:45:36 +02:00
Gerhard Sittig 238b874e44 lcr/es51919: minor style nits in the ES51919 packet parser
Use macros for frequency constants. They hopfully are more readable than
large number literals with their magnitude being not as apparent.
2019-06-20 16:45:36 +02:00
Gerhard Sittig 8556703a6c dmm/eev121gw: visibility nits (single display parse routine)
The EEVBlog 121GW meter support always registers the three-displays
parse routine with the serial-dmm device driver. The single-display
routine need not be public. Adjust the visibility.

Reduce indentation for a continued line in a nearby declaration
while we are here.
2019-06-20 16:45:36 +02:00
Daniel Anselmi 08ecb98e84 ipdbg-la: Fix an issue when capture rate is 100%.
If the capture ratio was set to 100%, the delay counter-value has an
overflow and a delay of 0 samples is used.

This fixes bug #1393.
2019-06-20 14:30:05 +02:00
Uwe Hermann bf6b9e7b16 serial: Shorten a few code snippets. 2019-06-15 17:35:42 +02:00
Uwe Hermann c87e9d26f4 serial_hid.h: Update SER_HID_CHUNK_SIZE comment. 2019-06-15 17:17:52 +02:00
Uwe Hermann a90ffc3730 udev: Split SiLabs CP210x/CP2110 items, mention more devices. 2019-06-15 16:39:55 +02:00
Uwe Hermann 92499a9c78 serial-lcr: Replace duplicated std_session_send_frame_end(). 2019-06-15 15:54:48 +02:00
Uwe Hermann aa29b255f8 configure.ac: Clarify/fix some pkg-config package names. 2019-06-15 15:52:22 +02:00
Uwe Hermann 9451e01e77 Eliminate VID_PID_TERM in favor of ALL_ZERO. 2019-06-15 15:45:12 +02:00
Uwe Hermann 66e19f47f4 ftdi-la: Fix VID/PID format in a log message.
Before: 0x 403:0x6001
After:  0x0403:0x6001
2019-06-14 00:15:24 +02:00
Gerhard Sittig 01ae826ba3 ftdi-la: do enter the error path upon VID:PID mismatch
Bug #1390 reports that "!desc" is always true (should be: false?). But
the actual problem would be that 'desc' is _not_ NULL when none of the
supported chips' VID:PID matched (FT232H happens to "get found" then,
erroneously).

Add a sentinel to the table of supported chips, such that 'desc' becomes
NULL upon mismatch, and the error path is entered.
2019-06-13 19:38:06 +02:00
Gerhard Sittig 03f169b36b serial-dmm: rename victor-dmm-ser entry, default to USB HID cable
The serial-dmm entry for Victor DMMs is able to communicate to either
geniune COM ports (RS232 or USB CDC) or the obfuscating USB HID cables.
The victor-dmm driver became obsolete and was removed. Rename the
serial-dmm entry, remove the no longer needed "-ser" suffix. Suggest a
default connection via the obfuscating USB HID cable, accept user
provided overrides for regular serial cables (same behaviour as before,
connection spec for serial ports keeps being mandatory).
2019-06-13 19:35:57 +02:00
Gerhard Sittig e45a8de41c victor-dmm: remove obsolete device driver, has moved to serial-dmm
Remove the victor-dmm device driver. Its functionality is contained in
the Victor specific serial-over-HID transport, the FS9922 DMM parser,
and the serial-dmm device driver. The additional implementation became
obsolete.
2019-06-13 19:34:43 +02:00
Gerhard Sittig 0cdb72c8f2 serial-hid: add support for (scrambling) Victor DMM cables
Introduce a serial transport which undoes the Victor DMM cable's
obfuscation to the DMM chip's original data packet. Which allows to
re-use the existing FS9922 support code, obsoleting the victor-dmm
device driver.
2019-06-13 19:34:09 +02:00
Gerhard Sittig a89884c16c uni-t-ut32x: don't provide a default conn= spec in the driver source
This undoes the essence of commit bf700f679a, which introduced the
default conn= spec. Which improved usability: Users just select the
device and need not specify the connection. But also resulted in the
UT32x thermometer driver's probe to "succeed" as soon as the WCH CH9325
chip was found, no data check was involved in the scan. Unfortunately
this chip is also used in the popular UT-D04 cable, and thus there were
many false positives.
2019-06-13 19:33:01 +02:00
Gerhard Sittig 97c8fa70da brymen-bm86x: retire libusb using driver, has moved to serial-dmm
Remove the src/hardware/brymen-bm86x/ hierarchy of source files. Its
functionality has moved to the bm86x packet parser and the serial-dmm
device driver.
2019-06-13 19:32:51 +02:00
Gerhard Sittig b800667daf serial-dmm: bm86x: increase packet request frequency
Request packets from the Brymen BM86x meter much faster. The previous
implementation in the separate driver used to immediately send another
request when a measurement arrived, with a 10ms granularity in the poll
routine, and a 500ms timeout between requests.

Considering the meter's update rate, stick with the 500ms timeout, but
increase the maximum request rate to 10 per second, with a minimum of 2
per second. This receives measurement data at the meter's capability
(compare DC and AC modes, seems to automatically adjust to the internal
operation, and match the display update rate).
2019-06-13 19:31:31 +02:00
Gerhard Sittig 0759e2f55b dmm/bm86x: add Brymen BM86x packet parser, register with serial-dmm
Move Brymen BM86x specific packet parse logic to a new src/dmm/bm86x.c
source file, and register the routines with the serial-dmm driver's list
of supported devices. Which obsoletes the src/hardware/brymen-bm86x/
hierarchy.

This implementation differs from the previous version: The parse routine
gets called multiple times after one DMM packet was received. Values for
the displays get extracted in separate invocations, the received packet
is considered read-only. Unsupported LCD segment combinations for digits
get logged. Low battery gets logged with higher severity -- the validity
of measurement values is uncertain after all. The parse routine uses
longer identifiers. Packet reception uses whichever serial transport is
available (need no longer be strictly USB HID nor libusb based). All
features of the previous implementation are believed to still be present
in this version.

This configuration queries measurement values each 0.5 seconds and
re-sends a not responded to request after 1.5 seconds. Which follows the
combination of the vendor's suggested flow (frequency) and the previous
implementation's timeout (3x 500ms). This implementation does not try to
re-connect to the HID device for each measurement, and neither checks
for the 4.0 seconds timeout (vendor's suggested flow). Local experiments
work without these.
2019-06-13 19:23:24 +02:00
Gerhard Sittig 7c7a112046 brymen-bm86x: rename specific Brymen BM86x driver (libusb implementation)
The src/hardware/brymen-bm86x/ source code contains specific support for
the Brymen BM86x devices, and directly depends on the libusb library.
Rename the registered device (append the "-usb" suffix) before adding
BM86x support to the serial-dmm driver.
2019-06-13 19:22:02 +02:00
Gerhard Sittig a10284cd18 serial-hid: introduce support for Brymen BU-86X IR adapters
The Brymen BU-86X infrared adapters are sold with BM869s meters. Raw
streams of data bytes get communicated by means of HID reports with
report number 0 and up to 8 data bytes each. Communication parameters
are fixed and need no configuration.
2019-06-13 18:33:23 +02:00
Gerhard Sittig 0527cc3ad7 serial-dmm: add support for default connections (USB cables)
Some meters which are supported by the serial-dmm driver don't strictly
require the user's COM port specification. When a known (usually bundled,
or even builtin) cable type is used, we can provide a default conn= spec
and thus improve usability. Prepare the DMM_CONN() macro, accept user
overrides.
2019-06-13 18:33:23 +02:00
Gerhard Sittig 09c650d5e9 serial-dmm: fixup 'conn' vs 'serialcomm' confusion
The 'conn' field in the device context and the CONN values in the
declarations of supported DMM models seemed inappropriate. They specify
the communication parameters (UART frame format and bitrate), not the
connection (port name). Adjust the respective identifiers.

Also rephrase the evaluation logic. Instead of checking for the absence
of user specs and optionally assigning a fallback value, just preset
from defaults and override from user specs when present. This simplifies
the logic (eliminates a check).
2019-06-13 18:33:23 +02:00
Gerhard Sittig db3aac1a29 serial-dmm: alpha-sort check for devices with multiple displays 2019-06-13 18:33:23 +02:00
Gerhard Sittig 684b26ef18 bluetooth: silence compiler warning (missing writev(2) declaration) 2019-06-13 18:33:10 +02:00
Gerhard Sittig bf5c4d46f8 serial-lcr: move device driver code from src/lcr/ to src/hardware/
Keep the ES51919 chip support in the src/lcr/ directory, and move device
driver specific code to the src/hardware/serial-lcr/ directory. Implement
the same driver layout for LCR meters as is used for DMM devices.

This also addresses a few issues in the serial-lcr driver: Unbreak --get
and --show, do process a few LCR packets after probing the device, to
gather current parameter values. Keep sending meta packets when these
parameters change during acquisition, like the previous implementation
did. Use common code for frame/time limits.

Note that although LCR meters usually operate with AC to classify L/C/R
components, one of the officially supported modes is DC resistance.
Which means that an output frequency of 0 is not just a fallback when
packet parsing fails, it's also a regular value of the freq parameter.
List all supported frequencies including DC in strict numerical order.

Although all currently supported devices use the same ES51919 chip, the
implementation is prepared to support other devices which use different
LCR meter chips as well. The list of known equivalent circuit models and
output frequencies is kept in src/lcr/ chip support. It's assumed that
one LCR packet communicates the data for all channels/displays similar
to the serial-dmm driver implementation.
2019-06-12 22:01:52 +02:00
Gerhard Sittig 67785f2568 sw_limits: add support for maximum frame counts 2019-06-09 14:51:02 +02:00
Gerhard Sittig e86cc12b66 output: also print meta strings in analog output module
Meta packets not only communicate numbers, but also strings. Print them.
This unbreaks the reflection of LCR meters' equivalent circuit model.
2019-06-09 14:51:02 +02:00
Gerhard Sittig 10cfb04826 serial-dmm: drop obsolete redundant 'baudrate' parameter value
The serial communication timing parameters during probe get determined
from earlier serial port configuration, which obsoletes the redundant
'baudrate' parameter, and eliminates potential inconsistency between
user specified parameters and builtin default values.
2019-06-09 14:51:02 +02:00
Gerhard Sittig 685ed70998 kern-scale: drop obsolete redundant 'baudrate' parameter value
The serial communication timing parameters during probe get determined
from earlier serial port configuration, which obsoletes the redundant
'baudrate' parameter, and eliminates potential inconsistency between
user specified parameters and builtin default values.
2019-06-09 14:51:02 +02:00
Gerhard Sittig d03815a066 serial: use timeout API in stream detect, obsoletes bitrate param
The serial_stream_detect() routine needs to estimate the time which is
needed to communicate a given amount of data. Since the serial port got
opened and configured before, the serial communication parameters are
known, and callers need not redundantly specify the bit rate.
2019-06-09 14:51:02 +02:00
Gerhard Sittig d478724801 serial: add support for optional "RX chunk" callback
The previous implementation provided a raw input stream of RX data from
read() calls to device drivers. This works great with genuine COM ports,
as well as with most setups which involve simple "cable expanders".

Recent additions of alternative transports (serial over HID and BLE)
added more protocol layers to the setup, and some device drivers are
reported to depend on the very framing of these transports: Mooshimeter
cares about individual BLE notification "frames", and the information
cannot get derived from the payload bytes. Some HID based cables which
obscure the DMM chips' serial protocol, or some HID based setups which
the serial layer does not abstract away as "a cable" may suffer from
similar requirements (do some drivers require access to individual HID
reports? Ikalogic? Victor DMM?).

Add support for an optional "RX chunk callback" which takes precedence
over "mere payload byte streams". Instead of returning payload bytes
from read() calls, the serial layer can call an application defined
routine and pass data bytes in the very framing which the physical
transport happens to use.

It's still up to the implementation of the specific transport whether
the callback approach is supported, and whether the wire's framing is
obeyed or whether payload data keeps getting provided as one raw stream.
It's also implementation dependent whether data reception transparently
occurs in background, or whether callers need to periodically "stimulate"
data reception by calling read or check routines which happen to call
back into the caller should RX data become available.

The approach that got implemented here is not universally applicable,
but serves those specific environments that were identified so far.
2019-06-04 18:59:04 +02:00
Gerhard Sittig 2fba14d05a udev: drop links to device/cable wiki pages from udev rule set 2019-06-04 18:59:04 +02:00
Gerhard Sittig 4ae1ab4555 udev: mark SiLabs CP2102 as generic, add SiLabs CP2110
The CP210x USB to UART bridge is not specific to CEM DT-8852, it's a
generic bridge chip that is also used in other cables and devices. Add
the CP2110 USB HID to UART bridge that is found in UNI-T cables and
devices, and reported to also be used in Voltcraft devices.
2019-06-04 18:59:04 +02:00
Gerhard Sittig 575663ab6a udev: add 'hidraw' subsystem to 60-libsigrok.rules
WCH CH9325 and SiL CP2110 chips (and other HID cables) won't match the
currently used 'usb' subsystem when the platform registers these as
'hidraw' devices. Adjust the 60-libsigrok.rules SUBSYSTEM condition.
2019-06-04 18:59:04 +02:00
Gerhard Sittig f9c3df65c1 doc: discuss how to enable PC communication on LCR meters 2019-06-04 18:59:04 +02:00
Gerhard Sittig e2a391aabc doc: outline conn= specs for HID and Bluetooth in README.devices
Add more examples of conn= specs for HID and Bluetooth devices to the
section which discusses COM ports. Outline the formal syntax and its
optional fields. Discuss how colons in device addresses interfere with
"-d <drv>:conn=<spec>" environments.
2019-06-04 18:59:04 +02:00
Gerhard Sittig 0ec42cbdb2 doc: update README, optional conn= specs for UNI-T meters
Recent adjustment in the libsigrok serial layer changed whether conn=
specs are mandatory or optional for some of the UNI-T meters.
2019-06-04 18:53:04 +02:00
Gerhard Sittig 07e42cb2cb doc: update README for serial over Bluetooth
Mention the optional external BlueZ dependency. Provide conn= examples
for Bluetooth communication. Mention the UT-D07 adapter.
2019-06-04 18:53:04 +02:00
Gerhard Sittig b79c342278 serial_bt: implement the serial over Bluetooth transport (conn=bt/...)
Introduce the serial_bt.c source file which implements the methods of a
serial transport and calls into the platform agnostic src/bt/ support
code.

Implement support for several chips and modules: RFCOMM (BT classic,
tested with HC-05), BLE122 (tested with 121GW), Nordic nRF51, and TI
CC254x (the latter untested). Read support is assumed to be complete,
write support for BLE may be incomplete due to lack of access to
hardware for tests.
2019-06-04 18:53:04 +02:00
Gerhard Sittig 7c8ae47dcb bluetooth: introduce Bluetooth communication API, implement BlueZ support
Create a src/bt/ subdirectory for source files. Declare a platform
agnostic internal API for Bluetooth communication, and provide an
implementation of that portable API when the BlueZ library is available.

This implementation assumes that HAVE_BLUETOOTH and HAVE_LIBBLUEZ can be
used interchangeably, which is true for this initial version. When
support for other platforms gets added, the common and the specific
parts need to get sorted. Trying that now would involve guessing. :)
2019-06-04 18:52:40 +02:00
Gerhard Sittig f085705f48 build: prepare serial over Bluetooth, search for optional BlueZ lib
Adding Bluetooth communication is desirable for all sigrok supported
platforms. The BlueZ library is available on Linux which will receive
support first. Check for the BlueZ library's presence, determine a
HAVE_BLUETOOTH summary state, and extend the HAVE_SERIAL_COMM check.
Print version details for the external library.

This commit extends build support and version information, but does not
yet include the implementation of the serial transport primitives.
2019-06-02 20:39:02 +02:00
Gerhard Sittig f736691d13 doc: mention serial-over-HID in README.devices (UT-D09 cable) 2019-06-02 20:39:02 +02:00
Gerhard Sittig 6e407e9850 serial-lcr: add driver item for the UNI-T UT612 model
Register another driver for the UNI-T UT612 LCR meter, which is based on the
ES51919/ES51920 chipset, too. This device had been usable before when the
internal UART connection was made accessible (read: with a hack). It became
officially supported in unmodified form with the addition of transparent
serial over HID support for SiLabs CP2110 chips.
2019-06-02 20:39:02 +02:00
Gerhard Sittig 164c5ae537 uni-t-ut32x: migrate from USB transfers to serial-over-HID communication
Switch the UT32x driver from running specific USB transfers to generic
serial communication. Preset the bitrate and frame format, but allow for
user specified overrides as well. Default to the WCH CH9325 HID chip,
but allow for overrides or more specific selection so that users can
resolve ambiguities with multiple cables.

The switch from libusb to hidapi removes a limitation that specifically
was reported for the Mac platform. The serial-over-HID variant should
now work as well. See bug #555.

Drop the background transfers. Stick with a local acquisition stop
routine, because a STOP request needs to get sent to the device. Reduce
the receive buffer size such that either blocking or non-blocking calls
will work. The additional flexibility of the buffer handling and packet
processing does not harm.
2019-06-02 20:39:02 +02:00
Gerhard Sittig 616bc3a170 serial_hid: add support for the SiLabs CP2110 chip (UT-D09, UT612)
Also reported to be seen in Voltcraft devices (VC-650, VC-890).
2019-06-02 20:39:02 +02:00
Gerhard Sittig 828eeea227 serial_hid: add support for the WCH CH9325 chip (UT-D04 cables, UT32x) 2019-06-02 20:39:02 +02:00
Gerhard Sittig edec0436db serial_hid: implement serial over HID transport
Do implement the transport methods for serial communication underneath
the common layer, by communicating HID requests and payload data by
means of HIDAPI library calls.

This commit adds the common logic of serial-over-HID communication and
implements the full internal serial transport API, including reception
in the background. But it does not yet support a single HID chip (which
each run their own proprietary protocol).

The implementation works with either hidapi-libusb or hidapi-hidraw
variant of the HIDAPI library, but was only tested on Linux.
2019-06-02 20:39:02 +02:00
Gerhard Sittig 4417074c68 serial: prepare serial over HID in common layer and build support
Search for the optional HIDAPI library. Call the library's init and exit
routine, and print version information. Extend the common serial layer's
code paths for open, list, and find USB to also support serial over HID.

This commit prepares serial over HID, but the HIDAPI specific transport
for serial communication still is empty in this implementation.
2019-06-02 20:39:02 +02:00
Gerhard Sittig ad5aa993ae serial: introduce local receive data buffer
Add a local RX buffer to the common code of libsigrok's serial layer.
Callers of the serial layer's API won't notice, this is an internal
detail of how alternative transports receive their data from the
physical line, and pass it to read() calls emitted by device drivers.

The libserialport specific code still calls into the library, and does
not use the RX buffer. Future HID and BLE support will use the buffer.
2019-06-02 20:39:02 +02:00
Gerhard Sittig 48b7c34629 serial: make LCR, modbus, SCPI over serial depend on generic serial comm
Add guards around the implementation of ES51919 chip support for LCR, as
well as modbus and SCPI over serial. To accept when the source files get
compiled in the absence of their dependencies, end up with an empty
implementation in that case.

This approach can simplify build rules when several optional external
dependencies result in differing sets of supported communication means.
2019-06-02 20:39:02 +02:00
Gerhard Sittig 1ac8c2181b serial: prepare for the absence of libserialport
Only reference the libserialport header when the library is available.
Allow to always compile the serial.c source file, but optionally end
up with an empty implementation. Make the sr_serial_dev_inst symbol
available outside of HAVE_SERIAL_COMM such that empty stub code can
compile. This prepares the introduction of alternative transports for
serial communication, while all of them remain optional.

The libsigrok serial layer internally uses parity and flow control
symbols which are provided by libserialport. Optionally locally declare
these symbols when libserialport is not available.
2019-06-02 20:39:02 +02:00
Gerhard Sittig bb15350e59 configure: make device drivers depend on "serial comm" not libserialport
A previous commit introduced the more generic "have serial communication"
condition, and adjusted the list of available libsigrok dependencies.

This commit adjusts device driver dependency declarations. This allows
to build e.g. DMM drivers in the presence of RFCOMM support but in the
absence of libserialport, because any of several optional external libs
can make serial communication available.
2019-06-02 20:39:02 +02:00
Gerhard Sittig 1df81f4b06 serial: introduce more general "have serial comm" feature flag
Introduce the HAVE_SERIAL_COMM identifier, which gets derived from, but
need not be identical to the HAVE_LIBSERIALPORT condition.

Derive the NEED_SERIAL automake condition from the general availability
of serial communication not the specific libserialport library.

Adjust source code references. Stick with HAVE_LIBSERIALPORT where the
specific library is meant, but switch to HAVE_SERIAL_COMM where the
availability of serial communication in general is meant.
2019-06-02 20:39:02 +02:00
Gerhard Sittig a7b8692ed0 serial: prepare alternative transports for serial communication
Add an indirection between the common serial communication code and the
libserialport specific support code. Prepare the use of alternative
transports like USB HID in the future. Decide in the open() routine
which transport to use for subsequent operations (based on port names).

In theory only the transport specific layer depends on the libserialport
library's availability. In this implementation all support for serial
communication still depends on the HAVE_LIBSERIALPORT preprocessor
symbol. This needs to get addressed in later commits.
2019-06-02 20:39:02 +02:00
Gerhard Sittig f992151332 ols: use serial layer's "has receive data" query
Eliminate a direct libserialport dependency in the OLS device driver.
Use libsigrok's internal serial layer's API instead to check for the
availability of receive data.
2019-06-02 20:39:02 +02:00
Gerhard Sittig 8c3df6e5cd serial: introduce "has receive data" query
Add a serial_has_receive_data() routine to the serial layer's API which
returns the number of (known to be) available RX data bytes. Implement
support in the libserialport specific code.
2019-06-02 20:39:02 +02:00
Gerhard Sittig ae4c1fb637 serial_libsp: move libserialport specific code to separate source file
Introduce a new serial_libsp.c source file, and move code from serial.c
there which is specific to libserialport. Keep the existing serial.c API
in place, this is a pure internal refactoring.

Adjust a little whitespace while we are here. Rearrange long lines to
keep related parameter groups adjacent (like pointer and size, or UART
frame length and flow control). Consistently reduce indentation of
continuation lines.
2019-06-02 20:39:02 +02:00
Gerhard Sittig 639c6f61c3 serial: determine timeout from most recent set_params() values
Store the most recent successfully applied set of parameters for serial
communication. Re-use these values as a fallback to calculate timeouts,
when the underlying transport fails to provide the current settings.
2019-06-02 20:39:02 +02:00
Gerhard Sittig dca683ef99 rohde-schwarz-sme-0x: remove obsolete libserialport reference
The rohde-schwarz-sme-0x device driver used to unconditionally reference
a libserialport header file. Remove that reference, it's not needed in
this specific driver.
2019-06-02 20:39:01 +02:00
Gerhard Sittig e24e74ed84 agilent-dmm: fixup whitespace nit (trailing space) 2019-06-02 20:39:01 +02:00
Gerhard Sittig 18037e79f1 doc: update manual driver addition in the HACKING document
Build support has changed to use linker sections for driver registration.
Update the subsection in the HACKING document which discusses the manual
addition of device drivers, to match what the new-driver script does for
driver authors.
2019-06-02 20:39:01 +02:00
Andreas Piesk 108d2ec2c2 saleae-logic16: Warn (instead of erroring out) if FPGA is unsupported
Don't exit with an error if the FPGA is detected as unsupported.

Just issue a warning with the detected version and continue. I have such
a clone and it works with the original Saleae software and with sigrok
despite the fact that its FPGA version is 0xff.
2019-06-01 17:15:55 +02:00
Vitaliy Vorobyov ca9f8961e3 serial-lcr: Add MASTECH MS5308 2019-05-14 19:56:57 +02:00
Uwe Hermann 3535a6eeee Fix an issue when building in directories that are symlinks.
Explicitly use SRCDIR and BUILDDIR in Doxyfile files to reference input
files. This seems to be a sufficient fix for an issue where the build
would fail when libsigrok/ was located in a directory that was a symlink.

This fixes bug #547.
2019-05-01 17:58:06 +02:00
Vitaliy Vorobyov dcd212f7a2 Add MASTECH MS2115B support. 2019-05-01 15:55:07 +02:00
Gerd v. Egidy 16a8e58068 agilent-dmm: add basic support for Agilent/Keysight U127x
Their commands are very similar to the U123x series, they just
add some more modes and the second channel. So use the re-functions
and just extend them where necessary.

Log reading not supported yet.

Basic testing done with a U1272A.
2019-05-01 15:43:00 +02:00
Gerd v. Egidy 878e0e9d21 agilent-dmm: fix support for Agilent/Keysight U1252A
- fix the resolution of the CONF?-response:
  the resolution is given with 6 decimal places
  (instead of 8) like this:

  VOLT +5.000000E+00,+1.000000E-04

- add more measurement modes that are possible with the meter:
  CONT,COND,TEMP,PULS
2019-05-01 15:43:00 +02:00
Gerhard Sittig 271392d969 serial: rename variable to reflect it's related to libserialport
Rename the rather generic 'data' struct member to 'sp_data', to better
reflect that it contains details which are specific to libserialport.
2019-04-28 17:41:12 +02:00
Gerhard Sittig 6213c38ef8 serial: update doxygen comments (flush vs drain, in vs out params)
It's important to remain aware that the serial layer's flush and drain
semantics differs from e.g. filesystem calls. The libserialport API is
said to follow the termios example.

Extend comments in the libsigrok API, to not depend on the libserialport
layer and the availability of its documentation. This raises awareness
during maintenance of sigrok device drivers, as well as the pending
addition of alternative transports for serial communication.

Adjust the doxygen comment for the read line routine while we are here.
Add "in" and "out" attributes for routine parameters.
2019-04-28 17:41:12 +02:00
Gerhard Sittig fcfa36fd6f libsigrok-internal.h: fix source file references in comments
The src/hardware/ subdirectory exclusively contains device drivers these
days, while common support code has moved to the src/dmm/, src/lcr/,
src/scale/, etc directories or src/ itself. Adjust comments in the
libsigrok-internal.h declaration blocks which reference source files.
2019-04-28 17:41:12 +02:00
Gerhard Sittig fdcdfe53d8 libsigrok-internal.h: nit, alpha-sort include directives 2019-04-28 17:41:12 +02:00
Gerhard Sittig e47a9562e9 device: rephrase sizeof() calls for reduced redundancy, use malloc0
Just allocate the memory needed to hold the very variable's size. No
need to duplicate the variable's type. Reduces redundancy and increases
robustness during maintenance.

Use g_malloc0() in sr_serial_new() to make sure all of the structure is
initialized.
2019-04-28 17:41:12 +02:00
Uwe Hermann 7d0f52f7e5 Consistently use the "Sysclk" spelling everywhere.
We use this spelling (not "SysClk") in most of the rest of the code-base,
as well as in the wiki.
2019-04-24 18:23:41 +02:00
Uwe Hermann 4ddd34b107 udev: Add Sysclk SLA50232 entry. 2019-04-24 18:23:41 +02:00
Uwe Hermann f3178f123d sysclk-sla5032: Minor asterisk placement consistency fixes. 2019-04-24 18:23:41 +02:00
Uwe Hermann 98ed645e40 sysclk-sla5032: Make a few functions static. 2019-04-24 18:18:57 +02:00
Uwe Hermann 9e0693f92d sysclk-sla5032: Merge sla5032.[ch] into protocol.[ch]. 2019-04-24 18:18:57 +02:00
Uwe Hermann 052cc011bf sysclk-sla5032: Shorten sla5032_start_sample() a bit. 2019-04-24 17:33:24 +02:00
Uwe Hermann d57a114347 sysclk-sla5032: Shorten a few code snippets a bit. 2019-04-22 13:39:48 +02:00
Uwe Hermann 262cb9968d sysclk-sla5032: Fix compiler warnings (max vs. MAX).
src/hardware/sysclk-sla5032/protocol.c: In function ‘la_start_acquisition’:
  src/hardware/sysclk-sla5032/protocol.c:244:8: warning: implicit declaration of function ‘max’ [-Wimplicit-function-declaration]
    pre = max(pre, 2);
          ^~~
2019-04-22 13:39:48 +02:00
Vitaliy Vorobyov 8da8c8265f Add initial Sysclk SLA5032 driver. 2019-04-22 13:39:48 +02:00
Dewelde Anthony ddbe6880a0 korad-kaxxxxp: Added support for TENMA 72-2535 V2.1 2019-04-17 17:59:22 +02:00
Uwe Hermann b89e6db910 scpi-pps: Fix typos and minor cosmetics. 2019-04-17 17:59:16 +02:00
Uwe Hermann fd2433153a scpi-pps: Fix "aquisition" typo everywhere. 2019-04-17 17:59:16 +02:00
Uwe Hermann 9652610080 sr_session_send_meta(): Drop unneeded check.
As of right now, sr_config_new() "cannot fail" and will never return NULL.
2019-04-17 17:45:04 +02:00
Frank Stettner 26e96658ab scpi-pps: Don't use SCPI_CMD_REMOTE and SCPI_CMD_LOCAL for HP 66xxB devices when in GPIB mode. 2019-04-17 17:45:04 +02:00
Frank Stettner 5ce427c71b scpi-pps: Add various HP power supplies:
HP 6632A, HP 6634A, HP 6611C, HP 6612C, HP 6613C and HP 6614C
2019-04-17 17:45:04 +02:00
Frank Stettner fdf0365257 scpi-pps: Implement init_acquisition() and update_status() for HP 66xxA power supplies. 2019-04-17 17:44:59 +02:00
Frank Stettner f083ae63c7 scpi-pps: Add config keys SR_CONF_OVER_VOLTAGE_PROTECTION_ACTIVE,
SR_CONF_OVER_CURRENT_PROTECTION_ACTIVE and
SR_CONF_OVER_TEMPERATURE_PROTECTION_ACTIVE to HP 66xxA power supplies.
2019-04-17 17:44:59 +02:00
Frank Stettner 0ad7074c9e scpi-pps: Add SR_CONF_REGULATION for HP 66xxA power supplies. 2019-04-17 17:44:59 +02:00
Frank Stettner dbc519f720 scpi-pps: Seperate existing HP 66xxA and 66xxB profiles. 2019-04-17 17:44:59 +02:00
Frank Stettner 969671a542 scpi-pps: Add missing frequency channel settings for acquisition. 2019-04-17 17:44:56 +02:00
Frank Stettner 3d1aa50f38 scpi-pps: Set device and channel group feature for HP 66xxB. 2019-04-17 17:44:56 +02:00
Frank Stettner f2bbcc330a scpi-pps: Add configurable sr_mqflags. 2019-04-17 17:44:56 +02:00
Frank Stettner fe4bb77492 scpi-pps: Implement init_acquisition() and update_status() for HP 66xxB power supplies. 2019-04-17 17:44:51 +02:00
Frank Stettner 6188675b72 scpi_libgpib: Add mutex to SPoll. 2019-04-17 17:44:51 +02:00
Frank Stettner 87aa1e63e3 scpi: Add enum scpi_transport_layer. 2019-04-17 17:44:51 +02:00
Frank Stettner 7e66bf0586 scpi-pps: Add init_acquisition() and update_status() for device specific
acquisition functions.
2019-04-17 17:43:07 +02:00
Frank Stettner 8b5eadf427 scpi-pps: Add config keys SR_CONF_OVER_VOLTAGE_PROTECTION_ACTIVE,
SR_CONF_OVER_CURRENT_PROTECTION_ACTIVE and
SR_CONF_OVER_TEMPERATURE_PROTECTION_ACTIVE to HP 66xxB power supplies.
2019-04-17 17:11:21 +02:00
Frank Stettner 43ff1110fb scpi-pps: Add SR_CONF_REGULATION for HP 66xxB power supplies. 2019-04-17 17:11:21 +02:00
Frank Stettner 5e7377f4c7 scpi-pps: Add enum pps_scpi_dialect and add to struct scpi_pps,
preset with reasonable values.
2019-04-17 17:11:21 +02:00
Frank Stettner 7d1a4a5239 session: Add helper sr_session_send_meta() to send SR_DF_META packages.
Replace individual functions in drivers for arachnid-labs-re-load-pro
and lcr/es51919 with sr_session_send_meta() helper function.
2019-04-17 17:11:19 +02:00
Uwe Hermann 6449b2e035 demo: Minor cosmetics. 2019-03-29 16:23:21 +01:00
Frank Stettner 1c0e1baaaa korad-kaxxxxp: Add another KA3005P with 0xBC as extra byte in the model ID. 2019-03-29 16:15:37 +01:00
Frank Stettner d1a3f3be45 korad-kaxxxxp: Add SR_MQFLAG_DC flag to the current channel package. 2019-03-29 16:15:37 +01:00
Frank Stettner 8107a9a650 scpi: Add connenction_id() function to all scpi drivers. 2019-03-29 16:15:37 +01:00
Frank Stettner 9618fde422 demo: Get/Set new config key offset. 2019-03-29 16:15:37 +01:00
Frank Stettner 78ec6cf99d Add new config key OFFSET. 2019-03-29 16:15:37 +01:00
Frank Stettner a6e5d2f676 demo: Get/Set amplitude while data acquisition is running. 2019-03-29 16:15:37 +01:00
Frank Stettner 94f364ec11 demo: Get/Set measurement quantity for the analog channels. 2019-03-29 16:15:37 +01:00
Frank Stettner 8430c9b62e demo: Set an initial mq, mq flag and digits to the analog package.
Without a measured quantity in packet.meaning->mq the C++ binding function
sigrok::Analog::mq() throws an exception and there is no way to check if
there is any measured quantity set in the analog package.
2019-03-29 16:15:37 +01:00
Frank Stettner a0bc8afd7d Free sr_config and sr_config lists in meta datafeeds correctly. 2019-03-29 16:15:37 +01:00
Soeren Apel 7ed4ae6307 input/trace32_ad: Add support for new file format (BINHDR2) 2019-03-24 21:33:54 +01:00
Soeren Apel 628dc330bc input/trace32_ad: Use only hex offsets 2019-03-24 13:48:44 +01:00
Uwe Hermann d025fce937 chronovu-la: Fix broken triggering.
This fixes bug #1369.
2019-03-22 00:59:39 +01:00
Thomas Andres 27a9b6639e korad-kaxxxxp: support for Stamos S-LS-31 power supply 2019-03-17 17:06:28 +01:00
Michael Klengel 88e6a8da9c manson-hcs-3xxx: Add HCS-3300 / DPPS-32-15 / HCS-3302 support.
Manson HCS-3300 (1-16 V, 30 A):

  $ sigrok-cli --show -d manson-hcs-3xxx:conn=/dev/cu.SLAB_USBtoUART5
  [...]
  sr: manson-hcs-3xxx: Unknown model ID 'HCS-3300' detected, aborting.

Voltcraft DPPS-32-15 (1-32 V, 15 A), identical to Manson HCS-3302:

  $ sigrok-cli --show -d manson-hcs-3xxx:conn=/dev/cu.SLAB_USBtoUART
  [...]
  sr: manson-hcs-3xxx: Unknown model ID 'HCS-3302' detected, aborting.
2019-03-09 18:23:05 +01:00
Michael Klengel dfd1daf25f manson-hcs-3xxx: Whitespace changes for models[]. 2019-03-09 18:23:05 +01:00
Frank Stettner 02d4db3562 hp-3478a: Check via GPIB serial poll if new data is available.
When just reading the data without check, the bus is blocked until new
data is available.
2019-03-09 18:01:11 +01:00
Uwe Hermann 1b6b9c01df ipdbg-la: Minor cosmetic and comment fixes. 2019-01-29 23:18:41 +01:00
Daniel Anselmi 8e249032d3 ipdbg-la: improve speed 2019-01-29 23:18:30 +01:00
danselmi c54ca32340 ipdbg-la: working on windows 2019-01-29 23:18:23 +01:00
Wolfram Sang f6ce25ec05 ols: add feature to support >256K memory
Add support for the Pepino-style of accessing >256K of memory. Because
this the only known extension of accessing >256K currently, we apply it
as soon as the sample size is bigger than 256K.  Let's hope other
devices (if any) will follow this style. If not, we need to add support
depending on the device name later.

Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
2019-01-13 20:07:27 +01:00
Wolfram Sang ec26d9e1df pipistrello: rename registers to match actual function
Magnus (creator of the Pipistrello) confirmed that he mixed up the
register names. The code was doing it correctly nonetheless but was
confusing to read because of this. Fix it to make it easier to
comprehend.

Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
2019-01-13 20:07:27 +01:00
Wolfram Sang 60143473c9 ols: mention compatible devices in driver name
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
2019-01-13 20:07:27 +01:00
Wolfram Sang ae4e6999c5 ols: extend reponse delay when scanning device
My Pepino needs 15ms instead of 10ms, so let's use 20ms to be on the
safe side.

Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
2019-01-13 20:07:27 +01:00
Wolfram Sang a88114183a ols: sort commands according to their hex value
Makes adding new ones easier.

Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
2019-01-13 20:07:27 +01:00
Wolfram Sang ea642977e5 ols: refactor using max_channels
Let max_channels really carry the number of maximum channels the
hardware supports. We will handle the limitation of only half the
channels available in 200MHz mode later. Note that there won't be a
regression because we only set the variable but never check it. The
desired result of this patch is the removal of the NUM_CHANNELS macro.
The number of channels needs to be dealt with at runtime.

Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
2019-01-13 20:07:27 +01:00
Wolfram Sang 4a34a74d73 ols: refactor channel initialization
We needs this twice so put it into a seperate function, so updates to it
will automatically handled for both callers.

Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
2019-01-13 20:07:27 +01:00
Wolfram Sang aad0c77708 ols: simplify calculation of readcount
Somewhen we probably want DIV_ROUND_UP from the Kernel.

Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
2019-01-13 20:07:27 +01:00
Wolfram Sang be15c51ed4 ols: drop wrong usage of macro
commit f51acd69 ("ols: combine demux samples") wrongly replaced the bit
pattern of 0x20 with the number of channels which just happens to be 32
as well. So, the code works but is confusing to read. Reword the
for-loop to make it more comprehensible.

Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
2019-01-13 20:07:27 +01:00
Wolfram Sang 6e5a1a0178 ols: use 32bit for handling sample counts
The OLS protocol sends 16bit values to specify the sample count and
delay count. However, this 16bit value is the number of 32bit words to
be sampled, so the actual sample count is 4 times larger and does not
fit into a uint16_t. Extend it to support the full range of 256K
(LogicShrimp will need this) and to prepare support for devices with
even more memory (Pepino).

Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
2019-01-13 20:07:27 +01:00
Wolfram Sang 6745488b1a ols: remove needless initialization
channel_mask is recalculated before it gets accessed, so this
initialization is not needed.

Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
2019-01-13 20:07:27 +01:00
Wolfram Sang 082537602a ols: remove unused define
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
2019-01-13 20:07:27 +01:00
Gerhard Sittig f0e6b41f7a uni-t-ut32x: rephrase the receive buffer and packets relation
The previous implementation assumed that a receive data chunk ends
exactly with a sensor packet's end. Yet the buffer had 32 bytes while
the packets have 19 bytes.

Separate the data reception from the packet processing. Collect whatever
chunks the USB connection provides, and scan the resulting buffer for
packets. Cope with either incomplete or corrupt or misaligned packets as
well as with multiple packets in receive chunks. The latter might happen
upon initial synchronization, when a device already sends data or the
serial port buffered previously communicated data.

In the regular case, the computer will process so fast that each single
character will be handled individually. We don't mind. The frequency is
some 60 times per second, and the data volume is 19 bytes. The software
works for the regular case, and synchronizes fast at startup or after
comm errors.
2019-01-13 19:34:10 +01:00
Gerhard Sittig a0ba75bda2 uni-t-ut32x: improve robustness of packet parser, more diagnostics
Always print the data bytes of received buffers in the packet parser,
then check some more fixed fields to not process invalid packets, then
process the packet content as the previous implementation did.

Call the packet parser for incomplete packets and discarded input
buffers as well (initial synchronization, re-sync after comm errors).
This results in the availability of more diagnostics during development.

Pass the packet's location and size from outside. This prepares the
logic to cope with situations where the receive buffer contains multiple
(potentially incomplete) packets.
2019-01-13 19:34:10 +01:00
Gerhard Sittig 4b3197828d uni-t-ut32x: use ASCII literals in packet parser, symbols for magic numbers
Slightly unobfuscate the UT32x packet parser. The protocol is mostly
ASCII based, checks for hex numbers may be unexpected. Use symbolic
identifiers for the packet length and some special characters.
2019-01-13 19:34:10 +01:00
Gerhard Sittig 2631d9320d uni-t-ut32x: comment on the "T1-T2" channel name (looks like a range) 2019-01-13 19:34:10 +01:00
Gerhard Sittig 9e11197246 uni-t-ut32x: use common code for sw limits, minor data type fixup (data source) 2019-01-13 19:34:10 +01:00
Gerhard Sittig bf700f679a uni-t-ut32x: pre-set to default conn= spec
The previous implementation of the UT32x driver expected to see a conn=
spec, without it no device is found. Default to the USB identification
of the CH9325 chip, to make the driver work out of the box. Users still
can provide conn= specs and override the default for other cables.
2019-01-13 19:34:10 +01:00
Gerhard Sittig de805ae50d doc: update README.devices (USB detection, enable serial comm)
Slightly rephrase README.devices since there is no strict distinction
into "fully automatic" and "always manual". Some drivers _accept_ conn=
specs when provided, _and_ support automatic detection of enumerable
devices, _and_ might implement defaults but also support overrides.

Nit, numerically sort the list of Uni-T cables (which is about to grow
in the future) for improved readability.

Add two more devices which require users to manually enable the serial
communication (Brymen BM257s, EEVBlog 121GW).
2019-01-13 19:34:10 +01:00
Martin Ling ea7a83a437 bindings: Add Output::format() 2018-12-30 14:10:13 +01:00
Martin Ling 47b821dc7d rigol-ds: Fix memory buffer readout on DS4000 series. 2018-12-29 03:24:23 +01:00
majekw e150d55046 Add support for YiXingDianZi MDSO in hantek-6xxx driver. 2018-12-28 13:49:33 +01:00
Mike Williams c3bfb95959 scpi-pps: add support for BK Precision 9130 2018-12-28 13:10:05 +01:00
Mike Williams 08e8c0e5bf scpi-dmm: add experimental Keysight 34465A support
Tested DC current, DC voltage, and resistance. Instrument gives an error
only on first measurement but the output of the measurements is correct.
2018-12-28 13:10:05 +01:00
Uwe Hermann 0bad836f95 contrib/60-libsigrok.rules: Mention FT232H/ftdi-la item. 2018-12-28 13:01:45 +01:00
Paul c7a51272a5 ftdi-la: added FT232H device ID 2018-12-28 13:01:03 +01:00
Martin Ling a9ed2eb069 bindings: Add new Context::create_end_packet() method. 2018-12-28 12:47:59 +01:00
Martin Ling 62bd644f55 python: Add override for Context.create_logic_packet() 2018-12-28 12:47:59 +01:00
Gerhard Sittig 6f7e15090e dmm/eev121gw: fix a typo in a comment 2018-12-27 11:26:19 +01:00
Gerhard Sittig fbbf21dcf5 pickit2: avoid NULL dereference in close code path 2018-12-27 11:26:19 +01:00
Daniel Anselmi f3549a1ccf ipdbg-la: Check if limit samples is valid (leq size of ringuffer) 2018-12-27 11:26:02 +01:00
Martin Ling 942719b46c Don't reference SR_PACKAGE_VERSION_STRING directly in backend.c.
Reporting build versus runtime versions makes sense for a client,
but not inside the library itself.
2018-12-20 19:12:34 +01:00
Martin Ling 2868bca35b Don't reference SR_PACKAGE_VERSION_STRING directly in output modules. 2018-12-20 19:12:34 +01:00
Uwe Hermann 3f34a40268 drivers: Make per-driver sr_dev_driver structs static. 2018-12-20 17:29:36 +01:00
Uwe Hermann 3aadf5c479 microchip-pickit2: Drop unneeded prefix. 2018-12-20 16:36:09 +01:00
Uwe Hermann e760f2cdaf microchip-pickit2: Minor cosmetics. 2018-12-20 16:36:09 +01:00
Gerhard Sittig bde6a99b33 microchip-pickit2: first driver implementation (acquisition works, triggers don't)
Fill in the scan, open/close, get/set/list, acquisition start/stop logic
such that data acquisition with a PICkit2 works.

Trigger support needs more attention. User specified triggers either
seem to not take effect, or the trigger position is not in the expected
location. It's yet to get determined what's the issue.

This implementation is based on protocol information gathered from the
pk2-la project.
2018-12-20 16:19:42 +01:00
Gerhard Sittig a5c0259c4a microchip-pickit2: Initial driver skeleton. 2018-12-20 16:19:42 +01:00
Gerhard Sittig d9a3c0b749 brymen-bm86x: drop redundant free call, fixup channel index
Remove a free() call in an error path for a list which immediately
before the call was determined to be NULL. Use index 0 and 1 for
channels P1 and P2 respectively (the previous implementation used 0
for both channels).
2018-12-20 16:19:42 +01:00
Gerhard Sittig 2887799404 scpi-dmm: run OPC queries immediately before essential commands
The current implementation of the SCPI DMM driver is conservative about
checking the device's being operational, but the *OPC? queries are found
in unfortunate locations. Run the OPC query right before running the
next "actual" command, not afterwards. And certainly not between sending
requests and potentially gathering responses in subsequent calls.

This commit does not change current behaviour, but improves maintenance
before pending commits.
2018-11-17 20:19:13 +01:00
Gerhard Sittig 08f3b427b6 scpi-dmm: return MQ table entry to "get MQ" routine callers
The "get MQ" helper routine communicates SCPI responses and translates
them to internal "MQ and flag" values. Optionally return the MQ table
entry reference to callers, so they don't have to repeat the table
lookup when the function's default precision is required, or should
future "start acquisition" requests need to refer to the meter's current
function.
2018-11-17 20:19:13 +01:00
Gerhard Sittig 64d03de1c2 scpi-dmm: adjust MQ table for Agilent 34405A
Rename the table to reflect that it's model specific. Remove the 4-wire
resistance function which this device does not support.
2018-11-17 20:17:48 +01:00
Gerhard Sittig 1d2f9963ab scpi-dmm: add support for model specific device options
Supported SCPI DMM devices will differ in the set of options and whether
parameters can get queried or configured. Use a "generic" set of devopts
during scan and for simpler models, prepare support for other sets of
devopts for more complex models.
2018-11-17 20:08:59 +01:00
Gerhard Sittig 31e65c62ec scpi-dmm: accept serialcomm= scan options 2018-11-17 20:08:59 +01:00
Gerhard Sittig 21bc4353f0 scpi: alpha-sort the vendor alias list 2018-11-17 20:07:21 +01:00
Gerhard Sittig 49b6732ec5 scpi: add Keysight vendor alias 2018-11-17 20:07:21 +01:00
Gerhard Sittig 0617bb5a4e scpi-dmm: move declaration of local variable out of header file 2018-11-17 20:07:21 +01:00
Michał Janiszewski 3e33089b72 Remove always-false condition 2018-11-10 23:20:29 +01:00
Sven Bursch-Osewold 4905215909 Python-Binding: Added data array for logic packet payload 2018-11-10 23:20:16 +01:00
Gerhard Sittig 3cdad416e4 scpi-dmm: Implement support for Agilent 34405A, prepare others
Implement the scpi-dmm driver in such a generic way that it could work
with several protocol variants and with differing models which happen to
use any of these protocol variants. Prepare a list of supported models
with their respective SCPI command set, set of DMM functions and their
precision.

Add support for Agilent 34405A. The ten functions of this device got
tested and are operational, in continuous mode as well as with sample
count or capture time limits. The driver can query the current meter's
function, can change the function, and can run acquisitions in either
the current mode or with a user specified function selection. There is
some potential for improvement: AUTO/MIN/MAX/HOLD indicators are not
supported by this implementation.
2018-11-10 23:14:49 +01:00
Gerhard Sittig 7a396ff5c5 scpi-dmm: Initial driver skeleton. 2018-11-10 20:11:35 +01:00
Gerhard Sittig a1ce15d4a1 scpi: nit, use glib to determine string vector length
Replace a DIY length calculation with a glib call.
2018-11-10 20:11:35 +01:00
Gerhard Sittig a019bc48fd scpi: introduce string un-quote helper routine
The SCPI protocol may communicate strings in quoted form, enclosed by a
matching pair of single or double quote characters, and occurances of
this very quote character within the string get doubled (escaped). Add a
common routine to undo the quotes.
2018-11-10 18:26:30 +01:00
Gerhard Sittig c10b0276da fluke-45: fix minor memory leaks in the probe routine
Free the SCPI hardware info after successful model detection, too. Only
allocate the device instance when a supported model was found. Link the
device context earlier right after allocation, for easier verification.
2018-11-10 18:26:30 +01:00
Gerhard Sittig 71db2d4d06 fluke-45: disable ECHO test, it confuses other SCPI devices
Disable the ECHO test in the Fluke 45 probe routine which violates the
SCPI protocol and makes other devices unavailable. This fixes bug #1272.
2018-11-10 18:26:30 +01:00
Gerhard Sittig 712f7d5e40 fluke-45: avoid NULL dereference in the probe routine
The Fluke 45 probe routine tries to detect whether the serial port is
"in echo mode" (which already is questionable before the IDN query).
In the absence of a response, the library segfaults. Fix it.
2018-11-10 18:26:30 +01:00
Gerhard Sittig 88c03eae85 README.devices: add example for -d driver:conn=usbtmc/bus.addr 2018-11-10 18:26:30 +01:00
Jon Burgess 3940abcb47 Free list returned by sr_session_dev_list()
==214948== 16 bytes in 1 blocks are definitely lost in loss record 161 of 6,440
==214948==    at 0x4C2EE0B: malloc (vg_replace_malloc.c:299)
==214948==    by 0x650F435: g_malloc (in /usr/lib64/libglib-2.0.so.0.5600.3)
==214948==    by 0x6527056: g_slice_alloc (in /usr/lib64/libglib-2.0.so.0.5600.3)
==214948==    by 0x65284B0: g_slist_copy_deep (in /usr/lib64/libglib-2.0.so.0.5600.3)
==214948==    by 0x592BBA6: sr_session_dev_list (session.c:402)
==214948==    by 0x56EF7B5: sigrok::Session::Session(std::shared_ptr<sigrok::Context>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) (classes.cpp:932)

==214948== 16 bytes in 1 blocks are definitely lost in loss record 162 of 6,440
==214948==    at 0x4C2EE0B: malloc (vg_replace_malloc.c:299)
==214948==    by 0x650F435: g_malloc (in /usr/lib64/libglib-2.0.so.0.5600.3)
==214948==    by 0x6527056: g_slice_alloc (in /usr/lib64/libglib-2.0.so.0.5600.3)
==214948==    by 0x65284B0: g_slist_copy_deep (in /usr/lib64/libglib-2.0.so.0.5600.3)
==214948==    by 0x592BBA6: sr_session_dev_list (session.c:402)
==214948==    by 0x56F1EB1: sigrok::Session::devices() (classes.cpp:967)
2018-10-22 00:02:40 +02:00
Uwe Hermann 827139ef49 siglent-sds: Consistently use gboolean/TRUE/FALSE. 2018-10-21 23:33:15 +02:00
Guido Trentalancia fa3d104f17 Additional USB PID for Rohde&Schwarz HMO series mixed-signal oscilloscopes
Add another possible USB PID for Rohde&Schwarz HMO series mixed-signal
oscilloscopes (previously branded Hameg).
2018-10-21 23:32:07 +02:00
Gerhard Sittig 0be955d23d dmm/eev121gw: drop an obsolete TODO comment (power measurement) 2018-10-18 19:18:46 +02:00
Gerhard Sittig 72b6f1c082 dmm/eev121gw: cosmetics, align ranges' scaling table entries
Align the scaling items such that all numbers are aligned. Drop unneeded
"prefixes" for the 2nd display's tables, the main and sub displays already
have their individual tables which reside in their respective groups.
2018-10-18 19:11:38 +02:00
Gerhard Sittig 39ea7b7d39 dmm/eev121gw: add missing scale items for sub display in power modes
Complete the voltage and current scale items for the sub display which
were incomplete for VA, mVA, and uVA power measurement modes before.
2018-10-18 19:08:50 +02:00
Uwe Hermann 59cae77e28 serial_stream_detect(): Make a code comment more generic. 2018-10-14 22:05:57 +02:00
Soeren Apel d10781808d demo: Fixup soft-trigger 2018-10-14 22:05:57 +02:00
luftek 6fc51fb1ee demo: Implement logic triggering.
Analog triggers and other items still need more work.
2018-10-14 21:37:40 +02:00
luftek 31f69b096f demo: Port trigger configuration from fx2lafw. 2018-10-14 21:37:30 +02:00
Uwe Hermann 07182332f0 Random whitespace/cosmetic/typo fixes. 2018-10-14 18:21:56 +02:00
Gerhard Sittig 015df4ae8f serial-dmm: add EEVblog 121GW device entry (-d eevblog-121gw:conn=<uart>)
Add an "eevblog-121gw" subdriver entry for the EEVblog 121GW multimeter.
Use device dependent channel names instead of the default "P1" etc names.

It's assumed that the device's binary packet data is available at a COM
port. This means that an external BT to UART gateway is required until
BLE communication will be one of libsigrok's native connection types.
2018-10-14 18:21:56 +02:00
Gerhard Sittig 1c3098aae0 dmm/eev121gw: introduce parser for EEVblog 121GW 19-byte binary packets
Introduce the dmm/eev121gw.c source file with parse routines for the
EEVblog 121GW meter's 19-bytes binary packets. Get the values and MQ
properties of the device's several displays (main, sub, bar) in several
individual parse calls.

This commit introduces initial support for the device. Some of the modes
and features are untested, as are some of the device's ranges.
2018-10-14 18:21:56 +02:00
Thomas Weißschuh 388aa0fb6b Newer versions of Victor DMMs (at least for 86) contain a direct
Mini-USB port. This port speaks the FS9922 protocol.

Picture of Mini-USB version:
http://roastlogger.co.uk/coffee/roastlogger/victor86.html

Signed-off-by: Thomas Weißschuh <thomas@t-8ch.de>
2018-10-14 17:43:34 +02:00
Uwe Hermann 023c6114c5 siglent-sds: Fix SR_CONF_AVERAGING/SR_CONF_AVG_SAMPLES handling. 2018-10-14 01:41:03 +02:00
marchelh c90065a949 siglent-sds: Add ESERIES device support.
Due to some SCPI command changes that Siglent made, the connection
failed due to the wrong commands being send to the device.

This might fix parts of bug #1242, though initial tests show that
further changes might be needed.

[Note: This commit consists of multiple squashed commits from
marchelh <marchelh@gmail.com> and various fixups and rebasing
operations by Uwe Hermann <uwe@hermann-uwe.de>]
2018-10-14 01:40:38 +02:00
Uwe Hermann 0540954d76 korad-kaxxxxp: Add Tenma 72-2540 V2.0/V2.1 support (untested).
The IDN strings were mentioned here:
https://github.com/kxtells/tenma-serial/issues/2
2018-10-13 17:26:47 +02:00
Gerhard Sittig e5fa47c1c9 serial: dump DMM packets during stream detection
Regular operation of serial DMM drivers optionally can dump packet bytes
after the intialization phase has synchronized to the stream. Failure to
synchronize to the stream left developers without a dump, which complicates
research what went wrong.

Do dump packet content while the serial_stream_detect() routine tries to
synchronize to the stream. Use the spew level since the dump occurs upon
every attempt, which translates to: every received byte until a valid
packet was seen (or the synchronization phase expired).
2018-10-13 15:57:01 +02:00
Gerhard Sittig 75aaf967e3 serial-dmm: print data bytes according to specific meter's packet length
The previous implementation always dumped 23 data bytes for received
packets. This could result in truncated diagnostics information, and/or
access to invalid buffer content.

Rephrase the packet dump routine such that the specific meter's exact
packet length gets dumped, and use the common hex dump support code.
2018-10-13 15:57:01 +02:00
Gerhard Sittig f1d0755b73 uni-t-dmm: use common hex dump helper routine 2018-10-13 15:57:01 +02:00
Gerhard Sittig d8bc7ca3e6 strutil: introduce hex dump routines (allocate a text buffer)
Introduce common support for hex dumps in the string util collection.
There are explicit allocation and release routines for the textual
representation of the data bytes, so that callers are free to chose
whether and how to decorate the dump and where to send the message.
2018-10-13 15:57:01 +02:00
Gerhard Sittig 08f8421a9e input/vcd: add channel list checks for file re-read
Keep (part of) previous results around when the VCD input module gets
reset, and check the header of the next import against previous runs to
avoid issues in applications. This addresses the VCD specific part of
bug #1241, and resolves the remaining part of bug #1306.
2018-10-13 15:17:51 +02:00
Gerhard Sittig 712f981dff device: introduce routines to compare channels and channel lists
Applications are not prepared to handle changes in the channel list
between multiple acquisitions from the same source (device drivers
or input modules). Introduce common helpers to compare channels and
channel lists.
2018-10-13 15:17:51 +02:00
Gerhard Sittig fe71c7e42e device: introduce common sr_channel_free() support code
There was the sr_channel_new() allocation routine, but releasing that
allocation was open-coded in call sites. Add the sr_channel_free()
routine for code re-use and consistency.
2018-10-13 15:06:43 +02:00
Gerhard Sittig 4237ab9e5b input/vcd: Expand the reset() logic
This addresses part of bug #1306. The reset() method of the VCD input
module was incomplete, and did not process new data upon second read.
Improve robustness and add missing reset instructions. Void invalid
pointers and avoid NULL dereferences in cleanup paths.
2018-10-13 15:04:50 +02:00
Gerhard Sittig 76f712a73f korad-kaxxxxp: add yet another KD3005P identification string
Apparently there are devices which identify as "KORADKD3005PV2.0" (no
whitespace, no trailing 0x01). Add another model entry.

Reported-By: Lars Pötter
2018-10-13 14:27:56 +02:00
Uwe Hermann 11cf492183 zeroplus-logic-cube: Only emit log message upon unexpected number of bytes. 2018-10-06 19:13:39 +02:00
Uwe Hermann 2377246220 Fix various gcc 8 compiler warnings related to ARRAY_SIZE.
Example:

  In file included from src/hardware/kecheng-kc-330b/protocol.h:26,
                   from src/hardware/kecheng-kc-330b/api.c:22:
  src/hardware/kecheng-kc-330b/api.c: In function ‘config_list’:
  src/libsigrok-internal.h:51:34: warning: division ‘sizeof (void *) / sizeof (void)’ does not compute the number of array elements [-Wsizeof-pointer-div]
   #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
                                    ^
  src/libsigrok-internal.h:55:32: note: in expansion of macro ‘ARRAY_SIZE’
   #define ARRAY_AND_SIZE(a) (a), ARRAY_SIZE(a)
                                  ^~~~~~~~~~
  src/libsigrok-internal.h:964:43: note: in expansion of macro ‘ARRAY_AND_SIZE’
    std_opts_config_list(key, data, sdi, cg, ARRAY_AND_SIZE(scanopts), \
                                             ^~~~~~~~~~~~~~
  src/hardware/kecheng-kc-330b/api.c:296:10: note: in expansion of macro ‘STD_CONFIG_LIST’
     return STD_CONFIG_LIST(key, data, sdi, cg, NULL, drvopts, devopts);
            ^~~~~~~~~~~~~~~
2018-10-06 19:13:39 +02:00
Peetz0r af930bcf7b fx2lafw: Add new VID:PID for usb-c-grok 2018-10-03 19:09:29 +02:00
Gerhard Sittig 7d40b5ee62 serial-dmm: introduce support for subdriver specific channel names
Default to the existing "P1" etc naming scheme for analog channels of
serial-dmm subdrivers. Add support for subdriver specific channel names
(which can reference the channel number if they desire). This is useful
for devices with multiple displays, or special purpose devices where
other names than P1 can better reflect the channel's nature.
2018-10-02 19:01:25 +02:00
Gerhard Sittig e91c9f6e25 serial-dmm: only send acquisition data for enabled channels
Respect the user's "channel enabled" status. Do not feed the session bus
when data for disabled channels was received.
2018-10-02 19:01:25 +02:00
Gerhard Sittig 48e2992f86 serial-dmm: count analog DMM channels starting at 1
Commit 556a926d43 introduced support for multiple displays in
subdrivers of serial-dmm, but also changed user visible channel numbers
to start from 0. Restore the previous behaviour, start counting from 1
which users may perceive as more natural (serial-dmm used to start at P1
in the past, scopes start with CH1 as well).
2018-10-02 19:01:25 +02:00
Gerhard Sittig 3ef305b079 brymen-bm86x: avoid NULL deref when usb->devhdl does not exist
There are code paths where dev_close() tries to access a USB handle
which does not exist. This was observed with this command:

  $ sigrok-cli -d brymen-bm86x --scan
2018-10-02 19:01:04 +02:00
Gerhard Sittig bd10287e7c Makefile: cosmetics, alpha-sort src/dmm/ entries 2018-10-02 19:01:04 +02:00
Uwe Hermann 822a9c0eda hantek-6xxx: Hantek 6022BL: Add VID/PID 04b5:602a support.
On Windows, this device can either enumerate as 04b4:602a or 04b5:602a,
depending on which vendor driver is currently being used, so we have to
support both in the hantek-6xxx driver as well.

This fixes bug #1295.
2018-10-02 15:15:27 +02:00
Martin Ling 56bcbbffd0 raw_analog: Set appropriate precision digits for sample format.
This fixes parts of bug #950.
2018-09-20 20:36:00 +02:00
Martin Ling cd1e7fd20d analog output: convert binary to digital digits of precision.
This fixes parts of bug #950.
2018-09-20 20:35:57 +02:00
Martin Ling 5e5fde6e2c Fix read past end of array in sr_analog_si_prefix_friendly.
In the case where the input unit was not in the array, the for loop would
complete, but the following test would then read past the end of the array
since 'i' would already have been incremented to the array size.

Spotted because unitless data was getting SI prefixes with no unit, though
this would not have been deterministically reproducible.

This fixes parts of bug #950.
2018-09-20 20:35:42 +02:00
Uwe Hermann 755793e991 scpi-pps: Add a missing "break" in config_get(). 2018-09-18 23:42:24 +02:00
Uwe Hermann 3bae09ab9f Make sr_packet_{copy,free} API calls public.
This fixes bug #1277.
2018-09-18 23:39:56 +02:00
Martin Ling 3d11872282 scpi-pps: Fix broken channel selection code.
Fixes bug #1279.
2018-09-11 13:08:12 +01:00
Martin Ling 88e4daa9ff scpi-pps: Use software sample and time limits. 2018-09-10 16:33:11 +01:00
Martin Ling 49f7cb2425 scpi-pps: Don't block waiting for a value on capture stop.
The comment says "A requested value is certainly on the way", but the code no
longer works this way. The receive handler requests a value and blocks until
it is received. There is no value pending between receive handler calls, so
this code now only leads to a timeout.
2018-09-10 16:12:58 +01:00
Martin Ling cda70c2c19 Add udev rules for Rigol DP800 series. 2018-09-10 13:51:17 +01:00
Uwe Hermann 04a0e0dc1c output/csv: Disable the dedup option by default.
Having this on by default is surprising to most users, since csv is
not usually associated with having a VCD-like dedup property/feature.
2018-09-05 21:50:02 +02:00
Uwe Hermann f696d27e05 std: Drop unneeded/duplicate log messages.
The sr_session_send() function will already log all of those anyway.
2018-09-05 20:31:48 +02:00
Andrej Valek ee1a7d2f9d hantek-4032l: Fix default threshold value selection (FP workaround).
Take value from generated array of range instead of using a hard-coded value.

Signed-off-by: Andrej Valek <andy@skyrain.eu>
2018-09-04 01:39:06 +02:00
Soeren Apel 653d087e15 std: Fix up non-zero FP value generation 2018-09-04 01:31:56 +02:00
Gerhard Sittig 0da8e0bd2b input: improve robustness, avoid NULL dereference in sr_input_send()
Applications might pass NULL for the buffer, and input modules might
accept it (or just cope). Eliminate a potential NULL dereference in
the emission of diagnostics messages.
2018-09-03 22:22:46 +02:00
Gerhard Sittig b736fa0c7d proto.h: move routine declaration to its respective group 2018-09-03 22:22:40 +02:00
Uwe Hermann 3ad0308c55 sr_resourcepaths_get(): Drop confusing log message.
This is not really needed and can sometimes confuse users.
2018-09-03 22:18:28 +02:00
Uwe Hermann 2efb3cd700 hantek-6xxx: Hantek 6022BE: Add VID/PID 04b5:6022 support.
On Windows, this device can either enumerate as 04b4:6022 or 04b5:6022,
depending on which vendor driver is currently being used, so we have to
support both in the hantek-6xxx driver as well.

This fixes bug #918.
2018-09-03 22:01:32 +02:00
Uwe Hermann 00f0016cc3 Consistently use the _WIN32 #define.
The _WIN32 variant is available pretty much on all compilers, others
might not be. G_OS_WIN32 would probably be an equally well-suited
alternative, but for now we standardize on _WIN32.

  http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system#WindowswithCygwinPOSIX
2018-09-01 21:11:45 +02:00
Uwe Hermann 9be587a148 ipdbg-la: Fix two compiler warnings on Windows.
This is happening because the send() and recv() functions
have different prototypes on POSIX and Windows. Using the casts
is required on Windows and doesn't hurt on POSIX systems.

  [...]/protocol.c: In function 'tcp_send':
  [...]/protocol.c:161:26: warning: pointer targets in passing argument 2 of 'send' differ in signedness [-Wpointer-sign]
    out = send(tcp->socket, buf, len, 0);
                            ^
  In file included from [...]/protocol.c:24:0:
  [...]/include/winsock2.h:997:34: note: expected 'const char *' but argument is of type 'const uint8_t * {aka const unsigned char *}'
     WINSOCK_API_LINKAGE int WSAAPI send(SOCKET s,const char *buf,int len,int flags);
                                    ^
  [...]/protocol.c: In function 'ipdbg_la_tcp_receive':
  [...]/protocol.c:201:32: warning: pointer targets in passing argument 2 of 'recv' differ in signedness [-Wpointer-sign]
      int len = recv(tcp->socket, buf, 1, 0);
                                  ^
  In file included from [...]/protocol.c:24:0:
  [...]/include/winsock2.h:992:34: note: expected 'char *' but argument is of type 'uint8_t * {aka unsigned char *}'
     WINSOCK_API_LINKAGE int WSAAPI recv(SOCKET s,char *buf,int len,int flags);
                                    ^
2018-09-01 21:08:10 +02:00
Uwe Hermann 3bfdadf6df ipdbg-la: Fix data_available() implementation on Windows.
[...]/protocol.c: In function 'data_available':
  [...]/protocol.c:73:38: error: 'bytes_available' undeclared (first use in this function)
    ioctlsocket(tcp->socket, FIONREAD, &bytes_available);
                                        ^
  [...]/protocol.c:73:38: note: each undeclared identifier is reported only once for each function it appears in
  [...]/protocol.c:84:1: warning: no return statement in function returning non-void [-Wreturn-type]
   }
   ^
2018-09-01 21:07:09 +02:00
Uwe Hermann 24fbd9f814 ipdbg-la: Fix a build issue on Windows.
[...]/protocol.c:41:23: fatal error: sys/ioctl.h: No such file or directory
2018-09-01 21:06:57 +02:00
Gerhard Sittig 4be5746d1d fx2lafw: silence error message in query for channel group's device options
The fx2lafw(4) driver supports mere logic analyzers as well as mixed
signal devices, but does not support channel group specific device
options. Avoid an error message when channel group device options get
queried, the condition is perfectly legal and non-fatal.

How to reproduce:
  $ pulseview -d fx2lafw
  $ sigrok-cli -d fx2lafw -g Logic --show

This fixes bug #1267.
2018-08-30 22:11:25 +02:00
Gerhard Sittig 1372bdcdb5 saleae and other FX2: show firmware name when loading fails
The "firmware load failed" message would be even more helpful if users
could learn which firmware file failed to load. Add those filenames to
various FX2-based drivers.

This addresses bug #1262.
2018-08-30 22:05:56 +02:00
Uwe Hermann ee425a466a Add a new sr_log_callback_get() API call. 2018-08-30 19:11:30 +02:00
Uwe Hermann 8bc8e9094c ipdbg-la: scan(): Use g_strdup_printf(). 2018-08-30 02:02:51 +02:00
Uwe Hermann 4d33f5e112 ipdbg-la: Make some functions static. 2018-08-30 01:56:35 +02:00
Uwe Hermann ac3625bef9 ipdbg-la: Avoid CamelCaps and ALLCAPS variable names. 2018-08-30 01:35:48 +02:00
Uwe Hermann 703fb45490 ipdbg-la: Drop some unneeded casts. 2018-08-30 01:22:10 +02:00
Uwe Hermann 4465837b7d ipdbg-la: data_available(): Return gboolean. 2018-08-30 01:22:10 +02:00
Uwe Hermann 3831eaf9f4 ipdbg-la: Use std_init() and std_dev_list(). 2018-08-30 01:22:02 +02:00
Uwe Hermann 4838c6ca5a ipdbg-la: Consistently use g_strerror(). 2018-08-30 00:53:18 +02:00
Uwe Hermann fac36d0a77 ipdbg-la: Drop unneeded g_malloc0() checks for small allocations. 2018-08-30 00:52:19 +02:00
Uwe Hermann 13ac501acd ipdbg-la: Drop unneeded sdi->status handling.
This is already done by the backend wrapper functions.
2018-08-30 00:50:35 +02:00
Uwe Hermann 77b6b98d1c ipdbg-la: Simplify config_get/_set/_list. 2018-08-30 00:47:03 +02:00
Uwe Hermann 1f9652a861 ipdbg-la: Fix devopts[] contents. 2018-08-30 00:39:40 +02:00
Uwe Hermann 1f15efc1f7 ipdbg-la: Drop various unneeded name prefixes. 2018-08-30 00:33:39 +02:00
Uwe Hermann 932ef10f12 ipdbg-la: Fix incorrect copyright headers.
As per Daniel Anselmi <danselmi@gmx.ch> in an email conversation, the
code was actually written by Eva Kissling <eva.kissling@bluewin.ch>
(as indicated in the commit logs as well). Fix the headers accordingly.
2018-08-30 00:33:39 +02:00
Uwe Hermann 8a9788e2b7 ipdbg-la: Consistently use the same naming everywhere.
Use "ipdbg-la" everywhere to refer to the driver, including
in function name prefixes etc. There's no need to encode
website details (.org) into the driver/function name(s).
2018-08-30 00:11:51 +02:00
Soeren Apel ed18648423 ipdbg-la: Allow rx to time out and handle invalid data properly
This is required for when we connect to invalid devices, e.g.
port 4243 of the IPDBG host instead of 4242.
2018-08-29 23:59:48 +02:00
Soeren Apel 8771222588 ipdbg-la: Remove SR_CONF_SERIALCOMM 2018-08-29 23:59:45 +02:00
Soeren Apel 9d2e5483dc ipdbg-la: Adjust to sigrok indentation style 2018-08-29 23:59:42 +02:00
Soeren Apel 7f4c9a0444 ipdbg-la: More style fixes 2018-08-29 23:59:39 +02:00
Soeren Apel 38e7493dd1 ipdbg-la: Style fixes 2018-08-29 23:59:35 +02:00
Eva Kissling b51288e3da ipdbg-la: stop-command 2018-08-29 23:59:32 +02:00
Eva Kissling b8fa29a175 ipdbg-la: stop-function pulseview 2018-08-29 23:59:30 +02:00
Eva Kissling a66099c6fa ipdbg-la: add edge trigger option 2018-08-29 23:59:27 +02:00
Eva Kissling 2f15f5bfec ipdbg-la: revers order of trigger settings 2018-08-29 23:59:25 +02:00
Eva Kissling a54144c0bd ipdbg-la: return correct samples limit 2018-08-29 23:59:22 +02:00
Eva Kissling 8f6b0eb12a ipdbg-la: add "loggs" 2018-08-29 23:59:20 +02:00
Eva Kissling 750303aab8 ipdbg-la: get rid of crash on shutdown 2018-08-29 23:59:17 +02:00
Eva Kissling d37c6daa84 ipdbg-la: reduce warnings (added explicit casts) 2018-08-29 23:59:14 +02:00
Eva Kissling a4210e1890 ipdbg-la: Add changes for IPDBG project 2018-08-29 23:59:10 +02:00
Uwe Hermann 17e0251d84 sr_buildinfo_libs_get(): Also support LIBUSBX_API_VERSION.
This fixes a build issue on some distros / libusb versions.
2018-07-22 18:01:22 +02:00
Uwe Hermann 0875f11de4 Fix multiple C++ bindings warnings with gcc 8.
bindings/cxx/classes.cpp: In function ‘int sigrok::call_log_callback(void*, int, const char*, __va_list_tag*)’:
  bindings/cxx/classes.cpp:242:17: warning: catching polymorphic type ‘class sigrok::Error’ by value [-Wcatch-value=]
    } catch (Error e) {
                   ^
  In file included from bindings/cxx/classes.cpp:1667:
  bindings/cxx/enums.cpp: In static member function ‘static Glib::VariantBase sigrok::ConfigKey::parse_string(std::__cxx11::string, sr_datatype)’:
  bindings/cxx/enums.cpp:789:13: warning: catching polymorphic type ‘class std::invalid_argument’ by value [-Wcatch-value=]
      } catch (invalid_argument) {
               ^~~~~~~~~~~~~~~~
  bindings/cxx/enums.cpp:804:13: warning: catching polymorphic type ‘class std::invalid_argument’ by value [-Wcatch-value=]
      } catch (invalid_argument) {
               ^~~~~~~~~~~~~~~~
2018-07-22 17:08:44 +02:00
Uwe Hermann 19d816c54a input/wav: Fix potential buffer overflow (and compiler warning).
With gcc 8 this yielded:

  src/input/wav.c: In function ‘receive’:
  src/input/wav.c:345:51: warning: ‘%d’ directive output may be truncated writing between 1 and 10 bytes into a region of size 6 [-Wformat-truncation=]
       snprintf(channelname, sizeof(channelname), "CH%d", i + 1);
                                                     ^~
  src/input/wav.c:345:48: note: directive argument in the range [1, 2147483647]
       snprintf(channelname, sizeof(channelname), "CH%d", i + 1);
                                                  ^~~~~~
  src/input/wav.c:345:5: note: ‘snprintf’ output between 4 and 13 bytes into a destination of size 8
       snprintf(channelname, sizeof(channelname), "CH%d", i + 1);
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2018-07-22 16:59:38 +02:00
Uwe Hermann 0f5bba9622 strutil.c: Use gboolean in favor of bool for consistency. 2018-07-22 16:37:58 +02:00
Gerhard Sittig 081aaebfc7 tests: add (negative) "." test case for rational conversion
A naive implementation of the parse rational conversion helper could
have accepted invalid input. Check for the expected conversion failure.
2018-07-22 16:36:15 +02:00
Gerhard Sittig 74d915331a tests: add more cases for text to rational number conversion
Test the ".1" and "1." cases which are assumed to be problematic on
MacOS (or may not have been supported before a recent update). Add more
tests with leading signs as well as whitespace instead of a sign.
2018-07-22 16:36:15 +02:00
Gerhard Sittig d875496366 strutil: insist in some mantissa for parse rational
The previous implementation accepted either empty integer or empty
fractional parts of a floating point number, but also when both parts
were missing ("." input). Insist in at least one of the parts to be
present.
2018-07-22 16:36:15 +02:00
Gerhard Sittig 7f5bfd6130 strutil: accept leading whitespace in parse rational
Programmatic output of floating point numbers might choose to print
spaces instead of an explicit '+' sign, to align the output with the
result of formatting negative numbers yet achieve a screen appearance
similar to what humans would have written. Skip leading whitespace
before insisting in seeing either signs or digits or decimals.
2018-07-22 16:36:15 +02:00
Gerhard Sittig 42408643f9 strutil: handle empty fractional in parse rational
Accept numbers like "123." where the period (dot) is present yet the
fractional part is empty. Adding a period but no additional digits is a
popular method of turning an otherwise integer literal into a float.
Compilers and strtod() routines accept this notation, too, so we have to
expect seeing such input.
2018-07-22 16:36:15 +02:00
Gerhard Sittig dd3202febf strutil: cosmetics, fixup minor style nits 2018-07-22 16:36:15 +02:00
Gerhard Sittig 83a05ca9b3 tests: echo text input when rational conversion fails
The previous implementation only echoed the p/q conversion results _if_
the return code signalled success but the result was unexpected. Although
the errno value for failed conversion attempts (non-zero return codes)
is not too helpful, seeing which text input failed the test is desirable.
2018-07-22 16:36:15 +02:00
Gerhard Sittig ed367d6820 input/vcd: abort VCD import when timestamp counts backwards
The VCD specification requests that timestamps will strictly increase as
one advances through the file. Add another check where the previous
implementation resulted in a tight loop and made the application stall.
Do print an error message and abort file processing in that case.

This fixes bug #1250.
2018-07-22 16:15:26 +02:00
Uwe Hermann e6104296c2 sr_buildinfo_libs_get(): Show LIBUSB_API_VERSION. 2018-07-19 23:56:33 +02:00
Uwe Hermann 9bf093011a configure.ac: Emit a warning if the C++ bindings are not being built. 2018-07-17 22:25:40 +02:00
Uwe Hermann 51bf39a163 strutil: Fix unit test failure (bug #1093).
Patch by Wojciech Lazarski, thanks a lot!
2018-07-17 19:06:05 +02:00
Gerhard Sittig 3387a5d8ee output: simplify trigger marker position calculation (readability)
This amends commit 67b345b981 which fixed the calculation of the
trigger marker's position. Improve readability of the formulae and
adjust comments.
2018-07-15 20:47:08 +02:00
Gerhard Sittig 67b345b981 output: fixup trigger marker position in ascii/bits/hex output modules
Adjust the calculation of the '^' marker's position in T: lines of the
-O ascii/bits/hex output modules such that it matches the sample data
lines' layout. Add comments which discuss the motivation of the marker
position's calculation, which differs among each of those modules.

Strictly speaking -O bits was already correct. But I chose to adjust and
comment the logic such that multiple output modules follow a common
pattern. If performance is an issue, the bits.c change might be worth
reverting.

This commit fixes bug #1238.
2018-07-15 19:40:00 +02:00
Uwe Hermann 769561cbe9 std: Improve prototypes of some functions. 2018-06-26 16:42:43 +02:00
Uwe Hermann 0f523f2b45 rigol-ds: Add initial Agilent MSO7034A support.
Digital channels (and various other features) are not yet supported.
2018-06-22 22:53:11 +02:00
Uwe Hermann 9ad1d49c4c rigol-ds: Improve a log message. 2018-06-22 19:20:44 +02:00
Uwe Hermann c26107b745 siglent-sds: Drop currently unused switch/case. 2018-06-22 18:54:28 +02:00
Uwe Hermann eb354840f0 siglent_sds_channel_start(): Use ternary operator to shorten code. 2018-06-22 18:54:28 +02:00
Uwe Hermann 55bece00aa rigol-ds: Add missing "return SR_ERR". 2018-06-22 10:53:03 +02:00
marchelh e5b41b8d7e siglent-sds: Fixed samplerate and memory depth calculation 2018-06-22 10:51:50 +02:00
marchelh 7e776c70b0 siglent-sds: Fix, USB connection problem partially solved, bug #1130 2018-06-22 10:51:39 +02:00
Uwe Hermann 5e7ac9f9ec udev: Add rule for Rigol DS4000 series devices. 2018-06-22 01:55:15 +02:00
Valentin Ochs 6b04525ba2 rigol-ds: Initial patch for Rigol DS4000 support
This fixes bug #1208.
2018-06-22 01:55:02 +02:00
Valentin Ochs 643c8824a5 rigol-ds: Rename the CHANINFO macro and comment it 2018-06-22 00:47:09 +02:00
Valentin Ochs 6bcc81ac3a rigol-ds: Store trigger sources and their number for each model
Store trigger sources and their number for each model when it is probed
and use that.

This fixes bug #299.
2018-06-22 00:35:44 +02:00
Uwe Hermann 32054b0963 tests: Expand test_analog_unit_to_string unit test. 2018-06-19 18:22:42 +02:00
Uwe Hermann 72cb20ed07 tests: Fix test_analog_unit_to_string unit test.
The loop body was never executed.
2018-06-19 18:22:42 +02:00
Uwe Hermann c5c6fa0f22 serial-dmm: Fix Voltcraft VC-96 sorting. 2018-06-18 16:30:04 +02:00
Uwe Hermann 4a6751fd07 dmm/vc96: Drop some obsolete debug output. 2018-06-18 16:30:04 +02:00
Matthias Schulz 9456d63610 Add support for the Voltcraft VC-96 DMM. 2018-06-18 16:30:04 +02:00
Adrian Stratulat b8fcae5a12 dtm0660: Do not apply the exponent twice on the value
This fixes bug #1236.
2018-06-18 15:26:46 +02:00
Joerg Alpers 10481ef05d Fix: Bug #1188 DSLogic triggering 2018-06-16 19:31:44 +02:00
JohnCh ab2b21fb68 fluke-45: Add initial driver implementation. 2018-06-15 15:48:49 +02:00
JohnCh e756c595b6 fluke-45: Initial driver skeleton. 2018-06-15 15:05:04 +02:00
Uwe Hermann f1e82915a8 gwinstek-gpd: Fix sr_dev_driver struct. 2018-06-15 00:18:22 +02:00
Uwe Hermann 380d3b2ae8 gwinstek-gpd: Avoid some unnecessary assignments. 2018-06-14 22:48:26 +02:00
Uwe Hermann eaa8c6597b gwinstek-gpd: Drop some unneeded debug logs. 2018-06-14 22:48:26 +02:00
Bastian Schmitz b872ab7d30 gwinstek-gpd: Initial implementation. 2018-06-14 14:19:08 +02:00
Soeren Apel 5eb39a91f3 wav: Don't assume CHUNK_SIZE >= total_samples 2018-06-06 22:07:04 +02:00
Uwe Hermann bf2a6eeaa0 hantek-4032l: Minor cosmetic fix. 2018-06-06 00:01:04 +02:00
Uwe Hermann c7b5c3588e hantek-4032l: Rename 'devc->buffer' to 'devc->buf'.
This is shorter and also avoids confusion with transfer->buffer.
2018-06-05 23:59:24 +02:00
Uwe Hermann 7b9387b8f0 hantek-4032l: Rename number_samples to num_samples. 2018-06-05 23:56:30 +02:00
Uwe Hermann 264a4cb2b8 hantek-4032l: Use MIN() where possible. 2018-06-05 23:55:23 +02:00
Uwe Hermann cbc656e45f hantek-4032l: Simplify some config_get/_set parts.
Also, drop some unneeded checks.
2018-06-05 23:43:23 +02:00
Uwe Hermann 583fc126d0 hantek-4032l: config_set(): Simplify SR_CONF_CAPTURE_RATIO case.
The sr_config_set() wrapper already checks the value.
2018-06-05 23:16:02 +02:00
Uwe Hermann 2dcd904c18 hantek-4032l: Drop some unneeded malloc checks.
As per guidelines in HACKING.
2018-06-05 23:02:58 +02:00
Uwe Hermann 61803a29aa hantek-4032l: Reduce indentation level a bit. 2018-06-05 22:59:29 +02:00
Uwe Hermann b8a954c586 zketech-ebd-usb: Fix a compiler warning. 2018-06-05 22:01:12 +02:00
Andrej Valek f49065c668 hantek-4032l: Add support for external clocks.
These options are NOT available for FPGA version 0.

- add option to select edge type

Signed-off-by: Andrej Valek <andy@skyrain.eu>
2018-06-05 22:01:12 +02:00
Andrej Valek bc294eaca8 Add SR_CONF_EXTERNAL_CLOCK_SOURCE key.
Signed-off-by: Andrej Valek <andy@skyrain.eu>
2018-06-05 22:01:12 +02:00
Andrej Valek 2a80186103 hantek-4032l: Separate threshold channels.
Split global threshold into channels A and B.

Signed-off-by: Andrej Valek <andy@skyrain.eu>
2018-06-05 22:01:12 +02:00
Andrej Valek caad0024fb hantek-4032l: Set new pwm threshold handling.
Calculate threshold values from <-6.0;6.0> range.

Signed-off-by: Andrej Valek <andy@skyrain.eu>
2018-06-05 17:16:39 +02:00
Andrej Valek 3dc976fe9f hantek-4032l: Implement trigger handling.
Send trigger position to upper layer.

Signed-off-by: Andrej Valek <andy@skyrain.eu>
2018-06-05 17:16:39 +02:00
Andrej Valek 4b75f84c01 hantek-4032l: Set maximum samples size to 64MB.
Signed-off-by: Andrej Valek <andy@skyrain.eu>
2018-06-05 17:11:43 +02:00
Andrej Valek 2958315ded hantek-4032l: Increase speed of data getting.
- add support for multiple transfers.
 - set nummber of samples to 1 for FPGA FW version 0
- increase size of data transfer buffer to 2kB.

Signed-off-by: Andrej Valek <andy@skyrain.eu>
2018-06-05 17:10:14 +02:00
Andrej Valek 43d8603571 hantek-4032l: Separate USB receive callbacks.
Callback for data transfer is separated from status. This change will be
used for better data transfer sending/receiving. Cast signal, that trigger
has been captured was moved into state: H4032L_STATUS_FIRST_TRANSFER.

Signed-off-by: Andrej Valek <andy@skyrain.eu>
2018-06-05 16:57:48 +02:00
Andrej Valek 7a7afc0086 hantek-4032l: Get FGPA version.
- get FPGA version in dev_open
 - enable some features only for newer FPGA
- decrease printing number of message of FPGA version

Signed-off-by: Andrej Valek <andy@skyrain.eu>
2018-06-05 16:57:48 +02:00
Andrej Valek 28f2d07fe5 hantek-4032l: Unify style.
Signed-off-by: Andrej Valek <andy@skyrain.eu>
2018-06-05 16:55:45 +02:00
Soeren Apel 9e850040db Fix #1167 by not creating sigrok channels twice
Also fixes a similar bug in the analog_raw input module that prevented
it from resetting properly - it freed its resources by calling cleanup().
2018-06-03 19:37:49 +02:00
Gerhard Sittig 3c9117094c input/logicport: remove obsolete reset/cleanup assignments
The in->buf truncation is done by common backend logic. The module's
cleanup() does zero out inc, which obsoletes the flag assignments.
2018-06-03 19:28:46 +02:00
Gerhard Sittig 4c40d096d4 input/logicport: don't re-create channels after input module reset
Split the creation of channels and groups as well as the creation of the
session feed buffer into separate routines. Re-allocate the buffer after
reset but do not re-create the channels and groups.

This implementation assumes that after reset() of the input module, the
very same set of channels (including their order, names and enabled
state, as well as group membership) results from processing the
subsequently fed file content. Reading rather different configurations
from the same input file by means of repeated reset and re-read may not
work as expected.
2018-06-03 19:28:46 +02:00
Gerhard Sittig 49d9a095e8 input/logicport: silence a non-fatal glib runtime assertion
Explicitly check GString pointers for validity before calling glib
routines that would access string content. This silences an assertion
error for a non-fatal runtime condition:

(process:17044): GLib-CRITICAL **: g_string_free: assertion 'string != NULL' failed
2018-06-03 19:28:46 +02:00
Gerhard Sittig a38c2bfbbb input: clear sdi_ready flag and receive() buffer in common code
Rephrase common input reset logic such that additional common code can
execute after the individual module's reset callback. No behaviour has
changed, the module's reset callback still is optional, and identical
log output gets emitted.

Do clear the sdi_ready flag in the common sr_input_reset() routine, so
that all input modules will parse header information again before
processing sample data when subsequent calls receive new file content.
Void the input module's receive() buffer from common reset code. This
unbreaks the feature of re-reading previously consumed input files.

Extend comments in the common reset and free code paths, which involve
the modules' reset and cleanup routines, which interact in non-trivial
ways. Discuss the responsibilities of common and individual routines, to
remain aware during maintenance.
2018-06-03 19:28:46 +02:00
Uwe Hermann 1e99158c1b hantek-6xxx: Drop some unused variables. 2018-06-02 23:23:55 +02:00
Sergey Alirzaev 4299fcc0b8 hantek-6xxx: FIFO sampling
It doesn't buffer all the samples before sending them out anymore.

This fixes bug #1214.
2018-06-02 23:12:29 +02:00
Uwe Hermann d828b05e65 scpi-pps: Rigol DP71x: Make OVP/OCP threshold listable. 2018-06-01 15:47:48 +02:00
Frank Stettner 1c8901f744 scpi: Use locale independent sr_vsnprintf_ascii() and sr_vsprintf_ascii() functions. 2018-06-01 15:46:17 +02:00
Frank Stettner 7ca40d2d1c tests: Tests for the locale independent sr_vsprintf_ascii() function. 2018-06-01 15:46:17 +02:00
Frank Stettner 21ef355e50 strutil: Locale independent sprintf() and vsprintf() functions 2018-06-01 15:46:17 +02:00
Frank Stettner 49a468ed8b scpi-pps: Add listable OVP/OCP threshold for HP 66xxx and prepared all other 2018-06-01 15:46:17 +02:00
Frank Stettner a61c8cce01 scpi-pps: Add HP 6631B, HP 66332A, HP 6633B and HP 6634B power supplies 2018-06-01 15:46:17 +02:00
Frank Stettner 7e381bfc3c scpi-pps: Add missing functionality for the HP 6632B power supply. 2018-06-01 15:46:17 +02:00
Frank Stettner 17a82e83ff scpi-pps: Reimplemention of switching channel groups (PSU channels)
Acquisition won't work correctly in a multi-threaded environment, when
config_set() and config_get() are called with a channel group.
The channel switching itself has moved to scpi/scpi.c, to be able to
handle switching in a thread safe way.
2018-06-01 15:46:17 +02:00
Frank Stettner fa2ce8c762 scpi-pps: Use thread safe SCPI functions, return float not double.
Use of the thread safe SCPI functions, so no write+read operation is
interruped.

Also return float values instead of double value in acquisition mode.
This is related to bug #779.
2018-06-01 15:46:17 +02:00
Frank Stettner fd20e59caa scpi: Synchronize read, write and write+read operations.
This ensures that SCPI read/write/write+read operations are thread safe.
F.e.: If a write operation expects a return value (in other words: a
read operation), it is not allowed to be interrupted by another write
operation.

To simplify things, the SCPI helper functions are moved from
scpi/helpers.c to scpi/scpi.c and also are renamed to fit the naming
scheme.

libgpib in particular will abort the program execution in case of
concurrent operations.
2018-06-01 15:46:17 +02:00
Uwe Hermann 1c5adc5ff7 scpi.c: Drop an unneeded log message.
The IDN string is already logged by sr_scpi_get_string().
2018-06-01 14:43:10 +02:00
Uwe Hermann 0c8aedb543 scpi_serial.c: Improve an error message. 2018-06-01 14:43:10 +02:00
Uwe Hermann 0261956fab scpi_serial.c: Drop an unneeded log message.
The number of bytes read is already logged by the serial backend:

  sr: [00:00.072857] scpi_serial: Read 1 bytes into buffer.
  sr: [00:00.073884] serial: Read 1/2008 bytes.
  sr: [00:00.073900] scpi_serial: Read 1 bytes into buffer.
  sr: [00:00.074896] serial: Read 1/2007 bytes.
  sr: [00:00.074905] scpi_serial: Read 1 bytes into buffer.
  sr: [00:00.075949] serial: Read 1/2006 bytes.
2018-06-01 14:43:10 +02:00
Uwe Hermann 319fe9cea6 scpi-pps: Add support for the Rigol DP711/DP712. 2018-06-01 14:43:10 +02:00
Gerhard Sittig 13ac09279a input/chronovu_la8: claim responsibility for LA16 files, devel comments
The chronovu_la8 input module is capable of handling either file type,
generated by LA8 or LA16 vendor software. Automatic detection is not
available, but user provided channel counts work fine.

Adjust the input module's name and description, and claim support for
.kdt as well as .kd1 files.

Add developer notes on implementation details, the file content's
constraints, and potential future adjustment.
2018-05-25 23:21:43 +02:00
Gerhard Sittig e8eb24222c input/chronovu_la8: only send data to the session, don't send the header
The file format is funny, a data part is leading (fixed size) and a
"header" part follows. The previous implementation sent the header part
to the session, too, pretending it was part of the data. This change
limits the number of samples that get sent to the session.

Comment on the file layout and header fields while we are here. This
information got lost in commit 02e24c0ce0 when the input module got
converted from do-it-yourself file operations to having intrinsic
handler routines invoked from common logic which handles the file.
2018-05-25 23:07:28 +02:00
Gerhard Sittig 20358f90b4 input/logicport: unobfuscate 64-bit-clean bit mask literals
Prefer the more portable UINT64_C() macro over the UL suffix when a
literal needs to span "more than 31 bit positions". Adjust other
locations for consistency across the source file.
2018-05-21 20:15:48 +02:00
Gerhard Sittig 67765e465a input/trace32_ad: fix potential buffer overflow for unexpected input data
Commit 8c4bff1d25 introduced a routine which prints what mostly should
be text, and avoids non-printable characters. This implementation used an
incorrect format string, which could result in data getting written past
the end of a buffer. Fix the format string.
2018-05-21 20:13:27 +02:00
Uwe Hermann 090f1e1e54 hwdriver.c: Fix two scan-build warnings.
src/hwdriver.c: In function ‘log_key’:
  src/hwdriver.c:648:13: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
    opstr = op == SR_CONF_GET ? "get" : op == SR_CONF_SET ? "set" : "list";
               ^~
  src/hwdriver.c: In function ‘check_key’:
  src/hwdriver.c:681:13: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
    opstr = op == SR_CONF_GET ? "get" : op == SR_CONF_SET ? "set" : "list";
               ^~
2018-05-19 22:23:16 +02:00
Uwe Hermann b4580cb9d0 siglent-sds: Fix multiple scan-build warnings.
src/hardware/siglent-sds/api.c:596:3: warning: Argument to g_free() is the address of a global variable, which is not memory allocated by malloc()
                  g_free(cmd);
                  ^~~~~~~~~~~
  src/hardware/siglent-sds/api.c:641:3: warning: Argument to g_free() is the address of a global variable, which is not memory allocated by malloc()
                  g_free(cmd);
                  ^~~~~~~~~~~
2018-05-19 22:01:28 +02:00
Uwe Hermann d5db6ea7e1 lecroy-xstream: Fix a potential memory leak.
Reported by scan-build:

  src/hardware/lecroy-xstream/protocol.c:680:12: warning: Potential leak of memory pointed to by 'analog.data'
                                  return SR_ERR;
                                         ^~~~~~
2018-05-19 22:01:26 +02:00
Uwe Hermann 4fc4b8e7aa hameg-hmo: Fix two potential memory leaks.
Reported by scan-build:

  src/hardware/hameg-hmo/api.c:533:12: warning: Potential leak of memory pointed to by 'pod_enabled'
                                  return SR_ERR;
                                         ^~~~~~
2018-05-19 22:01:21 +02:00
Uwe Hermann 24801f4e80 input/logicport: Fix outdated format_match().
Reported by scan-build:

  src/input/logicport.c:1186:18: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
    .format_match = format_match,
                    ^~~~~~~~~~~~
2018-05-19 22:01:18 +02:00
Gerhard Sittig 092843eb42 bindings: wrap sr_input_scan_file() in the C++ language binding
Allow C++ applications to have the input format automatically detected,
and get a corresponding InputFormat instance. This makes the format match
logic available to PulseView.
2018-05-17 22:31:27 +02:00
Gerhard Sittig c83bdde9da input: provide accessor routine for (struct sr_input *)->module
Add a public API routine which allows applications to query the
sr_input_module from an sr_input.
2018-05-17 22:31:27 +02:00
Gerhard Sittig 83df004be1 input/trace32_ad: data type nits, log verbosity in header parsing
Log determined header format when parsing trace32 file headers. Keep
another log message during regular processing, but silence it during
format match.

Use more appropriate data types for local and instance variables. Adjust
format strings accordingly.
2018-05-17 22:30:44 +02:00
Gerhard Sittig 80430d4d20 input/trace32_ad: rephrase the header parse logic
There were several issues with the previous implementation of the logic
which parses trace32 input files: A string comparison was inverted, and
compared a seven character literal to a five character copy of the input.
One more character was trimmed before CTRL-Z (the CP/M EOF), which often
is SPACE in input files, but might be excessive on other input files.

Replace a DIY character search while we are here. Use symbolic names for
special characters. Factor out a test and memory release, to simplify
error code paths in the remaining logic. Extend comments.
2018-05-17 22:30:44 +02:00
Gerhard Sittig 8c4bff1d25 input/trace32_ad: silence format match logging, improve robustness
There is not much point in log messages about format mismatch in the
auto detect phase, where each module gets queried in turn and most are
supposed to not match.

Do not print non-printable characters in log messages. Those could occur
in the format detection phase, or in the regular processing of input
files that either are unexpected or invalid (or is there a binary header
format variant even?).
2018-05-17 22:30:44 +02:00
Gerhard Sittig f54a55da2d input/chronovu_la8: address file size data type nits
Although the file format handled by this input module appears to be of
fixed size (8MiB plus 5 more bytes), it's more reliable to use a data
type for the file size that is larger than "an int". Although off_t
would be most portable, use uint64_t to match the code which passes the
parameter to the input module.
2018-05-17 22:25:40 +02:00
Gerhard Sittig 0dabb880af input: pass larger buffer to auto format detection
The previous implementation already was inconsistent (used to allocate
255 bytes and claimed that 128 bytes were sufficient). While existing
formats already required more than a few bytes of input (regular VCD
files' header sections exceed 255 bytes length).

Increase the buffer size that gets passed to input modules' match
method. Use 4MiB for consistency with other locations. Do not enforce a
minimum size, as there are valid input files which are shorter than 128
bytes. Auto-detection failed on those.

This addresses part of bug #1200.
2018-05-17 22:25:40 +02:00
Gerhard Sittig 54ee427df0 input: add confidence (detection strength) to format_match()
When users don't specify the input format, applications can try to have
the format auto-detected. Some of the tests were weak and could result
in false positives.

Add a 'confidence' parameter to the input modules' format_match()
method. Claim high confidence (1) for those formats which can check
magic strings or the presence of essential keywords (vcd, wav). Claim
medium confidence (10) for those formats which happened to mis-detect
inputs in the past (trace32_ad). Claim weak confidence (100) for those
formats which totally lack reliable conditions and rather guess than
detect (chronovu_la8).

Prefer the best match in public scan routines. Return at most one module
to callers even if multiple modules matched, to keep the current API.

This addresses part of bug #1200.
2018-05-17 22:23:35 +02:00
Uwe Hermann 7102443a4a input/logicport: Drop some unneeded allocation checks. 2018-05-17 21:09:48 +02:00
Gerhard Sittig e1b115bd4d input/logicport: introduce input module for LogicPort File (*.lpf)
Implement an input module for .lpf files, the "LogicPort File" format of
the Intronix LA1034 vendor software. This version supports wires with
enabled and inverted state, compressed samples, signal names, signal
groups (but not multiple assignment), and automatic format detection.

The logic which determines whether "the file header" was completely
received, and sample data can get sent to the session, implements an
assumption in the absence of a better and more reliable condition.

Invalid input gets rejected, but diagnostics is rather limited. Since
all channels get to be the member of a channel group, either specified
by the user in the input file, or arranged for in the input module, the
"missing separator" part of bug 1186 has become obsolete.
2018-05-17 21:07:42 +02:00
Uwe Hermann 3601d50e26 libsigrok.h: Fix multiple compiler warnings (-Wshift-overflow=2).
../include/libsigrok/libsigrok.h:653:19: warning: result of ‘1 << 31’ requires 33 bits to represent, but ‘int’ only has 32 bits [-Wshift-overflow=]
    SR_CONF_GET = (1 << 31),
                     ^~

[...]
2018-05-16 23:57:58 +02:00
Uwe Hermann 0519db864b sr_analog_to_float(): Fix multiple compiler warnings (-Wshadow).
src/analog.c:205:23: warning: declaration of ‘i’ shadows a previous local [-Wshadow]
       for (unsigned int i = 0; i < count; i++) {
                         ^
  src/analog.c:178:18: note: shadowed declaration is here
    unsigned int b, i, count;
                    ^
[...]
2018-05-16 23:57:58 +02:00
Uwe Hermann 741bcf503d sr_analog_to_float(): Fix a compiler warning (-Wshadow).
src/analog.c: In function ‘sr_analog_to_float’:
  src/analog.c:194:9: warning: declaration of ‘offset’ shadows a previous local [-Wshadow]
   float offset = analog->encoding->offset.p / (float)analog->encoding->offset.q;
         ^~~~~~
  src/analog.c:177:8: note: shadowed declaration is here
  float offset;
        ^~~~~~
2018-05-16 22:48:35 +02:00
Gerhard Sittig 53ea24610e demo: optionally accept frame limit spec at scan time
Allow developers to specify the (default) number of frames at compile
time (default to "off" as before). Accept the frame limit spec at scan()
time as well. This is useful when applications don't run config_set() at
runtime.

Tested with:
$ pulseview -d demo:logic_channels=0:analog_channels=1:limit_frames=4
2018-05-13 20:03:21 +02:00
Gerhard Sittig fb193945b6 demo: make frame generation (and maximum frame count) a runtime option
The previous implementation supported the generation of frames as a
compile time option. This change lets users adjust the feature at
runtime.

In the absence of a frame count limit no frame begin/end markers get
sent (the default behaviour of the previous implementation). When a
frame count limit is specified, the respective number of frames gets
sent and acquisition stops.

The fixed amount of 1000 samples per frame is an arbitrary choice. This
compile time option is easily adjusted in the source code.
2018-05-13 20:03:21 +02:00
Gerhard Sittig 0373343046 demo: introduce graycode generator mode
Introduce support for the "graycode" logic pattern. Generate up to
64 bits of graycode output (all logic lines, no repetition, not limited
by the generator's internal pattern buffer). The implementation was
tested with 16 channels.
2018-05-13 19:45:46 +02:00
Gerhard Sittig 015f09702a demo: add convenient bit mask for "all logic channels"
Keep a context variable around with a bit mask for all logic channels.
This is convenient in setup and generation routines, to avoid garbage
in unassigned bit positions of session feed packets.
2018-05-13 19:40:00 +02:00
Gerhard Sittig 817e759ddc demo: data type nits in the device context (enum, unsigned int)
Move the declaration of codes for pattern types before the declaration
of the context container such that the latter can reference the former.
Add 'int' to an unsigned variable that omitted the base type.
2018-05-13 19:27:51 +02:00
Gerhard Sittig cdb134eb19 input/trace32_ad: silence format errors during input format match
When auto-detection tries to find the input module that can handle a
file, unexpected input format should be considered non-fatal. Only emit
error messages when process_header() got invoked from process_buffer()
after initialization. Emit debug messages in early stages where no input
module context exists yet.
2018-04-28 23:42:42 +02:00
Uwe Hermann 55bcd7ad45 dreamsourcelab-dslogic: Properly set initial voltage threshold.
The initial voltage threshold in dev_open() was being set to a
default value in the devc->cur_threshold variable but not actually set
in the device itself.

Patch by Jörg Alpers <jalpers@gmx.net>, thanks a lot!
2018-04-28 23:39:59 +02:00
Uwe Hermann 8a14fc0828 dmm/ms8250d: Fix two log messages. 2018-04-27 00:07:21 +02:00
Mandl 67070942cc Add support for the MASTECH MS8250D multimeter 2018-04-27 00:07:21 +02:00
Uwe Hermann 2bd5d17c70 hantek-4032l: Emit FPGA version log message. 2018-04-24 21:09:42 +02:00
Uwe Hermann eca9772971 soft-trigger: Fix an issue causing triggers to not work. 2018-04-24 16:56:07 +02:00
Uwe Hermann ce97fc3f6a rigol-ds: Fix an issue causing only one channel to be acquired.
This fixes bug #1018.
2018-04-22 18:36:12 +02:00
Uwe Hermann 350501d0c3 rigol-ds: Make two log messages more specific.
Slightly modified version of a suggested change by Aleksander Alsekseev.
2018-04-22 16:49:33 +02:00
Andrej Valek a5b9880eb2 hantek-4032l: Add option to abort acquisition.
Signed-off-by: Andrej Valek <andy@skyrain.eu>
2018-04-22 11:16:34 +02:00
Andrej Valek 74c4c1747f hantek-4032l: Fix mismatch in magic number.
- fix LIBUSB_TIMEOUT errors
- fix same data receiving
- send reset vendor request before new data getting
- decrease USB polling timeout

This fixes bug #1190.

Signed-off-by: Andrej Valek <andy@skyrain.eu>
2018-04-22 11:15:05 +02:00
Andrej Valek e80e1858ef hantek-4032l: Fix structure packing.
- use pragma to handle different behavior between gcc and minGW bit-field packing
- bit-field integer variables needs to be align to 2-byte boundary
Compiler does not produce an error when accessing into non-__packed pointer.
However, the field might not be properly aligned for this type.
More information could be found on:
 - https://sourceforge.net/p/mingw-w64/bugs/275/
 - http://www.keil.com/support/man/docs/ARMCC/armcc_chr1359124990875.htm

Signed-off-by: Andrej Valek <andy@skyrain.eu>
2018-04-22 11:11:06 +02:00
Andrej Valek 972001561b hantek-4032l: Fix typo from device porting to new lib version.
Signed-off-by: Andrej Valek <andy@skyrain.eu>
2018-04-22 11:11:06 +02:00
Uwe Hermann 2c267f6819 log: Move log level check so that it affects all handlers.
Before this change, the loglevel check would only be performed for the
default log handler in libsigrok, but not for other handlers set
via sr_log_callback_set().

This fixes bug #698.
2018-04-22 00:23:10 +02:00
Uwe Hermann 7c59d8f310 output/csv: Make the label values option a list.
This allows UIs to display a drop-down with all possible choices,
instead of forcing the user to look up / remember all of them.
2018-04-21 23:30:44 +02:00
Uwe Hermann 31c41782e4 input/csv: Make the data format option a list.
This allows UIs to display a drop-down with all possible choices,
instead of forcing the user to look up / remember all of them.
2018-04-21 23:28:58 +02:00
Uwe Hermann d52107a159 soft-trigger: Use g_try_malloc() for potentially large allocation.
This fixes bug #1000.
2018-04-21 23:27:00 +02:00
Uwe Hermann 567fe53822 session_driver: Quickfix to prevent looped analog data reads.
A local buffer was too small, snprintf() was used to write the
name of the analog-1-1-xxx ZIP archive names in that buffer.

Due to the limited size, only 3 characters were usable for the last
number component, i.e. the code would loop around from analog-1-1-999
to analog-1-1-100 (instead of analog-1-1-1000).

As a quickfix, increase the buffer size by a large margin, a nicer
fix should be used later on.
2018-04-19 23:29:22 +02:00
Uwe Hermann 2003be8cec input/null: Add a null module that discards all data.
This is useful for testing purposes.
2018-04-19 22:15:54 +02:00
Uwe Hermann 1af7497d67 output/null: Add a null module that discards all data.
This is useful for testing purposes.
2018-04-19 20:10:50 +02:00
Uwe Hermann b20eb52055 input/output: Slightly improved module descriptions. 2018-04-19 18:21:07 +02:00
Uwe Hermann 9a4fd01af8 input modules: Increase chunk size to 4MB for all modules.
This reduces overhead and can slightly increase performance, depending
on the module.
2018-04-19 17:39:15 +02:00
Uwe Hermann 8bc2fa6d82 input modules: Name chunk size #defines CHUNK_SIZE consistently. 2018-04-19 17:38:05 +02:00
Uwe Hermann 1fb31414f2 input/trace32_ad: Drop unused #define. 2018-04-19 17:37:15 +02:00
Uwe Hermann 2cff7a2ba7 input/wav: Put internal buffer on the heap instead of the stack.
Increasing the buffer/chunk size could cause issues when trying to put
large arrays on the stack.
2018-04-19 17:37:15 +02:00
Uwe Hermann a33e4be826 input/binary: Increase chunk size from 4KB to 4MB.
This can slightly increase performance when loading larger files.
2018-04-14 22:23:02 +02:00
Uwe Hermann 408b6ab42b input/binary: Only calculate unitsize once. 2018-04-14 19:46:43 +02:00
Uwe Hermann 867293a101 input modules: Improve option names and descriptions.
These should be slightly more useful and contain more information
(should also work reasonably well for 'sigrok-cli --show' and as
tooltips in UIs).
2018-04-14 18:47:49 +02:00
Uwe Hermann d4b3f44fa7 zketech-ebd-usb: Drop unneeded log message.
The number of bytes sent is already logged by the libsigrok serial code.
2018-04-08 20:56:34 +02:00
Uwe Hermann b4bf6b3b4f configure.ac: zketech-ebd-usb driver needs libserialport. 2018-04-08 19:59:25 +02:00
Uwe Hermann 330a32b240 zketech-ebd-usb: Shorten function name prefix for better readability. 2018-04-08 19:59:25 +02:00
Uwe Hermann cb8a0efc5c zketech-ebd-usb: Make a few functions static. 2018-04-08 19:59:25 +02:00
Uwe Hermann ec4806dcf5 zketech-ebd-usb: Add some underscores to #defines. 2018-04-08 19:59:25 +02:00
Sven Bursch-Osewold 9890fb1f08 zketech-ebd-usb: First version of the driver. 2018-04-08 19:59:25 +02:00
Sven Bursch-Osewold c527132aec zketech-ebd-usb: Initial driver skeleton. 2018-04-08 19:59:25 +02:00
Uwe Hermann 23d68466f8 usbtmc: Silence some overly verbose log messages.
These trigger quite often with unrelated devices and confuse people.

  scpi_usbtmc: Failed to get configuration descriptor: LIBUSB_ERROR_NOT_FOUND, ignoring device.
2018-04-08 19:49:41 +02:00
Uwe Hermann 66d2cc3a27 rdtech-dps: User ternary operator. 2018-03-29 15:45:52 +02:00
James Churchill 69b0558395 rdtech-dps: New driver for RDTech DPS/DPH series PSUs. 2018-03-29 15:41:30 +02:00
James Churchill 0549416e36 rdtech-dps: Initial driver skeleton. 2018-03-26 15:41:01 +10:00
James Churchill 7b50a9b869 modbus: Return explicit SR_ERR values as required by modbus.c
The Modbus RTU implementation was inappropriately returning lengths
from the serial functions when the calling functions expect only an
sr_error_code value.
2018-03-26 15:41:01 +10:00
James Churchill d4e0701771 modbus: Increase modbus reply timeout to 500ms.
Needed by rdtech-dps driver, 100ms is too short.
2018-03-26 15:41:01 +10:00
Soeren Apel 366ccb8ab7 resource.c: Fix firmware loading bug (#1140) 2018-03-20 16:13:46 +01:00
Uwe Hermann 410883baf6 backend: Emit firmware search paths in a log message. 2018-03-18 18:26:57 +01:00
Soeren Apel addb7340dd Introduce sr_resourcepaths_get()
This provides an interface to fix #1128.
2018-03-18 18:25:36 +01:00
Axel Hinrichs e843992dda korad-kaxxxxp: Korad OEM: RND KA3005P 2018-03-12 16:34:43 +01:00
Gerhard Sittig 823b0e29ae output/csv: fix out-of-bounds array access in process_analog()
Make sure to not exceed the ctx->analog_samples[] array bounds. Don't
use the (huge) channel's index in the device's(!) channel list, instead
use the zero-based and dense index into the array of analog samples in
the accumulation buffer, before writing to the external file.

This fixes the segfault reported in bug #1124.
2018-03-12 15:55:22 +01:00
Gerhard Sittig a551cb0927 output/csv: use longer names for iteration variables
The process_analog() logic is rather complex, dealing with the total
list of channels in the device (which can be of different types), and a
number of submitted samples for a specified list of channels. Replace
the rather short variable names for i, j, c (and num_channels) with
something longer that hopefully increases readability of the complex
loop bodies.

Note that this change merely renames identifiers, and does not change
behaviour.
2018-03-12 15:55:22 +01:00
Gerhard Sittig b078dddb84 output/csv: reduce indentation in process_analog()
Instead of nesting indentation levels upon equality of a value, skip
iterations upon inequality. This reduces indentation, and might improve
readability.

[ Indentation changes, see 'diff -w -b' for the essence. ]
2018-03-12 15:55:22 +01:00
Frank Stettner 94cf02d0c2 hp-3478a: Remove unnecessary curly brackets. 2018-03-06 19:02:33 +01:00
Frank Stettner a575c90e81 hp-3478a: Set correct number of digits 2018-03-06 17:40:13 +01:00
Frank Stettner acc587ff24 hp-3478a: spec_digits must be parsed before range parsing. 2018-03-06 17:40:13 +01:00
Frank Stettner c3f8e1abf0 arachnid-labs-re-load-pro: Replace C++-style comments with C-style comments. 2018-03-06 17:39:37 +01:00
Frank Stettner cd97e39d89 metex14: Fix wrong measurement modes 2018-03-05 20:23:35 +01:00
Frank Stettner fd8dc1db01 metex14: Add power factor measurement mode 2018-03-05 20:23:26 +01:00
Uwe Hermann 187c300b59 libsigrok.h: Fix SR_CONF_UNDER_VOLTAGE_CONDITION_THRESHOLD order.
This has to be the last entry in its "category", otherwise it'll mean an
ABI breakage.
2018-03-03 19:25:57 +01:00
Uwe Hermann 0aaaee2dd3 arachnid-labs-re-load-pro: Simplify a code chunk. 2018-03-03 19:25:05 +01:00
Frank Stettner d7e348f481 arachnid-labs-re-load-pro: Add encoding.digits to analog packet 2018-03-03 19:25:05 +01:00
Frank Stettner 2153093941 arachnid-labs-re-load-pro: Index for channel "I" 2018-03-03 19:25:05 +01:00
Frank Stettner b3e715e528 arachnid-labs-re-load-pro: Get a response when in acquision mode. 2018-03-03 19:25:02 +01:00
Frank Stettner 706350360a arachnid-labs-re-load-pro: Make SR_CONF_REGULATION listable 2018-03-03 19:22:59 +01:00
Frank Stettner 3d70d77709 arachnid-labs-re-load-pro: Add SR_CONF_UNDER_VOLTAGE_THRESHOLD. 2018-03-03 19:10:51 +01:00
Frank Stettner 9edda1d25b arachnid-labs-re-load-pro: Setting correct current limit.
Use round() instead of just truncate the value.
2018-03-03 19:10:51 +01:00
Frank Stettner a217289951 arachnid-labs-re-load-pro: Change serial read in acquisition mode.
Use serial_readline in acquisition mode, otherwise data from the
Re:load Pro could get lost.
Use reloadpro_receive_data() for all commands when in acquisition
mode. When not using a single point of receiving data, data could get
lost.
2018-03-03 19:10:51 +01:00
Gerhard Sittig 4389a54204 pipistrello-ols: style nit, replace DIY endianess conversion 2018-03-03 18:58:59 +01:00
Gerhard Sittig 411b2f6822 link-mso19: improve endianess conversion, avoid mem access alignment issue
Prefer sigrok's endianess conversion helper over the inet htons()
routine which is harder to read (is "network order" little or big?).

Writing the conversion results in units of bytes also avoids misaligned
memory access. The header length is odd, each payload item got written
as an uint16_t item to an odd address.
2018-03-03 18:58:59 +01:00
Gerhard Sittig f7711ed56c uni-t-dmm: style nits, copy loop vs memmove 2018-03-03 18:58:59 +01:00
Gerhard Sittig 69229e5c15 saleae-logic-pro: style nits, copy loop vs memcpy 2018-03-03 18:58:59 +01:00
Gerhard Sittig 093b8ff478 pce-322a: style nits, copy loop vs memmove 2018-03-03 18:58:59 +01:00
Gerhard Sittig c372070333 mic-985xx: style nits, var decl vs assignment, copy loop vs memmove 2018-03-03 18:58:59 +01:00
Gerhard Sittig 7a65106e00 kern-scale: style nits, var decl vs assignment, copy loop vs memmove 2018-03-03 18:58:59 +01:00
Gerhard Sittig 0f6ff97bf8 center-3xx: style nits, var decl vs assignment, copy loop vs memmove 2018-03-03 18:58:59 +01:00
Uwe Hermann bdbb9151af siglent-sds: Drop superfluous log message.
This information is already emitted by other layers.
2018-03-03 18:45:58 +01:00
marchelh fdf0744fa4 siglent-sds: Added trigger position to device config code 2018-03-03 17:46:15 +01:00
marchelh e8fd027120 siglent-sds: Fixed issue with hard coded vdiv. 2018-03-03 17:46:15 +01:00
marchelh fe06061d96 siglent-sds: Drop unused variable from siglent_sds_read_header function 2018-03-03 17:45:21 +01:00
marchelh fe1aa53613 siglent-sds: Added averaging function. 2018-03-03 17:45:21 +01:00
marchelh 80eba3857a siglent-sds: Fixed timebase problem where NS could not be selected
This fixes bug #1120.
2018-03-03 17:28:49 +01:00
Frank Stettner d8df3c2a01 tests: Fix incomplete fail message for locale tests. 2018-02-21 11:37:19 +01:00
Frank Stettner 93497d0016 hp-3478a: Fix compiler warning. 2018-02-21 11:37:19 +01:00
Romain Tartière 6c1a76d126 Check usb_get_port_path() return value
This function can fail. If so, do not ignore the failure.
2018-02-21 11:37:19 +01:00
Romain Tartière 7bbe5a2b6a Ensure device is closed before usb_get_port_path()
The usb_get_port_path() function opens the passed device on FreeBSD,
which fails if the device has already been open.

This fixes bug #1109.
2018-02-21 11:36:58 +01:00
Gerhard Sittig 90cc52260c bindings/ruby: include config.h before any other header file 2018-02-21 11:19:17 +01:00
Gerhard Sittig 21964348bc bindings/python: include config.h before any other header file 2018-02-21 11:19:17 +01:00
Gerhard Sittig 1e95832b3e bindings/cxx: include config.h as early as possible
Move the inclusion of <config.h> before any other source code.
2018-02-21 11:19:17 +01:00
Gerhard Sittig dea7f6342a pce-322a: include config.h before any other header file 2018-02-21 11:19:17 +01:00
Uwe Hermann 5a64d1d954 beaglelogic: Use UINT64_MAX instead of (uint64_t)-1. 2018-02-20 20:03:21 +01:00
Uwe Hermann 71e22ba88f beaglelogic: Drop unneeded uint64_t cast. 2018-02-20 20:03:21 +01:00
Uwe Hermann 3f4c1174b6 lecroy-xstream: Fix potential issue by adding UINT64_C. 2018-02-20 20:03:21 +01:00
Uwe Hermann d9b716fc5f Use UINT64_C instead of "ULL" number suffix.
Avoid hardcoding a "ULL" number suffix, use the more portable and more
correct UINT64_C.
2018-02-20 20:03:21 +01:00
Uwe Hermann 405b9c10eb Random whitespace/cosmetic fixes. 2018-02-20 20:03:11 +01:00
Uwe Hermann 1135f8d9c7 siglent-sds: Fix two memory leaks. 2018-02-18 23:36:17 +01:00
Uwe Hermann d6d87fa2a2 siglent-sds: Drop incorrect glib includes. 2018-02-18 23:29:14 +01:00
Uwe Hermann 04c4a6776f hp-3478a: Shorten some functions. 2018-02-18 23:18:22 +01:00
Uwe Hermann 6ddedf5bac hp-3478a: Drop superfluous log message prefixes. 2018-02-18 23:13:34 +01:00
Frank Stettner d2c1730a28 hp-3478a: Initial HP 3478A diver 2018-02-18 23:13:34 +01:00
Frank Stettner 1d9eebf4be hp-3478a: Initial driver skeleton. 2018-02-18 22:59:31 +01:00
Uwe Hermann 374b0a94b2 output/analog: Fix a compiler warning on Mac OS X.
Apparently PRIu64 and G_GUINT64_FORMAT differ on some systems for
unknown reasons. Use G_GUINT64_FORMAT to get rid of the warning
for now.
2018-02-18 21:36:18 +01:00
Uwe Hermann 65788048f0 Fix two compiler warnings on MinGW/MSYS2.
The config.h file must always be included as first file.

  src/output/csv.c: In function 'gen_header':
  src/output/csv.c:64:20: warning: format '%u' expects argument of type 'unsigned int', but argument 3 has type 'uint64_t {aka long long unsigned int}' [-Wformat=]
   #define LOG_PREFIX "output/csv"
                      ^
  ./src/libsigrok-internal.h:753:42: note: in expansion of macro 'LOG_PREFIX'
   #define sr_info(...) sr_log(SR_LOG_INFO, LOG_PREFIX ": " __VA_ARGS__)
                                            ^
  src/output/csv.c:244:3: note: in expansion of macro 'sr_info'
     sr_info("Set sample period to %" PRIu64 " %s",
     ^
  src/output/csv.c: In function 'dump_saved_values':
  src/output/csv.c:462:34: warning: format '%u' expects argument of type 'unsigned int', but argument 3 has type 'uint64_t {aka long long unsigned int}' [-Wformat=]
       g_string_append_printf(*out, "%" PRIu64 "%s",
                                    ^

  In file included from src/hardware/ftdi-la/protocol.c:21:0:
  src/hardware/ftdi-la/protocol.c: In function 'send_samples':
  src/hardware/ftdi-la/protocol.h:28:20: warning: format '%u' expects argument of type 'unsigned int', but argument 3 has type 'uint64_t {aka long long unsigned int}' [-Wformat=]
   #define LOG_PREFIX "ftdi-la"
                      ^
  ./src/libsigrok-internal.h:751:42: note: in expansion of macro 'LOG_PREFIX'
   #define sr_spew(...) sr_log(SR_LOG_SPEW, LOG_PREFIX ": " __VA_ARGS__)
                                            ^
  src/hardware/ftdi-la/protocol.c:29:2: note: in expansion of macro 'sr_spew'
    sr_spew("Sending %" PRIu64 " samples.", samples_to_send);
    ^
2018-02-18 21:36:12 +01:00
Uwe Hermann e8e063738d siglent-sds: Fix multiple compiler warnings. 2018-02-18 17:40:59 +01:00
Uwe Hermann 567c6501d9 siglent-sds: Remove unused variable. 2018-02-18 17:14:08 +01:00
Frank Stettner 94b1d50642 dmm: Remove unnecessary casts 2018-02-18 17:08:06 +01:00
Frank Stettner 7fb4ff0237 metex14: Add missing modes and set correct digits value. 2018-02-18 17:08:06 +01:00
Gerhard Sittig 556a926d43 serial-dmm, metex14: add support for multiple channels per DMM
Optionally create multiple analog channels in serial-dmm's scan()
routine. Allow the meters' parse routines to fill in more than one
analog value from the inspection of a single packet.

Use "large" (4 times 14 bytes) packets for the Metex M-3860M and the
PeakTech 4390A meters, and have those large packets parsed by wrapping
the routines for regular 14-byte Metex packets, and sending four values
to the session bus after reception of one large packet.

Thanks to Frank Stettner <frank-stettner@gmx.net> for testing and
fixing the initial implementation of this extension.
2018-02-18 15:43:34 +01:00
Gerhard Sittig 51e1f5661c serial-dmm: style nit (init vs assign, memmove(3))
Move the initial assignment to the 'offset' variable to the very spot
where it gets evaluated and subsequently manipulated.

Replace a DIY copy loop with the corresponding memmove(3) call.
2018-02-18 15:43:34 +01:00
Uwe Hermann e4fb1a821d siglent-sds: Bring driver up-to-date with current code conventions.
Use ARRAY_AND_SIZE where possible, use std.c helpers where possible,
make scanopts/drvopts/devopts consistent with other drivers.
2018-02-17 19:10:19 +01:00
Uwe Hermann 8856f173df siglent-sds: Drop obsolete SR_ST_ACTIVE checks.
These are now done in the wrapper functions.
2018-02-17 19:10:19 +01:00
Uwe Hermann e5896840f6 siglent-sds: Random cosmetics, drop unused stuff. 2018-02-17 19:10:19 +01:00
Uwe Hermann 641107aa6c siglent-sds: Use PRIu64 for uint64_t variables.
This fixes various compiler warnings on some systems.
2018-02-17 16:01:58 +01:00
Uwe Hermann 2dedd64e11 siglent-sds: Fix SR_CONF_TRIGGER_SLOPE config_set() code.
Also use "r" and "f" as trigger slope values for now, since that's
what most other drivers do currently.

This also fixes two scan-build issues:

  api.c:559:3: warning: Value stored to 'tmp_str' is never read
                  tmp_str = g_variant_get_string(data, NULL);
                  ^         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  api.c:561:9: warning: Use of memory after it is freed
                  ret = siglent_sds_config_set(sdi, "%s:TRSL %s",
                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2018-02-17 00:51:53 +01:00
Uwe Hermann a7f066bfca udev: Add entries for Siglent USBTMC devices. 2018-02-17 00:51:53 +01:00
Uwe Hermann 70cfec9a14 siglent-sds: Add 100s timebase (seen on e.g. SDS1202X-E). 2018-02-17 00:51:53 +01:00
Uwe Hermann afcbb911f8 siglent-sds: Add SDS1052DL+ model. 2018-02-17 00:51:53 +01:00
Uwe Hermann 3e7fb88f21 siglent-sds: Various cosmetics and coding-style fixes.
Also, drop some unneeded comments and log messages.
2018-02-17 00:51:53 +01:00
Uwe Hermann 4868f15a86 hantek-4032l: Minor cosmetics. 2018-02-15 22:45:35 +01:00
Uwe Hermann d18bf7bdfc std.c: Add missing <sys/time.h> #include and _XOPEN_SOURCE.
This is required for gettimeofday() to be available (at least on
FreeBSD), causes compiler warnings otherwise.
2018-02-13 23:10:33 +01:00
Uwe Hermann a9a38e7511 siglent-sds: Replace non-portable strcasestr() with g_strstr_len().
The strcasestr() function is non-portable (e.g. not available on
MinGW, possibly elsewhere). Replace it with g_strstr_len() for the time
being. While the latter is not case-insensitive it appears that
that property doesn't matter here ("." should not be relevant anyway,
and e.g. an SDS1202X-E does indeed report "Mpts" as such).

Should it become necessary to have this code be case-insensitive,
we'll have to find a more portable solution than strcasestr().
2018-02-13 22:45:22 +01:00
Uwe Hermann 04fe775be6 siglent-sds: Drop currently unused <rpc/rpc.h> #include.
This causes some compile errors on platforms where RPC is not available, e.g.

  siglent-sds/api.c:25:21: fatal error: rpc/rpc.h: No such file or directory

Surrounding the #include (and later code) with "#if HAVE_RPC" should avoid
these compile errors, but since it's not used at all for now, drop it.
2018-02-13 22:09:58 +01:00
Gerhard Sittig 563c246329 README.devices: add Siglent SDS to the firmware and conn= sections 2018-02-12 00:13:49 +01:00
Gerhard Sittig 7a970e3170 usbtmc: only reset Siglent (and Atten) devices in open
Make the USB reset for USB TMC devices conditional. Check a whitelist,
which in this implementation exclusively contains the Siglent VID.

The whitelist's comment may need adjustment. The VID probably not only
applies to SDS devices, but could be used for SDG and others as well.
And lsusb output suggests the VID is used by Atten, too.
2018-02-12 00:13:49 +01:00
Gerhard Sittig 9a4cc7dd38 usbtmc: add the Siglent VID and reset USB devices in open
Add the Siglent's VID to a list of blacklisted USB TMC devices.
Unconditionally reset USB devices in the open routine.

This was taken from marchel's development for Siglent SDS. Though the
reset should probably be conditional, and only get applied to devices
which are known to need it.

The comment may need adjustment, maybe individual PID entries are
required. The VID probably not only applies to SDS devices, but could
be used for SDG and other gear as well. And lsusb output suggests the
VID is used by Atten, too.
2018-02-12 00:13:49 +01:00
mhooijboer b33606718c siglent-sds: initial driver implementation for Siglent SDS
Implement a first version of the driver for the Siglent SDS1000 and
SDS2000 oscilloscopes.

[ gsi: This commit corresponds to git 0228126017e6 of marchelh's tree,
  I adjusted the source to closer match the project's coding style. The
  conversion was verified by this command:

  $ git diff --word-diff=color -w -b <branch>:<dir> <branch>:<dir>

  Changes include: Whitespace adjustment, dead code removal, separation
  of variable declaration and assignment, alpha-sorted includes. Line
  length was not addressed and not every location got adjusted, to keep
  the diff minimal and to reduce effort during review of this version. ]
2018-02-12 00:13:49 +01:00
mhooijboer 89f5fab97c siglent-sds: Initial driver skeleton. 2018-02-12 00:13:49 +01:00
Gerhard Sittig ca25a3ee0b README.devices: discuss conn= and USB/TCP/VXI in addition to RS232
The conn= specification is not strictly related to RS232 communication.
Provide examples for other USB specs (as they are used for some DMM and
LCR drivers), as well as TCP and VXI (which are often found with MSO
drivers).
2018-02-12 00:13:49 +01:00
Frank Stettner a7e48f3c06 korad-kaxxxxp: Simplify korad_kaxxxxp_receive_data() event loop function. 2018-02-11 23:16:37 +01:00
Frank Stettner 8f39d5698d korad-kaxxxxp: Use locale independent sr_snprintf_ascii() function 2018-02-11 23:15:52 +01:00
Frank Stettner 3f9b48ae5f korad-kaxxxxp: Synchronize read and write operations. 2018-02-11 23:15:52 +01:00
Frank Stettner 23165d7bb2 korad-kaxxxxp: Add two channels "V" and "I", remove channel "CH1" 2018-02-11 23:15:52 +01:00
Frank Stettner 16e88c6b93 tests: Tests for the locale independent sr_vsnprintf_ascii() function. 2018-02-11 23:15:52 +01:00
Frank Stettner 79034d4f39 strutil: Locale independent snprintf() and vsnprintf() functions 2018-02-11 23:15:39 +01:00
Gerhard Sittig eac9fcd268 hameg-hmo: fix potential NULL dereference
Check for successful allocation before accessing struct members. Return
with an error from device initialization when allocation fails.

This was reported by clang's scan-build.
2018-02-10 15:34:20 +01:00
Gerhard Sittig addbb09bf8 hameg-hmo: fix potential memory leak
Make sure to release the allocated "pod enabled" memory, too, when SCPI
communication during channel setup fails. Defer the return with an error
(instead of duplicating the free() invocation).

This was reported by clang's scan-build.
2018-02-10 15:34:01 +01:00
Gerhard Sittig f396351704 output/srzip: fix potential "use after free"
The compiler marks a potential use after free, which the current
implementation won't trigger. The error only occurs when a sigrok
channel is neither logic nor analog.

Address the issue nevertheless, to silence the compiler warning, and to
protect against possible programming errors when a future implementation
should support more channel types.

This was reported by clang's scan-build.
2018-02-10 15:33:23 +01:00
Gerhard Sittig 499f5045dd session: fix another potential memory leak
This was reported by clang's scan-build.
2018-02-10 15:32:03 +01:00
Gerhard Sittig 972398f471 output/wav: fixup coding style nits, adjust data types
Fixup unbalanced braces for more complex if statements, to better
reflect the project's official coding style.

Adjust data types in the float_to_le() routine. A float value gets
copied to a buffer of bytes (uint8_t). Don't use 'char' on the other
side of assignments, to not assume a specific width for char, and to
avoid potential signedness issues. Copy from bytes to bytes instead.
2018-02-09 22:40:58 +01:00
Gerhard Sittig 23eeac46ed output/wav: change default for scale factor from 0.0 to 1.0
The WAV output module supports an optional 'scale' factor, in its
absence the samples will pass unmodified. The builtin help text is
unexpected, and reads:

  $ sigrok-cli -O wav --show
  ...
  Options:
    scale: Scale values by factor (default 0.0)

Setup a default scale factor of 1.0, which results in identical
behaviour and better reflects what is happening.
2018-02-09 22:40:58 +01:00
Gerhard Sittig aa0979482f output/vcd: assume packed input data image, unbreak 2nd+ channel
The previous implementation only emitted data for the first enabled
channels, and "saw no changes" after emission of the initial value for
channels on positions that followed a disabled channel.

Assume that the received data from the session bus communicates the bits
of enabled channels in a packed representation. Skip the mapping of
output bit indices to sigrok channel numbers.

This fixes the remaining part of bug #519.

Tested by inspecting in gtkwave the result of command:
  $ sigrok-cli -d demo -C D1,D3,D6 -c samplerate=2M --samples 2500 -O vcd -o trace.vcd

When we find that all input sources (device drivers, and input modules)
provide a dense bit field, all of the mapping logic can get removed
here. This commit just quickly disables the logic.
2018-02-09 22:40:58 +01:00
Gerhard Sittig a299a95413 output/vcd: assign adjacent names to enabled channels
Identifiers for channels in the VCD header section could be "sparse"
when sigrok channels were disabled. Make sure to not assign names to
disabled channels. This will e.g. assign !, ", and # to channels D1, D3,
and D6, when D0, D2, D4-D5, and D7 are disabled.

This addresses part of bug #519.
2018-02-09 22:40:58 +01:00
Gerhard Sittig 64aa214a22 several DMMs: set DC flag for diode mode
Few DMM drivers already did it. This commit adjusts the remaining DMM
drivers, to set the "DC" flag for measurements in diode mode.

This fixes bug #144.

Although I don't have the hardware to test, the nature of the change and
the arrangement of driver code suggests it's good. When a meter already
communicated the "DC" status, the change does nothing and won't harm.
The change ensures "DC" is flagged for those meters which previously
didn't, which is desirable.
2018-02-09 22:40:58 +01:00
Gerhard Sittig b8278e0943 strutil: accept trailing whitespace after number text
Some SCPI based drivers fail to convert response data, because strutil
conversion helpers sr_atol() and sr_atof() don't like trailing spaces
after the number's text that successfully got converted.

It's yet to get determined whether all call sites of the conversion
routines like their eating adjacent whitespace. But given that the
conversion routine explicitly checks for end of the string after the
number, no call site should expect or even depend on trailing text to
keep its whitespace.

See bug #788 for a discussion and example data.
2018-02-09 22:40:58 +01:00
Gerhard Sittig 751ba4c8ed strutil: support tera/peta/exa suffixes in symbolic size specs
Synchronize sr_parse_sizestring() with sr_si_string_u64() capabilities.
Add support for the T/P/E suffixes. Since this conversion helper deals
with integer values exclusively, there is no issue with case insensitive
matches. The value cannot be pico. Neither is there an ambiguity with
the 10e6 notation.

This addresses bug #763.

Fix a style nit while we are here. Put braces around both arms of a
complex conditional.
2018-02-09 22:40:50 +01:00
Gerhard Sittig 57a88297dd beaglelogic: silence compiler warning
Explicitly assign NULL to param to avoid the "may be used uninitialized"
warning reported in bug #1094. Behaviour remains unchanged. All references
to the variable were under "if (!conn)", and the assigning arm of the
branch checked for "if (!param)" after assignment. So the error could
not happen, but compilers may not have noticed depending on the width of
their scope during compilation.

Move the initialization of 'conn' closer to the conditional assignment,
such that all paths are seen in one spot during maintenance.

This fixes bug #1094.
2018-02-09 21:59:18 +01:00
Gerhard Sittig 6f63b1ee67 usb: re-use existing values, don't re-determine bus and device address
Avoid repeated libusb bus number and device address retrieval operations,
instead use variables where the information previously got stored to.
2018-02-09 21:59:18 +01:00
Gerhard Sittig 241c03029d log: flush log lines, to cope with non-terminal output (pipes)
Although log messages are terminated by a line feed, output still might
get buffered when the program does not talk to a terminal (that it is
aware of). Add an fflush(3) call to the printf(3) sequence such that log
output will immediately show up when writing to pipes or sockets, too.
2018-02-09 21:59:18 +01:00
Gerhard Sittig 928560e6f5 backend: fixup resource leak in sr_init() error code path
Early sr_init() steps can just 'return' fine. After allocation of the
'context' memory, make all error paths 'goto done' before returning,
to undo the memory allocation.
2018-02-09 21:59:18 +01:00
Gerhard Sittig 309bb27ee4 README.devices: the PRINT button must get pressed for Metrix MX56C 2018-02-09 21:59:18 +01:00
Gerhard Sittig 11e3a56380 srzip: don't access non-existing option
The srzip output module dropped support for the "filename" option in
commit 37875f7506 on 2015-07-30, but still used to assign to slot
options[0] which clobbers the array's sentinel. Remove those accesses
to the non-existing option.
2018-02-09 21:59:18 +01:00
Uwe Hermann 793e9963b8 hantek-4032l: Fix a compiler warning.
api.c: In function 'config_set':
  api.c:352:5: warning: format '%ld' expects argument of type 'long int', but argument 3 has type 'uint64_t' [-Wformat=]
       sr_err("invalid sample range 2k...64M: %ld",
       ^
2018-02-09 21:44:23 +01:00
Uwe Hermann 3347fe26a0 beaglelogic: Fix a compiler warning.
beaglelogic_tcp.c: In function 'beaglelogic_tcp_send_cmd':
 beaglelogic_tcp.c:114:3: warning: format '%lu' expects argument of type 'long unsigned int', but argument 4 has type 'size_t' [-Wformat=]
     sr_dbg("Only sent %d/%lu bytes of command: '%s'.", out,
     ^
2018-02-09 21:44:23 +01:00
Gerhard Sittig 93b5cd6919 yokogawa-dlm: fix several compiler warnings (assignment, memory)
Check pointers' validity before dereferencing them. Release partially
allocated memory in an error path. Remove an assignment which never took
effect.

This was reported by clang's scan-build.
2018-02-09 21:37:40 +01:00
Gerhard Sittig 2da5c95f3d tondaj-sl-814: fix a potential memory leak
Release an allocated device instance in an error path.

This was reported by clang's scan-build.
2018-02-09 21:37:40 +01:00
Gerhard Sittig aedbf89d85 sysclk-lwla: silence potential NULL dereference compiler warning
Check pointers' validity before dereferencing them.

This was reported by clang's scan-build.
2018-02-09 21:37:40 +01:00
Gerhard Sittig 08eba2d301 scpi-pps: silence potential NULL dereference compiler warning
Check pointers' validity before dereferencing them.

This was reported by clang's scan-build.
2018-02-09 21:37:40 +01:00
Gerhard Sittig 6a821db6f2 saleae-logic-pro: silence "assigned, not used" compiler warning
Remove an assignment that never took effect.

This was reported by clang's scan-build.
2018-02-09 21:37:40 +01:00
Gerhard Sittig 0306ae30b6 rigol-ds: silence potential NULL dereference compiler warning
Check pointers' validity before dereferencing them.

This was reported by clang's scan-build.
2018-02-09 21:37:39 +01:00
Gerhard Sittig b04cbd0ba3 ols, pipistrello-ols: silence "assigned, not used" compiler warning
Each code path either assigns to 'flags', or leaves the routine. There
is no potential path that leaves the variable at the initially assigned
value, so the assignment took no effect. Remove it.

Nit: Trim the source code line length while we are here.

This was reported by clang's scan-build.
2018-02-09 21:37:39 +01:00
Gerhard Sittig 8eadb70a37 norma-dmm: fix a potential memory leak
Release an allocated buffer in an error path.

This was reported by clang's scan-build.
2018-02-09 21:37:39 +01:00
Gerhard Sittig e4924d752b motech-lps-30x: fix several compiler warnings
Check pointers' validity before dereferencing them. Explicitly assign a
default value to variables, before conversion routines conditionally
assign the "real" value (and don't in case of conversion errors). This
avoids processing "garbage" data.

Strictly speaking I cannot see how the conversion routine returns OK and
has _not_ assigned a result. But the explicit assignment won't harm
either, and matches the fallback when the conversion fails (detectibly).
Which means that runtime behaviour won't change.

This was reported by clang's scan-build.
2018-02-09 21:37:39 +01:00
Gerhard Sittig fe535a89c9 maynuo-m97: fix potential NULL dereference
Check pointers' validity before dereferencing them.

This was reported by clang's scan-build.
2018-02-09 21:37:39 +01:00
Gerhard Sittig 4072d5b42f manson-hcs-3xxx: fix potential NULL dereference
Check pointers' validity before dereferencing them.

This was reported by clang's scan-build.
2018-02-09 21:37:39 +01:00
Gerhard Sittig f62c2ad65d lecroy-xstream: fix several compiler warnings (assignment, memory)
Remove an assignment that won't take effect. Check pointers' validity
before dereferencing. Fix a memory leak.

This was reported by clang's scan-build.
2018-02-09 21:37:39 +01:00
Gerhard Sittig b65adcedb8 lascar-el-usb: fix potential NULL dereference and memory leak
Check for successful allocation of multiple memory ranges, and release
partial allocations in the error path when one of them failed. This
fixes a potential memory leak, as well as avoids NULL dereferences.

This was reported by clang's scan-build.
2018-02-09 21:37:39 +01:00
Gerhard Sittig fc69eecca0 korad-kaxxxxp: fix potential NULL dereference
Check pointers' validity before dereferencing them.

This was reported by clang's scan-build.
2018-02-09 21:37:39 +01:00
Gerhard Sittig 1674225a2f hp-3457a: fix potential NULL dereference
Check the active channels' list for not being empty, before
dereferencing pointers.

This was reported by clang's scan-build.
2018-02-09 21:37:39 +01:00
Gerhard Sittig e93ca8a4d6 hantek-6xxx: fix potential NULL dereference
Check pointers' validity before dereferencing.

This was reported by clang's scan-build.
2018-02-09 21:37:39 +01:00
Gerhard Sittig b0e80e9aa9 hameg-hmo: fix several compiler warnings (assignments, memory)
Silence warnings about assigned values that never get used, potential
NULL deference, and potential memory leaks.

This was reported by clang's scan-build.
2018-02-09 21:37:39 +01:00
Gerhard Sittig 56e9672b11 gmc-mh-1x-2x: fix potential memory leak
The scan_2x_bd232() routine used to always prepare one spare context,
and filled it in when a device was found, just to allocate another one
and continue scanning.

Free the last allocated context unconditionally, as it was allocated
unconditionally, and never used.

This was reported by clang's scan-build.
2018-02-09 21:37:39 +01:00
Gerhard Sittig 0d1c51f57f fx2lafw: silence "NULL dereference" compiler warning
Check pointers' validity before dereferencing them.

This was reported by clang's scan-build.
2018-02-09 21:37:39 +01:00
Gerhard Sittig f6051b9eca ftdi-la: silence "assigned but never used" compiler warning
Stick with the prepared but unfinished "limit msec" code path, but
silence the warning about an unused variable value.

This was reported by clang's scan-build.
2018-02-09 21:37:35 +01:00
Gerhard Sittig 051e4beb79 dreamsourcelab-dslogic: avoid division by zero
Do not align to block_size when its value is zero.

This was reported by clang's scan-build.
2018-02-09 21:34:17 +01:00
Gerhard Sittig 8e2fd23acb dreamsourcelab-dslogic: avoid NULL pointer dereference
Check pointers' validity before dereferencing them.

This was reported by clang's scan-build.
2018-02-09 21:34:17 +01:00
Gerhard Sittig 755eb22156 chronovu-la: avoid NULL pointer dereference
Check pointers' validity before dereferencing them.

This was reported by clang's scan-build.
2018-02-09 21:34:17 +01:00
Gerhard Sittig 05b0cc416f beaglelogic: fixup use of uninitialized data in TCP routines
Make sure that failure to communicate via TCP results in access to
uninitialized data.

This was reported by clang's scan-build.
2018-02-09 21:34:17 +01:00
Gerhard Sittig 71f2000bfb beaglelogic: fixup memory leak in the TCP command send routine
Release allocated memory in an error code path.

This was reported by clang's scan-build.
2018-02-09 21:34:17 +01:00
Gerhard Sittig f6c685e4d3 atten-pps3xxx: silence NULL dereference compiler warnings
Check pointers' validity before dereferencing them.

This was reported by clang's scan-build.
2018-02-09 21:34:17 +01:00
Gerhard Sittig 7ee8511be4 session_driver: avoid division by zero, catch API violation
Avoid a division by zero, by not using a zero unitsize in a modulo
operation. As a byproduct, avoid processing and counting input that
neither has analog nor logic data. This should never have happened,
but the change now catches the error if invalid input is seen.

This was reported by clang's scan-build.
2018-02-09 21:34:09 +01:00
Gerhard Sittig f129014ca4 session: fixup access to uninitialized memory
The sr_packet_copy() routine could have written to an arbitrary memory
location. Make sure to allocate the space before writing to it, and
check for successful allocation before accessing the memory.

It's assumed that this error never took effect, as the routine appears
to be unused.

This was reported by clang's scan-build.
2018-02-09 21:32:11 +01:00
Gerhard Sittig da6f107eff scpi: avoid uninitialized use of a variable
The 'opc' variable was only conditionally assigned to (depends on
successful SCPI communication). Ensure there always is a known value.

This was reported by clang's scan-build.
2018-02-09 21:32:11 +01:00
Gerhard Sittig d3ec7035bc output/srzip: silence "use after free" compiler warning
Defer memory g_free() until after the data gets accessed one last time.

This was reported by clang's scan-build.
2018-02-09 21:32:04 +01:00
Gerhard Sittig a21fef07b6 output/csv: silence NULL dereference compiler warnings
Check pointers' validity before dereferencing them.

This was reported by clang's scan-build.
2018-02-09 20:52:26 +01:00
Gerhard Sittig 603643fa71 input/raw_analog: silence "use after free" compiler warning
The cleanup() call will void the memory which 'inc' points to. Move the
dereference before the release.

This was reported by clang's scan-build.
2018-02-08 21:47:21 +01:00
Soeren Apel d8fb599c67 lecroy-xstream: Wait for trigger before acquiring additional frames 2018-01-11 02:21:50 +01:00
Soeren Apel 724b4945d5 lecroy-xstream: Properly handle a stopping acquisition 2018-01-11 02:21:50 +01:00
Soeren Apel 2498512972 lecroy-xstream: Keep acquiring infinitely if no frame limit is set 2018-01-11 02:21:50 +01:00
Uwe Hermann d3f14af7ed hantek-dso: Capture ratio is a uint64_t.
From src/hwdriver.c:

  {SR_CONF_CAPTURE_RATIO, SR_T_UINT64, "captureratio",
          "Pre-trigger capture ratio", NULL},
2018-01-11 02:21:50 +01:00
Uwe Hermann 04069272b4 hantek-dso: config_set(): Shorten SR_CONF_CAPTURE_RATIO case.
The sr_config_set() wrapper already checks for SR_CONF_CAPTURE_RATIO
being 0..100.
2018-01-11 02:21:50 +01:00
Uwe Hermann be702d16d0 hantek-dso: Add missing SR_PRIV. 2018-01-11 02:21:50 +01:00
Uwe Hermann 6deb361bbf hantek-dso: Sample rate is a uint64_t.
Also make 'base' uint64_t, otherwise there'll be compiler warnings.
2018-01-11 02:21:50 +01:00
Uwe Hermann ab8df2b1a6 hantek-dso: Random cosmetics, drop unneeded debug output. 2018-01-11 02:21:50 +01:00
Philipp Marek 8f484ca78e hantek-dso: dso2250: Fix capture runaway, only do the requested number of frames.
After the first capture ->num_frames never got to be _equal_
to ->limit_frames; fixed by resetting to zero in dev_acquisition_stop(),
and protected against similar problems in the future by switching to
greater-or-equal instead.
2018-01-11 02:21:50 +01:00
Philipp Marek 12f62ce620 hantek-dso: dso2250: Allow setting TRIGGER_LEVEL as well. 2018-01-11 02:21:50 +01:00
Philipp Marek 16a1dca4ad hantek-dso: Fix a memory leak. 2018-01-11 02:21:50 +01:00
Philipp Marek be10b96d40 hantek-dso: Fix segfault when accessing already free()d memory.
This fix was guessed from other drivers' code.

This fixes bug #458.
2018-01-11 02:21:30 +01:00
Philipp Marek 95983cc3fe hantek-dso: dso2250: It's not HORIZ_TRIGGERPOS but CAPTURE_RATIO.
Seems a bit unfortunately named; if my current guess is right,
perhaps it should be
  :%s/SR_CONF_HORIZ_TRIGGERPOS/SR_CONF_HORIZ_DISPLAYOFFSET/g
2018-01-11 01:48:57 +01:00
Philipp Marek 11e3319656 hantek-dso: dso2250: Support sample rates correctly.
Fast mode not done yet, only 125MHz allowed right now.
2018-01-10 22:34:23 +01:00
Philipp Marek 3b2b703177 hantek-dso: dso2250: Report the sample rate back.
So that cursor (and other) measurements and the time axis are correct.
2018-01-10 22:34:20 +01:00
Philipp Marek 87f56d0178 hantek-dso: dso2250: Initial support for the Hantek DSO 2250.
Crashes after first acquiration, but at least it _does_ acquire data.
2018-01-10 22:33:37 +01:00
Uwe Hermann af2f9a5d85 udev rules: Add Hantek 4032L IDs. 2018-01-05 20:31:09 +01:00
Andreas Zschunke 5089a14345 hantek-4032l: Add initial driver implementation.
[Note: This patch is basically a squashed version of the initial driver
commits by Andreas Zschunke <andreas.zschunke@gmx.net>, two fixes by
Andrej Valek <andy@skyrain.eu>, and various coding style / cosmetic
fixes by Uwe Hermann <uwe@hermann-uwe.de> to make the driver a lot more
consistent with the rest of the libsigrok code-base.]
2018-01-05 20:28:14 +01:00
Andreas Zschunke 6a25fa4238 hantek-4032l: Initial driver skeleton. 2018-01-05 18:22:20 +01:00
Michał Janiszewski be61937929 zeroplus-logic-cube: Add LAP-16032U 2018-01-01 14:41:23 +01:00
Stefan Brüns bbcffe51d2 rigol-ds: Fix crash when fetching logic channels
When refactoring the code, some places where sr_scpi_send was replaced
by rigol_ds_config_set the first argument was not changed from sdi->conn
to sdi. Fix the remaining ones.

Fix: https://sigrok.org/bug/1073

Signed-off-by: Stefan Brüns <stefan.bruens@rwth-aachen.de>
2017-12-26 19:21:42 +01:00
Uwe Hermann 8e45ba3f4e zeroplus-logic-cube: Fix Logian-16L metadata.
According to a vendor software screenshot of a user on IRC, this
device is detected as having 200MHz max. samplerate and 128kBit
memory per channel.
2017-12-25 15:42:06 +01:00
Uwe Hermann fb1d341d6e zeroplus: Add support for Meilhaus Logian-16L.
Untested yet, but pretty likely to work.
2017-12-25 14:30:00 +01:00
Uwe Hermann 42d14d9108 sysclk-lwla: Fix a regression with (at least) the LWLA1034.
This regression was introduced in f1ba6b4b2c.

Due to how the sysclk-lwla driver does up to 3 open/close operations in
one dev_open() API callback we cannot rely on the sr_dev_open() and
sr_dev_close() wrappers setting the sdi->status variable in this case.

Tested on LWLA1034.
2017-12-25 12:48:58 +01:00
Uwe Hermann 6c1a4cb44c sysclk-lwla: Fix a segfault in dev_close(). 2017-12-24 15:24:35 +01:00
Uwe Hermann 56c8dd821e sr_dev_close(): Drop unneeded variable. 2017-12-24 15:23:40 +01:00
Gerhard Sittig f9bc17d4c0 input/vcd: fixup VCD timestamp to sigrok samplenum mapping
When processing of large VCD input files was spread across multiple
parse_contents() invocations, the resulting sigrok stream of sample data
had gaps in them and total timing was off. For instance 74ms of input
data were interpreted as spanning some 600ms or 300ms, depending on the
number of channels in the input stream.

Move the "previous timestamp" variable to the input module context. This
eliminates the inappropriate gaps and fixes the translation of VCD file
timestamps to sigrok sample numbers.

This fixes bug #1075.
2017-12-22 11:47:03 +01:00
Uwe Hermann 51d64bf501 output/csv: Fix a typo. 2017-12-21 16:06:48 +01:00
Uwe Hermann c108ef087e 60-libsigrok.rules: Add note about sigrok-androidutils. 2017-12-17 20:38:27 +01:00
Uwe Hermann 767d4f37c7 fx2lafw: Update comments listing supported devices. 2017-12-17 20:19:13 +01:00
Uwe Hermann 5a01d09482 60-libsigrok.rules: Add missing entries and comments. 2017-12-17 20:17:22 +01:00
Uwe Hermann 6605f1b9bb zeroplus-logic-cube: Add LAP-C(16128+) USB VID/PID.
Untested, so we don't know for sure it'll work.

This fixes bug #1045.
2017-12-17 19:46:23 +01:00
Stefan Brüns bd70ec4b73 hameg-hmo: Forward internal channel state to sigrok channel state
This fixes bug #883.
2017-12-10 14:24:36 +01:00
Holger Müller 41802ca4c0 korad-kaxxxxp: Add support for Korad KD3005P 2017-12-09 23:17:12 +01:00
Uwe Hermann b2e9b6d48a Makefile.am: Add/update udev rules files. 2017-11-22 12:49:22 +01:00
Stefan Brüns 75696630c1 cleanup udev part of README.devices, reflect split rules
Remove vague statements from the README. On all current distributions,
the udev paths are identical, anyone deliberately deviating from the
defaults should be able to handle it by themselves.

Rules in /etc/udev/rules.d/ should only be used for customization, or
for locally built packages.
2017-11-22 12:49:22 +01:00
Stefan Brüns f19fc2af33 contrib: Split device access policy from the device database
Split the distribution independent database from the access policy rules.
This avoids warnings due to granting permissions to the commonly unknown
plugdev group, and allows simple overrides of the used access policy.
2017-11-22 12:49:22 +01:00
Stefan Brüns 157fd444e9 contrib: remove duplicate rules for fx2lafw DSOs 2017-11-22 12:49:22 +01:00
Stefan Brüns d2a7e9bf08 contrib: rename udev rules for correct rule ordering on systemd systems
The "uaccess" tag has to be added before the "seat" rule is evaluated.
The upstream default for the seat rule is "71-seat.rules", so use
60-libsigrok.rules for appropriate lexicographical sorting.

Also use a dash instead of underscore, the latter is commonly used as a
replacement character of unsafe characters in autogenerated identifiers.

This fixes bug #1059.
2017-11-22 12:49:05 +01:00
Frank Stettner 7c517d02f7 scpi-pps: Channel group device options for HP 663xx 2017-11-11 19:46:52 +01:00
Frank Stettner 4f0463a079 drivers: Fix locale dependent string to float conversion
Some drivers used locale dependent functions for converting strings
to float/double values. These functions fail when the decimal mark
is a "," in the locale settings but the string contains a ".".

This fixes bug #1064.
2017-11-11 19:46:52 +01:00
Frank Stettner 688e44ae06 output/analog: Display META packets 2017-11-11 19:46:52 +01:00
Frank Stettner 2472271e08 arachnid-labs-re-load-pro: Add SR_DF_META packets for changed values/states 2017-11-11 19:46:44 +01:00
Frank Stettner b76a414d51 arachnid-labs-re-load-pro: Stop monitoring when open/close device 2017-11-11 19:46:44 +01:00
Frank Stettner 0b7c07850c conrad-digi-35-cpu: Add SR_CONF_LIST for voltage_target and current_limit. Change current_limit lower limit. 2017-11-07 12:07:19 +01:00
Frank Stettner ae32859759 lipgpib: Enhanced error message 2017-11-07 12:04:30 +01:00
Soeren Apel 767ca13532 demo: Properly handle low samplerates
A "low samplerate" in this case means anything where
samples_todo is less than SAMPLES_PER_FRAME. This case
wasn't handled properly before, resulting in wrong
amounts of data being sent out.
2017-11-02 14:28:16 +01:00
Soeren Apel e0b6855bd4 lecroy-xstream: Fix sample rate
We can't use the memory size command because it returns
the *maximum* memory used, not the *actual* memory used.
Hence, we only know the number of samples per div once
sample data actually comes in.
2017-11-02 07:29:22 +01:00
Soeren Apel 86f76e6cae lecroy-xstream: Perform acquisition if no data is available 2017-11-02 07:29:22 +01:00
Soeren Apel 6e9606dbae lecroy-xstream: Comment/style fixes 2017-11-02 07:29:22 +01:00
Timo Rothenpieler 095eba19d6 hantek-6xxx: use lower MAX_PACKET_SIZE on Windows
WinUSB seems to have a maximum size of 2M, reads of a larger size fail.

This fixes bug #1048.
2017-10-19 15:01:06 +02:00
Soeren Apel 79100d4e8b lecroy-xstream: Implement config_channel_set API callback 2017-10-03 17:31:48 +02:00
Soeren Apel 5000c12f57 lecroy-xstream: Fix trigger source/slope 2017-10-03 17:31:48 +02:00
Soeren Apel 952c7376e4 lecroy-xstream: Random whitespace/style fixes 2017-10-03 17:31:48 +02:00
Soeren Apel e7d2cd1e05 lecroy-xstream: Use best-effort strategy for unknown models
As there is a huge range of supported LeCroy scopes, naming
the IDN response for every single one of them is going to be
impossible. Hence, it makes more sense to treat all LeCroy
devices as if they were scopes and supported. This approach
lets users try to see how far they get and if they run into
issues, they can then be treated separately - e.g. by creating
a custom device profile.
Unless we do this, the vast majority of LeCroy scopes will
not be recognized by the driver.
2017-10-03 17:31:48 +02:00
Sylvain Pelissier 6158728cdb lecroy-xstream: Fix COMM_HEADER and COMM_FORMAT 2017-10-03 17:31:48 +02:00
Sylvain Pelissier 47bbc4b531 SCPI: Ignore IDN header in *IDN? response 2017-10-03 17:31:48 +02:00
Soeren Apel f55bea7626 Demo: Implement multi-frame development feature 2017-10-03 17:31:48 +02:00
Soeren Apel b7602846fd Add std_session_send_frame_begin/end helpers 2017-10-03 17:31:48 +02:00
Joel Holdsworth 55584d38dd dreamsourcelab-dslogic: Fixed deinterleaving when non-contiguous set of channels are enabled 2017-09-26 21:48:04 +02:00
Uwe Hermann cb17f580b9 beaglelogic: Inline beaglelogic_devc_alloc(). 2017-09-26 19:51:55 +02:00
Uwe Hermann f82525e60d beaglelogic: Minor whitespace and consistency fixes. 2017-09-26 19:51:55 +02:00
Uwe Hermann 00f2e9bc6b beaglelogic: No need to check g_free() argument.
glib's g_free() function will gracefully handle NULL as input.
2017-09-26 19:51:55 +02:00
Kumar Abhishek a31010b3e4 beaglelogic: Coding style fixes
In beaglelogic_native.c and beaglelogic_tcp.c

Signed-off-by: Kumar Abhishek <abhishek@theembeddedkitchen.net>
2017-09-26 18:14:46 +02:00
Kumar Abhishek ca0d1a21af beaglelogic: Fix regression in continuous sampling
Signed-off-by: Kumar Abhishek <abhishek@theembeddedkitchen.net>
2017-09-26 18:14:46 +02:00
Kumar Abhishek 3124d3bc48 beaglelogic: Update copyright notices in all files
Signed-off-by: Kumar Abhishek <abhishek@theembeddedkitchen.net>
2017-09-26 18:14:46 +02:00
Kumar Abhishek f154b40ddd beaglelogic: Fix compiler warnings in beaglelogic_tcp.c
Signed-off-by: Kumar Abhishek <abhishek@theembeddedkitchen.net>
2017-09-26 18:14:46 +02:00
Kumar Abhishek a486fca9e2 beaglelogic: Close device after detection, and reopen upon open
Signed-off-by: Kumar Abhishek <abhishek@theembeddedkitchen.net>
2017-09-26 18:14:46 +02:00
Kumar Abhishek f955ffe83f beaglelogic: Changes for proper operation in PulseView
Set samplelimit to a sane value (was causing PulseView to
crash earlier), as well as advertise samplerate using SR_CONF_LIST
so that PulseView can show the sample rates.

Signed-off-by: Kumar Abhishek <abhishek@theembeddedkitchen.net>
2017-09-26 18:14:46 +02:00
Kumar Abhishek d6f20d0366 beaglelogic: Fix PulseView crash on close
Use dev_clear instead of std_dev_clear to clean up our private
data structure.

Signed-off-by: Kumar Abhishek <abhishek@theembeddedkitchen.net>
2017-09-26 18:14:46 +02:00
Kumar Abhishek f7d7ee82dd beaglelogic: Add beaglelogic_tcp_drain function
The function drains off all the remaining data in the receive socket
and is triggered before starting a capture and after a capture is
completed. In the absence of this function, there is a possibility of
data corruption and also the NodeJS TCP server throws an error if the
buffer is not completely read out before the socket is closed.

Signed-off-by: Kumar Abhishek <abhishek@theembeddedkitchen.net>
2017-09-26 18:14:46 +02:00
Kumar Abhishek 9b2b3ef93e beaglelogic: Implement TCP protocol
BeagleLogic now supports two modes of interface - one being the
native mode running on an ARM system like the BeagleBone Black
and the other mode acting like a TCP client for the BeagleLogic
server running off a BeagleBone compatible system. This makes it
convenient for desktop users to retrieve samples from BeagleLogic,
no more copying files and SSHing into the BeagleBone hardware in
order to use BeagleLogic.

Signed-off-by: Kumar Abhishek <abhishek@theembeddedkitchen.net>
2017-09-26 18:14:46 +02:00
Kumar Abhishek 0bca2e75f5 beaglelogic: Re-organize to prepare for TCP support
Organize driver functions into an ops structure (there will be
separate structures for both native and TCP mode of operation).

Signed-off-by: Kumar Abhishek <abhishek@theembeddedkitchen.net>
2017-09-26 18:14:46 +02:00
Kumar Abhishek 88d2037bca beaglelogic: Split beaglelogic code into .h and .c file
The code earlier was in a single .h file, so it's now separated into a C file
and H file

Signed-off-by: Kumar Abhishek <abhishek@theembeddedkitchen.net>
2017-09-26 18:14:46 +02:00
Kumar Abhishek e71062d99b beaglelogic: Flexible sampleunit depending on enabled channels
If a channel in the higher-than-8-bit group is enabled then use
16-bit captures. Otherwise just do 8-bit captures.

Signed-off-by: Kumar Abhishek <abhishek@theembeddedkitchen.net>
2017-09-26 18:14:46 +02:00
Kumar Abhishek 55f26c42de beaglelogic: Remove 'as root' from warning message
Starting with Linux kernel version 4.9, BeagleLogic attributes
setting does not require root permissions.

Signed-off-by: Kumar Abhishek <abhishek@theembeddedkitchen.net>
2017-09-26 18:14:31 +02:00
Kumar Abhishek 713f3f8480 beaglelogic: Enable seamless continuous capturing
This is done by setting triggerflags to 1 unless SR_CONF_LIMIT_SAMPLES is set

Signed-off-by: Kumar Abhishek <abhishek@theembeddedkitchen.net>
2017-09-26 18:06:34 +02:00
Kumar Abhishek 6eab3021ec beaglelogic: Update scan() to return all 14 channels by default
This is unlike the previous behavior to return 8 channels and then
use logic_channels to get all the 14 channels

Signed-off-by: Kumar Abhishek <abhishek@theembeddedkitchen.net>
2017-09-26 18:06:34 +02:00
Uwe Hermann 1f488f50b9 sr_parse_rational(): Make is_negative a bool. 2017-09-24 21:17:51 +02:00
Stefan Brüns 41c47f2c6a strutil: Fix sr_parse_rational for integral parts between -0 and -1
Values like '-0.1' would be parsed as being positive, as the integral
type does not discern +0 and -0. Also allow values without leading
integral value, to match behaviour of strtod/sr_atof.
2017-09-24 21:04:46 +02:00
Joel Holdsworth f05600f4be dreamsourcelab-dslogic: Fixed enabling of triggers 2017-09-19 00:31:11 +02:00
Joel Holdsworth 16d4c982a3 dreamsourcelab-dslogic: Moved devc and usb assignment into initializers 2017-09-19 00:31:11 +02:00
Joel Holdsworth 9f58023066 dreamsourcelab-dslogic: Improved naming of variables in fpga_configure 2017-09-19 00:31:11 +02:00
Joel Holdsworth b7a3d79e46 dreamsourcelab-dslogic: Fixed trigger-stages field in trig_glb 2017-09-19 00:31:11 +02:00
Joel Holdsworth b23ecd6ce7 dreamsourcelab-dslogic: Simplified trigger population 2017-09-19 00:31:06 +02:00
Uwe Hermann 689749b741 Drop libftdi 0.x support, require libftdi 1.x.
There were some issues when using libftdi 0.x recently that are fixed
when switching to libftdi 1.x (not really worth the effort to investigate).

libftdi 1.x has been around several years now and should be available
in most recent distros and OSes. For the rare cases where it is not,
it's easy enough to get it via backport packages, or build from source,
or sigrok users can just use our binary installers for most OSes.

This also "fixes"/obsoletes bug #959.
2017-09-17 17:01:07 +02:00
Uwe Hermann 19c9b17648 serial-dmm: Add PeakTech 4390A alias.
This is a rebadged Metex M-3860M.
2017-09-15 22:03:32 +02:00
Uwe Hermann 86a1571135 dreamsourcelab-dslogic: Fix incorrect default threshold setting.
This was leading to an invalid threshold config value and indirectly
to frontend issues.

Slightly modified patch from James Churchill <pelrun@gmail.com>, thanks!
2017-09-14 11:15:06 +02:00
Frank Stettner 57837aeda5 conrad-digi-35-cpu: Fix key names for setting voltage and current 2017-09-13 14:11:07 +02:00
Frank Stettner fcc73918b0 serial-dmm: Add Metex M-3860M 2017-09-13 14:03:40 +02:00
Frank Stettner eea576077b conrad-digi-35-cpu: Add and use missing dev_context structure 2017-09-13 14:03:40 +02:00
Uwe Hermann bc98407b8f dreamsourcelab-dslogic: config_list: Handle SR_CONF_TRIGGER_MATCH.
This fixes bug #1032.
2017-09-13 13:05:42 +02:00
Uwe Hermann 7bf81cb7a9 chronovu-la: Silence overly verbose log message.
This triggered all kinds of unrelated / confusing log messages
for unrelated hardware devices, e.g.:

  sr: [00:00.613080] chronovu-la: Unknown iProduct string 'USB-based Instrument'.
  sr: [00:00.614374] chronovu-la: Unknown iProduct string 'GL3220      '.
  sr: [00:00.614907] chronovu-la: Unknown iProduct string 'USB 3.0 HUB      '.
  sr: [00:00.615558] chronovu-la: Unknown iProduct string 'USB 2.0 HUB      '.
  sr: [00:00.619846] chronovu-la: Unknown iProduct string 'Bluetooth USB Host Controller'.
  sr: [00:00.620411] chronovu-la: Unknown iProduct string 'USB 3.0 HUB      '.
  sr: [00:00.624293] chronovu-la: Unknown iProduct string 'UAC1 DAC'.
  sr: [00:00.627849] chronovu-la: Unknown iProduct string 'BRCM20702 Hub'.
  sr: [00:00.628640] chronovu-la: Unknown iProduct string 'USB 2.0 HUB      '.
  sr: [00:00.674777] chronovu-la: Unknown iProduct string 'USB2223'.
  sr: [00:00.675034] chronovu-la: Unknown iProduct string ''.
  sr: [00:00.675180] chronovu-la: Unknown iProduct string ''.
  sr: [00:00.675205] hwdriver: Scan found 0 devices (chronovu-la).
2017-09-12 22:15:32 +02:00
Marcus Comstedt 393375e1fe drivers: Remove dependency on linker implementation specific behaviour 2017-09-02 17:06:37 +02:00
Uwe Hermann 9014d45968 z60_libsigrok.rules: Add Brymen BU-86X adapter IDs. 2017-08-21 18:24:42 +02:00
turboaffe 9520fd4134 manson-hcs-3xxx: enabled output guaranteed write 2017-08-19 19:21:54 +02:00
turboaffe 6508294dca manson-hcs-3xxx: added new name for 3304, adjustment to new manson fw 2017-08-19 19:21:54 +02:00
Gerhard Sittig 5753d2e84b brymen-bm86x: support channel selection (enable/disable channels)
The previous implementation unconditionally submitted analog data
whenever values could get extracted out of received serial packets.
This commit checks the channels' enabled state before submission. Care
is taken to obey the user's acquisition limits, exclusively counting
submitted not received values.
2017-08-19 19:21:54 +02:00
Gerhard Sittig 503519b70a lsr/es51919: support channel selection (enable/disable P1/P2)
Upon reception of serial data from the ES51919 LCR chipset, the data for
channels P1 and P2 was extracted from the packet, and unconditionally got
sent to the sigrok session.

Do check the channels' enabled state before submission. This fixes for
serial-lcr what recently got reported for a Brymen DMM. Tested with

  $ sigrok-cli -d peaktech-2170:conn=/dev/ttyUSB0 --channels P2

and other --channels specifications.
2017-08-19 19:21:53 +02:00
Gerhard Sittig 12788e7e40 lcr/es51919: clean but don't free dev context in cleanup callback
The es51919_serial_clean() routine is called by std_dev_clear_with_callback().
Common code unconditionally frees the 'priv' part. The cleanup callback only
shall release descending resources which are local to the callee and opaque
to the caller.

This fixes a double free error. Tested with PeakTech 2170.

  $ sigrok-cli -d peaktech-2170:conn=/dev/ttyUSB0 --show
2017-08-19 19:21:51 +02:00
Uwe Hermann 1503d4571b resource: Also check $SIGROK_FIRMWARE_DIR for firmware files.
If the SIGROK_FIRMWARE_DIR environment variable is specified, look there
first for firmware files.
2017-08-15 22:15:47 +02:00
Gerhard Sittig dde0175d19 asix-sigma: download sample data upon user initiated stop, too
When the acquisition was stopped before a configured limit was reached,
no sample data was retrieved. This is because the api.c stop routine did
unregister the receive callback.

Pass the stop request to the receive routine instead when stop is called
while the acquisition is still running. Have sample data downloaded very
much like it's done for reached limits, and existing logic will run the
stop routine again after state was advanced to "idle".

Extend the 'state' tracking while we are here, mark sample download as
well (that was omitted in the previous implementation). Though the
omission was non-fatal. Move the release of 'dram_line' to some earlier
location (as soon as the resource is not needed any longer), before some
rather complex calls to other routines will execute.

Reported-By: Michael Kaplan <M.KAPLAN@evva.com>
2017-08-11 18:52:23 +02:00
Uwe Hermann 379e95c587 drivers: Use serial_write_blocking() everywhere.
This fixes bug #962.
2017-08-07 14:22:52 +02:00
Uwe Hermann b5df922e4f sr_voltage_string(): Add a space before the unit.
This makes the output consistent with most of the other functions
in libsigrok.
2017-08-06 19:45:45 +02:00
Uwe Hermann c911599da7 Add sr_voltage_string() unit tests. 2017-08-06 19:38:31 +02:00
Uwe Hermann d2391b5453 drivers: Use g_strdup_printf() where possible. 2017-08-06 19:38:31 +02:00
Uwe Hermann 8ebad34370 drivers: Random whitespace fixes. 2017-08-06 17:31:46 +02:00
Uwe Hermann db85496ed1 drivers: Simplify some more trigger slope settings. 2017-08-06 17:31:46 +02:00
Uwe Hermann 3782e57129 drivers: Reduce unnecessarily high indentation in some places. 2017-08-06 17:31:46 +02:00
Uwe Hermann 612336970d drivers: Consistently use the same method to check for !cg. 2017-08-06 17:31:46 +02:00
Uwe Hermann fcd6a8bdf1 drivers: Factor out std_cg_idx(). 2017-08-06 17:31:46 +02:00
Uwe Hermann d1ac53ccd5 drivers: Start counting at 0 for some loops. 2017-08-06 17:31:46 +02:00
Uwe Hermann b3fd09937c drivers: Use NUM_CHANNELS in favor of hardcoded values. 2017-08-06 17:31:46 +02:00
Uwe Hermann bd633efa32 drivers: Use std_*idx*() helpers in some more places. 2017-08-03 16:35:19 +02:00
Uwe Hermann 76f0fa5dfb lecroy-xstream: Use array-based approach for timebases/vdivs.
This makes the driver more consistent with the rest of the code-base
and allows us to use the new array helpers in a few more places.
2017-08-03 16:35:19 +02:00
Uwe Hermann 692716f5d1 drivers: Use array-based approach in some places.
This allows us to use the new array helpers in a few more places.
2017-08-03 16:35:19 +02:00
Uwe Hermann 373e92a491 drivers: Consistently name SCPI helper functions 'probe_device'. 2017-07-31 16:23:32 +02:00
Uwe Hermann 21fe5dba36 drivers: Drop some unneeded voltage_/volt_ prefixes. 2017-07-31 16:23:32 +02:00
Uwe Hermann e124cf9b7a drivers: Drop some unneeded _names suffixes. 2017-07-31 16:23:32 +02:00
Uwe Hermann efad7cccec drivers: SR_CONF_CAPTURE_RATIO fixes.
Move the check for the capture ratio being 0..100 into the wrappers,
drop unneeded helper functions, fix incorrect variable types, minor
other consistency fixes.
2017-07-31 16:23:32 +02:00
Uwe Hermann 758906aa71 drivers: Remove some unneeded 'ret' variables. 2017-07-31 16:23:31 +02:00
Uwe Hermann 50ccb36f20 drivers: Random SR_CONF_LIMIT_* cleanups.
Drop unneeded variables and checks (performed by the wrappers already).
2017-07-31 16:23:31 +02:00
Uwe Hermann 697fb6ddfc drivers: Factor out std_*_idx*(). 2017-07-31 16:23:31 +02:00
Uwe Hermann 94e64a0b89 drivers: Replace struct voltage_threshold with an array.
This makes the code-base more consistent and will allow for wider usage
of upcoming array helper functions.
2017-07-31 16:23:31 +02:00
Uwe Hermann 87dc541027 drivers: Move SR_ERR_CHANNEL_GROUP log messages to wrappers. 2017-07-31 16:23:31 +02:00
Uwe Hermann 00ed77f27c drivers/input: Remove some hardcoded values. 2017-07-31 16:23:31 +02:00
Uwe Hermann 95c1fe62f7 drivers: Use g_variant_new_printf() where possible. 2017-07-31 16:23:31 +02:00
Uwe Hermann 9fb9afb573 drivers: Factor out std_gvar_thresholds(). 2017-07-31 16:23:31 +02:00
Uwe Hermann 43995cda36 drivers: Factor out std_gvar_tuple_double(). 2017-07-31 16:23:31 +02:00
Uwe Hermann a162eeb2e8 drivers: Factor out std_gvar_tuple_u64(). 2017-07-31 16:23:31 +02:00
Uwe Hermann dd7a72ea69 drivers: Consistently use same indentation for config_*() API calls. 2017-07-31 16:23:31 +02:00
Uwe Hermann 58ffcf9712 std_gvar_tuple_array(): Change to allow for more ARRAY_AND_SIZE usage.
Thanks to Marcus Comstedt <marcus@mc.pp.se> for the hint!
2017-07-21 19:04:34 +02:00
Uwe Hermann 8dacbcf68f drivers: Consistently use the exact driver name as LOG_PREFIX. 2017-07-21 18:46:27 +02:00
Uwe Hermann f272d7ddc0 drivers: Consistently make LOG_PREFIX the first item after #includes. 2017-07-21 18:46:27 +02:00
Uwe Hermann b15ff1c92a drivers: Eliminate some unnecessary vendor/model #defines.
Most drivers use the vendor/model strings directly already; make all
of them do that consistently.
2017-07-21 18:46:26 +02:00
Uwe Hermann f8195cb2da drivers: Shorten some unnecessarily long arrays. 2017-07-21 17:06:40 +02:00
Uwe Hermann 76d10d1324 drivers: Consistently use the name trigger_matches[] everywhere. 2017-07-21 17:06:40 +02:00
Uwe Hermann 9e411f4be8 rigol-ds: config_set: Move error printing to wrapper. 2017-07-21 17:06:40 +02:00
Uwe Hermann 0f8bee7162 rigol-ds: Update a code comment. 2017-07-21 17:06:40 +02:00
Uwe Hermann 396cdca0c3 rigol-ds: Drop two unneeded #defines. 2017-07-21 17:06:40 +02:00
Uwe Hermann 53012da658 drivers: Use ARRAY_AND_SIZE where possible. 2017-07-21 17:06:40 +02:00
Uwe Hermann 105df67463 drivers: Factor out std_gvar_array_*(). 2017-07-21 16:54:05 +02:00
Uwe Hermann 7bc3cfe6ff drivers: Factor out std_gvar_min_max_step_thresholds(). 2017-07-21 16:54:05 +02:00
Uwe Hermann bcee129962 scpi-pps: Change some floats to doubles.
This makes the code more consistent with the rest of the code-base
and also allows std_gvar_min_max_step_array() to work here.

Without this change:

  src/hardware/scpi-pps/api.c: In function ‘config_list’:
  src/hardware/scpi-pps/api.c:570:40: warning: passing argument 1 of ‘std_gvar_min_max_step_array’ from incompatible pointer type [-Wincompatible-pointer-types]
      *data = std_gvar_min_max_step_array(ch_spec->voltage);
                                          ^~~~~~~
  In file included from src/scpi.h:30:0,
                   from src/hardware/scpi-pps/api.c:23:
  src/libsigrok-internal.h:964:19: note: expected ‘const double *’ but argument is of type ‘const float *’
   SR_PRIV GVariant *std_gvar_min_max_step_array(const double a[3]);
                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~
  src/hardware/scpi-pps/api.c:573:40: warning: passing argument 1 of ‘std_gvar_min_max_step_array’ from incompatible pointer type [-Wincompatible-pointer-types]
      *data = std_gvar_min_max_step_array(ch_spec->frequency);
                                          ^~~~~~~
  In file included from src/scpi.h:30:0,
                   from src/hardware/scpi-pps/api.c:23:
  src/libsigrok-internal.h:964:19: note: expected ‘const double *’ but argument is of type ‘const float *’
   SR_PRIV GVariant *std_gvar_min_max_step_array(const double a[3]);
                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~
  src/hardware/scpi-pps/api.c:576:40: warning: passing argument 1 of ‘std_gvar_min_max_step_array’ from incompatible pointer type [-Wincompatible-pointer-types]
      *data = std_gvar_min_max_step_array(ch_spec->current);
                                          ^~~~~~~
  In file included from src/scpi.h:30:0,
                   from src/hardware/scpi-pps/api.c:23:
  src/libsigrok-internal.h:964:19: note: expected ‘const double *’ but argument is of type ‘const float *’
   SR_PRIV GVariant *std_gvar_min_max_step_array(const double a[3]);
                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~
2017-07-21 16:49:01 +02:00
Uwe Hermann 54d471f498 drivers: Factor out std_gvar_min_max_step{,_array}(). 2017-07-21 16:49:01 +02:00
Uwe Hermann 463160cbca drivers: Factor out std_gvar_samplerates{,_steps}(). 2017-07-21 16:49:01 +02:00
Uwe Hermann db944f1622 drivers: Factor out std_gvar_tuple_{array,rational}(). 2017-07-21 16:40:15 +02:00
Uwe Hermann 6b82c3e57a drivers: Consistently name per-cg options 'devopts_cg_*'. 2017-07-21 15:45:03 +02:00
Uwe Hermann 4b25cbffa1 drivers: Drop some unnecessary prefixes. 2017-07-21 15:45:03 +02:00
Uwe Hermann ca314e060f drivers: Drop unneeded or duplicate comments.
Drop various comments which are not really needed, too verbose, document
obvious things, are duplicated across all drivers, or simply incorrect.
2017-07-21 15:23:56 +02:00
Uwe Hermann c8e789fa0c baylibre-acme: Add SR_CONF_POWERMETER key. 2017-07-19 15:40:41 +02:00
Uwe Hermann 31bdc10ec2 Add SR_CONF_POWERMETER. 2017-07-19 15:40:41 +02:00
Uwe Hermann b258c09f26 testo: Drop unneeded sdi->driver assignment.
This is already done by std_scan_complete().
2017-07-19 15:39:23 +02:00
Uwe Hermann 05199c0ac9 drivers: Provide proper drvopts.
The device class config keys should be in drvopts (not devopts).
2017-07-19 15:39:23 +02:00
Uwe Hermann 55fb76b348 drivers: Always use same scanopts/drvopts/devopts/devopts_cg* order. 2017-07-19 15:11:01 +02:00
Uwe Hermann e66d1892d0 drivers: Add and use STD_CONFIG_LIST().
This ensures consistent handling of the SR_CONF_SCAN_OPTIONS and
SR_CONF_DEVICE_OPTIONS (with sdi NULL or non-NULL) config keys
and also reduces copy-pasted boilerplate in the drivers a bit.

This function does not handle channel-group specific items, that's
very driver-specific and thus left to the individual drivers.

Also move some generic checks and error messages from the drivers into
the sr_config_list() wrapper.
2017-07-19 15:11:01 +02:00
Uwe Hermann 13d2ac54f4 saleae-logic-pro: Use sr_dev_acquisition_stop() wrapper. 2017-07-17 11:26:12 +02:00
Jan Luebbe f2b8a31be5 saleae-logic-pro: Detect and abort on capture errors
The HW simply stops sending data on overflows, so if we receive no data
in one second, we abort the acquisition. We also need to allocate more
buffers to support higher sample rates.
2017-07-16 19:28:58 +02:00
Jan Luebbe da39089014 saleae-logic-pro: Implement bitstream upload and initialization
The control packets can be longer than 256 bytes, so change the
low-level functions accordingly.
2017-07-16 19:25:46 +02:00
Jan Luebbe f1aca068c7 saleae-logic-pro: Implement FX3 firmware upload 2017-07-16 19:24:27 +02:00
Uwe Hermann a9010323dd drivers: Remove some uneeded 'ret' variables. 2017-07-13 11:59:11 +02:00
Uwe Hermann b4fde527b6 session_driver: Use std_cleanup(). 2017-07-13 11:59:11 +02:00
Uwe Hermann 029b20425b session_driver: Don't open-code std_dev_clear(). 2017-07-13 11:59:11 +02:00
Uwe Hermann 3553451f1e clear_helper(): Use a cast to shorten all implementations. 2017-07-13 11:59:11 +02:00
Uwe Hermann 8bf18daabb sr_dev_clear(): Always free sdi->priv (devc).
Until now, clear_helper() callbacks for std_dev_clear_with_callback()
were expected to g_free(devc), but not all of them did that.

Have std_dev_clear_with_callback() unconditionally g_free(sdi->priv)
(i.e., devc), regardless of whether a clear_helper() callback was
provided or not. It was doing g_free(sdi->priv) when no callback
was provided already anyway.

This makes the individual drivers' clear_helper() implementations
shorter and prevents errors such as missing g_free(devc) calls.

This works, because all drivers either call std_dev_clear_with_callback()
directly, or indirectly via std_dev_clear().

This also allows us to remove some no-longer needed dev_clear()
and clear_helper() implementations that only did g_free(devc)
in favor of std_dev_clear().
2017-07-13 11:59:11 +02:00
Uwe Hermann 53279f13e4 dev_clear(): Consistently name callback 'clear_helper()'. 2017-07-13 11:59:11 +02:00
Uwe Hermann f778bf02ea std: Add and use std_dev_clear() where possible.
Be explicit and consistent in the drivers about which dev_clear function
will be called to avoid confusion and inconsistencies.

Drop some open-coded implementations of std_dev_clear().
2017-07-13 11:59:11 +02:00
Uwe Hermann 6e43c3d531 std: Rename std_dev_clear() to std_dev_clear_with_callback(). 2017-07-13 11:59:11 +02:00
Uwe Hermann 4d67b9d9dc std: Factor out some API call dummy implementations. 2017-07-13 11:59:11 +02:00
Uwe Hermann 91057d2fc2 Various log message cleanups.
Drop unneeded log messages, add some others that might be useful,
document which ones we're intentionally not emitting.

Don't log "$operation successful" type of messages in most cases,
that's too verbose; logging failures only is sufficient there.

baylibre-acme: Don't log "No such file or directory" messages during scan,
this triggers on all kinds of unrelated devices (e.g. "AMDGPU i2c bit
bus 0x91" in this case):

  sr: [...] baylibre-acme: Name for probe 1 can't be read: Failed to open file “/sys/class/i2c-adapter/i2c-1/1-0040/name”: No such file or directory
  sr: [...] baylibre-acme: Name for probe 2 can't be read: Failed to open file “/sys/class/i2c-adapter/i2c-1/1-0041/name”: No such file or directory
  sr: [...] baylibre-acme: Name for probe 3 can't be read: Failed to open file “/sys/class/i2c-adapter/i2c-1/1-0044/name”: No such file or directory
  sr: [...] baylibre-acme: Name for probe 4 can't be read: Failed to open file “/sys/class/i2c-adapter/i2c-1/1-0045/name”: No such file or directory
  sr: [...] baylibre-acme: Name for probe 5 can't be read: Failed to open file “/sys/class/i2c-adapter/i2c-1/1-0042/name”: No such file or directory
  sr: [...] baylibre-acme: Name for probe 5 can't be read: Failed to open file “/sys/class/i2c-adapter/i2c-1/1-004c/name”: No such file or directory
  sr: [...] baylibre-acme: Name for probe 6 can't be read: Failed to open file “/sys/class/i2c-adapter/i2c-1/1-0043/name”: No such file or directory
  sr: [...] baylibre-acme: Name for probe 6 can't be read: Failed to open file “/sys/class/i2c-adapter/i2c-1/1-0049/name”: No such file or directory
  sr: [...] baylibre-acme: Name for probe 7 can't be read: Failed to open file “/sys/class/i2c-adapter/i2c-1/1-0046/name”: No such file or directory
  sr: [...] baylibre-acme: Name for probe 7 can't be read: Failed to open file “/sys/class/i2c-adapter/i2c-1/1-004f/name”: No such file or directory
  sr: [...] baylibre-acme: Name for probe 8 can't be read: Failed to open file “/sys/class/i2c-adapter/i2c-1/1-0047/name”: No such file or directory
  sr: [...] baylibre-acme: Name for probe 8 can't be read: Failed to open file “/sys/class/i2c-adapter/i2c-1/1-004b/name”: No such file or directory
2017-07-13 11:59:11 +02:00
Uwe Hermann 12852b0337 std: Simplifications, random fixes, Doxygen cosmetics.
- sr_dev_clear(): Don't try to clear uninitialized drivers (the same
   check was previously done in std_dev_clear()).

 - Document some places where we intentionally don't emit log messages.

 - std: Various Doxygen fixes and updates.

 - std: Add some more sanity-checks on input parameters.
2017-07-13 11:59:11 +02:00
Uwe Hermann e374786753 session_file: Start out with SR_ST_INACTIVE like all drivers. 2017-07-08 14:25:23 +02:00
Uwe Hermann f1ba6b4b2c sr_dev_close(): Set status to SR_ST_INACTIVE.
This ensures consistent checks and log messages across all drivers
and reduces the per-driver boilerplate.
2017-07-08 14:25:23 +02:00
Uwe Hermann 7e46362338 sr_dev_open(): Set status to SR_ST_ACTIVE upon success.
This ensures consistent checks and log messages across all drivers
and reduces the per-driver boilerplate.
2017-07-08 14:25:23 +02:00
Uwe Hermann 6402c37916 sr_dev_open(): Factor out SR_ST_ACTIVE check.
This ensures consistent checks and log messages across all drivers
and reduces the per-driver boilerplate.
2017-07-08 14:25:23 +02:00
Uwe Hermann 093e1cba6b sr_dev_close(): Factor out SR_ERR_DEV_CLOSED check.
This ensures consistent checks and log messages across all drivers
and reduces the per-driver boilerplate.
2017-07-07 21:51:25 +02:00
Uwe Hermann 89ab9fc39c sr_config_commit(): Factor out SR_ERR_DEV_CLOSED check.
This ensures consistent checks and log messages across all drivers
and reduces the per-driver boilerplate.
2017-07-07 21:51:22 +02:00
Uwe Hermann c3cd66a00c sr_config_set(): Factor out SR_ERR_DEV_CLOSED check.
This ensures consistent checks and log messages across all drivers
and reduces the per-driver boilerplate.
2017-07-07 21:51:19 +02:00
Uwe Hermann f670835f1f Add sr_dev_acquisition_start(), factor out SR_ERR_DEV_CLOSED check.
This ensures consistent checks and log messages across all drivers
and reduces the per-driver boilerplate.
2017-07-07 21:51:16 +02:00
Uwe Hermann d2f7c417fd Add sr_dev_acquisition_stop(), factor out SR_ERR_DEV_CLOSED check.
This ensures consistent checks and log messages across all drivers
and reduces the per-driver boilerplate.
2017-07-07 21:51:10 +02:00
Soeren Apel 6ad2fbaad2 Introduce A2L methods
The memory allocation for sr_datafeed_logic is broken, the memory
will never be freed. #994 is used to handle this issue.
2017-07-06 00:16:24 +02:00
Soeren Apel 895cbcdd3c Bindings: constify data pointer 2017-07-06 00:07:30 +02:00
Roland Hieber 8b9fa09859 gitignore nano and vim swap files
When .*.swp already exists, vim will try .*.swo, then .*.swn, and so
forth. Ignore those files too.

Signed-off-by: Roland Hieber <rohieb@rohieb.name>
2017-07-04 12:18:03 +02:00
Richard f97c159536 serial-dmm: Add support for the SparkFun 70C multimeter. 2017-07-04 12:10:29 +02:00
Richard b0e1a1ecc4 Mark some arrays as const 2017-07-04 12:10:29 +02:00
Uwe Hermann fbbafc6909 saleae-logic-pro: Fix two compiler warnings.
src/hardware/saleae-logic-pro/protocol.c:389:12: warning: 'set_led' defined but not used [-Wunused-function]
   static int set_led(const struct sr_dev_inst *sdi, uint8_t r, uint8_t g, uint8_t b)
              ^
    CC       src/hardware/saleae-logic-pro/api.lo
  src/hardware/saleae-logic-pro/api.c: In function 'dev_acquisition_handle':
  src/hardware/saleae-logic-pro/api.c:332:9: warning: missing initializer for field 'tv_sec' of 'struct timeval' [-Wmissing-field-initializers]
    struct timeval tv = {};
           ^
  In file included from /usr/include/x86_64-linux-gnu/sys/time.h:27:0,
                   from include/libsigrok/libsigrok.h:24,
                   from src/hardware/saleae-logic-pro/protocol.h:25,
                   from src/hardware/saleae-logic-pro/api.c:23:
  /usr/include/x86_64-linux-gnu/bits/time.h:32:14: note: 'tv_sec' declared here
       __time_t tv_sec;  /* Seconds.  */
                ^
2017-07-03 11:57:02 +02:00
Uwe Hermann b605edf38f Revert "C++: Avoid std::map::emplace() for GCC 4.7 compatibility"
This reverts commit 8c52989811.

We now require g++ >= 4.8.1 which supports std::map::emplace(), as does
clang >= 3.3.
2017-07-03 11:20:26 +02:00
Uwe Hermann bb0c52719e saleae-logic-pro: Random minor cosmetics/consistency fixes. 2017-06-28 12:35:05 +02:00
Uwe Hermann b6189f7c8a saleae-logic-pro: Driver name consistency fixes. 2017-06-28 12:35:05 +02:00
Jan Luebbe ca7d19b5c8 saleae-logicpro: Initial implementation.
The driver currently support only digital channels and a limited set of
sample rates.
2017-06-28 12:09:32 +02:00
Jan Luebbe a8e913c452 saleae-logicpro: Initial driver skeleton. 2017-06-28 12:09:32 +02:00
Gerhard Sittig 1f4f98e05c asix-sigma: Only open the USB device once (fails with newer libftdi)
The asix-sigma driver was reported to fail in combination with newer
libftdi versions, because the firmware upload routine opened again an
already opened device, and then failed to claim the interface. Which was
not fatal before with previous libftdi versions.

Remove the redundant open call. Remove the local FTDI context variable,
which brings the firmware upload routine in line with all other calls
that communicate to the USB device.

This fixes bug #471.

Suggested-By: Marian Cingel <cingel.marian@gmail.com>
2017-06-27 13:28:25 +02:00
Gerhard Sittig ac9534f48a asix-sigma: Only change number of channels after successful firmware upload
The asix-sigma driver supports different samplerates, which will involve
different firmware images and will affect the number of available logic
channels as well as their memory layout in downloaded sample data.

Make sure to only store the configuration's parameters after the setup
of that configuration has successfully completed, and make sure to store
a consistent set of parameters. Specifically don't change the number of
channels when the firmware upload failed.

This fixes part of bug #471.

Suggested-By: Marian Cingel <cingel.marian@gmail.com>
2017-06-27 13:28:25 +02:00
Gerhard Sittig 7bcf21683e asix-sigma: Propagate errors from firmware upload
The firmware upload code paths in the asix-sigma driver used to return
either the SR_OK code, or the magic number 0 for error conditions. Which
happens to be identical and cannot be told apart by callers.

Provide proper SR_ERR return codes for error conditions, such that
callers can tell whether the firmware upload succeeded.

This fixes part of bug #471.

Suggested-By: Marian Cingel <cingel.marian@gmail.com>
2017-06-27 13:28:25 +02:00
Gerhard Sittig ad466f86cc strutil: Assume bool is true when no value is specified
Adjust the string to boolean conversion for an edge case. Accept empty
text (either NULL or empty strings) to mean true instead of false.

This behaviour is more useful from the user's point of view, when the
option's name alone will enable a feature, and an explicit "option=yes"
specification is not strictly necessary. All calling applications in
mainline already implemented this semantics.
2017-06-25 20:42:21 +02:00
Gerhard Sittig e7eb29685c C++ binding: Nits, style cleanup (braces, whitespace) 2017-06-25 20:42:21 +02:00
Gerhard Sittig 61a6d983bd C++ binding: Allow to re-use ConfigKey::parse_string() for Option class
Split the data type detection from the actual data type conversion in
the ConfigKey::parse_string() method. Allow the Option class to re-use
the public ConfigKey method, to share the maximum amount of data type
conversion code for both Driver and InputFormat option specs.

This is the least intrusive yet most reliable and consistent approach in
the libsigrok C++ binding that allows applications to support driver scan
and input file format options from command line arguments.
2017-06-25 20:42:21 +02:00
Uwe Hermann 276d7b18bb hung-chang-dso-2100: Fix a gcc 7 compiler warning.
../src/hardware/hung-chang-dso-2100/api.c: In function ‘config_commit’:
  ../src/hardware/hung-chang-dso-2100/api.c:562:9: warning: this statement may fall through [-Wimplicit-fallthrough=]
     state = 0x01;
     ~~~~~~^~~~~~
  ../src/hardware/hung-chang-dso-2100/api.c:563:2: note: here
    default:
    ^~~~~~~
  ../src/hardware/hung-chang-dso-2100/api.c:565:6: warning: this statement may fall through [-Wimplicit-fallthrough=]
     if (ret != SR_OK)
        ^
  ../src/hardware/hung-chang-dso-2100/api.c:567:2: note: here
    case 0x01:
    ^~~~
2017-06-24 18:56:53 +02:00
Uwe Hermann 317c97bebb output/csv: Fix a gcc 7 compiler warning.
../src/output/csv.c: In function ‘receive’:
  ../src/output/csv.c:580:8: warning: this statement may fall through [-Wimplicit-fallthrough=]
     *out = g_string_new(ctx->frame);
     ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~
  ../src/output/csv.c:582:2: note: here
    case SR_DF_END:
    ^~~~
2017-06-24 18:29:26 +02:00
Uwe Hermann 1a14a62349 input/wav: Fix incorrect memset() call.
../src/input/wav.c: In function ‘send_chunk’:
  ../src/input/wav.c:200:2: warning: ‘memset’ used with length equal to number of elements without multiplication by element size [-Wmemset-elt-size]
    memset(fdata, 0, CHUNK_SIZE);
    ^~~~~~
2017-06-24 17:26:02 +02:00
Uwe Hermann 41b8fca1a1 input/raw_analog: Fix gcc 7 compiler warnings.
../src/input/raw_analog.c: In function ‘init’:
  ../src/input/raw_analog.c:133:31: warning: ‘%d’ directive output may be truncated writing between 1 and 10 bytes into a region of size 6 [-Wformat-truncation=]
     snprintf(channelname, 8, "CH%d", i + 1);
                                 ^~
  ../src/input/raw_analog.c:133:28: note: directive argument in the range [1, 2147483647]
     snprintf(channelname, 8, "CH%d", i + 1);
                              ^~~~~~
  ../src/input/raw_analog.c:133:3: note: ‘snprintf’ output between 4 and 13 bytes into a destination of size 8
     snprintf(channelname, 8, "CH%d", i + 1);
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2017-06-24 17:23:56 +02:00
Gerhard Sittig 4a465510fb demo: Mask out logic data for disabled channels in datafeed packets
The previous implementation used to provide datafeed packets which
contain logic data in positions that correspond to disabled channels.

Do mask out logic data of disabled channels in the memory image before
it is sent to the session's datafeed. This implementation works fine for
those situations where either all logic channels are enabled (default
configuration) or when only the upper channels get disabled (which can
be considered a typical use case).

For those configurations where enabled channels follow disabled channels
(i.e. setups with gaps in the sequence of enabled channels) behaviour
will be unexpected: Neither is the mask adjusted to contain gaps, nor
will enabled channels get mapped to result in a dense representation.
The respective code paths are marked with TODO comments.

Add a comment to discuss a non-obvious generator call for analog data in
the acquisition start routine, while we are here.
2017-06-24 16:33:50 +02:00
Gerhard Sittig 1b7b72d49e demo: Skip generating data when all channels in a group are disabled
The generator logic determines how many samples per group (analog and
logic) need to get produced, then keeps iterating until each group has
reached the specified count. Different groups can generate different
numbers of samples per iteration, they have their own stride.

It's essential to check whether all channels in a group are disabled, to
then completely skip the respective half of the generation loop. Without
this check, the group would be expected to generate data but it won't,
which results in an endless loop. This was observed with analog channels.

There was another issue with logic channels. Unexpected logic data was
seen in the output although neither logic channel was selected.

This commit fixes bug #923.
2017-06-23 19:33:24 +02:00
Gerhard Sittig 01f2adb07a demo: Don't generate analog output data for disabled channels
Skip the emission of session datafeed packets for disabled analog
channels.

Implementation detail: Allow for quick lookup of the channel that is
associated with an analog generator, as the data generation routines
only pass generator references in later calls.

This fixes part of bug #923 (which initially is about unexpected
logic data while analog channels were affected in similar ways).
2017-06-23 19:33:24 +02:00
Gerhard Sittig d114464551 demo: Only send average result data when averaging is active
After the requested number of samples was sent, another session df
packet was emitted with one sample for the analog channels, which
contained the most recent result of averaging. Make this emission
depend on the "averaging requested?" flag.

This fixes bug #930.
2017-06-23 19:33:24 +02:00
Gerhard Sittig d91d0b1250 demo: Unbreak execution with all analog channels disabled
The 'demo' driver supports scan options to adjust the number of
supported channels, and runtime control for the enabled state of
channels.

Starting with zero analog channels created (scan option) resulted in a
runtime assertion. Creating but disabling analog channels (GUI checkbox,
CLI option) resulted in unexpected output for disabled channels.

Move the creation of a hash table out of the conditional loop that
iterates over created analog channels. Which results in the table's
always being valid, and iteration during data acquisition yields no
analog output as is expected.

This fixes bug #625.
2017-06-23 19:33:24 +02:00
Gerhard Sittig f1c79a6a35 demo: Drop previous "default enabled" logic (experiment remainder)
A previous implementation of the demo driver supported the creation of
larger channel counts yet only enabling part of them by default. This
was kind of pointless, I just was not aware of the available scan
options.

Drop the "enabled channels" limitation, enable all channels that get
created (like the implementation before the experiment did), and create
as many channels as was compiled in by default or later got specified
by scan options.
2017-06-23 19:33:24 +02:00
Uwe Hermann ecadb11845 dreamsourcelab-dslogic: Drop an assert(). 2017-06-21 18:02:50 +02:00
Uwe Hermann 4984ca28f7 dreamsourcelab-dslogic: Don't check for USB manufacturer/product.
Before firmware upload some models (e.g. the original DSLogic or the
DSLogic Pro) don't have any USB manufacturer or product strings set, so
they wouldn't be detected.
2017-06-21 18:02:50 +02:00
Uwe Hermann 7962b129c3 dreamsourcelab-dslogic: Drop an unneeded dslogic_ prefix. 2017-06-20 23:33:29 +02:00
Uwe Hermann 44b46d7036 dreamsourcelab-dslogic: Naming and other consistency fixes. 2017-06-20 23:33:29 +02:00
Joel Holdsworth f74485b608 dslogic: Recast samples into sigrok-compatible sample words 2017-06-20 00:18:16 +02:00
Joel Holdsworth 03a0002ed4 dslogic: Fixed buffer size calculation 2017-06-20 00:18:16 +02:00
Joel Holdsworth 6dfa2c39bf dslogic: Factored out enabled_channel_count, enabled_channel_mask 2017-06-20 00:18:16 +02:00
Joel Holdsworth 5e23d42f07 dslogic: Don't leak the trigger transfers array 2017-06-20 00:18:16 +02:00
Joel Holdsworth 5e7e327ac8 dslogic: Removed trigger_fired option 2017-06-20 00:18:16 +02:00
Joel Holdsworth 658caaf0d1 dslogic: Merged trigger_request into dslogic_acquisition_start 2017-06-20 00:18:16 +02:00
Joel Holdsworth 4bd770f56b dslogic: Moved all protocol handling to protocol.c
Previously the USB communication code was split between api.ci,
dslogic.c and protocol.c, with protocol internals split between
both. This patch puts all the protocol handling code into one
source file reducing the number of internal interfaces and making
the code more readable.
2017-06-20 00:18:16 +02:00
Joel Holdsworth b0acb693f9 fx2lafw: Moved all protocol handling to protocol.c
Previously the USB communication code was split between api.c
and protocol.c, with protocol internals split between both. This
patch puts all the protocol handling code into one source file
reducing the number of internal interfaces and making the code
more readable.
2017-06-20 00:18:16 +02:00
Joel Holdsworth 2f3cf5c21d dslogic: Fixed FPGA setting code 2017-06-20 00:18:16 +02:00
Joel Holdsworth 731fcfb456 dslogic: Declare memory depths 2017-06-20 00:18:16 +02:00
Joel Holdsworth 1ee7074616 dslogic: Fixed voltage selection 2017-06-20 00:18:16 +02:00
Joel Holdsworth 3c749da174 dslogic: Updated matching of device with loaded firmware 2017-06-20 00:18:16 +02:00
Joel Holdsworth 84f6d40a11 dslogic: Renamed D0-16 channels to 0-16 2017-06-20 00:18:16 +02:00
Joel Holdsworth 780c5e2466 dslogic: Added half and quater-mode flags 2017-06-20 00:18:16 +02:00
Joel Holdsworth 6c317a8d75 dslogic: Simplified supported_device table 2017-06-20 00:18:16 +02:00
Joel Holdsworth 3566348b92 dslogic: Refactored firmware selection into dslogic_fpga_firmware_upload 2017-06-20 00:18:16 +02:00
Joel Holdsworth adcb9951f8 fx2lafw/dslogic: Split DSLogic into a separate driver 2017-06-20 00:18:16 +02:00
Joel Holdsworth 69f7d9b4a9 usb.c: Moved in usb_match_manuf_product 2017-06-20 00:18:16 +02:00
Joel Holdsworth e40ee26b45 fx2lafw/dslogic: Updated dslogic_fpga_config structure to reflect v0.97 firmware 2017-06-20 00:18:16 +02:00
Joel Holdsworth cf398cc058 fx2lafw/dslogic: Imported FPGA config mode flags 2017-06-20 00:18:16 +02:00
Joel Holdsworth cd189a44f8 fx2lafw/dslogic: Use const buffer instead of memset 2017-06-20 00:18:16 +02:00
Joel Holdsworth c2f35321b3 fx2lafw/dslogic: Fixed dslogic_set_vth package structure 2017-06-20 00:18:16 +02:00
Joel Holdsworth ac0facf4e0 fx2lafw/dslogic: Added register address #defines 2017-06-20 00:18:16 +02:00
Joel Holdsworth 9d71f81532 fx2lafw/dslogic: Updated bRequest #defines to reflect libsigrok4DSL 2017-06-20 00:18:16 +02:00
Joel Holdsworth 9082b5ccf7 fx2lafw: Call dslogic_get_number_of_transfers into fx2lafw_get_number_of_transfers 2017-06-20 00:18:16 +02:00
Joel Holdsworth c33f32a922 fx2lafw/dslogic: Added DSLogic Plus and Basic variants 2017-06-20 00:18:16 +02:00
Uwe Hermann a7600dc5c7 Makefile.am: Install MIME info file in $(datadir)/mime/packages.
This fixes bug #983.
2017-06-15 18:46:14 +02:00
378 changed files with 73398 additions and 18062 deletions

3
.gitignore vendored
View File

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

708
Doxyfile

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

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

View File

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

2
NEWS
View File

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

10
README
View File

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

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -45,6 +45,8 @@ which provides access to the error code and description."
%module(docstring=DOCSTRING) classes %module(docstring=DOCSTRING) classes
%{ %{
#include "config.h"
#include <stdio.h> #include <stdio.h>
#include <pygobject.h> #include <pygobject.h>
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
@ -53,8 +55,6 @@ which provides access to the error code and description."
PyObject *PyGObject_lib; PyObject *PyGObject_lib;
PyObject *GLib; PyObject *GLib;
#include "config.h"
#if PYGOBJECT_FLAGS_SIGNED #if PYGOBJECT_FLAGS_SIGNED
typedef gint pyg_flags_type; typedef gint pyg_flags_type;
#else #else
@ -112,6 +112,9 @@ typedef guint pyg_flags_type;
g_free(value); g_free(value);
} }
/* Use the same typemap above for Glib::VariantContainerBase */
%apply Glib::VariantBase { Glib::VariantContainerBase }
/* Map from callable PyObject to LogCallbackFunction */ /* Map from callable PyObject to LogCallbackFunction */
%typecheck(SWIG_TYPECHECK_POINTER) sigrok::LogCallbackFunction { %typecheck(SWIG_TYPECHECK_POINTER) sigrok::LogCallbackFunction {
$1 = PyCallable_Check($input); $1 = PyCallable_Check($input);
@ -337,7 +340,14 @@ Glib::VariantBase python_to_variant_by_key(PyObject *input, const sigrok::Config
return Glib::Variant<double>::create(PyFloat_AsDouble(input)); return Glib::Variant<double>::create(PyFloat_AsDouble(input));
else if (type == SR_T_INT32 && PyInt_Check(input)) else if (type == SR_T_INT32 && PyInt_Check(input))
return Glib::Variant<gint32>::create(PyInt_AsLong(input)); return Glib::Variant<gint32>::create(PyInt_AsLong(input));
else else if ((type == SR_T_RATIONAL_VOLT) && PyTuple_Check(input) && (PyTuple_Size(input) == 2)) {
PyObject *numObj = PyTuple_GetItem(input, 0);
PyObject *denomObj = PyTuple_GetItem(input, 1);
if ((PyInt_Check(numObj) || PyLong_Check(numObj)) && (PyInt_Check(denomObj) || PyLong_Check(denomObj))) {
const std::vector<guint64> v = {(guint64)PyInt_AsLong(numObj), (guint64)PyInt_AsLong(denomObj)};
return Glib::Variant< std::vector<guint64> >::create(v);
}
}
throw sigrok::Error(SR_ERR_ARG); throw sigrok::Error(SR_ERR_ARG);
} }
@ -390,6 +400,7 @@ std::map<std::string, Glib::VariantBase> dict_to_map_options(PyObject *dict,
/* Ignore these methods, we will override them below. */ /* Ignore these methods, we will override them below. */
%ignore sigrok::Analog::data; %ignore sigrok::Analog::data;
%ignore sigrok::Logic::data;
%ignore sigrok::Driver::scan; %ignore sigrok::Driver::scan;
%ignore sigrok::InputFormat::create_input; %ignore sigrok::InputFormat::create_input;
%ignore sigrok::OutputFormat::create_output; %ignore sigrok::OutputFormat::create_output;
@ -548,4 +559,42 @@ std::map<std::string, Glib::VariantBase> dict_to_map_options(PyObject *dict,
} }
} }
/* Return NumPy array from Logic::data(). */
%extend sigrok::Logic
{
PyObject * _data()
{
npy_intp dims[2];
dims[0] = $self->data_length() / $self->unit_size();
dims[1] = $self->unit_size();
int typenum = NPY_UINT8;
void *data = $self->data_pointer();
return PyArray_SimpleNewFromData(2, dims, typenum, data);
}
%pythoncode
{
data = property(_data)
}
}
/* Create logic packet from Python buffer. */
%extend sigrok::Context
{
std::shared_ptr<Packet> _create_logic_packet_buf(PyObject *buf, unsigned int unit_size)
{
Py_buffer view;
PyObject_GetBuffer(buf, &view, PyBUF_SIMPLE);
return $self->create_logic_packet(view.buf, view.len, unit_size);
}
}
%pythoncode
{
def _Context_create_logic_packet(self, buf, unit_size):
return self._create_logic_packet_buf(buf, unit_size)
Context.create_logic_packet = _Context_create_logic_packet
}
%include "doc_end.i" %include "doc_end.i"

View File

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

View File

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

View File

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

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

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

105
src/binary_helpers.c Normal file
View File

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

1099
src/bt/bt_bluez.c Normal file

File diff suppressed because it is too large Load Diff

109
src/conversion.c Normal file
View File

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

View File

@ -1,7 +1,7 @@
/* /*
* This file is part of the libsigrok project. * This file is part of the libsigrok project.
* *
* Copyright (C) 2012 Bert Vermeulen <bert@biot.com> * Copyright (C) 2015 Aurelien Jacobs <aurel@gnuage.org>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -17,22 +17,27 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef LIBSIGROK_HARDWARE_VICTOR_DMM_PROTOCOL_H #include <config.h>
#define LIBSIGROK_HARDWARE_VICTOR_DMM_PROTOCOL_H
#include <stdint.h> #include <stdint.h>
#include <libsigrok/libsigrok.h> #include <libsigrok/libsigrok.h>
#include "libsigrok-internal.h" #include "libsigrok-internal.h"
#define LOG_PREFIX "victor-dmm" SR_PRIV uint16_t sr_crc16(uint16_t crc, const uint8_t *buffer, int len)
{
int i;
#define DMM_DATA_SIZE 14 if (!buffer || len < 0)
return crc;
/** Private, per-device-instance driver context. */ while (len--) {
struct dev_context { crc ^= *buffer++;
struct sr_sw_limits limits; for (i = 0; i < 8; i++) {
}; int carry = crc & 1;
crc >>= 1;
if (carry)
crc ^= 0xA001;
}
}
SR_PRIV int victor_dmm_receive_data(struct sr_dev_inst *sdi, unsigned char *buf); return crc;
}
#endif

View File

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

View File

@ -379,7 +379,7 @@ static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
if (info->is_dc) if (info->is_dc)
analog->meaning->mqflags |= SR_MQFLAG_DC; analog->meaning->mqflags |= SR_MQFLAG_DC;
if (info->is_diode) if (info->is_diode)
analog->meaning->mqflags |= SR_MQFLAG_DIODE; analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
if (info->is_peak_max) if (info->is_peak_max)
analog->meaning->mqflags |= SR_MQFLAG_MAX; analog->meaning->mqflags |= SR_MQFLAG_MAX;
if (info->is_peak_min) if (info->is_peak_min)
@ -446,7 +446,7 @@ static gboolean flags_valid(const struct asycii_info *info)
return TRUE; return TRUE;
} }
#ifdef HAVE_LIBSERIALPORT #ifdef HAVE_SERIAL_COMM
/** /**
* Arrange for the reception of another measurement from the DMM. * Arrange for the reception of another measurement from the DMM.
* *
@ -455,8 +455,6 @@ static gboolean flags_valid(const struct asycii_info *info)
* without the PC's intervention. * without the PC's intervention.
* *
* @param[in] serial The serial connection. * @param[in] serial The serial connection.
*
* @private
*/ */
SR_PRIV int sr_asycii_packet_request(struct sr_serial_dev_inst *serial) SR_PRIV int sr_asycii_packet_request(struct sr_serial_dev_inst *serial)
{ {
@ -519,7 +517,7 @@ SR_PRIV int sr_asycii_parse(const uint8_t *buf, float *floatval,
int ret, exponent; int ret, exponent;
struct asycii_info *info_local; struct asycii_info *info_local;
info_local = (struct asycii_info *)info; info_local = info;
/* Don't print byte 15. That one contains the carriage return. */ /* Don't print byte 15. That one contains the carriage return. */
sr_dbg("DMM packet: \"%.15s\"", buf); sr_dbg("DMM packet: \"%.15s\"", buf);

View File

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

1577
src/dmm/bm52x.c Normal file

File diff suppressed because it is too large Load Diff

457
src/dmm/bm85x.c Normal file
View File

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

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

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

View File

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

1353
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) if (info->is_auto)
analog->meaning->mqflags |= SR_MQFLAG_AUTORANGE; analog->meaning->mqflags |= SR_MQFLAG_AUTORANGE;
if (info->is_diode) if (info->is_diode)
analog->meaning->mqflags |= SR_MQFLAG_DIODE; analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
if (info->is_hold) if (info->is_hold)
/* /*
* Note: HOLD only affects the number displayed on the LCD, * Note: HOLD only affects the number displayed on the LCD,

View File

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

View File

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

View File

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

View File

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

457
src/dmm/mm38xr.c Normal file
View File

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

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

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

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

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

View File

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

View File

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

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

34
src/driver_list_start.c Normal file
View File

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

34
src/driver_list_stop.c Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,197 +0,0 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include "protocol.h"
static const uint32_t scanopts[] = {
SR_CONF_CONN,
SR_CONF_SERIALCOMM,
};
static const uint32_t devopts[] = {
SR_CONF_MULTIMETER,
SR_CONF_CONTINUOUS,
SR_CONF_LIMIT_SAMPLES | SR_CONF_SET,
SR_CONF_LIMIT_MSEC | SR_CONF_SET,
};
static GSList *brymen_scan(struct sr_dev_driver *di, const char *conn,
const char *serialcomm)
{
struct sr_dev_inst *sdi;
struct dev_context *devc;
struct sr_serial_dev_inst *serial;
GSList *devices;
int ret;
uint8_t buf[128];
size_t len;
serial = sr_serial_dev_inst_new(conn, serialcomm);
if (serial_open(serial, SERIAL_RDWR) != SR_OK)
return NULL;
sr_info("Probing port %s.", conn);
devices = NULL;
/* Request reading */
if ((ret = brymen_packet_request(serial)) < 0) {
sr_err("Unable to send command: %d.", ret);
goto scan_cleanup;
}
len = 128;
ret = brymen_stream_detect(serial, buf, &len, brymen_packet_length,
brymen_packet_is_valid, 1000, 9600);
if (ret != SR_OK)
goto scan_cleanup;
sr_info("Found device on port %s.", conn);
sdi = g_malloc0(sizeof(struct sr_dev_inst));
sdi->status = SR_ST_INACTIVE;
sdi->vendor = g_strdup("Brymen");
sdi->model = g_strdup("BM85x");
devc = g_malloc0(sizeof(struct dev_context));
sr_sw_limits_init(&devc->sw_limits);
sdi->inst_type = SR_INST_SERIAL;
sdi->conn = serial;
sdi->priv = devc;
sr_channel_new(sdi, 0, SR_CHANNEL_ANALOG, TRUE, "P1");
devices = g_slist_append(devices, sdi);
scan_cleanup:
serial_close(serial);
return std_scan_complete(di, devices);
}
static GSList *scan(struct sr_dev_driver *di, GSList *options)
{
struct sr_config *src;
GSList *devices, *l;
const char *conn, *serialcomm;
devices = NULL;
conn = serialcomm = NULL;
for (l = options; l; l = l->next) {
src = l->data;
switch (src->key) {
case SR_CONF_CONN:
conn = g_variant_get_string(src->data, NULL);
break;
case SR_CONF_SERIALCOMM:
serialcomm = g_variant_get_string(src->data, NULL);
break;
}
}
if (!conn)
return NULL;
if (serialcomm) {
/* Use the provided comm specs. */
devices = brymen_scan(di, conn, serialcomm);
} else {
/* But 9600/8n1 should work all of the time. */
devices = brymen_scan(di, conn, "9600/8n1/dtr=1/rts=1");
}
return devices;
}
static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
{
struct dev_context *devc;
(void)cg;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv;
return sr_sw_limits_config_set(&devc->sw_limits, key, data);
}
static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg)
{
(void)sdi;
(void)cg;
switch (key) {
case SR_CONF_SCAN_OPTIONS:
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
break;
case SR_CONF_DEVICE_OPTIONS:
*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
break;
default:
return SR_ERR_NA;
}
return SR_OK;
}
static int dev_acquisition_start(const struct sr_dev_inst *sdi)
{
struct dev_context *devc;
struct sr_serial_dev_inst *serial;
if (sdi->status != SR_ST_ACTIVE)
return SR_ERR_DEV_CLOSED;
devc = sdi->priv;
sr_sw_limits_acquisition_start(&devc->sw_limits);
std_session_send_df_header(sdi);
/* Poll every 50ms, or whenever some data comes in. */
serial = sdi->conn;
serial_source_add(sdi->session, serial, G_IO_IN, 50,
brymen_dmm_receive_data, (void *)sdi);
return SR_OK;
}
static struct sr_dev_driver brymen_bm857_driver_info = {
.name = "brymen-bm857",
.longname = "Brymen BM857",
.api_version = 1,
.init = std_init,
.cleanup = std_cleanup,
.scan = scan,
.dev_list = std_dev_list,
.dev_clear = NULL,
.config_get = NULL,
.config_set = config_set,
.config_list = config_list,
.dev_open = std_serial_dev_open,
.dev_close = std_serial_dev_close,
.dev_acquisition_start = dev_acquisition_start,
.dev_acquisition_stop = std_serial_dev_acquisition_stop,
.context = NULL,
};
SR_REGISTER_DEV_DRIVER(brymen_bm857_driver_info);

View File

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

View File

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

View File

@ -1,75 +0,0 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBSIGROK_HARDWARE_BRYMEN_DMM_PROTOCOL_H
#define LIBSIGROK_HARDWARE_BRYMEN_DMM_PROTOCOL_H
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <glib.h>
#include <libsigrok/libsigrok.h>
#include "libsigrok-internal.h"
#define LOG_PREFIX "brymen-dmm"
#define DMM_BUFSIZE 256
enum packet_len_status {
PACKET_HEADER_OK,
PACKET_NEED_MORE_DATA,
PACKET_INVALID_HEADER,
};
/** Private, per-device-instance driver context. */
struct dev_context {
struct sr_sw_limits sw_limits;
uint8_t buf[DMM_BUFSIZE];
int bufoffset;
int buflen;
int next_packet_len;
};
/**
* Callback that assesses the size and status of the incoming packet.
*
* @return PACKET_HEADER_OK - This is a proper packet header.
* PACKET_NEED_MORE_DATA The buffer does not contain the entire header.
* PACKET_INVALID_HEADER Not a valid start of packet.
*/
typedef int (*packet_length_t)(const uint8_t *buf, int *len);
SR_PRIV int brymen_dmm_receive_data(int fd, int revents, void *cb_data);
SR_PRIV int brymen_packet_request(struct sr_serial_dev_inst *serial);
SR_PRIV int brymen_packet_length(const uint8_t *buf, int *len);
SR_PRIV gboolean brymen_packet_is_valid(const uint8_t *buf);
SR_PRIV int brymen_parse(const uint8_t *buf, float *floatval,
struct sr_datafeed_analog *analog, void *info);
SR_PRIV int brymen_stream_detect(struct sr_serial_dev_inst *serial,
uint8_t *buf, size_t *buflen,
packet_length_t get_packet_size,
packet_valid_callback is_valid,
uint64_t timeout_ms, int baudrate);
#endif

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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