CHDK Wiki
(wait for get_shooting() to be true (needed on A720IS))
(→‎Other differences: add note about io failing if fileio sem taken)
Tag: sourceedit
(32 intermediate revisions by 12 users not shown)
Line 1: Line 1:
  +
  +
 
{| align="right" style="border-collapse:collapse; font-size: x-small;"
 
{| align="right" style="border-collapse:collapse; font-size: x-small;"
 
| __TOC__
 
| __TOC__
Line 12: Line 14:
   
 
'''License: Lua is Open Source software, its licenses are compatible with GPL.'''
 
'''License: Lua is Open Source software, its licenses are compatible with GPL.'''
  +
====Advantages Versus uBasic====
  +
*error messages shown and program halts when you have typos in your script versus uBasic which silently fails
  +
*multi-letter variable names are allowed (except for camera editable parameters found in the header)
  +
*richer language constructs (step increments in for loops, if then else, complete conditionals)
  +
*consistent ''x=get_*()'' (versus uBasic where sometimes it is ''x=get_*'' sometimes it is ''get_* x'')
  +
*Lua scripts can be executed from a PC using the [[PTP Extension]]
  +
  +
====Disadvantages Versus uBasic====
  +
*since Lua was late to the party (2008), and as most people know at least a little bit about BASIC programming, most CHDK examples are given in uBasic
  +
*language syntax doesn't match BASIC, C, so can be frustrating to learn
  +
*CHDK Lua information is limited (however google of "lua for loop example" will often yield several results)
  +
  +
====Recommendation====
  +
New users should strongly consider using Lua over uBasic if writing new scripts for themselves. Lua is much more powerful and will yield lower frustration in the long run. Review the examples below for syntax examples. If only making simple changes to existing uBasic scripts, stick with uBasic.
   
 
==Important Links==
 
==Important Links==
  +
[[CHDK_Scripting_Cross_Reference_Page|CHDK Scripting Cross Reference Page]]
  +
  +
Useful Tutorials:
  +
*'''[http://lua-users.org/wiki/TutorialDirectory LUA-Users.org Tutorials]'''
  +
 
Lua dependent CHDK wikia articles:
 
Lua dependent CHDK wikia articles:
*<big>[[LUA/LUA syntax|Lua Syntax]]</big>
+
*<big>[[Lua/Lua syntax|Lua Syntax]]</big>
*<big>[[LUA/LUA Reference|Lua Command Reference]]</big>
+
*<big>[[Lua/Lua Reference|Lua Command Reference]]</big>
 
External links:
 
External links:
 
*'''[http://www.lua.org/home.html The programming language Lua - Homepage]'''
 
*'''[http://www.lua.org/home.html The programming language Lua - Homepage]'''
 
:→[http://www.lua.org/news.html NEWS]
 
:→[http://www.lua.org/news.html NEWS]
:→[http://www.lua.org/manual/ Reference Manuals]
+
:→[http://www.lua.org/manual/5.1/ Language 5.1 Reference Manual] (complete language definition)
 
:→[http://www.lua.org/license.html License]
 
:→[http://www.lua.org/license.html License]
   
Line 26: Line 47:
 
*A CHDK version with built-in Lua support is needed, e.g. CHDK builds > version 0.5 / changeset 512
 
*A CHDK version with built-in Lua support is needed, e.g. CHDK builds > version 0.5 / changeset 512
 
*The script should be saved with the filename extension '''.lua''' in the CHDK scripts folder {{scaps|chdk/scripts}}
 
*The script should be saved with the filename extension '''.lua''' in the CHDK scripts folder {{scaps|chdk/scripts}}
*Lua scripts support libraries, these files has to be placed either in {{scaps|chdk/scripts}} or {{scaps|chdk/lualib}}, see [[LUA/LUA syntax#Libraries|Lua syntax: Libraries]].
+
*Lua scripts support libraries, these files have to be placed either in {{scaps|chdk/scripts}} or {{scaps|chdk/lualib}}, see [[Lua/Lua syntax#Libraries|Lua syntax: Libraries]].
*Loading, starting, pausing & stopping works exactly in the same way as on UBASIC scripts
+
*Loading, starting, pausing & stopping work exactly in the same way as on UBASIC scripts
 
*UBASIC scipts are also working as usual, the filename extension (.lua or .bas) tells CHDK how to run the script
 
*UBASIC scipts are also working as usual, the filename extension (.lua or .bas) tells CHDK how to run the script
*For advanced Lua development, you may with to run scripts on your computer. Set up a [[LUA Dev Environment]]
+
*For advanced Lua development, you may wish to run scripts on your computer. Set up a [http://chdk.wikia.com/wiki/Lua_Development_Environment Lua Dev Environment]
   
 
'''A first Lua sample script:'''
 
'''A first Lua sample script:'''
  +
<source lang="lua">
<pre>
 
 
for i = 1,10 do
 
for i = 1,10 do
 
print( "Picture "..i )
 
print( "Picture "..i )
Line 38: Line 59:
 
sleep( 2000 )
 
sleep( 2000 )
 
end
 
end
</pre>
+
</source>
   
 
==Lua standard libraries: io, os, string, and math==
 
==Lua standard libraries: io, os, string, and math==
CHDK has included experimental support for the lua standard [http://www.lua.org/manual/5.1/manual.html#5.7 IO] and [http://www.lua.org/manual/5.1/manual.html#5.8 OS] libraries since changeset 517. These allow you to manipulate files and directories. See [http://chdk.setepontos.com/index.php/topic,2267.0.html this post] for important differences, limitations and warnings.
+
CHDK has included support for the lua standard [http://www.lua.org/manual/5.1/manual.html#5.7 IO] and [http://www.lua.org/manual/5.1/manual.html#5.8 OS] libraries since changeset 517. These allow you to manipulate files and directories. See [http://chdk.setepontos.com/index.php/topic,2267.0.html this post] for important differences, limitations and warnings.
   
 
Support for the [http://www.lua.org/manual/5.1/manual.html#5.4 string] library has been added in changeset 606.
 
Support for the [http://www.lua.org/manual/5.1/manual.html#5.4 string] library has been added in changeset 606.
   
Support for the [http://www.lua.org/manual/5.1/manual.html#5.6 math] library exists in a modified form. Lua numbers are floats but chdk lua uses 32bit ints instead. The portions of the math library that make sense for ints are included.
+
Support for the [http://www.lua.org/manual/5.1/manual.html#5.6 math] library exists in a modified form. In standard Lua, numbers are floats but CHDK Lua is configured to use 32bit ints instead. The portions of the math library that make sense for ints are included.
   
 
'''→''' A '''test script''' to check the correct functionality of the library functions (including a list of successfully tested cameras) is also available: [[Lua#lua IO & OS library test|'''Lua IO+OS library test''']] !
 
  +
===Differences in the base library===
'''→''' A '''test script''' to check the correct functionality of the library functions (including a list of successfully tested cameras) is also available: [[LUA#lua IO & OS library test|'''Lua IO+OS library test''']] !
 
  +
====Missing features====
  +
* '''module''' is not implemented.
  +
* dynamic linking binaries and related features are not supported
  +
* package.seeall is not supported
  +
* Prior to CHDK 1.2 changeset 2732, package.path is not supported.
   
 
===Differences from standard lua iolib===
 
===Differences from standard lua iolib===
Line 66: Line 92:
 
:: dryos has no errno (or not found until now), and simply reports "error"
 
:: dryos has no errno (or not found until now), and simply reports "error"
 
* file:read("*n") will behave slightly differently because it doesn't use scanf. Shouldn't matter for sanely structured files, but corner cases will be different.
 
* file:read("*n") will behave slightly differently because it doesn't use scanf. Shouldn't matter for sanely structured files, but corner cases will be different.
  +
* On cameras running DryOS 2.3 R50 and later, functions that write to a file do not appear to update the create and modify times.
  +
* In CHDK 1.3 and later, IO calls may return an error if the camera firmware is doing IO. This is particularly likely if video is being recorded, or video has stopped and the video is still being processed.
   
 
===Differences from standard lua oslib===
 
===Differences from standard lua oslib===
Line 81: Line 109:
 
::<tt>status[,errstring[,errno]]=os.mkdir("A/path")</tt>
 
::<tt>status[,errstring[,errno]]=os.mkdir("A/path")</tt>
 
:Attempts to create a directory at the named path. Returns true on success or nil,"error string",errno.
 
:Attempts to create a directory at the named path. Returns true on success or nil,"error string",errno.
* '''os.stat''' ''(implemented since build 0.6.5 / changeset 541)''
+
* '''os.stat''' ''(implemented since build 0.6.5 / changeset 541)''
 
::<tt>stat_table[,errstring[,errno]=os.stat("filename")</tt>
 
::<tt>stat_table[,errstring[,errno]=os.stat("filename")</tt>
:Returns a table on success, or nil followed by the values of strerror and errno
+
:Returns a table on success, or nil followed by the values of strerror and errno
 
:The table has the following fields (all numbers)
 
:The table has the following fields (all numbers)
 
::{| class = "wikitable"
 
::{| class = "wikitable"
|dev || device number
+
|dev || device number - not present on dryos >= R39
 
|-
 
|-
|mode || not clear which bits are useful. It does change depending on whether you look at a file or directory (but you should use attrib or is_* below instead)
+
|mode || not clear which bits are useful. It does change depending on whether you look at a file or directory (but you should use attrib or is_* below instead) - not present on dryos >= R39
 
|-
 
|-
 
|size || size in bytes
 
|size || size in bytes
 
|-
 
|-
|atime || time of last access
+
|atime || time of last access - not present on dryos >= R39
 
|-
 
|-
 
|mtime || time of last modification
 
|mtime || time of last modification
Line 98: Line 126:
 
|ctime || time of last change of file status
 
|ctime || time of last change of file status
 
|-
 
|-
|blksize || block size in bytes. This is NOT the dos sector size. 512 on all I've tested, possibly hardware block size.
+
|blksize || block size in bytes. This is NOT the dos sector size. 512 on all I've tested, possibly hardware block size. - not present on dryos >= R39
 
|-
 
|-
|blocks || Number of blksize blocks in the file. blocks*blocksizes is not the same as "size on disk", per above.
+
|blocks || Number of blksize blocks in the file. blocks*blocksizes is not the same as "size on disk", per above. - not present on dryos >= R39
 
|-
 
|-
 
|attrib || bitmask of dos attributes (see stdlib.h)
 
|attrib || bitmask of dos attributes (see stdlib.h)
Line 117: Line 145:
 
* '''os.listdir''' ''(implemented since build 0.7.4 / changeset 555)''
 
* '''os.listdir''' ''(implemented since build 0.7.4 / changeset 555)''
 
::<tt>dir_table[,errstring[,errno]]=os.listdir("dirpath"[,showall])</tt>
 
::<tt>dir_table[,errstring[,errno]]=os.listdir("dirpath"[,showall])</tt>
:List the contents of a directory. Returns array of file names, or nil, "error message", errno.
+
:List the contents of a directory. Returns array of file names, or nil, "error message", errno.
:If showall is true, the array includes ".", ".." and deleted entries
+
:If showall is true, the array includes ".", ".." and deleted entries (on vxworks)
:Sample/Usage: see [[LUA#Listdir_sample]]
+
:Sample/Usage: see [[Lua#Listdir_sample]]
 
:'''Notes:'''
 
:'''Notes:'''
:* Except for the root directory, names ending in / will not work. (untested on DryOS)
+
:* Except for the root directory, names ending in / will not work.
 
:* DryOS only returns 8.3 names. VxWorks returns long names.
 
:* DryOS only returns 8.3 names. VxWorks returns long names.
 
:* DryOS will report success and return an empty table if you call listdir on a file.
 
:* DryOS will report success and return an empty table if you call listdir on a file.
  +
  +
* '''os.idir''' ''(available in chdk 1.3 build 3415 and later)''
  +
: An alternative to os.listdir, which does not require loading the entire directory listing into memory.
  +
::<tt>iteratator, userdata = os.idir("dirpath"[,showall])</tt>
  +
: or more typically
  +
::<tt>for fname in os.idir("dirpath"[,showall]) do ...</tt>
  +
: each call to iterator(userdata) returns the next directory entry or nil if all entries have been returned .
  +
:<tt>showall</tt> behaves the same as os.listdir
  +
:Calling iterator(userdata,false) will immediately close the directory handle. This cannot be used with the typical <tt>for</tt> syntax given above, you must explicitly get the iterator yourself:
  +
<code>
  +
local idir,ud=os.idir('A/')
  +
repeat
  +
name=idir(ud)
  +
-- break out of loop under some condition
  +
if somefunction(name) then
  +
break
  +
end
  +
until not name
  +
idir(ud,false) -- ensure directory handle is closed
  +
</code>
  +
:'''NOTES''':
  +
:* Except for the root directory, names ending in / will not work
  +
:* If the path does not exist, or is not a directory, or there is some other error opening the directory, the iterator will immediately return nil, the same as an empty directory with showall=false.
  +
:* The directory handle is kept open until all directory entries are iterated or the userdata is GC'd. This means that:
  +
:*# Deep recursive traversals may run into handle limits.
  +
:*# If you break out of a loop using the iterator, the handle may remain open for a while. You can explicitly close the handle described above.
   
 
====Other differences====
 
====Other differences====
 
* Similar error reporting limitations to io
 
* Similar error reporting limitations to io
* '''os.date''': Does not distinguish between local and GMT. It's possible support could be added for some cameras.
+
* '''os.date''': Does not distinguish between local and GMT. In general, the cameras are not aware of a current timezone, even when they allow you to set one in the UI.
  +
* The timestamp values used by os functions (time, date, stat, utime etc) are similar to, but not identical to unix timestamps. See [[Camera timestamps]] for more information.
 
* '''os.difftime''': Just returns <tt>(unsigned int)t1 - (unsigned int)t2</tt>
 
* '''os.difftime''': Just returns <tt>(unsigned int)t1 - (unsigned int)t2</tt>
   
Line 148: Line 203:
 
If the libraries have not already been tested on your camera and firmware version, you should run the script before attempting to use them. This script tests the various IO and OS functions, generating <tt>/llibtst.log</tt> and reporting pass or fail in the console. If not all tests are run, or there are failures, it may leave other files or directories in the root.
 
If the libraries have not already been tested on your camera and firmware version, you should run the script before attempting to use them. This script tests the various IO and OS functions, generating <tt>/llibtst.log</tt> and reporting pass or fail in the console. If not all tests are run, or there are failures, it may leave other files or directories in the root.
   
{{Attention|'''Failures could crash your camera'''. It is also possible, although not likely, that it could '''corrupt your SD card'''. Use caution if your camera has not been tested.}} The following cameras have been successfully tested as of January 05, 2010:<pre>
+
{{Attention|'''Failures could crash your camera'''. It is also possible, although not likely, that it could '''corrupt your SD card'''. Use caution if your camera has not been tested.}} The following cameras have been successfully tested as of May 14, 2013:<pre>
a470-102c
+
a430-100b a470-102c
 
a540-100b
 
a540-100b
 
a550-100c a560-100a a570-1.00e a570-101a a590-101b
 
a550-100c a560-100a a570-1.00e a570-101a a590-101b
Line 155: Line 210:
 
a710-100a a720-100c
 
a710-100a a720-100c
 
ixus40_sd400-1.01b ixus70_sd1000-101b ixus80_sd1100-100c ixus850_sd800-100e ixus860_SD870-100C ixus90_sd790-100d
 
ixus40_sd400-1.01b ixus70_sd1000-101b ixus80_sd1100-100c ixus850_sd800-100e ixus860_SD870-100C ixus90_sd790-100d
S2IS (unknown sub) s3is-100a sx10-101a sx100is-100b tx1-101b
+
S2IS (unknown sub) s3is-100a
  +
sx10-101a sx100is-100b sx110is 100b tx1-101b
 
</pre>No failures or crashes have been reported.
 
</pre>No failures or crashes have been reported.
   
Line 166: Line 222:
 
*'''NA''' means the script doesn't count the result of that particular call as a pass or fail, because the results are variable or not meaningful.
 
*'''NA''' means the script doesn't count the result of that particular call as a pass or fail, because the results are variable or not meaningful.
   
More informations and a sample log file can be found in reyalp's forum post: [http://chdk.setepontos.com/index.php/topic,2267.msg21479.html#msg21479 preliminary lua iolib and oslib port]
+
More information and a sample log file can be found in reyalp's forum post: [http://chdk.setepontos.com/index.php/topic,2267.msg21479.html#msg21479 preliminary lua iolib and oslib port]
   
 
{{Notice|'''<u>Additional Notes:</u>'''}}
 
{{Notice|'''<u>Additional Notes:</u>'''}}
Line 174: Line 230:
   
 
==Some Lua scripts==
 
==Some Lua scripts==
{{notice|Additional example scripts are included in the 'complete' CHDK download packages, they are also directly available from [http://tools.assembla.com/chdk/browser/trunk/CHDK/SCRIPTS/examples CHDK SVN: SCRIPTS/examples].}}
+
{{notice|Additional example scripts are included in the 'complete' CHDK download packages, they are also directly available from [http://tools.assembla.com/chdk/browser/trunk/CHDK/SCRIPTS/EXAM CHDK SVN: script examples].}}
 
----
 
----
   
Line 202: Line 258:
 
@param j Seq dur (s)/n of shots/seq
 
@param j Seq dur (s)/n of shots/seq
 
@default j 1
 
@default j 1
--]]
+
]]
   
 
drivemode_continuous = 1
 
drivemode_continuous = 1
Line 305: Line 361:
   
 
----
 
----
  +
 
===Minimalistic Intervalometer===
 
===Minimalistic Intervalometer===
 
Often, we want the camera to just take pictures on an interval without being smart about anything. This script was built to fill the need for a very, very simple intervalometer.
 
Often, we want the camera to just take pictures on an interval without being smart about anything. This script was built to fill the need for a very, very simple intervalometer.
Line 364: Line 421:
 
[MENU] close the script
 
[MENU] close the script
   
{{Attention|Do not use any illegal folder names - you may lose data or the filesystem could be corrupted !}}
+
{{Attention|Do not use any illegal folder names - you may lose data or the filesystem could be corrupted !}}
   
 
<source lang="lua">
 
<source lang="lua">
Line 541: Line 598:
   
 
===Universal Tv mode===
 
===Universal Tv mode===
This is a script for a enhanced tv mode. It should work with all cameras, even with models with or without tv mode.
+
This is a script for a enhanced tv mode. It should work with all cameras, even with models with or without tv mode.
   
 
It was released by 'msl' in the CHDK forum in [http://chdk.setepontos.com/index.php/topic,2497.msg23230.html#msg23230 this post],a german version is available at www.wirklemms.de
 
It was released by 'msl' in the CHDK forum in [http://chdk.setepontos.com/index.php/topic,2497.msg23230.html#msg23230 this post],a german version is available at www.wirklemms.de
Line 606: Line 663:
 
end
 
end
 
if is_pressed "display" then
 
if is_pressed "display" then
key = "DISP"
+
key = "DISP"
x = 1
+
x = 1
end
+
end
 
if is_pressed "left" then
 
if is_pressed "left" then
 
key = "LEFT"
 
key = "LEFT"
Line 618: Line 675:
 
end
 
end
 
if is_pressed "up" then
 
if is_pressed "up" then
key = "UP"
+
key = "UP"
x = 1
+
x = 1
end
+
end
if is_pressed "down" then
+
if is_pressed "down" then
key = "DOWN"
+
key = "DOWN"
x = 1
+
x = 1
end
+
end
 
until x == 1
 
until x == 1
 
set_led (8,1)
 
set_led (8,1)
Line 709: Line 766:
 
</source>
 
</source>
 
----
 
----
 
   
 
===Listdir sample===
 
===Listdir sample===
Line 845: Line 901:
 
</source>
 
</source>
 
----
 
----
  +
  +
===TagMe, the Lua EXIF tagger===
  +
* Autor: Stefan Dittforth ("stift")
  +
* Published: 06-Sept-2009 in the german forum
  +
* Forum links: [http://www.wirklemms.de/chdk/forum/viewtopic.php?t=1555 German forum], [http://chdk.setepontos.com/index.php/topic,4533.0.html International forum]
  +
  +
'''This script allows a user to select a text from a configurable list of text strings and write this string into the EXIF UserComment tag for a list of images'''
  +
  +
*The functions for reading and modifying the EXIF information are in a seperate module EXIF.lua which can be imported and reused in other scripts
  +
*The script is excellent commented, the download package also includes a very good user's guide
  +
*There are lots of useful functions and informations in the script and the exif module
  +
*It nicely demonstrates advanced Lua programming technics
  +
  +
:{{tagb|→ }}The download package, including the script, the exif lib and the documentation (in english & german) is available from [http://chdk.setepontos.com/index.php/topic,4533.0.html '''here''']
   
 
==RAW development==
 
==RAW development==
Since CHDK version 0.8.4 there are some new commands to merge/develop RAW images directly in the camera, read [[LUA/LUA_Reference#RAW_development|Lua Reference: RAW development]] for more informations.
+
Since CHDK version 0.8.4 there are some new commands to merge/develop RAW images directly in the camera, read [[Lua/Lua_Reference#RAW_development|Lua Reference: RAW development]] for more informations.
   
There's also a script to demonstrate the usage of this new feature: [[LUA/LUA_Reference#Sample_.2F_test_script|Lua Reference: Sample test script]]
+
There's also a script to demonstrate the usage of this new feature: [[Lua/Lua_Reference#Sample_.2F_test_script|Lua Reference: Sample test script]]
 
[[Category:Development]]
 
[[Category:Development]]
[[Category:LUA]]
+
[[Category:Lua]]

Revision as of 21:59, 22 March 2015


thumb frameless

What is Lua ?

Lua is a powerful, fast, light-weight, embeddable scripting language. Lua combines simple procedural syntax with powerful data description constructs based on associative arrays and extensible semantics. Lua is dynamically typed, runs by interpreting bytecode for a register-based virtual machine, and has automatic memory management with incremental garbage collection, making it ideal for configuration, scripting, and rapid prototyping. (quoted from www.lua.org)

Lua was brought to CHDK by "Velo" in the forum in April 2008: Lua Scripting Integration

License: Lua is Open Source software, its licenses are compatible with GPL.

Advantages Versus uBasic

  • error messages shown and program halts when you have typos in your script versus uBasic which silently fails
  • multi-letter variable names are allowed (except for camera editable parameters found in the header)
  • richer language constructs (step increments in for loops, if then else, complete conditionals)
  • consistent x=get_*() (versus uBasic where sometimes it is x=get_* sometimes it is get_* x)
  • Lua scripts can be executed from a PC using the PTP Extension

Disadvantages Versus uBasic

  • since Lua was late to the party (2008), and as most people know at least a little bit about BASIC programming, most CHDK examples are given in uBasic
  • language syntax doesn't match BASIC, C, so can be frustrating to learn
  • CHDK Lua information is limited (however google of "lua for loop example" will often yield several results)

Recommendation

New users should strongly consider using Lua over uBasic if writing new scripts for themselves. Lua is much more powerful and will yield lower frustration in the long run. Review the examples below for syntax examples. If only making simple changes to existing uBasic scripts, stick with uBasic.

Important Links

CHDK Scripting Cross Reference Page

Useful Tutorials:

Lua dependent CHDK wikia articles:

External links:

NEWS
Language 5.1 Reference Manual (complete language definition)
License

Running Lua scripts

  • A CHDK version with built-in Lua support is needed, e.g. CHDK builds > version 0.5 / changeset 512
  • The script should be saved with the filename extension .lua in the CHDK scripts folder chdk/scripts
  • Lua scripts support libraries, these files have to be placed either in chdk/scripts or chdk/lualib, see Lua syntax: Libraries.
  • Loading, starting, pausing & stopping work exactly in the same way as on UBASIC scripts
  • UBASIC scipts are also working as usual, the filename extension (.lua or .bas) tells CHDK how to run the script
  • For advanced Lua development, you may wish to run scripts on your computer. Set up a Lua Dev Environment

A first Lua sample script:

for i = 1,10 do
  print( "Picture "..i )
  shoot()
  sleep( 2000 )
end

Lua standard libraries: io, os, string, and math

CHDK has included support for the lua standard IO and OS libraries since changeset 517. These allow you to manipulate files and directories. See this post for important differences, limitations and warnings.

Support for the string library has been added in changeset 606.

Support for the math library exists in a modified form. In standard Lua, numbers are floats but CHDK Lua is configured to use 32bit ints instead. The portions of the math library that make sense for ints are included.

A test script to check the correct functionality of the library functions (including a list of successfully tested cameras) is also available: Lua IO+OS library test !

Differences in the base library

Missing features

  • module is not implemented.
  • dynamic linking binaries and related features are not supported
  • package.seeall is not supported
  • Prior to CHDK 1.2 changeset 2732, package.path is not supported.

Differences from standard lua iolib

Missing features

  • io.popen: CHDK has no other processes, no pipes
  • standard file handles: stdin/stdout/stderr all start out closed, as do io.input() and io.output()
  • io.tmpfile: Not implemented yet, but may be added later.

Added features

  • file:_getfptr()
fptrval=file:_getfptr()
Returns the actual FILE * associated with the file object. This is strictly for development/debugging, but combined with peek makes verifying FILE structure hack much simpler.

Other differences

  • Error detection and reporting is more limited:
vxworks reports errno, but no text description
dryos has no errno (or not found until now), and simply reports "error"
  • file:read("*n") will behave slightly differently because it doesn't use scanf. Shouldn't matter for sanely structured files, but corner cases will be different.
  • On cameras running DryOS 2.3 R50 and later, functions that write to a file do not appear to update the create and modify times.
  • In CHDK 1.3 and later, IO calls may return an error if the camera firmware is doing IO. This is particularly likely if video is being recorded, or video has stopped and the video is still being processed.

Differences from standard lua oslib

Missing features

  • os.clock: not implemented. Note this relates to CPU time used by a process, not time of day (which is handled by os.time and os.date)
  • os.execute: no processes, revisit for ELF edition
  • os.exit: not meaningful for CHDK
  • os.getenv: environment variables exist in vxworks, but usefulness is doubtful
  • os.setlocale: functions may exist, but it's unlikely the rest of the firmware uses them
  • os.tmpname: TODO, not implemented yet (a beta implementation is available in the forum). Also trivial to implement entirely in lua script.

Added features

The following are not in the standard lua OS lib, but are added in CHDK

  • os.mkdir
status[,errstring[,errno]]=os.mkdir("A/path")
Attempts to create a directory at the named path. Returns true on success or nil,"error string",errno.
  • os.stat (implemented since build 0.6.5 / changeset 541)
stat_table[,errstring[,errno]=os.stat("filename")
Returns a table on success, or nil followed by the values of strerror and errno
The table has the following fields (all numbers)
dev device number - not present on dryos >= R39
mode not clear which bits are useful. It does change depending on whether you look at a file or directory (but you should use attrib or is_* below instead) - not present on dryos >= R39
size size in bytes
atime time of last access - not present on dryos >= R39
mtime time of last modification
ctime time of last change of file status
blksize block size in bytes. This is NOT the dos sector size. 512 on all I've tested, possibly hardware block size. - not present on dryos >= R39
blocks Number of blksize blocks in the file. blocks*blocksizes is not the same as "size on disk", per above. - not present on dryos >= R39
attrib bitmask of dos attributes (see stdlib.h)
The following boolean values are set based on attrib, so you don't have to do bit testing for the most common values of interest:
is_dir
is_file
Notes:
  • It is possible to stat things that are neither file nor directory, e.g. volume labels. So you should test for exactly what you want, rather than assuming that not is_file means directory.
  • Files larger than 2gb would appear to have a negative size in lua.
  • os.utime (implemented since build 0.6.5 / changeset 541)
status[,errstring[,errno]]=os.utime("filename"[,atime[,mtime]])
Set the modification and access time of the named file. If either time is missing or nil, the current time is used. Returns true on success, or nil, "error message", errno. To set one time and leave the other unchanged, you must use stat to get the current value.
  • os.listdir (implemented since build 0.7.4 / changeset 555)
dir_table[,errstring[,errno]]=os.listdir("dirpath"[,showall])
List the contents of a directory. Returns array of file names, or nil, "error message", errno.
If showall is true, the array includes ".", ".." and deleted entries (on vxworks)
Sample/Usage: see Lua#Listdir_sample
Notes:
  • Except for the root directory, names ending in / will not work.
  • DryOS only returns 8.3 names. VxWorks returns long names.
  • DryOS will report success and return an empty table if you call listdir on a file.
  • os.idir (available in chdk 1.3 build 3415 and later)
An alternative to os.listdir, which does not require loading the entire directory listing into memory.
iteratator, userdata = os.idir("dirpath"[,showall])
or more typically
for fname in os.idir("dirpath"[,showall]) do ...
each call to iterator(userdata) returns the next directory entry or nil if all entries have been returned .
showall behaves the same as os.listdir
Calling iterator(userdata,false) will immediately close the directory handle. This cannot be used with the typical for syntax given above, you must explicitly get the iterator yourself:

 local idir,ud=os.idir('A/')
 repeat
   name=idir(ud)
   -- break out of loop under some condition
   if somefunction(name) then
       break
   end
 until not name
 idir(ud,false) -- ensure directory handle is closed

NOTES:
  • Except for the root directory, names ending in / will not work
  • If the path does not exist, or is not a directory, or there is some other error opening the directory, the iterator will immediately return nil, the same as an empty directory with showall=false.
  • The directory handle is kept open until all directory entries are iterated or the userdata is GC'd. This means that:
    1. Deep recursive traversals may run into handle limits.
    2. If you break out of a loop using the iterator, the handle may remain open for a while. You can explicitly close the handle described above.

Other differences

  • Similar error reporting limitations to io
  • os.date: Does not distinguish between local and GMT. In general, the cameras are not aware of a current timezone, even when they allow you to set one in the UI.
  • The timestamp values used by os functions (time, date, stat, utime etc) are similar to, but not identical to unix timestamps. See Camera timestamps for more information.
  • os.difftime: Just returns (unsigned int)t1 - (unsigned int)t2

General notes from IO and OS testing on vxworks

  • os.remove works on files and empty directories. Attempting to remove a non-empty directory fails gracefully.
  • os.rename works on files and empty directories. Attempting to rename a non-empty directory may result in filesystem corruption !
  • os.rename only works within a given directory. You can not use rename to move a file to another directory. Attempting to do so may cause unpredictable results.
  • os.rename may produce unpredictable results if the target name already exists.
  • os.mkdir will not create a directory if the name has a trailing /, but fails gracefully
  • io functions are very likely limited to files of less that two gigabytes, and certainly less than four.
  • unlike some OSes, file:seek cannot be used to extend a file

Future versions should attempt to handle some of these situations more gracefully. Dryos may behave differently.

The string library

Unlike io and os, the string library does not differ substantially from the lua standard. If it fails on your camera, the worst result is likely to be a crash.

Lua Reference Manual - String Manipulation
Programming in Lua - The String Library

Lua library test

If the libraries have not already been tested on your camera and firmware version, you should run the script before attempting to use them. This script tests the various IO and OS functions, generating /llibtst.log and reporting pass or fail in the console. If not all tests are run, or there are failures, it may leave other files or directories in the root.

Attention

Failures could crash your camera. It is also possible, although not likely, that it could corrupt your SD card. Use caution if your camera has not been tested.

The following cameras have been successfully tested as of May 14, 2013:

a430-100b                 a470-102c
a540-100b
a550-100c                 a560-100a               a570-1.00e             a570-101a             a590-101b
a620-100f                 a630-100c               a650-1.00d
a710-100a                 a720-100c
ixus40_sd400-1.01b        ixus70_sd1000-101b      ixus80_sd1100-100c     ixus850_sd800-100e    ixus860_SD870-100C   ixus90_sd790-100d
S2IS (unknown sub)        s3is-100a               
sx10-101a                 sx100is-100b            sx110is 100b           tx1-101b

No failures or crashes have been reported.

The pass/fail in the console only provides a general indication. The logfile should be examined to be sure everything is working.

The log is formatted such that most lines end with OK or ERR followed by possible return values, and then PASS, FAIL, or NA.

  • PASS or FAIL indicate whether the test received the result it expected.
  • OK and ERR indicate whether the function being tested reported success or failure, which may represent a PASS or FAIL depending on circumstances.
  • NA means the script doesn't count the result of that particular call as a pass or fail, because the results are variable or not meaningful.

More information and a sample log file can be found in reyalp's forum post: preliminary lua iolib and oslib port

Notice

Additional Notes:

  • The script also serves as an example of how to use the libraries.
  • Since version 0.6.5 / changeset #541 the test script in its latest version is included in the distribution directory CHDK/SCRIPTS/TEST/LLIBTST.LUA in the 'complete' Autobuild download package, it is also available from here.

Some Lua scripts

Notice

Additional example scripts are included in the 'complete' CHDK download packages, they are also directly available from CHDK SVN: script examples.


yet another accurate intervalometer

--[[
rem 20080805
@title yet another accurate intervalometer
@param a Duration (min)/-1 disable
@default a -1
@param b Duration (sec)/n of seqs
@default b 5
@param c Delay 1st sequence (min)
@default c 0
@param d Delay 1st sequence (sec)
@default d 3
@param e Trigger every n min
@default e 0
@param f ...every n sec
@default f 3
@param g ...every .n sec
@default g 0
@param h Endless?
@default h 0
@param i Seq dur (m)/-1
@default i -1
@param j Seq dur (s)/n of shots/seq
@default j 1
]]

drivemode_continuous = 1

if a < -1 then a = -1 end
if ( a > -1 and b < 0 ) then b = 0 end
if ( a == -1 and b < 1 ) then b = 1 end
if c < 0 then c = 0 end
if d < 0 then d = 0 end
if e < 0 then e = 0 end
if f < 0 then f = 0 end
if g < 0 then g = 0 end
if ( h < 0 or h > 1 ) then h = 0 end
if i < -1 then i = -1 end
if ( i > -1 and j < 0 ) then j = 0 end
if ( i == -1 and j < 1 ) then j = 1 end
if (( i == -1 and j > 1 ) or i > -1 ) then
  if get_drive_mode() ~= drivemode_continuous then
    print( "set drive mode" )
    print( "to continuous" )
    sleep(1500)
    cannot_continue = true
  end
end

if a > -1 then duration = a*60000 + b*1000 else duration = b end
delay_first= c*60000 + d*1000
if g < 0 then delay = e*60000 + f*1000 + g*10 else delay = e*60000 + f*1000 + g*100 end
if i > -1 then sequence = i*60000 + j*1000 else sequence = j end


function shoot_by_numbers( sequence_target )
sequence_current = 0
repeat
  tick_target = get_tick_count() + delay
  sequence_current = sequence_current + 1
  print( "sequence " .. sequence_current .. " of " .. sequence_target )
  if i == -1 then shoot_count( sequence ) else shoot_tick( sequence ) end
  while ( get_tick_count() < tick_target and sequence_current < sequence_target ) do
  end
until sequence_current >= sequence_target
end

function shoot_by_duration( duration )
duration_target = get_tick_count() + duration
repeat
  tick_target = get_tick_count() + delay
  if i == -1 then shoot_count( sequence ) else shoot_tick( sequence ) end
  print( (duration_target-get_tick_count())/1000 .. " sec to go" )
  while ( get_tick_count() < tick_target and get_tick_count() < duration_target ) do
  end
until get_tick_count() >= duration_target
end

function shoot_forever()
tick_initial = get_tick_count()
sequence_current = 0
repeat
  tick_target = get_tick_count() + delay
  sequence_current = sequence_current + 1
  print( "sequence " .. sequence_current )
  if i == -1 then shoot_count( sequence ) else shoot_tick( sequence ) end
  print ( (get_tick_count()-tick_initial)/1000 .. " sec elapsed")
  while ( get_tick_count() < tick_target ) do
  end
until false
end

function shoot_count( count_inc )
count_target = get_exp_count() + count_inc
if count_target > 9999 then count_target = count_target - 9999 end
press( "shoot_half" )
press( "shoot_full" )
repeat
until get_exp_count() == count_target
release( "shoot_full" )
repeat
until get_shooting() == false
end

function shoot_tick( tick_duration )
tick_target = get_tick_count() + tick_duration
press( "shoot_half" )
press( "shoot_full" )
while ( get_tick_count() < tick_target ) do
end
release( "shoot_full" )
repeat
until get_shooting() == false
end

if not cannot_continue then
  tick_target = get_tick_count() + delay_first
  print( "waiting " .. delay_first/1000 .. " sec" )
  while ( get_tick_count() < tick_target ) do
    tick_current = get_tick_count()
  end
  if h == 1 then shoot_forever() end
  if a > -1 then shoot_by_duration( duration ) else shoot_by_numbers( duration ) end
end

Minimalistic Intervalometer

Often, we want the camera to just take pictures on an interval without being smart about anything. This script was built to fill the need for a very, very simple intervalometer.

This might serve well also as a script for you to read so that you can understand how scripting works. To use: create an empty text file called "mint.lua" in CHDK/SCRIPTS on the flash card. Paste the code below into the file. Start CHDK, press the shortcut key, press Set, select Load Script from File, find mint.lua, go wild.

Should work on any camera and should be very accurate. Enjoy!

--[[
@title Minimalistic Intervalometer
@param a Shooting interval, min
@default a 0
@param b ...sec
@default b 10
--]]

Interval = a*60000 + b*1000

function TakePicture()
	press("shoot_half")
        repeat sleep(50) until get_shooting() == true
	press("shoot_full")
	release("shoot_full")
	repeat sleep(50) until get_shooting() == false	
        release "shoot_half"
end

repeat
	StartTick = get_tick_count()
	TakePicture()
	sleep(Interval - (get_tick_count() - StartTick))
until false

Char input demo

This is a demo script in Lua. You can input a text as a folder name, if you want the folder will be created (A/name). In the script parameter menu you can control the keyboard delay for repeating.

It was released by 'msl' in the CHDK forum in this post, a german version is available at www.wirklemms.de

Using the script:

first consol menu
[<-][->]      select a char in 1 step
[zoom in/out] select a char in 5 steps
[SET]         write a char
[+/-]         delete a char
[UP]          Selection uppercase, lowercase and special cases
[DOWN]        return to first char (a)
[MENU]        ready and go to the second Menu
second consol menu

display the input

[SET]         return to new input
[DISP]        write the input name as folder and close the script
[MENU]        close the script
Attention

Do not use any illegal folder names - you may lose data or the filesystem could be corrupted !


--[[
rem 26-Oct-2008 by msl
@title char input
@param f key delay
@default f 200
]]
 
key_delay = f
output=""
 
function button()
 local x = 0
 repeat
 wait_click(key_delay)
  if is_pressed "remote" then
   key = "REMOTE"
   x = 1
  end
  if is_pressed "set" then
   key = "SET"
   x = 1
  end
  if is_pressed "erase" then
   key = "ERASE"
   x = 1
  end
  if is_pressed "display" then
   key = "DISP."
   x = 1
  end
  if is_pressed "menu" then
   key = "MENU"
   x = 1
  end
  if is_pressed "up" then
   key = "UP"
   x = 1
  end
  if is_pressed "down" then
   key = "DOWN"
   x = 1
  end
  if is_pressed "left" then
   key = "LEFT"
   x = 1
  end
  if is_pressed "right" then
   key = "RIGHT"
   x = 1
  end
  if is_pressed "zoom_in" then
   key = "ZOOM_IN"
   x = 1
  end
  if is_pressed "zoom_out" then
   key = "ZOOM_OUT"
   x = 1
  end
 until  x == 1
 set_led (8,1)
 sleep (10)
 set_led (8,0)
end
 
function tabToStr()
	output=table.concat(word)
end
 
function input()
 
	abc_lower = {"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p",
								"q","r","s","t","u","v","w","x","y","z"}
	abc_upper = {"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P",
								"Q","R","S","T","U","V","W","X","Y","Z"}
	abc_spec = {"0","1","2","3","4","5","6","7","8","9",",",".","-",";",":","_",
							"/",".JPG",".CRW",".CR2",".THM",".WAV",".LUA",".BAS",".TXT"," "}
	word = {}
	a=0
	b=0
	actChar=""
	repeat
		print("[<-][->][SET] [+/-][MENU]")
		print("[ZOOM in/out]  [UP][DOWN]")
		button()
    cls()
    if key == "RIGHT" then a=a+1 end
    if key == "LEFT" then a=a-1 end
    if key == "UP" then b=b+1 end
    if key == "DOWN" then a=1 end
    if key == "ZOOM_IN" then a=a+5 end
    if key == "ZOOM_OUT" then a=a-5 end
    if a >= 27 then a=1 end
    if a <= 0  then a=26 end
    if b>=3 then b=0 end
    if b==0 then
			actChar=abc_lower[a]
			char_info="lower case"
		end
		if b==1 then
			actChar=abc_upper[a]
			char_info="upper case"
		end
		if b==2 then
			actChar=abc_spec[a]
			char_info="special char"
		end
		print(char_info..": "..actChar)
    if key == "SET" then table.insert(word,actChar) end
    if key == "ERASE" then table.remove(word) end
    tabToStr()
    print("input: "..output)
    print (" ")
  until key == "MENU"
end
 
function make_dir(dirname)
	os.mkdir(dirname)
end
 
 
x=0
repeat
  input()
  cls()
  print("INPUT: "..output)
  print("[SET]  new input")
  print("[DISP] make dir and stop")
  print("[MENU] stop")
  button()
  if key == "SET" then cls() end
  if key == "DISP." then
	  dir = "A/"..output
	  make_dir(dir)
	  print "ready"
	  sleep(3000)
	  x=1
  end
  if key == "MENU" then
		print "ready"
	  sleep(3000)
	  x=1
  end
until x==1
 
--[[
 
***possible commands***
 
function make_dir(dirname)
	os.mkdir(dirname)
end
 
function delete_dir(dirname)
	os.remove(dirname)
end
 
function rename_file(old_filename, new_filename)
	os.rename(old_filename, new_filename)
end
 
function delete_file(filename)
	os.remove(filename)
end
 
***missing commands***
 
-os.list_dir
 
]]


Universal Tv mode

This is a script for a enhanced tv mode. It should work with all cameras, even with models with or without tv mode.

It was released by 'msl' in the CHDK forum in this post,a german version is available at www.wirklemms.de

  • You can select a Tv value from 64s to 1/10000s
  • The zoom can be used while running the script
  • You can select a focus mode
  • Continuous shooting is also possible

Using the script:

The console menu:
[<-][->]       select a Tv value
[UP][DOWN]     zooming
[DISP.]        select a focus mode
[SET][Remote]  shooting
[MENU]         exit

In the script parameter menu you can adjust the start Tv value, the key delay and the shoot delay.

--[[
rem 26-Oct-2008 by msl 
@title Tv mode universal
@param a integer value  [Tv]
@default a 0
@param b key delay [ms]
@default b 80
@param c shoot delay [s]
@default c 0
]]
 
function print_Tv()
	tv_output = {"64s","50s","40s","32s","25s","20s","15s","13s","10s","8s","6s",
	"5s","4s","3.2s","2.5s","2s","1.6s","1.3s","1s","0.8s","0.6s","0.5s","0.4s",
	"0.3s","1/4s","1/5s","1/6s","1/8s","1/10s","1/13s","1/15s","1/20s","1/25s",
	"1/30s","1/40s","1/50s","1/60s","1/80s","1/100s","1/125s","1/160s","1/200s",
	"1/250s","1/320s","1/400s","1/500s","1/640s","1/800s","1/1000s","1/1250s",
	"1/1600s","1/2000s","1/2500s","1/3200s","1/4000s","1/5000s","1/6400s",
	"1/8000s","1/10000s"}
	print_tv = "Tv  : "..tv_output[tv_input+19]
end 
 
function mf_mode()
	mf_output = {"normal","macro","","infinite"}
	print_mf = "focus: "..mf_output[mf_input]
end
 
function button()
	local x = 0
	repeat
	wait_click(key_delay)
	if is_pressed "remote" then
	  key = "SET"
	  x = 1
	end
	if is_pressed "set" then
		key = "SET"
		x = 1
	end
	if is_pressed "menu" then
		key = "MENU"
		x = 1
	end
	if is_pressed "display" then
		key = "DISP"
		x = 1
	end
	if is_pressed "left" then
		key = "LEFT"
		x = 1
	end
	if is_pressed "right" then
		key = "RIGHT"
		x = 1
	end
	if is_pressed "up" then
		key = "UP"
		x = 1
	end
	if is_pressed "down" then
		key = "DOWN"
		x = 1
	end
	until  x == 1
	set_led (8,1)
	sleep (10)
	set_led (8,0)
end 
 
--script start
 
if a < -18 then a = -18 end
if a > 40 then a = 40 end
if b < 50 then b = 50 end
if c < 0 then c = 0 end
tv_input = a
key_delay = b
shoot_delay = c
max_zoom = get_zoom_steps()
zoom = get_zoom()
 
repeat
	if get_propset() == 2 then
		mf_input = get_prop(6)+1
	else
		mf_input = get_prop(11)+1
	end
	cls()
	print_Tv()
	mf_mode()
	print("[<-][->]  ",print_tv)
	print("[Up][Down] zoom:",zoom.."/".. max_zoom)
	print("[DISP.]  ",print_mf)
	print("[SET] [Remote]   shoot")
	print("[MENU]           exit")
	button()
 
	if key == "DISP" then
		mf_input = mf_input + 1
		if mf_input == 3 then mf_input = 4 end
		if mf_input == 5 then mf_input = 1 end
		if get_propset() == 2 then
			set_prop(6,mf_input-1)
		else
			set_prop(11,mf_input-1)
		end
	end
	if mf_input == 2 then
		set_zoom(0)
	else
		if key == "UP"  then
			zoom = zoom + 1
			if zoom > max_zoom then zoom = max_zoom end
			set_zoom(zoom)
		end
		if key == "DOWN" then
			zoom = zoom - 1
			if zoom < 0 then zoom = 0 end
			set_zoom(zoom)
		end
	end
	if key == "RIGHT" then tv_input = tv_input + 1 end
	if key == "LEFT" then tv_input = tv_input - 1 end
	if tv_input > 40 then tv_input = -18 end
	if tv_input < -18 then tv_input = 40 end
	if key == "SET" then
		if shoot_delay > 0 then
			cls()
			print("wait "..shoot_delay.." s")
			sleep(shoot_delay * 1000) 
		end
		TV = tv_input * 32
		press "shoot_half"
		repeat
		      until get_shooting() == true
		if get_propset() == 2 then
			set_prop(262,TV)
		else
			set_prop(69,TV)
		end
		press "shoot_full"
		release "shoot_full"
		release "shoot_half"
	end
until key == "MENU"

Listdir sample

This scripts demonstrates the usage of os.listdir, scroll down the list with any key...

--[[
@title Listdir
rem 10-11-2008 by msl
--]]

dir = os.listdir("A/CHDK", true) --'true' shows also . and ..
count = table.getn(dir)
x = 0
for i=1, count do
	print(i..".",dir[i])
	x = x + 1
	if x == 4 then
		wait_click(0)
		x = 0
	end
end
print("------------") -- end of the list
sleep(3000)
wait_click(0)


Lotto demo

This script is a little mathematical demo.

--Example lua script that generates random numbers in various ways.
--idea & code by PhyrePhoX and msl
--[[
@title lotto demo
@param n how many
@default n 6
@param r max
@default r 49
@param s min
@default s 1
@param e exclusive 1=on
@default e 1
@param o sort
@default o 1
@param z sound 1=on
@default z 1
]]

--The comment block above will be read as parameters. 

--Declare a function for key request with led and sound feedback

function button()                                     -- declare function
	local x = 0                                   -- local variable only valid for this function
	repeat                                        -- start loop
		wait_click(150)                       -- wait for key klick
		if is_pressed "set" then              -- check which key ist pressed
			key = "SET"
			x = 1
		end
		if is_pressed "menu" then
			key = "MENU"
			x = 1
		end
	until  x == 1                                 -- end of loop
	set_led (8,1)                                 -- led feedback
	sleep (10)
	set_led (8,0)
	if sound == 1 then play_sound(4) end          -- sound feedback if set
end

--Start script

--Declare usefull variable names for the parameter variables

count     = n
min       = s
max       = r
exclusive = e
order     = o
sound     = z

--Check parameters, if wrong ending the script

if (min >= max) then
	print("Wrong params, dumbass!;-)")
	wait_click(0)
	else
	if ((exclusive == 1) and ((max - min + 1)<count)) then
		print("Wrong params, dumbass!;-)")
		wait_click(0)
		else

--If parameters ok start the main loop to dice

		repeat
		  result= {}                                             -- create a table for result
			if exclusive == 1 then                           -- if exclusive is set
				array = {}                               -- create a table for mix
				for i = min, max do                      -- loop for fill the table
					array[i] = i
				end
				for i = min, max do                      -- loop for mix the table
					rnd = math.random(min, max)      -- create a random number
					buffer = array[i]                -- change a number in the table
					array[i] = array[rnd]
					array[rnd] = buffer
				end
				for c=1, count do                        -- loop for output the result
					result[c] = array[c]
				end
			else
				for i = min, max do                      -- loop for no exclusive result
					result[i] = math.random(min, max)-- create a random number
				end
			end

--Output the result

			if order == 1 then table.sort(result) end -- order result if set
			output = table.concat(result,", ")        -- create a string of the table
   		        print("dice [SET]     end [MENU]")        -- output in console
			print()
			print(output)                             -- print a string variable
			button()                                  -- call the function
			cls()                                     -- clear the console
		until key == "MENU"                               -- end of loop if pressed "MENU"
end                                             -- "SET" repeat the loop
end

--All functions, conditions and loops (except repeat) will closing with end

TagMe, the Lua EXIF tagger

This script allows a user to select a text from a configurable list of text strings and write this string into the EXIF UserComment tag for a list of images

  • The functions for reading and modifying the EXIF information are in a seperate module EXIF.lua which can be imported and reused in other scripts
  • The script is excellent commented, the download package also includes a very good user's guide
  • There are lots of useful functions and informations in the script and the exif module
  • It nicely demonstrates advanced Lua programming technics
The download package, including the script, the exif lib and the documentation (in english & german) is available from here

RAW development

Since CHDK version 0.8.4 there are some new commands to merge/develop RAW images directly in the camera, read Lua Reference: RAW development for more informations.

There's also a script to demonstrate the usage of this new feature: Lua Reference: Sample test script