Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Topics - a1ex

Pages: [1] 2 3 ... 6
Reverse Engineering / Interrupt IDs
« on: January 23, 2018, 07:16:12 PM »
After writing these notes (in particular, the section about interrupts), I've noticed we didn't document what all these interrupts are used for. This info is interesting for emulation and understanding how Canon code works; they are not used directly in ML code.

So, here's my first attempt to list all the interrupts we know about. Sources of info:

- startup-logs or emulation logs with register_interrupt calls enabled (some have names in Canon code):
Code: [Select]
grep --text -nro " register_interrupt(.*)" startup-logs/ tests/*/gdb.log | grep -o register_interrupt.*

- interrupts declared in QEMU, model_list.c
Code: [Select]
cat qemu-2.5.0/hw/eos/model_list.c | grep -o "\..*interrupt.*=.*,"

- interrupts scattered in QEMU source: eos_trigger_int (either hardcoded IDs or arrays)
Code: [Select]
FILES=$(cat qemu-2.5.0/hw/eos/Makefile.objs | grep -E "eos/\w+.o" | grep -oE "\w+.o" | cut -d . -f 1 | sed -e 's/$/.c/' | sed -e 's!^!qemu-2.5.0/hw/eos/!')
cat $FILES | grep "eos_trigger_int\|^\w.*(" | grep -B 1 eos_trigger_int
cat $FILES | grep -zoE " [a-zA-Z_]*interrupt[a-zA-Z]*\[[^[]*] = {[^{]*}" | tr "\\n" " " | tr "\\0" "\\n"

- Omar interrupts

Results (machine output, take with a grain of salt):

Code: [Select]
0x03: WdtInt
0x09: dryos_timer
0x0A: dryos_timer
0x0D: Omar
0x0E: UTimerDriver
0x10: OC4_14, hptimer
0x18: hptimer
0x19: OCH_SPx
0x1A: OCH_SPx, hptimer
0x1B: OCHxEPx, dryos_timer
0x1C: OCH_SPx, Omar, hptimer
0x1D: OCHxEPx
0x1E: OCH_SPx, UTimerDriver, hptimer
0x1F: OCHxEPx
0x20: ICAPCHx
0x21: ICAPCHx
0x22: ICAPCHx
0x23: ICAPCHx
0x24: ICAPCHx
0x25: ICAPCHx
0x26: ICAPCHx
0x27: ICAPCHx
0x28: OC4_14, hptimer
0x29: OCHxEPx, sd_dma
0x2A: MREQ_ISR, mpu_mreq
0x2C: DmaAD
0x2D: DmaDA, Omar
0x2E: UTimerDriver, uart_rx
0x2F: BLTDMA, BLTDMAC0, BltDmac, dma
0x30: CFDMADriver, cf_dma
0x32: SDDMADriver, SdDmaInt, sd_dma
0x35: SlowMossy
0x36: SIO3_ISR, mpu_sio3
0x37: INTC_SIO4
0x38: uart_rx
0x39: OCH_SPx, uart_rx
0x3A: uart_tx
0x3C: Omar
0x3E: UTimerDriver
0x41: WRDMAC1
0x42: ASIFAdc
0x43: ASIFDac
0x49: OCHxEPx
0x4A: CFDriver, MREQ2_ICU, cf_driver, sd_driver
0x4B: SDDriver, SdConInt, sd_driver
0x4D: Omar
0x4E: UTimerDriver
0x52: IMGPOWDET, MREQ_ISR, mpu_mreq
0x58: EDmacWR0, WEDmac0, edmac
0x59: EDmacWR1, OCH_SPx, WEDmac1, edmac
0x5A: EDmacWR2, LENSIF_SEL, WEDmac2, edmac
0x5B: EDmacWR3, WEDmac3, edmac
0x5C: EDmacWR4, Omar, WEDmac4, edmac
0x5D: EDmacRD0, REDmac0
0x5E: EDmacRD1, REDmac1, UTimerDriver, edmac
0x5F: EDmacRD2, REDmac2, edmac
0x60: CompleteReadOperation
0x61: AfComplete
0x62: AfOverRun
0x63: Obinteg
0x64: JP51_INT_R, JpCore, jpcore
0x65: ADKIZ, ADMERG, IntDefectCorrect, prepro_execute
0x66: Integral, WB Integ, WbInteg
0x67: Block, WbBlock
0x68: EngInt PBVD, Engine PB VD, PB_VD, display
0x69: EngInt PBERROR, EngInt PBVD, OCHxEPx, PB_ERR, Pb error
0x6A: HEAD1, Head1, head
0x6B: HEAD2, Head2, head
0x6C: HEADERROR, HeadError
0x6D: EDmacWR5, Omar, WEDmac5, edmac
0x6E: EDmacRD3, REDmac3, UTimerDriver, edmac
0x70: HarbInt
0x74: BLTDMA, BLTDMAC1, BltDmac, dma
0x75: BltDmac, dma
0x76: BltDmac, dma
0x79: OCH_SPx
0x7A: XINT_7
0x7C: Omar
0x7E: UTimerDriver
0x82: CFDriver, cf_driver
0x83: WEDmac8, edmac
0x89: OCHxEPx
0x8A: INT_LM, WEDmac9, edmac
0x8B: REDmac6
0x90: WEDmac6
0x91: REDmac4
0x92: REDmac5, REDmac7, edmac
0x93: CompleteOperation
0x95: edmac
0x96: REDmac10, edmac
0x97: REDmac11, edmac
0x98: CAMIF_0
0x99: OCH_SPx
0x9A: CompleteOperation
0x9C: Omar, SEQ
0x9E: REDmac13, edmac
0x9F: edmac
0xA0: BltDmac, EekoBltDmac, dma
0xA1: BltDmac, EekoBltDmac, dma
0xA3: Jp57, JpCore2
0xA5: RDDMAC15, edmac
0xA8: BltDmac, CAMIF_1, dma
0xA9: BltDmac, OCHxEPx, dma
0xAA: CompleteOperation
0xB1: SDDriver, sd_driver
0xB2: OCH_SPx
0xB3: OCH_SPx
0xB8: CFDMADriver, SDDMADriver, sd_dma
0xB9: OCH_SPx
0xBC: Omar
0xBE: SdDmaInt0, sd_dma
0xC0: WEDmac6, edmac
0xC1: REDmac4, edmac
0xC8: REDmac5, edmac
0xC9: Fencing_A, OCHxEPx
0xCA: INT_LM, WEDmac10, edmac
0xCB: WEDmac11, edmac
0xCD: Omar
0xCE: SerialFlash
0xD0: Fencing_B
0xD1: Fencing_C
0xD2: WEDmac12, edmac
0xD3: WEDmac13, edmac
0xD9: HEAD3, Head3, ICAPCHx, head
0xDA: WEDmac14
0xDB: WRDMAC15, edmac
0xDC: Omar
0xDE: SerialFlash
0xE0: HEAD4, head
0xE1: SsgStopIrq
0xE2: REDmac8, edmac
0xE3: CFDMADriver, cf_dma
0xE4: GaUSB20Hal
0xEE: SdConInt0, sd_driver
0xF9: ICAPCHx, WEDmac7
0xFC: OCH_SPx, Omar
0xFE: SerialFlash, dryos_timer, serial_flash
0x102: RDDMAC13
0x109: ICAPCHx
0x10C: BltDmac
0x10E: SerialFlash
0x111: Eeko WakeUp
0x119: ICAPCHx
0x129: ICAPCHx
0x12A: mpu_mreq
0x139: ICAPCHx
0x13E: xdmac
0x140: ICOCCHx
0x141: ICAPCHx
0x142: ICAPCHx
0x147: SIO3_ISR, mpu_sio3
0x148: ICAPCHx
0x149: ICAPCHx
0x14A: ICAPCHx
0x14E: xdmac
0x150: ICAPCHx
0x151: ICAPCHx
0x152: ICAPCHx
0x158: OCH_SPx
0x159: ICAPCHx, OCH_SPx
0x15A: OCH_SPx
0x15D: uart_rx
0x15E: xdmac
0x162: SerialFlash
0x169: ICAPCHx
0x16D: uart_tx
0x16E: xdmac
0x171: SDDMADriver, sd_dma
0x172: SDDriver, sd_driver
0x179: ICAPCHx
0x17B: SerialFlash, serial_flash
0x189: ICAPCHx
0x18B: WdtInt


- group by camera generation, DIGIC version etc
- other sources of info (such as strings present in the interrupt handling function, or other notes about them)
- brute-force interrupts (trigger manually) and see what the firmware is trying to do
- auto-build the above list on Jenkins (so it will be always up to date, at least with QEMU sources)

Following this request, I've decided to revive the old filepref module. Renamed it to

- custom image file prefix (IMG_1234.JPG -> ABCD1234.JPG; from the old filepref module)
- change image file number to any value (IMG_1234.JPG -> IMG_5678.JPG; experimental, restart required)

- timestamped file names (original request). Please don't expect it anytime soon - I don't know how to change the file number (last 4 characters) without restart. Maybe you can figure it out?
- date-stamped file names? (MMDD1234). This one might be easier; still need to find out how to reset the counter.
- continuous numbering? (12349999 -> 12350000, ABCD9999 -> ABCE0000). This one should be easy.
- customize folder number? (didn't try, but noticed the property in QEMU).

Known/possible issues:
- on 5D3, Canon file naming options must be set to default.
- might conflict with Dual ISO custom file naming (not tested).
- only tested on 5D3 and 60D.

- Image file prefix is also available to Lua (lua_fix builds)

Binary: (only the first feature works; the second one requires a custom ML build)

Reverse Engineering / TFT SIO communication (
« on: November 26, 2017, 03:51:30 PM »
Some notes after looking into this.

QEMU logs: zip

How I've got them:
Code: [Select]
make -C ../magic-lantern/60D_install_qemu
./ 60D,firmware="boot=1" -d debugmsg,io
# same for 600D, 650D, 700D, 70D
In ML menu, selected Display -> Advanced -> Orientation -> Normal/Mirror/Reverse, then copied the console output. Had to silence a few things in QEMU to get clean logs. The important lines are those like this:
Code: [Select]
[  DisplayMgr:ff0611b4 ] (82:02) SIO [3]:0xf01d

60D, 600D:
Code: [Select]
[ GuiMainTask:ff325714 ] (04:03) -->Mirror start
[  DisplayMgr:ff0611b4 ] (82:02) SIO [0]:0x1000
[  DisplayMgr:ff0611b4 ] (82:02) SIO [1]:0xbe01
[  DisplayMgr:ff0611b4 ] (82:02) SIO [2]:0xe401
[  DisplayMgr:ff0611b4 ] (82:02) SIO [3]:0xf01d
[ GuiMainTask:ff325774 ] (04:03) -->Normal start
[  DisplayMgr:ff0611b4 ] (82:02) SIO [0]:0x1001
[  DisplayMgr:ff0611b4 ] (82:02) SIO [1]:0xbe01
[  DisplayMgr:ff0611b4 ] (82:02) SIO [2]:0xe401
[  DisplayMgr:ff0611b4 ] (82:02) SIO [3]:0xf01d
[ GuiMainTask:ff325744 ] (04:03) -->Reverse start
[  DisplayMgr:ff0611b4 ] (82:02) SIO [0]:0x1000
[  DisplayMgr:ff0611b4 ] (82:02) SIO [1]:0xbe01
[  DisplayMgr:ff0611b4 ] (82:02) SIO [2]:0xe401
[  DisplayMgr:ff0611b4 ] (82:02) SIO [3]:0xf09d

700D, 650D:
Code: [Select]
cat 700D-*.log | grep -E "DisplayMgr.*SIO|-->"
[ GuiMainTask:ff4d91bc ] (04:03) -->Mirror start
[  DisplayMgr:ff128980 ] (82:01) SIO [0]:0x36
[  DisplayMgr:ff128980 ] (82:01) SIO [1]:0x140
[ GuiMainTask:ff4d921c ] (04:03) -->Normal start
[  DisplayMgr:ff128980 ] (82:01) SIO [0]:0x36
[  DisplayMgr:ff128980 ] (82:01) SIO [1]:0x100
[ GuiMainTask:ff4d91ec ] (04:03) -->Reverse start
[  DisplayMgr:ff128980 ] (82:01) SIO [0]:0x36
[  DisplayMgr:ff128980 ] (82:01) SIO [1]:0x1c0

70D (EOS M matches this):
Code: [Select]
cat 70D-*.log | grep -E "DisplayMgr.*SIO|-->"
[ GuiMainTask:ff504660 ] (04:03) -->Mirror start
[  DisplayMgr:ff134c18 ] (82:02) SIO [0]:0x602
[ GuiMainTask:ff5046c0 ] (04:03) -->Normal start
[  DisplayMgr:ff134c18 ] (82:02) SIO [0]:0x600
[ GuiMainTask:ff504690 ] (04:03) -->Reverse start
[  DisplayMgr:ff134c18 ] (82:02) SIO [0]:0x606

Experimental code (don't click me):
Code: [Select]
static void run_test()

    #ifdef CONFIG_5D3_113
    void (*lcd_sio_init)() = (void *) 0xFF12D284;
    void (*lcd_sio_write)(uint32_t * data, int size) = (void *) 0xFF12D1E0;
    void (*lcd_sio_finish)(void * sio_obj) = (void *) 0xFF13BDC8;
    void ** p_lcd_sio_obj = (void **) 0x246F0;
    // 650D 104: FF127E88, FF127D88, FF13B868, 23C48.
    // 700D 115: FF128A28, FF128928, FF13C420, 23C58.

    printf("LCD sio start\n");
    lcd_sio_write((uint32_t[]) { 0x36, 0x140 }, 2);
    printf("LCD sio finish\n");

5D3: the above code turns off the screen, but leaves the backlight on.
650D: wip
700D: ?

SIO initialization sequences are different (likely different TFT controllers). 650D and 700D are identical.

5D3 has an interesting SIO sequence when display brightness is set to Auto.

Code: [Select]
11949> DisplayMgr:ff12d238:82:02: SIO [0]:0x34
11981> DisplayMgr:ff12d238:82:02: SIO [1]:0x1700
119B5> DisplayMgr:ff12d238:82:02: SIO [2]:0x1808
119E9> DisplayMgr:ff12d238:82:02: SIO [3]:0x1960
11A1C> DisplayMgr:ff12d238:82:02: SIO [4]:0x35

Hypothesis: high byte is TFT register address, low byte is value (similar to ADTG, CMOS, audio).

5D3: register 0x19 appears to be gamma correction (0-63). The remaining two bits cause some flicker in saturated blue (?!)

Register 0 is set to 0x34 on TftDeepStanby; 0x35 brings back the image.

Code: [Select]
    for (int i = 0; i < 64; i++)
        lcd_sio_write((uint32_t[]) { 0x34, 0x1900 | (i + (rand() & 3) * 64), 0x35 }, 3);

The search space appears small (256 registers, 256 possible values), so let's brute-force it:
Code: [Select]
    for (int reg = 0; reg < 0x100; reg++)
        for (int val = 0; val < 0x100; val++)
            bmp_printf(FONT_LARGE, 50, 50, "%02x: %02x", reg, val);
            lcd_sio_write((uint32_t[]) { 0x34, (reg << 8) | val, 0x35 }, 3);

        /* restore the display back to working condition */

Documenting other registers (either on 5D3 or on other models) is welcome. Other than trial and error, I don't have a better way to analyze them.

Other registers present (found with { 0x34, rand() & 0xFFFF, 0x35 }, but not written down):
- color adjusments (temperature?)
- mirroring, flipping
- half resolution
- scaling, translation (both H and V)

So far, the image gets back to normal when switching the display mode (such as going into Canon menu).

Just playing with this dataset and

Do you mean you want to try some super resolution algorithms ?
I have about 45 frames of this castle, before I start panning to the right...
Uploading frame 0 to 45 right now, takes about half an hour.
Same link as before.

- before: dcraw M27-1337-frame_000002.dng
- after: averaged with frames 1 and 3, warped with optical flow to match frame 2

To reproduce the above result, get the files below, install the dependencies (follow comments and error messages), then type:
Code: [Select]
make -j2 M27-1337_frame_000002-a.jpg

or "make -j8" to render the entire sequence on a quad-core processor.

Makefile (use Firefox for copying the text; Google Chrome and Safari will not work!)
Code: [Select]
# experiment: attempt to reduce aliasing on hand-held footage using optical flow
# requires

# replace with path to pyflow repository
FLOW=python ~/src/pyflow/

# default target: render all frames as jpg
all: $(patsubst %.dng,%-a.jpg,$(wildcard M27-1337_frame_*.dng))

# render DNGs with dcraw
%.ppm: %.dng
dcraw $<

# helper to specify dependencies on previous or next image
# assumes the file name pattern is: prefix_000123 (underscore followed by 6 digits)
# fixme: easier way to... increment a number in Makefile?!
inc = $(shell stem="$1"; echo $${stem%_*}_$$(printf "%06d" $$((10\#$${stem//*_/}+$2))) )

# enable secondary expansion (needed below)

# next or previous frames
%-n.png: %.ppm $$(call inc,%,1).ppm
$(FLOW) $^ [email protected]

%-p.png: %.ppm $$(call inc,%,-1).ppm
$(FLOW) $^ [email protected]

# average
%-a.png: %.ppm %-n.png %-p.png
convert -average $^ [email protected]

# fallback rules: first / last file will only have "next" / "previous" neighbours
# FIXME: these rules may be chosen incorrectly instead of the above in some edge cases; if in doubt, delete them and see if it helps
%-a.png: %.ppm %-n.png
convert -average $^ [email protected]

%-a.png: %.ppm %-p.png
convert -average $^ [email protected]

# convert to jpg
%.jpg: %.ppm
convert $< [email protected]
%.jpg: %.png
convert $< [email protected]

# 100% crops
%-crop.jpg: %.jpg
convert $< -crop 400x300+900+650 [email protected]

# careful if you have other files in this directory ;)
rm -f *.ppm *.jpg *.png *.npy

# do not delete intermediate files

# example:
# make -j8
# make -j2 M27-1337_frame_000002-a.jpg
Code: [Select]
# Modified the demo from
# -> just save the warped image and the computed flow; filenames from command line

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
# from __future__ import unicode_literals
import numpy as np
from PIL import Image
import time
import pyflow
import sys

    print("%s %s -> %s" % (sys.argv[1], sys.argv[2], sys.argv[3]))
    print("usage: %s input1.jpg input2.jpg output.npy" % sys.argv[0])
    raise SystemExit

im1 = np.array([1]))
im2 = np.array([2]))
im1 = im1.astype(float) / 255.
im2 = im2.astype(float) / 255.

# Flow Options:
alpha = 0.012
ratio = 0.75
minWidth = 20
nOuterFPIterations = 7
nInnerFPIterations = 1
nSORIterations = 30
colType = 0  # 0 or default:RGB, 1:GRAY (but pass gray image with shape (h,w,1))

s = time.time()
u, v, im2W = pyflow.coarse2fine_flow(
    im1, im2, alpha, ratio, minWidth, nOuterFPIterations, nInnerFPIterations,
    nSORIterations, colType)
e = time.time()
print('Time Taken: %.2f seconds for image of size (%d, %d, %d)' % (
    e - s, im1.shape[0], im1.shape[1], im1.shape[2]))

flow = np.concatenate((u[..., None], v[..., None]), axis=2)[3] + ".npy", flow)

import cv2
cv2.imwrite(sys.argv[3], im2W[:, :, ::-1] * 255)

Exercise for the reader: use more frames to compute the correction.

Have fun.

General Development Discussion / Full-screen histogram WIP
« on: October 30, 2017, 10:26:45 PM »
Something like this?

Topic split from here.

General Development Discussion / Automated tests for nightly builds in QEMU
« on: September 19, 2017, 10:35:56 PM »
Another pipe dream came true :) - this time, a dream of mine.

Have you noticed a bunch of screenshots on the nightly builds page?

Were you wondering what's up with them?

These screenshots are created on the build server, by emulating the very builds available for download, unmodified, in QEMU.

In other words, most of the nightly builds are no longer 100% untested when they appear on the download page :)

This is not an overnight development - it's built upon all these years of fiddling with QEMU. A short while ago I couldn't give a good answer regarding the usefulness of the emulator - now you can see it live.

Right now there are only a few tests, with OCR-based menu navigation (using tesseract):

1) navigate to Debug -> Free Memory and take a screenshot from there
2) load the Lua module and run the Hello World script
3) load the file_man module and browse the filesystem
4) play the first 3 levels of the Sokoban game (lua_fix only; example for 1200D)

- add more tests (easy, but time-consuming)
- emulate more camera components (e.g. image playback to be able to test ML overlays)
- check code coverage
- diff the screenshots
- nicer reports

For now, have fun watching the testing script playing Sokoban in QEMU :)

Emulation log

If you are wondering what's the point of testing this game: it covers many backend items, such as menu navigation, module loading, script config files, making sure keys are not missed randomly during script execution, checking whether the camera has enough memory to run scripts - most of these are real bugs found on some camera models from the current nightly builds.

At least, these tests will catch the long-standing issue of some camera models running out of memory, thus not being able to boot. Not very funny for a build considered somewhat stable...

And the emulation is still pretty limited, so I'm just adding tests for what works :)

A while ago I've got the suggestion to use openQA, but I'm still wrapping my head around it. If you can show how it could save us from reinventing the wheel, I'm all ears.

Sneak preview of what I'm working on:

Code: [Select]
at ../../src/stdio.c:44 (streq), task module_task
lv:0 mode:3

module_task stack: ad340 [69c60-1dd3b0]
0x0006DC34 @ 7162c:1dd400
0x0007CF7C @ 6dd3c:1dd3f0
0x00069C00 @ 7cf9c:1dd3e0
0x000AD644 @ 69c5c:1dd3b0

What's the meaning of these codes?

Code: [Select]
eu-addr2line -s -S --pretty-print -e magiclantern 0x0006DC34 0x0007CF7C 0x00069C00 0x000AD644
entry_guess_icon_type at menu.c:694
streq at stdio.c:43
ml_assert_handler at boot-hack.c:596
backtrace_getstr at backtrace.c:859

eu-addr2line -s -S --pretty-print -e magiclantern 7162c 6dd3c 7cf9c 69c5c
menu_add.part.25+0x100 at menu.c:1212
entry_guess_icon_type+0x108 at menu.c:711
streq+0x20 at stdio.c:44
ml_assert_handler+0x5c at boot-hack.c:605

Putting all together:
Code: [Select]
menu_add (menu.c:1212) called entry_guess_icon_type (located menu.c:694)
 entry_guess_icon_type (menu.c:711) called streq (located at stdio.c:43)
  streq (stdio.c:44) called ml_assert_handler (located at boot-hack.c:605) - that's the ASSERT macro
   ml_assert_handler (boot-hack.c:605) called backtrace_getstr (located backtrace.c:859)

Heh, that backtrace went a little bit too far :)

Note: the above line numbers are valid for this changeset.

Works for Canon code too (but it's unable to figure out indirect calls):
Code: [Select]
at RscMgr.c:2513, task InnerDevelopMgr
lv:0 mode:3

InnerDevelopMgr stack: ad360 [697d8-19e498]
0xUNKNOWN  @ de48:19e568
0xUNKNOWN  @ 17bbc:19e540
0x000178B4 @ ff139c38:19e528
0xUNKNOWN  @ 178e4:19e518
0xUNKNOWN  @ 1796c:19e4f8
0xFF0F2F14 @ ff301928:19e4e0
0x00001900 @ ff0f2f80:19e4d0
0x000AD664 @ 697d4:19e498

Will post more details after committing the source.

In the mean time, I'd appreciate a small script (easy coding task) that would take a crash log as input (as in the above examples) and create a human-readable output from it (as in the "putting all together" example). To get the debugging info required for name translation, you'll need this changeset.

Some early notes (5D3 1.2.3).

PROP_REBOOT (software reboot):
Code: [Select]
    int reboot = 0;
    prop_request_change(PROP_REBOOT, &reboot, 4);

0x80010001 PROP_TERMINATE_SHUT_REQ (0=request, 3=execute, 4=cancel)
Code: [Select]
08F1E>    PropMgr:000aecf0:00:00: *** mpu_send(06 04 04 07 00), from ff12298c
09101> **INT-36h*:000aed58:00:00: *** mpu_recv(06 05 02 0b 00 00), from ff2e87f8
09388>    PropMgr:ff0cdc60:8c:03: terminateChangeCBR : SHUTDOWN (0)
093AA>    PropMgr:ff0cde2c:8c:16: SHUTDOWN_REQUEST

Opening battery door:
0x80010002 PROP_ABORT
Code: [Select]
786D6> **INT-36h*:000aed88:00:00: *** mpu_recv(06 05 06 26 01 00), from ff2e87f8
78821> **INT-36h*:000aed88:00:00: *** mpu_recv(06 05 06 13 01 00), from ff2e87f8
7915B> **INT-36h*:000aed88:00:00: *** mpu_recv(06 05 04 0d 00 00), from ff2e87f8
86E81> **INT-36h*:000aed88:00:00: *** mpu_recv(06 04 02 0c 01), from ff2e87f8
8A249>    PropMgr:ff0f8f74:00:03: [SEQ] CreateSequencer (Terminate, Num = 2)
8A2CB>    PropMgr:000aeb2c:00:00: *** task_create("Terminate", 0x11, 0x1000, 0xff0f8e40, &"Sequencer"), from ff0f8ffc
8A1F8>  Terminate:000aeb0c:00:00: *** terminateAbort(0x200000, 0x0, 0x0, 0x200000), from ff0f8edc
8A5D7>  Terminate:000aeb0c:00:00: *** terminateAbort(0x10, 0x0, 0x0, 0x10), from ff0f8edc

Saving settings to ROM at shutdown:
Code: [Select]
8A16A>    PropMgr:ff1282a4:02:03: Compare FROMAddress (0) 0x40710e00 0xff060000 Size 2424

Code: [Select]
      RAM_DebugMsg(140, 22, "Write to FROM");

When opening the battery door, I've identified prop_erase/prop_write calls to 0x3000000 (0xff21c8bc, triggered from PROP_ABORT), 0x5000000 and 0x2000000 (0xff0ce424, Terminate task).

On normal shutdown (power button or card door), terminateShutdown is used instead of terminateAbort.

Canon settings are organized like this (see PROPAD_CreateFROMPropertyHandle):

Code: [Select]
name   ROM addr   N * sector_size?  block_size?   prop_class
TUNE   0xF8B20000   23 * 0x20000      0x2E0000    0x1000000
TUNE2  0xF0020000   42 * 0x10000      0x2A0000    0x1000000
FIX    0xF8E60000    4 * 0x20000       0x80000    0
RING   0xF8F40000    2 * 0x20000        0x1000    0x2000000
RASEN  0xF8EE0000    3 * 0x20000       0x20000    0x4000000, 0x5000000, 0xE000000
LENS   0xF8E00000    3 * 0x20000       0x20000    0xB000000
CUSTOM 0xF8060000    2 * 0x20000        0x1000    0x3000000

The prop_class fields is the "category" of properties stored in each block. Examples:
- RING: 0x02040002 PROP_LANGUAGE, 0x02040003 PROP_VIDEO_SYSTEM, 0x02040005 PROP_DATE_FORMAT
- TUNE: 0x1010022/25...37 vertical stripe correction parameters
- TUNE2: 0x10500d1...d4 (see above)
- RASEN: unknown (0x5010002 contains '', 0x5010003 contains 'Wft-canon')
- CUSTOM: some of them look like picture style parameters (probably settings for C modes)

See also

As you probably have guessed from the latest developments (QEMU, EDMAC graphs, JPCORE, EEKO), our understanding on how LiveView works has improved considerably. Finally, all my fiddling with QEMU, at first sight with little or no purpose for the everyday users, starts paying off.

Today, Magic Lantern proudly announces new ground-breaking features that were previously thought impossible or very hard to achieve.

We proudly present....

4K RAW Video Recording!


Twitter announcement

On the 5D Mark III, you now have the following new resolutions:

* 1920x960 @ 50p (both 1:1 crop and full-frame - 3x3 pixel binning) - continuous*)
* 1920x800 @ 60p (same as above)  - continuous*)
* 1920x1080 @ 45p and 48p (3x3 binning)  - continuous at 45p*)
* 1920x1920 @ 24p (1:1 square crop) - continuous*)
* 3072x1920 @ 24p (1:1 crop)
* 3840x1536 @ 24p (1:1 crop) (corrupted frames at 1600)
* 4096x2560 @ 12.5p (1:1 crop) - continuous*) at 8 FPS
* 4096x1440 @ 25p (1:1 crop)
* Full-resolution LiveView: 5796x3870 at 7.4 fps (128ms rolling shutter) - continuous*) at 5 FPS!
* Full-width LiveView - decrease vertical resolution in the crop_rec submenu, all the way to 5796x400 @ 48 fps :)

The last feature complements the well-known full-resolution silent pictures - the new implementation will be usable at fast shutter speeds, without the exposure gradient - but with rolling shutter (just like regular LiveView frames).

*) Continuous recording for the above resolutions can be achieved as long as you can get a LJ92 compression ratio (compressed / 14-bit uncompressed) of about 50-55%, with preview set to Frozen LV (previously known as Hacked Preview) for an additional speed boost. Otherwise, you'll have to reduce the resolution or the frame rate.

The following table shows how compression rate changes with ISO and bit depth; please check the figures for your particular scene in the raw video submenu, as they can vary a lot, depending on the scene content.

Bits per pixel      14  12  11  10   9   8
ISO  100 1/100     61% 53% 50% 48% 46% 43%
ISO  200 1/200     62% 54% 51% 49% 47% 44%
ISO  400 1/400    63% 54% 51% 49% 47% 45%
ISO  800 1/800     65% 55% 52% 50% 48% 46%
ISO 1600 1/1600    67% 56% 53% 50% 48% 46%
ISO 3200 1/3200    70% 57% 53% 50% 49% 47%
ISO 6400 1/6250    76% 60% 55% 52% 50% 48%
ISO 12800 1/12500  79% 63% 57% 53% 50% 49%

Credits: Greg (full-width LiveView), g3gg0 (video timer, DIGIC registers documentation and lots of other low-level insights).

Complete list of new video modes:
Code: [Select]
                                /*   24p   25p   30p   50p   60p */
    [CROP_PRESET_3X_TALL]       = { 1920, 1728, 1536,  960,  800 }, /* 1920 */
    [CROP_PRESET_3x3_1X]        = { 1290, 1290, 1290,  960,  800 }, /* 1920 */
    [CROP_PRESET_3x3_1X_48p]    = { 1290, 1290, 1290, 1080, 1080 }, /* 1920; 1080p45/48 <- 50/60p in menu */
    [CROP_PRESET_3K]            = { 1920, 1728, 1504,  760,  680 }, /* 3072 */
    [CROP_PRESET_UHD]           = { 1536, 1472, 1120,  640,  540 }, /* 3840 */
    [CROP_PRESET_4K_HFPS]       = { 2560, 2560, 2500, 1440, 1200 }, /* 4096 half-FPS */
    [CROP_PRESET_FULLRES_LV]    = { 3870, 3870, 3870, 3870, 3870 }, /* 5796 */

What else could you wish for?


Where's the catch?

This is only a very rough proof of concept. It has not been battle-tested and has many quirks. Some of them may be easy to fix, others not so. In particular:

* It feels quite buggy. I'm still hunting the issues one by one, but it's hard, as Canon's LiveView implementation is very complex, and our understanding on how it works is still very limited.
* Write speeds are high. For example, 10-bit 4096x2500 at 15 fps requires 180 MB/s. 1080p45 should be a little more manageable at 111 MB/s.
* Canon preview is broken in most modes; you need to use the grayscale preview in the raw recording module.
* High-resolution modes (in particular, full-res LiveView) may cause trouble with memory management. This is very tricky to solve, as we only get 3 full-resolution buffers in LiveView, with restrictions on the order in which they must be freed, and lots of other quirks.
* Since these settings were pushed to limit, the risk of corrupted frames is high. If it happens, decrease the vertical resolution a bit (from the crop_rec submenu).
* When refreshing LiveView settings, the camera might lock-up (no idea why). Pressing MENU twice appears to fix it.

May I fine-tune the new modes?

Yes! I've included some of the knobs on the user interface. Normally you shouldn't need to touch these buttons, but if you do, you might be able to squeeze a few more pixels.

Does it work with FPS override?

Sort of. It's not reliable at this point, so it's best not to try yet.


During my tests, I didn't manage to get a sensor temperature higher than 60 degrees. Your mileage may vary.


This mod changes some low-level sensor parameters that are not well understood. They were all figured by trial and error, and there are no guarantees about the safety of these changes.

As usual, if it breaks, it's your fault, sorry.

Will it work on other camera models?

I hope so; however, this is an area where I hope to get contributions from others (yes, from you). If these new features don't motivate you to look into it, I wonder what else will.

I'll explain how all this works in the coming days or weeks.

Is it difficult to port to other camera models?

So far, the 3x3 720p mode from crop_rec was ported to EOS M (rbrune), 700D (dfort) and 100D (nikfreak). So it shouldn't be that hard...

Will you port this to my camera model, please?

No, sorry. I have better things to do - such as, preparing the April 1st prank for next year :)

Wait a minute, didn't you say you are primarily a still photo user? Why are you even doing this?

If you look close, the usefulness for video is fairly limited, as the write speeds (and therefore the recording times) are not practical.

But the full-resolution LiveView is - in my opinion - very useful for still photo users. Although the current implementation is not very polished (it's just a proof of concept), I hope you'll like the idea of a 7.4 FPS burst mode, 100% silent, without shutter actuations.

Right now, you can take the mlv_lite module with pre-recording and half-shutter trigger: at 10 bits per pixel, you get 5 frames pre-recorded, and saved to card as soon as you touch the half-shutter button. Or, you can capture one frame for each half-shutter press, with negative shutter lag! (since the captured frame will always be pre-recorded).

And if a burst at 7.4 fps is not enough, you may also look at the 4K modes (12-15 fps).

(I know, I know, GH4 already does this, at much higher frame rates...)

The help menu for full-res LiveView says 5796x3870, but MLV Lite only records 5784x3856. What's going on?

The raw recording modules have a couple of alignment constraints (e.g. can only start cropping from a multiple of 8 pixels, and the size of the cropped area (that goes into the MLV file) must be multiple of 16 bytes (that is, W*bpp/8 + H mod 16 must be 0).

To capture the full resolution, you may use the silent picture module. However, this module is not the best when it comes to memory management and buffering. Currently, you'll get an impressive buffer of 2 frames in burst mode :)

But hey - it outputs lossless DNG!

What about that lossless compression routine?

It's included, although I didn't manage to test it much. There is a lot of room for improvement, but for a proof of concept, it seems to work.

update: also got lossless compression at reduced bit depths (8...12-bit).

P.S. The initial announcement was disguised as an April Fools joke, just like the original crop_rec.

Twitter announcement

From original April Fools post:

With our latest achievements in wizardry with ARM programming and DIGIC reverse engineering, we can speak of a new era of raw video recording.

On models like the 5D Mark III, the next upcoming releases will feature an improved version of our crop_rec module that delivers the following new resolutions:
* 1920x960 @ 50p (both 1:1 crop and full-frame - 3x3 pixel binning)
* 1920x800 @ 60p (same as above)
* 1920x1080 @ 45p and 48p (3x3 binning)
* 1920x1920 @ 24p (1:1 square crop)
* 3072x1920 @ 24p (1:1 crop)
* 3840x1600 @ 24p (1:1 crop)
* 4096x2560 @ 12.5p (1:1 crop)
* Full-resolution LiveView: 5796x3870 at 7.4 fps (128ms rolling shutter).

The last feature complements the well-known full-resolution silent pictures - the new implementation will be usable at fast shutter speeds, without the exposure gradient - but with rolling shutter (just like regular LiveView frames).

Please understand that providing the source code for those highly DIGIC optimized routines is a bit troublesome and will need some extra legal care. After this step is taken and as soon we are finished with ensuring the product quality you are used from Magic Lantern, we will upload the code to our repository.

Consider this being a huge leap towards our next mind boggling goal:

8K RAW Video Recording!

Sample DNG from 5D Mark III, to show that our proof of concept is working:


Stay tuned for more information!

Modules Development / Writing modules tutorial #1: Hello, World!
« on: March 16, 2017, 10:24:14 PM »
So far, if you wanted to write your own module, the best sources of documentation were (and probably still are) reading the source code, the forum, the old wiki, and experimenting. As a template for new modules, you probably took one of the existing modules and removed the extra code.

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:

Hello, World!

Let's start from scratch:
Code: [Select]
hg clone -u unified
cd magic-lantern/modules/
mkdir hello
cd hello
touch hello.c

Now edit hello.c in your favorite text editor:
Code: [Select]
/* A very simple module
 * (example for module authors)
#include <dryos.h>
#include <module.h>
#include <menu.h>
#include <config.h>
#include <console.h>

/* 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("Hello, World!\n");
    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 (!get_halfshutter_pressed())
        /* 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));
    return 0;

/* Note: module unloading is not yet supported;
 * this function is provided for future use.
static unsigned int hello_deinit()
    return 0;

/* 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:
Code: [Select]
cp ../ettr/Makefile .
sed -i "s/ettr/hello/" Makefile

Let's compile it:
Code: [Select]

The build process created a file named README.rst. Update it and recompile.

Code: [Select]
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:
Code: [Select]
make install

Otherwise, try:
Code: [Select]
make install CF_CARD=/path/to/your/card

or, if you have such device:
Code: [Select]
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.

Some ideas:
- 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.

General Development Discussion / Recording RAW and H.264 at the same time
« on: February 11, 2017, 02:34:52 PM »
I was experimenting with shooting raw video while simultaneously recording H.264 [...]

[...]it is too much of a hack[...]

Here's an attempt to make it a bit less of a hack:

Currently, focus peaking gives you the option to use two image buffers: the LiveView one (720x480 when used on internal LCD) and the so-called HD one (usually having higher resolution). Of course, the peaking results with the two options are slightly different.

To simplify the code, I'd like to use only the LiveView buffer, like most other overlays.

Is there any reason to use the high-res buffer? In other words, did any of you get better results by using it?

General Development Discussion / Thread safety
« on: February 05, 2017, 02:12:43 AM »
While refactoring the menu code, I've noticed it became increasingly complex, so evaluating whether it's thread-safe was no longer an easy task (especially after not touching some parts of the code for a long time). The same is true for all other ML code. Not being an expert in multi-threaded software, I started to look for tools that would at least point out some obvious mistakes.

I came across this page, which seems promising, but looks C++ only. This paper appears to be from the same authors (presentation here), and C is mentioned too, so adapting the example is probably doable.

Still, annotation could use some help from a computer. So I found pycparser and wrote a script that recognizes common idioms from ML code (such as TASK_CREATE, PROP_HANDLER, menu definitions) and annotates each function with a comment telling what tasks call this function.

Therefore, if a function is called from more than one task, it must be thread-safe. The script only highlights those functions that are called from more than one task (that is, those that may require attention).

Still, I have a gut feeling that I'm reinventing the wheel. If you know a better way to do this, please chime in.


Note: in DryOS, tasks == threads.

General Development Discussion / Experiment - Dynamic My Menu
« on: January 31, 2017, 09:51:00 PM »
Today I was a bit tired of debugging low-level stuff like Lua tasks or camera-specific quirks, but still wanted to write something cool. So here's something I wanted for a long time. The feedback back then wasn't exactly positive, so it never got implemented, but I was still kinda missing it.

Turns out, it wasn't very hard to implement, so there you have it.

What is it?

You already know the Modified menu (where it shows all settings changed from the default value), and My Menu (where you can select your favorite items manually). This experiment attempts to build some sort of "My Menu" dynamically, based on usage counters.

How it works?

After a short while of navigating ML menu as you usually do, your most recently used items and also your frequently used items should appear there. As long as you don't have any items defined for My Menu, it will be built dynamically. The new menu will be named "Recent" and will keep the same icon as My Menu.

Every time you click on some menu item, the usage counter for that item is incremented. All the other items will have a "forgetting factor" applied, so the most recently used items will raise to the top of the list fairly quickly.

Clicking the same item over and over will only be counted once (so scrolling through a long list of values won't give extra priority to menu items). Submenu navigation doesn't count; only changing a value or running an action are counted.

Time is discrete (clicks-based). It doesn't care if you use the camera 10 hours a day or a couple of minutes every now and then.

To have both good responsiveness to recent changes, but also learn your habits over a longer time, I've tried two usage counters: one for short term and another for long term memory. If, let's say during some day, you need to keep toggling a small set of options, it should learn that quickly. But, if no longer need those options after that special day, those menu items will be forgotten quickly, and the ones you use daily (stored in the "long term memory") should be back soon.

So, the only difference between the "long term" and the "short term" counters is the forgetting factor: 0.999 vs 0.9. In other words, the "long term" counters have more inertia.

When deciding whether a menu item is displayed or not, the max value between the two is used, resulting a list of "top 11 most recently or frequently used menus". The small gray bars from the menu are the usage counters (debug info).

I have no idea how well this works in practice - it's something I came up with a few hours ago, and the tuning parameters are pretty much arbitrary.

Source code committed, and if there is interest, I can prepare an experimental build as well.

General Development Discussion / Touch-friendly ML menu
« on: January 06, 2017, 07:02:44 PM »
Some experiments I did last summer on a 700D (which I no longer have).

I remember it worked to some extent, but had some quirks. Don't remember the exact details, but I hope it could be useful (or at least fun to tinker with).

General Chat / Script for undeleting CR2 files
« on: January 01, 2017, 09:17:31 PM »
Looks like my 5D3 decided to reuse the file counters on two different cards. When sorting some photos, one CR2 just got overwritten by another image with the same name.

How to undelete it?

Testdisk's undelete tool didn't help (the file wasn't deleted, but overwritten). PhotoRec would have probably worked, given enough time, extra HDD space and patience to sort through the output files (not practical). I found a guide using debugfs, which didn't seem to work (too much low-level stuff I wasn't familiar with), and this article seemed promising. I knew a pretty tight time interval for the missing file (a couple of seconds, from previous and next file in the set), so I wrote a quick Python script to scan the raw filesystem for CR2 files with the EXIF date/time in a given range.

It worked for me.

It's all hardcoded for my system, but should be easy to adjust for other use cases.

Code: [Select]
# CR2 recovery script
# Scans the entire partition for CR2 files between two given timestamps,
# assuming they are stored in contiguous sectors on the filesystem.
# Hardcoded for 5D Mark III.

import os, sys, re
from datetime import datetime

d0 = datetime.strptime("2016:06:10 17:31:36", '%Y:%m:%d %H:%M:%S')
d1 = datetime.strptime("2016:06:10 17:31:42", '%Y:%m:%d %H:%M:%S')

f = open('/dev/sda3', 'r')

nmax = 600*1024
for k in xrange(nmax):
    p = k*100.0 / nmax*1024*k)
    block =*1024)
    if "EOS 5D Mark III" in block:
        i = block.index("EOS 5D Mark III")
        print k, hex(i), p
        b = block[i : i+0x100]
        date_str = b[42:61]
        try: date = datetime.strptime(date_str, '%Y:%m:%d %H:%M:%S')
        except: continue
        if date >= d0 and date <= d1:
            print date
            out = open("%X.CR2" % k, "w")
  *1024*k + i - 0x100)

Reverse Engineering / ProcessTwoInTwoOutLosslessPath
« on: December 18, 2016, 09:06:41 PM »
Managed to call ProcessTwoInTwoOutLosslessPath, which appears to perform the compression for RAW, MRAW and SRAW formats. The output looks like some sort of lossless JPEG, but we don't know how to decode it yet (this should help).

Proof of concept code (photo mode only for now):

Reverse Engineering / lv_set_raw / lv_select_raw
« on: December 11, 2016, 10:16:59 AM »
These are used for selecting the LiveView raw stream (aka "raw type", see PREFERRED_RAW_TYPE in raw.c).

There is a function that gives some more information about these modes: lv_select_raw in 70D, 80D, 750D/760D, 5D4 and 7D2. The debug strings also reference the PACK32 module (which is something that can write a raw image to memory), so probably this setting connects the input of PACK32 to various image processing modules from Canon's pipeline.

Some related pages: Register_Map, EekoAddRawPath, raw_twk, 12-bit raw video, mv1080 on EOSM...

The names appear to match between DIGIC 5 and 6 cameras, so here's a summary of the LV raw modes:

Code: [Select]
      5D4           80D              760D 7D2M 70D 700D     100D 5D3
0x00: DSUNPACK                                                     
0x01: UNPACK24                                                     
0x02: ADUNPACK                                                     
0x03: DARKSUB       <-               <-   <-   <-                   
0x04: SHADING       <-               <-   <-   <-  SHADE    <-   <-
0x05: ADDSUB        TWOLINEADDSUB    <-   <-   <-                   
0x06: DEFC          <-               <-   <-   <-                   
0x07: DFMKII        DEFMARK          <-   <-   <-  <-       <-     
0x08: HIVSHD        <-               <-   <-   <-  <-       <-   <-
0x09: SMI           <-               <-   <-   <-                   
0x0a: PEPPER_CFIL   <-               <-   <-   <-                   
0x0b: ORBIT         <-               <-   <-   <-  <-       <-   <-
0x0c: TASSEN        <-               <-   <-   <-                   
0x0d: PREWIN1       PEPPER_WIN       <-   <-   <-                   
0x0e: RSHD          <-               <-   <-   <-  <-       <-   <-
0x0f: BEATON        <-               <-   <-   <-                   
0x10: HEAD          <-               <-   <-   <-  CCD      <-   <-
0x11: AFY           <-               <-   <-   <-                   
0x12: DEFOE         <-               <-   <-   <-  DEFCORRE <-   <-
0x13: ORBBEN        <-               <-   <-   <-                   
0x14: PEPPER_DOUBLE                                                 
0x15: JUSMI         <-               <-   <-   <-                   
0x16: SUSIE         <-               <-   <-   <-                   
0x17: KIDS          <-               <-   <-   <-                   
0x18: CHOFF         <-               <-   <-   <-                   
0x19: CHGAIN        <-               <-   <-   <-                   
0x1a: CAMPOFF       <-               <-   <-   <-                   
0x1b: CAMPGAIN      <-               <-   <-   <-                   
0x1c: DEGEEN1       <-               <-   <-   <-  DEGEEN   <-     
0x1d: DEGEEN2       <-               <-   <-   <-                   
0x1e: YOSSIE        <-               <-   <-   <-                   
0x1f: FURICORE      <-               <-   <-   <-                   
0x20: EXPUNPACK                                                     
0x21: SUBUNPACK                                                     
0x22: PREFIFO       INVALID,PRE_FIFO <-   <-   <-                   
0x23: SAFARI_IN     <-               <-   <-   <-                   
0x24: DPCM_DEC      <-               <-   <-   <-                   
0x25: MIRACLE                                                       
0x26: FRISK                                                         
0x27: CLEUR         <-                                             
0x28: OTHERS                                                       
0x29: SHREK         SHREK_IN         <-   <-   <-                   
0x2a: DITHER                                                       
0x2b: DFMKII2       DEFMARKII2       <-   <-                       
0x2c: PREWIN2       PEPPER_WIN2      <-   <-                       
0x2d: CDM           <-               <-   <-                       
0x2e: LTKIDS_IN     <-               <-   <-                       
0x2f: PREWIN3       PEPPER_WIN3      <-   <-                       
0x30: SIMPPY                                                       
0x31: PEPPER_DIV_A                                                 
0x32: PEPPER_DIV_B                                                 
0x33: SUBSB_OUT                                                     
0x34: SIBORE_IN                                                     
0x35: PEPPER_DIV                                                   

DIGIC 4 has a different mapping. 60D:
Code: [Select]
RSHD     => 0x0B
SHADE    => 0x01
HIVSHD   => 0x07
ORBIT    => 0x09
DEFCORRE => 0x04
CCD      => 0x05 (currently used)
DEFMARK  => 0x06

There are more valid raw types than the ones named in the above tables. For example, on 5D3 (trial and error):
Code: [Select]
0x00 => valid image stream in some unknown format
0x01 => bad
0x02 => scaled by digital ISO (DEFCORRE?)
0x03 => bad
0x04 => SHADE (bad pixels, scaled by digital ISO)
0x05 => bad
0x06 => bad
0x07 => DEFMARK (bad pixels)
0x08 => HIVSHD (bad pixels, appears to fix some vertical stripes)
0x09 => bad
0x0A => bad
0x0B => bad
0x0C => bad
0x0D => bad
0x0E => RSHD (bad pixels, scaled by digital ISO)
0x0F => bad

0x10 => CCD (clean image, some vertical stripes in certain cases)
0x11 => bad
0x12 => DEFCORRE (scaled by digital ISO)
0x13 => bad
0x14 => valid image stream in some unknown format (different from 0)
0x15 => bad
0x16 => bad
0x17 => bad pixels
0x18 => bad
0x19 => bad
0x1A => bad
0x1B => bad
0x1C => bad pixels
0x1D => bad
0x1E => bad pixels
0x1F => bad

0x20 => valid image stream in some compressed format?
0x21 => bad
0x22 => clean image
0x23 => bad
0x24 => bad
0x25 => bad
0x26 => bad
0x27 => bad pixels
0x28 => valid image stream in some compressed format?
0x29 => bad
0x2A => some strange column artifacts
0x2B => bad
0x2C => bad
0x2D => bad
0x2E => some strange posterization
0x2F => bad

0x30 => valid image stream in some compressed format?
0x31 => bad
0x32 => clean image
0x33 => bad
0x34 => valid image stream in some unknown format
0x35 => bad
0x36 => bad
0x37 => bad pixels
0x38 => valid image stream with some missing columns?!
0x39 => same
0x3A => clean image
0x3B => bad
0x3C => bad pixels, strange column artifacts (like 0x2A, but with bad pixels)
0x3D => bad
0x3E => posterization (same as 46)
0x3F => bad

0x40 - 0x7F => same as 0x00 - 0x3F (checked most good modes and some bad modes)

On 5D3 and 60D, the raw type "CCD" is the one we are using for raw video.

On EOS M, the only valid raw types appear to be 7, 11, 48, 50, 75, 80, 87 according to dfort.

Would be nice if somebody has the patience to try all the raw types on the 70D, as it's the only camera that runs ML now and has lv_select_raw.

Reverse Engineering / EDMAC internals
« on: November 26, 2016, 01:28:55 PM »
Until now, we didn't know much about how to configure the EDMAC. Recently we did some experiments that cleared up a large part of the mystery.

Will start with size parameters. They are labeled xa, xb, xn, ya, yb, yn, off1a, off1b, off2a, off2b, off3 (from debug strings). Their meaning was largely unknown, and so far we only used the following configuration:

Code: [Select]
xb = width
yb = height-1
off1b = padding after each line

Let's start with the simplest configuration (memcpy):

Code: [Select]
xb = size in bytes. 

Unfortunately, it doesn't work - the image height must be at least 2.

Simplest WxH

How Canon code sets it up:
Code: [Select]
  CalculateEDmacOffset(edmac_info, 720*480, 480):
     xb=0x1e0, yb=0x2cf

Transfer model (what the EDMAC does, in a compact notation):
Code: [Select]
xb * (yb+1)        (xb repeated yb times)

WxH + padding (skip after each line)

Code: [Select]
(xb, skip off1b) * (yb+1)

Note: skipping does not change the contents of the memory,
so the above is pretty much the same as:
Code: [Select]
(xb, skip off1b) * yb
followed by xb (without skip)

xa, xb, xn (usual raw buffer configuration)

Code: [Select]
xa = xb = width
xn = height-1

To see what xa and xn do, let's look at some more examples (how Canon code configures them):
Code: [Select]
  edmac_setup_size(ch, 0x1000000):
    xn=0x1000, xa=0x1000

  edmac_setup_size(6, 76800):
    xa=0x1000, xb=0xC00, xn=0x12

  CalculateEDmacOffset(edmac_info, 0x100000, 0x20):
    xa=0x20, xb=0x20, yb=0xfff, xn=0x7

  CalculateEDmacOffset(edmac_info, 1920*1080, 240):
    xa=0xf0, xb=0xf0, yb=0xb3f, xn=0x2

The above can be explained by a transfer model like this:
Code: [Select]
(xa * xn + xb) * (yb+1)

Adding ya, yn (to xa, xb, xn, yb)

Some experiments (trial and error, 5D3):
Code: [Select]
  xa = 3276, xb = 1638, xn = 1055                  => 3276*1055 + 1638 transferred
  xa = 3276, xb = 32,   xn = 1055                  => 3276*1055 + 32
  xa = 3276, xb = 0,    xn = 1055                  => 3276*1056 - 20 (?!)
  xa = 3276, xb = 3276, xn = 95, yb = 10           => 3276*96*11
  xa = 3276, xb = 3276, xn = 95, yb = 7,  yn = 3   => 3276*96*11
  xa = 3276, xb = 3276, xn = 10, yb = 62, yn = 33  => 3276*11*96
  xa = 3276, xb = 3276, xn = 10, yb=3, yn=5, ya=2  => 3276*11*19
  xa = 3276, xb = 3276, xn = 10, yb=5, yn=3, ya=6  => 3276*11*27
  xa = 3276, xb = 3276, xn = 10, yb=5, yn=3, ya=7  => 3276*11*30
  xa = 3276, xb = 3276, xn = 10, yb=7, yn=8, ya=9  => 3276*11*88
  xa = 3276, xb = 3276, xn = 10, yb=8, yn=3, ya=28 => 3276*11*96

Code: [Select]
(xa * xn + xb) REP (yn REP ya + yb)

Here, a REP b means 'perform a, repeat b times' => a * (b+1).

So far, so good, the above model appears to explain the behavior
when there are no offsets, and looks pretty simple.

There is a quirk: if xb = 0, the behavior looks strange.
Let's ignore it for now.

Adding off1b (to xa, xb, xn, ya, yb, yn)

What do we do about the offset off1b?

Code: [Select]
xa = 3276, xb = 3276, xn = 10, yb=95, off1b=100
=> copied 3276*10*96 + 3276, skipped 100,
   (CP 3276, SK 100) repeated 94 times (95 runs).

It copies a large block, then it starts skipping after each line.
Let's decompose our model and reorder the terms.
Then, let's skip off1b after each xb.

Code: [Select]
(xa * xn)        REP (yn REP ya + yb)
(xb, skip off1b) REP (yn REP ya + yb)

Let's check a more complex scenario:
Code: [Select]
xa = 3276, xb = 3276, xn = 10, yb=8, yn=3, ya=28, off1b=100
=> (CP 3276*10*29 + 3276,   SK 100), (CP 3276, SK 100) * 27,
   (CP 3276*10*29 + 3276*2, SK 100), (CP 3276, SK 100) * 27,
   (CP 3276*10*29 + 3276*2, SK 100), (CP 3276, SK 100) * 27,
   (CP 3276*10*9  + 3276*2, SK 100), (CP 3276, SK 100) * 8.

There's some big operation that appears repeated 3 times (yn),
although the copied block sizes are a little inconsistent (first is smaller).

After that, (xa * xn) is executed 9 times (yb+1).
At the end, (xb, skip off1b) is executed 9 times (also yb+1).

In the big operation, the 29 is clearly ya+1.

What if off1b is skipped after all xb iterations, but not the last one?
This could explain why we have an extra 3276 (the *2) on the last 3 log lines.

Regroup the terms like this:
Code: [Select]
  => ((CP 3276*10*29), (CP 3276, SK 100) * 28, CP 3276) * 3,
      (CP 3276*10*9 ), (CP 3276, SK 100) * 9.

Our model starts to look like this:
Code: [Select]
   (xa * xn)   (ya+1)
   (xb, skip off1b) *  ya
    xb without skip
  * yn

followed by:

   (xa * xn)   (yb+1)
   (xb, skip off1b) * (yb+1)

So far so good, it's a bit more complex,
but explains all the above observations.
Of course, the last line may be as well:
Code: [Select]
  (xb, skip off1b) * yb, xb without skip

Adding off1a

Let's try another offset: off1a = 44.
The log from this experiment is pretty long, so I'll simplify it by regrouping the terms.

Code: [Select]
xa = 3276, xb = 3276, xn = 10, yb=8, yn=3, ya=28, off1a=44, off1b=100
=> (
     ((CP 3276, SK 44)  * 28, CP 3276) * 10,
     ((CP 3276, SK 100) * 28, CP 3276),
   ) * 3,
     ((CP 3276, SK 44)  * 8, CP 3276) * 10,
     ((CP 3276, SK 100) * 8, CP 3276)

This gives good hints about what is happening when:
Code: [Select]
   ((xa, skip off1a) * ya, xa) * xn
    (xb, skip off1b) * ya, xb
) * yn,

   ((xa, skip off1a) * yb, xa) * xn
    (xb, skip off1b) * yb, xb

Adding the remaining offsets (all parameters are now used)

Let's add off2a, off2b and off3. They are pretty obvious now, so I'll skip the log file (which looks quite intimidating anyway).

Code: [Select]
   ((xa, skip off1a) * ya, xa, skip off2a) * xn
    (xb, skip off1b) * ya, xb,
     skip off3
) * yn,

   ((xa, skip off1a) * yb, xa, skip off2b) * xn
    (xb, skip off1b) * yb, xb

So, there is a pattern: perform N iterations with some settings, then perform the last iteration with slightly different parameters. The pattern repeats at all iteration levels (somewhat like fractals).

Just by looking at the memory contents, we can't tell what what the skip value is used for the very last iteration. However, by reading the memory address register (0x08) directly from hardware (not from the shadow memory), we can get the end address (after the EDMAC transfer was finished). For a write transfer, this includes the transferred data and also the skip offsets. Now it's straightforward to notice the last offset is off3, so our final model for EDMAC becomes:

EDMAC transfer model

Code: [Select]
   ((xa, skip off1a) * ya, xa, skip off2a) * xn
    (xb, skip off1b) * ya, xb, skip off3
) * yn,

   ((xa, skip off1a) * yb, xa, skip off2b) * xn
    (xb, skip off1b) * yb, xb, skip off3

The offset labels now start to make sense :)

C code (used in qemu):
Code: [Select]
for (int jn = 0; jn <= yn; jn++)
    int y     = (jn < yn) ? ya    : yb;
    int off2  = (jn < yn) ? off2a : off2b;
    for (int in = 0; in <= xn; in++)
        int x     = (in < xn) ? xa    : xb;
        int off1  = (in < xn) ? off1a : off1b;
        int off23 = (in < xn) ? off2  : off3;
        for (int j = 0; j <= y; j++)
            int off = (j < y) ? off1 : off23;
            cpu_physical_memory_write(dst, src, x);
            src += x;
            dst += x + off;

The above model is for write operations. For read, the skip offsets are applied to the source buffer - that's the only difference.

Offsets can be positive or negative. In particular, off1a and off1b only use 17 bits (digic 3 and 4) or 19 bits (digic 5), so we have to extend the sign.

The above model explained all the combinations that are not edge cases (such as yb=0 or odd values). Here are the tests I've ran: 5D3 vs QEMU.

For more details, please have a look at the "edmac" and "qemu" branches.

To be continued.

Jenkins is overloading the server too much for my taste lately, so I'm considering rewriting the nightly builds page as static HTML, without any JavaScript. Another reason for the rewrite: the builds page is impossible to load on slow network connections.

Any volunteers to help me with this task? I'm going to use a Python script similar to this one, and here's what I came up with so far (edited manually, based on the previous template):

Here's a proof of concept Python code to retrieve Jenkins build data, using JenkinsAPI:
Code: [Select]
from jenkinsapi.jenkins import Jenkins
J = Jenkins('')
B = J['500D.111'].get_last_good_build()
artifact = list(B.get_artifacts())[0]
print artifact.url

Feedback is also welcome (while I'm at it). There's some extra functionality I'd like to add, too.

Modules Development / Burst mode tweaks (
« on: September 15, 2016, 08:16:34 PM »
A while ago I had a fairly strange problem: I was taking pictures with a manual 200mm lens, and had trouble keeping the subject in the frame. Why? Because, during a burst sequence, the display is turned off. I was focusing manually from LiveView, so couldn't look through the viewfinder.

So, here's a module that implements this tweak: during a burst sequence, it shows a live preview of the captured images. RAW only.

Also included a tweak that limits the number of pictures in a burst sequence (for example, if you want to take 2 pictures on a single shutter press). I'm not sure where this could be useful, but was simple enough to write.

I wrote this about one or two months ago, but didn't get the opportunity to battle-test it yet.


If it works fine on most models and people find it useful, I'll include it in the nightly.

Topic split from

Old discussion about vertical stripes:

With crop_rec, these stripes also appear in H.264. They can be fixed in post, but it would be best if we could avoid them in the first place.

Vertical stripe fix for H.264:


Note: the stripes we are talking about in this thread are visible in highlights (e.g. sky at low ISO).

Is the vertical banding present in the highlights or shadows?

If the banding is in the highlights, darkframe subtraction won't help. Banding in the highlights is a sign of a multiplicative defect (the column gains are off slightly, which is fixed by multiplying pixels values by some correction factor).

If the banding is in the shadows, the "vertical stripe fix" won't help. Banding in the shadows is a sign of an additive defect (there is some linear offset, which is fixed by simply subtracting some correction value from the pixel values).

Original message:
I'd say let's review the vertical stripe fix on 1.1.3, and if it's everything alright, I'll include it in the main builds (and fix the 1.2.3 crop build) soon.

Since I'm a bit stuck with DIGIC 6, I took the cpuinfo module from CHDK and integrated it with the portable display code. This should give detailed info about the hardware (CPU, caches, memory configuration and so on).

Besides the DIGIC 6 cameras, I'm also interested in the results from recent ports (70D, 100D, 1200D); tests from other cameras are also welcome, but they are mostly for fun.

Source code: the recovery branch

autoexec.bin - for all ML-enabled cameras
CPUI1300.FIR (1300D)

This code is pretty verbose - it will show a few pages of low-level info. You will need to take screenshots to be able to read all that stuff.

As I'm on a very slow network connection, please do not upload large screenshots. If possible, it would be best if you could write down the info as plain text. If not, please try to keep the image size small (under 50K each).

Reverse Engineering / MPU communication
« on: July 22, 2016, 11:26:59 AM »
There was some progress understanding the communication between the main CPU and the MPU (a secondary CPU that controls buttons, lens communication, shutter actuation, viewfinder and others), so I think it's time to open a new thread.


* QEMU docs: MPU Communication
* Code to dump MPU firmware: modules/mpu_dump
* NikonHacker emulator for TX19A:
* Communication protocol emulated in QEMU: qemu/eos/mpu.c
* How to log the MPU messages: [1] [2] [3] (you can use this build)
* Early discussion regarding button interrupt:
* Button codes in QEMU:
* First trick implemented using a MPU message:

500D, LV
Code: [Select]
mpu_send(06 04 09 00 00)
mpu_recv(3c 3a 09 00 3c 3c e0 00 3f 80 00 00 38 12 c0 00 b9 cb c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 08 11 10 50 49 02 59 88 88 00 32 00 00 00 00 00 01 00 00 00)

0x32 - focal length
0x10 - aperture

Now we can read lens_info in Photo mode.
Just call mpu_send(06 04 09 00 00). CPU receives data and automatically overwrite property lens_info.

Pages: [1] 2 3 ... 6