This is one tiny step to improve upon that: I'd like to write a series of guides on how to write your own modules and how to use various APIs provided by Magic Lantern (some of them tightly related to APIs reverse engineered from Canon firmware, such as properties or file I/O, others less so, such as ML menu).
Will start with the simplest possible module:
Let's start from scratch:
hg clone -u unified https://bitbucket.org/hudson/magic-lantern
Now edit hello.c in your favorite text editor:
/* A very simple module
* (example for module authors)
/* Config variables. They are used for persistent variables (usually settings).
* In modules, these variables also have to be declared as MODULE_CONFIG.
static CONFIG_INT("hello.counter", hello_counter, 0);
/* This function runs as a new DryOS task, in parallel with everything else.
* Tasks started in this way have priority 0x1A (see run_in_separate_task in menu.c).
* They can be interrupted by other tasks with higher priorities (lower values)
* at any time, or by tasks with equal or lower priorities while this task is waiting
* (msleep, take_semaphore, msg_queue_receive etc).
* Tasks with equal priorities will never interrupt each other outside the
* "waiting" calls (cooperative multitasking).
* Additionally, for tasks started in this way, ML menu will be closed
* and Canon's powersave will be disabled while this task is running.
* Both are done for convenience.
static void hello_task()
/* Open the console. */
/* Also wait for background tasks to settle after closing ML menu */
/* Plain printf goes to console. */
/* There's very limited stdio support available. */
printf("You have run this demo %d times.\n", ++hello_counter);
printf("Press the shutter halfway to exit.\n");
/* note: half-shutter is one of the few keys that can be checked from a regular task */
/* to hook other keys, you need to use a keypress hook - see hello2 */
/* while waiting for something, we must be nice to other tasks as well and allow them to run */
/* (this type of waiting is not very power-efficient nor time-accurate, but is simple and works well enough in many cases */
/* Finished. */
static struct menu_entry hello_menu =
.name = "Hello, World!",
.select = run_in_separate_task,
.priv = hello_task,
.help = "Prints 'Hello, World!' on the console.",
/* This function is called when the module loads. */
/* All the module init functions are called sequentially,
* in alphabetical order. */
static unsigned int hello_init()
menu_add("Debug", hello_menu, COUNT(hello_menu));
/* Note: module unloading is not yet supported;
* this function is provided for future use.
static unsigned int hello_deinit()
/* All modules have some metadata, specifying init/deinit functions,
* config variables, event hooks, property handlers etc.
We still need a Makefile; let's copy it from another module:
cp ../ettr/Makefile .
sed -i "s/ettr/hello/" Makefile
Let's compile it:
The build process created a file named README.rst. Update it and recompile.
make clean; make
Now you are ready to try your module in your camera. Just copy the .mo file to ML/MODULES on your card.
If your card is already configured for the build system, all you have to do is:
make install CF_CARD=/path/to/your/card
or, if you have such device:
make install WIFI_SD=y
That's it for today.
To decide what to cover in future episodes, I'm looking for feedback from anyone who tried (or wanted to) write a ML module, even if you were successful or not.
- printing on the screen (bmp_printf, NotifyBox)
- keypress handlers
- more complex menus
- properties (Canon settings)
- file I/O
- status indicators (lvinfo)
- animations (e.g. games)
- capturing images
- GUI modes (menu, play, LiveView, various dialogs)
- semaphores, message queues
- DryOS internals (memory allocation, task creation etc)
- custom hooks in Canon code
- your ideas?
Of course, the advanced topics are not for second or third tutorial.