Tutorial
This is a quick tutorial on using the Python extensions in DevWare. If you are familiar with DevWare ini file commands see also the Ini File Equivalents chapter below.
Python Console Window
DevWare has a simple Python console window. Select the menu item View?Python Console to show the window.
All output directed to stdout or stderr (print() calls and error messages) goes to the top part of the window. In the bottom portion of the window you can type any command or expression for immediate execution.
The Python input() function (sys.stdin.readline()) causes a small pop-up dialog to appear where the user can enter the requested data.
Python in Ini Files
You can put Python code in an ini file, and use the Presets dialog or User Toolbar to execute it.
There are two ways embed Python in ini files. To execute single Python lines mixed with other ini file commands use a PYTHON= command.
[my preset]
REG= 0x3012, 0
PYTHON= print('set 0x3012 to 0')
Output from Python commands shows up in the Python Console window.
To execute a block of Python code of any size, create a preset with only Python in it. So the ini file interpreter knows to expect Python syntax instead of ini syntax you must have the string 'Python:' somewhere in the name of the preset.
[Python: clear some regs]
for addr in range(0x3600, 0x3800, 2):
reg.reg(addr).value = 0
Python code executes in the context of the _main_ module. DevWare automatically does an import sys, import midlib and import devware, and adds the directory of the ini file to sys.path. It creates a variable called reg that gives convenient access to sensor registers (more on this shortly), and a variable called demo2 (if you are running on a DEMO2 or DEMO2X) or mides (if you are using a MIDES board) for camera board FPGA registers. You can easily create these variables in your own modules too.
If there is a preset called only [Python:], DevWare will automatically execute it when it loads the ini file. This gives you a convenient place to put additional import statements, function definitions, or any other one-time-execute code. Example:
[Python:]
import os.path
import re
def image_size_a(w, h):
reg.PRI_A_IMAGE_WIDTH = w
reg.PRI_A_IMAGE_HEIGHT = h
reg.SEQ_CMD = 6
Aborting a running script
If a Python script is running in the main DevWare UI thread, then the DevWare user interface is not responsive while the script is running. This is the typical case when the user initiates a script in an ini file. In order to allow interrupting a script and aborting its execution, DevWare includes a mechanism which monitors the amount of time the script is running. If the script runs for more than the timeout time, DevWare will show a dialog window allowing the user to abort it. This is useful for cases where the script is running longer than intended, or is in an infinite loop.
In order for this option to work, the library signal has to be imported. This can be done either at the beginning of the individual script, or at the beginning of the default Python preset [Python:] (see section Python in Ini Files).
The following example shows a script with an infinite loop, which can be aborted by the user if the timeout has been set:
[Python: infinite loop]
import signal
i = 0
while i < 1:
i = 0
You set the timeout value by using the DevWare option variable Script Timeout: devware.setoption('Script Timeout', 10). Assigning this variable an integer number would set the timeout to the specified value in seconds. It is not possible to set a timeout in fractions of seconds.
Disable the timeout completely by setting the variable to the value 0.
Once the value has been set, it can always be modified to a new timeout value at any time during the execution of the Python script. DevWare checks whether a different timeout value has been set every 1 second.
Midlib Module Overview
Midlib is the library that all DevSuite applications use to access the camera devices. The midlib module provides classes that represent the physical devices on the camera or emulator platform, and classes to represent registers and register bitfields. I/O to the devices is performed by using methods and attributes on instances of these classes that correspond to specific chips and registers.
Accessing Registers
To read or write a register, create a midlib.Register object connected to the desired register and then get or set its value attribute. To illustrate, this example explicitly calls the midlib.Register constructor to create a Register object, and then writes to the register.
blacklevel = midlib.Register(symbol='DATA_PEDESTAL').value # read
midlib.Register(symbol='DATA_PEDESTAL').value = 42 # write
By default the midlib.Register() constructor looks for registers on the sensor. You can also specify another chip (if there's a chip data (.cdat) file loaded for it). You can alternately specify the register by address instead of name.
Explicitly calling the midlib.Register constructor is cumbersome, so for convenience there is the RegisterSet class. The RegisterSet class has helpful attributes and methods for constructing Register objects and writing to registers with short, simple syntax.
A RegisterSet object automatically has attributes corresponding to each of the registers. The predefined variable reg is the register set for the sensor, so reg.DATA_PEDESTAL implicitly calls the Register constructor to construct a Register object for the DATA_PEDESTAL register. The above example can be written as:
blacklevel = reg.DATA_PEDESTAL.value # read
reg.DATA_PEDESTAL.value = 42 # write
As further shorthand, assigning to the register symbol attribute is equivalent to assigning to the value (or float_value) attribute of the register object.
reg.DATA_PEDESTAL = 42
But understand that reg.DATA_PEDESTAL on the right hand side of an assignment or in an expression is the Register object. So
a = reg.DATA_PEDESTAL
sets a to the Register object, not the value of the register. To use the value of the register in an assignment or any expression, either use the value or float_value attribute, or explicitly cast the Register object to an int or float.
a = int(reg.DATA_PEDESTAL)
DevWare Caches Register Values
DevWare keeps the last value read or written to a register in a cache. As an optimization, the value attribute does a cached read. That is, it normally just returns the last read or written value without doing any I/O to the device. So doing a register read like this is very cheap and there is no need for you to cache register values in your Python code. But sometimes you do need to re-do I/O, for example to read a status register that changes automatically. In that case use the uncached_value attribute.
a = reg.JPEG_STATUS.uncached_value # force reading the hardware
Using Register Objects
Registers as Python objects is very useful. For example you could write generic functions that can operate on any kind of register. This function sets a register to its default value as defined in the sensor data file.
def restore_default(rr):
rr.value = rr.default
restore_default(reg.DATA_PEDESTAL)