In this page I'm trying to understand the Magic Lantern structure and document its API.

Related: Extending Magic Lantern

API docs generated by Doxygen:


5d-hack.c[edit | edit source]

It seems that 5d-hack.c also works on the 550D, so renaming it might remove a tiny amount of confusion.

audio.h and audio.c[edit | edit source]

int16_t audio_read_level(int channel)[edit | edit source]

Read the raw level from the audio device. Expected values are signed 16-bit?

  • channel: 0 (left) or 1 (right)

How it works: reads the value from 0xC0920000 + 0x110.

uint8_t audio_ic_read(unsigned cmd)[edit | edit source]

void audio_ic_write(unsigned cmd)[edit | edit source]

Read and write commands to the AK4646. These two functions are wrappers to DryOS APIs _audio_ic_read and _audio_ic_write.

Datasheet for the AK4646 audio chip is here: Datasheets

According to this post, both 550D and 5D use the AK4646 chip, or a compatible one.

I believe the first two bytes (MSB) of cmd are the address of the audio registers, and the last two bytes are the value written there.

Audio registers:

#define AUDIO_IC_PM1	0x2000
#define AUDIO_IC_PM2	0x2100
#define AUDIO_IC_SIG1	0x2200
#define AUDIO_IC_SIG2	0x2300
#define AUDIO_IC_ALC1	0x2700
#define AUDIO_IC_ALC2	0x2800
#define AUDIO_IC_IVL	0x2900
#define AUDIO_IC_IVR	0x2C00
#define AUDIO_IC_OVL	0x2A00
#define AUDIO_IC_OVR	0x3500
#define AUDIO_IC_ALCVOL	0x2D00
#define AUDIO_IC_MODE3	0x2E00
#define AUDIO_IC_MODE4	0x2F00
#define AUDIO_IC_PM3	0x3000
#define AUDIO_IC_FIL1	0x3100
#define AUDIO_IC_HPF0	0x3C00
#define AUDIO_IC_HPF1	0x3D00
#define AUDIO_IC_HPF2	0x3E00
#define AUDIO_IC_HPF3	0x3F00
#define AUDIO_IC_LPF0	0x6C00
#define AUDIO_IC_LPF1	0x6D00
#define AUDIO_IC_LPF2	0x6E00
#define AUDIO_IC_LPF3	0x6F00

Sample code from audio.c:

./audio.c:515:	audio_ic_write( AUDIO_IC_PM1 | 0x6D ); // power up ADC and DAC
./audio.c:527:	audio_ic_write( AUDIO_IC_PM3 | 0x00 ); // internal mic
./audio.c:529:	audio_ic_write( AUDIO_IC_PM3 | 0x07 ); // external input
./audio.c:532:	audio_ic_write( AUDIO_IC_ALC1 | gain.alc1 ); // disable all ALC

void audio_ic_set_input_volume(int channel, int gain)[edit | edit source]

  • channel: 0 or 1
  • gain: in DB.
./audio.c:537:	audio_ic_set_input_volume( 0, dgain_r );
./audio.c:538:	audio_ic_set_input_volume( 1, dgain_l );

dgain_r and dgain_l are audio.dgain.r and audio.dgain.l from magic.cfg (0 by default).

This is defined in audio.c. To use it, you have to declare it in audio.h.

void audio_ic_set_mgain(unsigned bits)[edit | edit source]

/** Write the MGAIN2-0 bits.
 * Table 19 for the gain values:
 *       0 == +0 dB
 *       1 == +20 dB
 *       2 == +26 dB
 *       3 == +32 dB
 *       4 == +10 dB
 *       5 == +17 dB
 *       6 == +23 dB
 *       7 == +29 dB
 * Why is it split between two registers?  I don't know.

mgain is audio.mgain from magic.cfg, and the default value is 4 (i.e. 10 dB).

This is defined in audio.c. To use it, you have to declare it in audio.h.

What is mgain? Some kind of master gain, for both channels?

bmp.h and bmp.c[edit | edit source]

void bmp_printf(fontspec, x, y, const char * fmt, ...)[edit | edit source]

This is printf at (x,y) with a given font.

  • fontspec: FONT_HUGE, FONT_LARGE, FONT_MED or FONT_SMALL. You can include color info, too.
  • x and y: coordinates of the text, in pixels, unsigned. (0,0) is on the upper left corner.
  • fmt: the same like printf. Handles newlines.

To print in colors, use the FONT macro, defined in bmp.h:


Color example from AJ:

bmp_printf( FONT(FONT_SMALL,COLOR_RED,COLOR_BG), 000, g_bmp_height-16,
                     "AJ: XYC range. x=%d y=%d c=%d ",x,y,colour);

List of colors (bmp.h):

/** Some selected colors */
#define COLOR_EMPTY		0x00 // total transparent
#define COLOR_BG		0x14 // transparent gray
#define COLOR_BG_DARK		0x03 // transparent black
#define COLOR_WHITE		0x01 // Normal white
#define COLOR_BLUE		0x0B // normal blue
#define COLOR_RED		0x08 // normal red
#define COLOR_YELLOW		0x0F // normal yellow

uint8_t * bmp_vram(void)[edit | edit source]

Returns Bitmap overlay VRAM address (bvram).

  • Pixel format: 8-bit fixed palette (see VRAM and Cropmarks).
  • Size: bmp_width() x bmp_height() pixels (720x480).
  • Pitch (size of a scanline in memory): pitch = bmp_pitch() => 960
  • Addressing mode (how to get the address of a pixel):
first_row = bvram + y * pitch + x;

void bmp_fill(color, x, y, w, h);[edit | edit source]

  • color: uint8_t
  • x,y,w,h: uint32_t (these numbers describe a rectangle)
  • Fill a section of bitmap memory with solid color. Only has a four-pixel resolution in X.
  • Is there a color palette? Yes! (see the VRAM and Cropmarks pages)

struct bmp_file_t* bmp_load(const char * name);[edit | edit source]

Load a BMP file into memory so that it can be drawn on screen. Used for cropmarks.

  • How to draw it on screen? Pixel by pixel, on the BMP overlay. The code is in zebra.c.

property.h and property.c[edit | edit source]

void prop_request_change(unsigned property, void* addr, size_t len)[edit | edit source]

Change a property. This is a DryOS call.

  • property: an ID from the List of Properties (they are declared in property.h)
  • addr: pointer to the new property value
  • len: size of the value located at addr
  • What data type do properties have? I believe most of them are integers or strings. The list of properties do not specify the data type.

Example code from lens.h:

static inline void lens_set_aperture(unsigned aperture) 
    prop_request_change( PROP_APERTURE, &aperture, sizeof(aperture) ); 

#define PROP_HANDLER(id)[edit | edit source]

Use this to get notified when a property changes. This macro allows you to declare a function which is called automatically (something like interrupts).

Example code from lens.c:

        const uint32_t raw = *(uint32_t *) buf;
        lens_info.raw_iso = raw;
        lens_info.iso = raw/2 < COUNT(iso_values)
                ? iso_values[ raw / 2 ]
                : 0;
        return prop_cleanup( token, property );

void prop_get_value(unsigned property, void * addr, size_t * len);[edit | edit source]

Parameters: same as prop_request_change. This is a DryOS call, only identified in 5D2/1.1.0. Not sure if it works in 550D.

todo: Does initial value of len matter?

lens.c and lens.h[edit | edit source]

Control ISO, shutter, aperture and stuff like that.

Semaphores[edit | edit source]

lens_sem = create_named_semaphore( "lens_info", 1 ); 
focus_done_sem = create_named_semaphore( "focus_sem", 1 ); 
job_sem = create_named_semaphore( "job", 1 );

Functions[edit | edit source]

void lens_set_aperture(unsigned aperture)[edit | edit source]

  • aperture: see lens.h for possible values. There are macros like APERTURE_1_8, APERTURE_4_0 and so on.

void lens_set_iso(unsigned iso)[edit | edit source]

  • iso: see lens.h for possible values. There are macros from ISO_100 to ISO_12500.

void lens_set_shutter(unsigned shutter)[edit | edit source]

  • shutter: see lens.h for possible values. There are macros from SHUTTER_30 to SHUTTER_4000.

void lens_set_ae(int cmd)[edit | edit source]

Exposure compensation?

  • cmd: it seems to be the desired exposure, in EV, or 1/3 EV, or something like this. Not sure.

int lens_get_ae(void)[edit | edit source]

// This is currently broken. Returns 0.

int lens_take_picture(int wait)[edit | edit source]

Takes a picture.

  • wait: number of milliseconds to wait (this is a timeout)

Internally, this function calls:

call( "Release" );

and does a bit of black magic with some semaphores.

uint16_t bswap16(uint16_t val)[edit | edit source]

bswap16(0xABCD) => 0xCDAB

menu.h and menu.c[edit | edit source]

See How to create a menu

ptp.h and ptp.c[edit | edit source]

These files contain macros and functions for extending PTP capabilities of the camera.

Until I understand how this works, see the PTP page.

It would be nice to create some Python wrappers for these capabilities. See Remote_control_with_PTP_and_Python. I'll try to create some Python bindings for Mweerden's patched libptp/ptpcam. Also, I'd like to be able to upload files on the camera via PTP and to poke/peek memory locations. CHDK does this afaik.

tasks.h[edit | edit source]

#define INIT_FUNC(NAME, ENTRY)[edit | edit source]

Define an initialization function, which is executed at firmware startup (I think so).

  • NAME: a string, used in debug messages
  • ENTRY: pointer to a function with this signature: static void functionname(void)

These init functions are called here:

  • [5d-hack.c] my_init_task -> menu_init -> call_init_funcs

#define TASK_CREATE(NAME, ENTRY, ARG, PRIORITY, FLAGS)[edit | edit source]

Creates a task which runs in parallel with the Canon firmware. Each feature in ML seems to have its own task: focus_task, bracket_task, dump_task, zebra_task, menu_task and so on.

  • NAME: a string, used in debug messages.
  • ENTRY: pointer to a function with this signature: static void functionname(void)
  • ARG: it seems unused, and always 0.
  • PRIORITY: Task priority. Values from ML code: 0x10, 0x18, 0x1e, 0x1f. I don't know whether higher values mean higher priority or viceversa. [AJ: 0x1F = 31 is the lowest prioriity. Example task priorities ]
  • FLAGS: 0x1000 (I don't know what that means)

The tasks are started in 5d-hack.c, in my_init_task, AFTER call_init_funcs, with several calls to task_create, which is a function from the Canon code.

#define TASK_OVERRIDE(orig_func, replace_func)[edit | edit source]

This REPLACES a Canon task with some custom function from Magic Lantern. I don't understand how it does that, but it works!!!

$ grep -nr "TASK_OVERRIDE" ./
./tasks.h:107:#define TASK_OVERRIDE( orig_func, replace_func ) \
./hotplug.c:68:TASK_OVERRIDE( hotplug_task, my_hotplug_task );
./gui.c:221:TASK_OVERRIDE( gui_main_task, my_gui_main_task );
./audio.c:876:TASK_OVERRIDE( sounddev_task, my_sounddev_task );
./audio.c:977:TASK_OVERRIDE( audio_level_task, my_audio_level_task );
Community content is available under CC-BY-SA unless otherwise noted.