https://wiki.octave.org/wiki/api.php?action=feedcontributions&user=84.181.17.245&feedformat=atomOctave - User contributions [en]2024-03-29T11:19:02ZUser contributionsMediaWiki 1.39.2https://wiki.octave.org/wiki/index.php?title=Instrument_control_package&diff=6562Instrument control package2015-08-30T06:38:56Z<p>84.181.17.245: /* Serial */</p>
<hr />
<div>Instrument-Control is a package for interfacing the outside world of hardware via Serial, i2c or Parallel interfaces. It is currently under development by Andrius Sutas and Stefan Mahr, you can browse the [https://sourceforge.net/p/octave/instrument-control/ci/default/tree/ mercurial repository here] and download the package [http://octave.sourceforge.net/instrument-control/index.html here].<br />
<br />
= Compatibility =<br />
<br />
Below is a table showing package compatibility with various platforms:<br />
<br />
{| class="wikitable" style="text-align:center"<br />
|-<br />
! !! Linux !! Windows (Cygwin) !! Windows (native) !! FreeBSD !! Mac OS X <br />
|-<br />
! Serial<br />
| bgcolor="green" | v0.1.0 || bgcolor="green" | v0.2.0 || bgcolor="green" | v0.2.1 || bgcolor="skyblue" | stalled || bgcolor="yellow" | WIP<br />
|-<br />
! Parallel<br />
| bgcolor="green" | v0.1.0 || - || - || bgcolor="skyblue" | stalled || -<br />
|-<br />
! i2c<br />
| bgcolor="green" | v0.1.0 || - || - || bgcolor="skyblue" | stalled || - <br />
|-<br />
! TCP<br />
| bgcolor="green" | v0.2.0 || bgcolor="green" | v0.2.0 || bgcolor="green" | v0.2.0 || bgcolor="skyblue" | stalled || bgcolor="yellow" | WIP<br />
|-<br />
! USBTMC<br />
| bgcolor="green" | v0.2.0 || - || - || - || - <br />
|-<br />
! GPIB<br />
| bgcolor="green" | v0.2.0 [[#Linux|(*)]] || - || - ||- || - <br />
|-<br />
! VXI11<br />
| bgcolor="green" | v0.2.0|| bgcolor="green" | v0.2.0 [[#Windows_.28cygwin.29|(*)]] || - || - || bgcolor="yellow" | WIP [[#MacOS|(*)]]<br />
|}<br />
<br />
Where: <span style="background:green">(VER)</span> - Included since VER version; <span style="background:yellow">(WIP)</span> - Work In Progress and will probably be included in next release; <span style="background:skyblue">(stalled)</span> - Some work has been done, but it's not tested and no one is actively contributing; (-) - Not supported / Untested.<br />
<br />
You might see errors while doing "pkg install", which mean that package is unable to support related interface on your platform (e.g. due to missing header files), therefore one should <b>always</b> check for the supported interfaces before trying to use them:<br />
<br />
{{Code|Check for interface support|<syntaxhighlight lang="octave" style="font-size:13px"><br />
pkg load instrument-control<br />
<br />
if (exist("serial") == 3)<br />
disp("Serial: Supported")<br />
else<br />
disp("Serial: Unsupported")<br />
endif<br />
<br />
#similarly with:<br />
#exist("parallel") == 3<br />
#exist("i2c") == 3<br />
</syntaxhighlight>}}<br />
<br />
= Requirements =<br />
== Linux ==<br />
<br />
For GPIB support, please install [http://linux-gpib.sourceforge.net linux-gpib] before installing instrument-control.<br />
<br />
== Windows (cygwin) ==<br />
<br />
For VXI11 support, please install 'rpcgen', 'libtirpc-devel', and 'libtirpc1' before installing instrument-control.<br />
<br />
== MacOS ==<br />
<br />
You need to build rpcgen from source [http://mirror.ancl.hawaii.edu/pub/FreeBSD/FreeBSD-current/src/usr.bin/rpcgen].<br />
<br />
= Examples =<br />
== Serial ==<br />
=== Configuring interface ===<br />
You might want to configure interface in a loopback mode for testing.<br />
* If you have a Serial adapter, then simply connect pins 3 (Tx) and 2 (Rx) together (assuming your adapter is [http://en.wikipedia.org/wiki/File:DE9_D-subminiature_RS-232_pinout.png RS-232 DE9], otherwise check before doing anything). One can also insert an LED in series to view the actual bitstream.<br />
* If you do not have a Serial adapter then create a virtual port using:<br />
<pre><br />
$ socat PTY,link=/dev/ttyS15 PTY,link=/dev/ttyS16<br />
</pre><br />
<br />
which will open two interconnected interfaces, where one (e.g. /dev/ttyS15) can be opened in Octave and second (e.g. /dev/ttyS16) using something like GNU screen:<br />
<pre><br />
$ screen /dev/ttyS16 <baudrate><br />
</pre><br />
<br />
do not forget to change interface permissions if you want to use them with Octave/screen without root privileges.<br />
<br />
=== Example: basic use ===<br />
Here is a simple example to get started with the serial package. It tests the RxD and TxD lines. Make sure you have defined a loopback or connected the pins of your adapter.<br />
{{Code|Serial port example|<syntaxhighlight lang="octave" style="font-size:13px"><br />
# Opens serial port ttyUSB1 with baudrate of 115200 (config defaults to 8-N-1)<br />
s1 = serial("/dev/ttyUSB1", 115200) <br />
# Flush input and output buffers<br />
srl_flush(s1); <br />
# Blocking write call, currently only accepts strings<br />
srl_write(s1, "Hello world!") <br />
# Blocking read call, returns uint8 array of exactly 12 bytes read<br />
data = srl_read(s1, 12) <br />
# Convert uint8 array to string, <br />
char(data) <br />
</syntaxhighlight><br />
}}<br />
<br />
Chaging some configurations is simple done by calling helper functions<br />
{{Code|Serial port example: helper functions|<syntaxhighlight lang="octave" style="font-size:13px"><br />
set(s1, "baudrate", 9600) # Change baudrate<br />
set(s1, "bytesize", 5) # Change byte size (config becomes 5-N-1)<br />
set(s1, "parity", "E") # Changes parity checking (config becomes 5-E-1),<br />
# possible values [E]ven, [O]dd, [N]one.<br />
set(s1, "stopbits", 2) # Changes stop bits (config becomes 5-E-2), possible<br />
# values 1, 2.<br />
</syntaxhighlight><br />
}}<br />
Some properties can be set at opening time<br />
{{Code|Serial port example: constructor call|<syntaxhighlight lang="octave" style="font-size:13px"><br />
s2 = serial("/dev/ttyS0", 9600, 10) # Opens serial port ttyS0 in<br />
# 9600 baudrate with 1s read timeout<br />
</syntaxhighlight><br />
}}<br />
<br />
Do not forget to close the ports when you are done!<br />
{{Code||<syntaxhighlight lang="octave" style="font-size:13px"><br />
fclose(s1) # Closes and releases serial interface object<br />
fclose(s2) # Closes and releases serial interface object<br />
</syntaxhighlight><br />
}}<br />
<br />
=== Example: Windows, serial port >COM9 ===<br />
Opening a serial port higher than COM9 requires special syntax. [https://support.microsoft.com/en-us/kb/115831]<br />
{{Code|open Windows higher serial port example|<syntaxhighlight lang="octave" style="font-size:13px"><br />
# Opens serial port COM10<br />
s1 = serial("\\\\.\\COM10");<br />
</syntaxhighlight><br />
}}<br />
<br />
== Parallel ==<br />
=== Configuring interface ===<br />
You will need to load following modules:<br />
<pre><br />
# modprobe parport<br />
# modprobe ppdev<br />
</pre><br />
<br />
Now you should see devices like "/dev/parport0". In case you do not, you will need to create them manually and give sufficient privileges for your user:<br />
<br />
<pre><br />
# mknod /dev/parport0 c 99 0 -m 666<br />
</pre><br />
<br />
=== Example 1: LED trace ===<br />
For this example you will need to connect 8 LEDs to Parallel interface Data port as shown below:<br />
<br />
[[File:parport_schematic.png|300px|text-bottom]]<br />
<br />
And then the actual script:<br />
{{Code|trace.m|<syntaxhighlight lang="octave" style="font-size:13px"><br />
delay = 0.1;<br />
<br />
pp = parallel("/dev/parport0", 0);<br />
pp_data(pp, 0);<br />
<br />
pins = pow2([0, 1, 2, 3, 4, 5, 6, 7]);<br />
<br />
while 1<br />
for p = pins<br />
pp_data(pp, p);<br />
sleep(delay);<br />
endfor <br />
<br />
# Reverse the order<br />
pins = pins(end:-1:1);<br />
endwhile<br />
<br />
pp_close(pp);<br />
</syntaxhighlight>}}<br />
<br />
Run it and you should see LEDs "tracing" forwards and backwards.<br />
<br />
<br />
=== Example 2: LED dimming a.k.a. PWM control ===<br />
Use the same schematic as in Example 1.<br />
<br />
{{Code|dim.m|<syntaxhighlight lang="octave" style="font-size:13px"><br />
delay = 0.00005;<br />
<br />
pp = parallel("/dev/parport0", 0);<br />
pp_data(pp, 0);<br />
<br />
dRange = 0:100;<br />
while 1<br />
for duty = dRange<br />
pp_data(pp, 255); <br />
<br />
for dOn = 0:duty<br />
sleep(delay);<br />
endfor <br />
<br />
pp_data(pp, 0);<br />
<br />
for dOff = 0:(100-duty)<br />
sleep(delay);<br />
endfor<br />
endfor<br />
<br />
# Reverse order<br />
dRange = dRange(end:-1:1);<br />
endwhile<br />
<br />
pp_close(pp);<br />
</syntaxhighlight>}}<br />
<br />
Run it and you should see LEDs changing brightness from lowest to maximum.<br />
<br />
<br />
=== Example 3: Logic analyzer ===<br />
We can surely make something more interesting, right? Enter basic logic analyzer.<br />
<br />
Assume you are working with [[http://datasheets.maximintegrated.com/en/ds/MAX31855.pdf this]] temperature sensor. Something is not right. You do not have one of those expensive logic analyzers, but you do have a Parallel port! You remember that someone made a package for interfacing it with GNU Octave. So you connect your probes to appropriate Data port terminals and change settings accordingly. In this example: <br />
{| class="wikitable"<br />
|-<br />
! Probe !! Port terminal<br />
|-<br />
| !CS || DATA0<br />
|-<br />
| SCK || DATA1<br />
|-<br />
| SO || DATA2<br />
|}<br />
NB: Parallel ports usually have weak pull-ups to +5V even when in "input" mode, so do not do this if unsure.<br />
One could potentially use different terminals in Control/Status ports to get true high-impedance inputs.<br />
<br />
And write a simple script below:<br />
<br />
{{Code|logic_analyzer.m|<syntaxhighlight lang="octave" style="font-size:13px"><br />
#####################################################################<br />
# Settings<br />
#####################################################################<br />
<br />
# Channels to capture<br />
#channels = [0, 1, 2, 3, 4, 5, 6, 7];<br />
channels = [2, 1, 0];<br />
<br />
# Channel labels<br />
#channel = {"CH0"; "CH1"; "CH2"; "CH3"; "CH4"; "CH5"; "CH6"; "CH7"};<br />
channel = {"SO"; "SCK"; "!CS"};<br />
<br />
# Trigger channel<br />
triggerCh = 0;<br />
<br />
# When to trigger<br />
trigger = 0; # Capture on low. For high - 1<br />
<br />
#####################################################################<br />
<br />
samplesTime = [];<br />
samplesValue = [];<br />
<br />
#pp_close(pp);<br />
pp = parallel("/dev/parport0", 1);<br />
<br />
printf("Waiting for trigger...\n");<br />
fflush(stdout);<br />
<br />
data = pp_data(pp);<br />
while (bitget(data, triggerCh + 1) != trigger)<br />
oldData = data;<br />
data = pp_data(pp);<br />
endwhile<br />
<br />
printf("Capturing...\n");<br />
fflush(stdout);<br />
<br />
startTime = time();<br />
samplesTime(end + 1) = 0;<br />
samplesValue(end + 1) = oldData;<br />
<br />
while (bitget(data, triggerCh + 1) == trigger)<br />
data = pp_data(pp);<br />
samplesTime(end + 1) = time() - startTime;<br />
samplesValue(end + 1) = data;<br />
endwhile<br />
<br />
# Statistics<br />
printf("Average sample rate: %f kHz\n", size(samplesValue)(2) / samplesTime(end) / 1000.0);<br />
<br />
pp_close(pp);<br />
<br />
# Plotting<br />
<br />
figure;<br />
for p = 1:size(channels)(2)<br />
subplot (size(channels)(2), 1, p)<br />
plot(samplesTime, bitget(samplesValue, channels(p) + 1))<br />
<br />
ylabel(channel{p});<br />
axis([-0.01, samplesTime(end)+ 0.01, -1, 2], "manual");<br />
set(gca(), 'ytick', -1:2);<br />
set(gca(), 'yticklabel', {''; '0'; '1'; ''});<br />
endfor<br />
xlabel ("t");<br />
</syntaxhighlight>}}<br />
<br />
If connections and settings are correct you should see something like this:<br />
<br />
[[File:logic_analyzer.png|600px|text-bottom]]<br />
<br />
Now you can fully debug what is going with your hardware from comfort of GNU Octave.<br />
<br />
== i2c ==<br />
i2c<br />
<br />
== TCP ==<br />
=== Example: basic use ===<br />
For testing you could start a tcp listener<br />
<pre><br />
$ socat TCP-LISTEN:8000 -<br />
</pre><br />
<br />
Now you can connect your listener.<br />
<br />
{{Code|TCP example|<syntaxhighlight lang="octave" style="font-size:13px"><br />
# Open TCP connection to 127.0.0.1:8000<br />
t0 = tcp("127.0.0.1",8000)<br />
# write to listener<br />
tcp_write(t0, "Hello world!") <br />
# Blocking read call, returns uint8 array of exactly 12 bytes read<br />
data = tcp_read(t0, 12) <br />
# Convert uint8 array to string, <br />
char(data) <br />
</syntaxhighlight><br />
}}<br />
There are several ways to set timeout of read call.<br />
{{Code|set TCP timeout|<syntaxhighlight lang="octave" style="font-size:13px"><br />
# Open TCP connection to 127.0.0.1:8000 with timeout of 100 ms<br />
t0 = tcp("127.0.0.1",8000,100)<br />
# set timeout to blocking<br />
tcp_timeout(t0, -1) <br />
# the timeout can be overwritten for single read call, in this case 1000ms<br />
data = tcp_read(t0, 12, 1000) <br />
# close tcp session<br />
tcp_close(t0)<br />
</syntaxhighlight><br />
}}<br />
<br />
== USBTMC ==<br />
=== Configuring interface ===<br />
Recent linux kernels support USBTMC out of the box. Connect your instrument and check if /dev/usbtmc* exists. Set appropriate permissions to /dev/usbtmc*<br />
=== Example: basic use ===<br />
{{Code|USBTMC example|<syntaxhighlight lang="octave" style="font-size:13px"><br />
# Open interface to USB instrument<br />
t0 = usbtmc('/dev/usbtmc0')<br />
# write to listener<br />
usbtmc_write(t0, '*IDN?') <br />
# Blocking read call, returns uint8 array<br />
data = usbtmc_read(t0, 10000) <br />
# Convert uint8 array to string, <br />
char(data) <br />
# close usbtmc session<br />
usbtmc_close(t0)<br />
</syntaxhighlight><br />
}}<br />
<br />
== VXI11 ==<br />
=== Example: basic use ===<br />
{{Code|VXI11 example|<syntaxhighlight lang="octave" style="font-size:13px"><br />
# Open VXI11 connection to 192.168.100.100<br />
t0 = vxi11('192.168.100.100')<br />
# write to listener<br />
vxi11_write(t0, '*IDN?') <br />
# read from instrument, returns uint8 array<br />
data = vxi11_read(t0, 10000) <br />
# Convert uint8 array to string, <br />
char(data) <br />
# close usbtmc session<br />
vxi11_close(t0)<br />
</syntaxhighlight><br />
}}<br />
=== Limitations ===<br />
For now,<br />
* it's not possible to connect more than one instrument per IP address (e.g. VXI11-GPIB gateways)<br />
* only instrument ''inst0'' can be connected<br />
* setting timeout is not implemented (defaults: 10 seconds global timeout, 2 seconds read timeout)<br />
<br />
== GPIB ==<br />
=== Configuring interface ===<br />
For using GPIB you need to install and configure the linux-gpib kernel modules and libraries.<br />
=== Example: basic use ===<br />
{{Code|GPIB example|<syntaxhighlight lang="octave" style="font-size:13px"><br />
# Open GPIB instrument with ID 7 and set timeout to 1 second (see ibtmo / NI-488.2 Function Reference)<br />
t0 = gpib(7,11)<br />
# write to listener<br />
gpib_write(t0, '*IDN?') <br />
# read from instrument, returns uint8 array<br />
data = gpib_read(t0, 10000)<br />
# Convert uint8 array to string, <br />
char(data) <br />
# close usbtmc session<br />
gpib_close(t0)<br />
</syntaxhighlight><br />
}}<br />
=== Limitations ===<br />
* Setting minor, sad, send_eoi and eos_mode is not implemented yet.<br />
* Every read or write command opens and closes a new gpib session, since the linux-gpib session pointer is only valid for single command.<br />
<br />
[[Category:Octave-Forge]]</div>84.181.17.245