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:
- for 5D: http://a1ex.bitbucket.org/ML/5D/index.html
- for 550D: http://a1ex.bitbucket.org/ML/550D/index.html
5d-hack.c[]
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[]
int16_t audio_read_level(int channel)[]
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)[]
void audio_ic_write(unsigned cmd)[]
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)[]
- 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)[]
/** 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[]
void bmp_printf(fontspec, x, y, const char * fmt, ...)[]
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:
FONT(font,fg,bg)
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)[]
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);[]
- 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);[]
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[]
void prop_request_change(unsigned property, void* addr, size_t len)[]
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)[]
Use this to get notified when a property changes. This macro allows you to declare a function which is called automatically (something like interrupts).
- id: an ID from the List of Properties (they are declared in property.h)
Example code from lens.c:
PROP_HANDLER( PROP_ISO ) { 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);[]
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[]
Control ISO, shutter, aperture and stuff like that.
Semaphores[]
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[]
void lens_set_aperture(unsigned aperture)[]
- 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)[]
- iso: see lens.h for possible values. There are macros from ISO_100 to ISO_12500.
void lens_set_shutter(unsigned shutter)[]
- shutter: see lens.h for possible values. There are macros from SHUTTER_30 to SHUTTER_4000.
void lens_set_ae(int cmd)[]
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)[]
// This is currently broken. Returns 0.
int lens_take_picture(int wait)[]
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)[]
bswap16(0xABCD) => 0xCDAB
[]
ptp.h and ptp.c[]
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[]
#define INIT_FUNC(NAME, ENTRY)[]
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)[]
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 http://magiclantern.wikia.com/wiki/2.0.4_Tasks ]
- 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)[]
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 );