Important MIES concepts for developers¶
This document should help new developers understand some of the guiding principles behind MIES.
Coding Guidelines¶
Can be found here.
Documentation¶
Our documentation toolchain consists of doxygen/breathe/sphinx. All
documentation for the code should be in procedure files. All public accessible
functions should have a documentation block, for complex interfaces the use of
@param is recommended. See AFH_ExtractOneDimDataFromSweep()
for an
example.
Caller/Callee graphs can be created by executing doxygen in Packages/doc and can be browsed at Packages/doc/html/index.html.
The full documentation can be generated with tools/build-documentation.sh.
Global objects¶
Global objects like variables, strings, waves and datafolders should only be used if necessary. Local variables, strings, free waves and free datafolders should therefore be preferred if possible.
Reasons to use global objects:
Persistent storage
Performance reasons
All access to global objects must be handled via getter functions in File MIES_WaveDataFolderGetters.ipf or File MIES_GlobalStringAndVariableAccess.ipf. The documentation for these getter functions must include the wave layout, and purpose of the object. This documentation should be the primary, and only, source for finding out what the object holds. Using a single access point for global objects allows to quickly find all users of that object.
For waves we use wave versioning, see Group WaveVersioningSupport. This is done in order to enable a smooth upgrade when the wave layout changes and old experiments are loaded with the old wave layout.
The use of dimension labels in waves for better readability is recommended.
User data on GUI objects or traces should only be used sparingly.
Convenience Wrapper¶
Some Igor Pro functionality is wrapped in separate functions for better
readability and error checking. These include interacting with GUI controls,
see File MIES_GuiUtilities.ipf, checking strings IsEmpty()
or numbers
IsFinite()
.
Setting GUI values programmatically must always be done via
PGC_SetAndActivateControl()
as that calls the GUI procedure as well.
Assertions¶
We employ assertions to check function invariants . The relevant
functions are ASSERT()
and ASSERT_TS()
. Adding assertions
to the code greatly improves the error reporting capabilities of MIES and
should be used where appropriate.
Debug output¶
MIES uses the DEBUGGING_ENABLED symbol for toggling compilation with and
without debug output. The relevant functions are DEBUGPRINT()
,
DEBUGPRINT_TS()
, DEBUGPRINTv()
,
DEBUGPRINTs()
and DEBUGPRINTSTACKINFO()
. The debug mode
can be toggled on a per-file basis from MIES Panels->Advanced->Open debug
panel or globally via EnableDebugMode()
/DisableDebugMode()
.
Dynamically growing waves¶
Often one is adding entries to a wave one at a time. In order to minimize the
performance cost one can employ a technique where the actual size of the wave
and the used size differ in order to minimize the number of resize operations.
The relevant functions are EnsureLargeEnoughWave()
(with example
code), SetNumberInWaveNote()
, GetNumberFromWaveNote()
and
RemoveUnusedRows()
.
Datafolders¶
The current data folder (cdf) should never be set or expected to be something
fixed. For dealing with that environment the following functions have been
created: UniqueWaveName()
, UniqueDataFolder()
,
createDFWithAllParents()
and GetListOfObjects()
.
Deleting waves and datafolders¶
Due to the way Igor Pro works deleting a datafolder/wave may not succeed as the
object is currently in use. Use KillOrMoveToTrash()
to work around
that issue.
Wave cache¶
In order to avoid having to do the same lengthy calculation over and over again MIES has a wave cache. To use that cache you have to implement a function which derives a key from all the input parameters and is unique for the combination of parameters and different for all other combinations. This key is then used to store and retrieve the wave from the cache. See File MIES_Cache.ipf for further examples.
Background functions¶
For DAQ we use a variety of background functions, all are listed at Group BackgroundFunctions. For debugging purposes the background watchdog panel from MIES Panels->Advanced->Start Background … allows to view the state of the background functions during execution.
Structured wave metadata¶
Structured metadata can be stored and retrieved into/from the wave note using
GetNumberFromWaveNote()
/SetNumberInWaveNote()
,
GetStringFromWaveNote()
/SetStringInWaveNote()
and
AddEntryIntoWaveNoteAsList()
/HasEntryInWaveNoteList()
.
DA_Ephys panel¶
The main data acquisition panel is created via the window macro
DA_Ephys()
. After changing it, be sure to call MIES
Panels->Advanced->Reset And Store … for setting the default values and
recreating the window macro.
Access to the GUI control settings is done via the GUI state wave which caches
the settings for performance reasons. The functions
DAG_GetNumericalValue()
and DAG_GetTextualValue()
can be used to
query the values of (nearly) all GUI controls.
The names of GUI controls which come in groups, like headstages, DA/AD/TTL
channels must be derived by calling GetPanelControl()
. Their state can be
queried with DAG_GetChannelState()
.
Versioned panels¶
All panels are versioned. The version number must be increased if a stored
panel in an old experiment would misbehave with new code. The relevant
constants are DA_EPHYS_PANEL_VERSION
, DATABROWSER_PANEL_VERSION
,
SWEEPBROWSER_PANEL_VERSION
and WAVEBUILDER_PANEL_VERSION
.
Tabbed panels¶
For TabControl GUI elements we use routines from ACL_TabUtilities.ipf and ACL_UserdataEditor.ipf for convenient programming.