diff -r 02d771ecb347 platform/5D3.113/features.h --- a/platform/5D3.113/features.h Sat Oct 12 09:19:57 2013 +0300 +++ b/platform/5D3.113/features.h Mon Oct 14 09:58:07 2013 +0300 @@ -24,3 +24,5 @@ #undef FEATURE_VOICE_TAGS // No sound recorded #define FEATURE_LV_FOCUS_BOX_SNAP_TO_X5_RAW + +#define FEATURE_ELECTRONIC_LEVEL_LOGGING diff -r 02d771ecb347 platform/5D3.113/include/platform/state-object.h --- a/platform/5D3.113/include/platform/state-object.h Sat Oct 12 09:19:57 2013 +0300 +++ b/platform/5D3.113/include/platform/state-object.h Mon Oct 14 09:58:07 2013 +0300 @@ -7,4 +7,6 @@ #define MOVREC_STATE (*(struct state_object **)0x27850) #define SSS_STATE (*(struct state_object **)0x25E44) +#define SCS_STATE (*(struct state_object **)0x25284) + #endif // __platform_state_object_h diff -r 02d771ecb347 src/shoot.c --- a/src/shoot.c Sat Oct 12 09:19:57 2013 +0300 +++ b/src/shoot.c Mon Oct 14 09:58:07 2013 +0300 @@ -54,6 +54,10 @@ static CONFIG_INT("post.deflicker.level", post_deflicker_target_level, -4); #endif +#ifdef FEATURE_ELECTRONIC_LEVEL_LOGGING +static CONFIG_INT("electronic.level.log", electronic_level_log, 0); +#endif + void move_lv_afframe(int dx, int dy); void movie_start(); void movie_end(); @@ -3780,6 +3784,17 @@ }, }, #endif + + #ifdef FEATURE_ELECTRONIC_LEVEL_LOGGING + { + .name = "Post Rotate", + .priv = &electronic_level_log, + .max = 1, + .help = "Save orientation (roll/pitch angle) in a sidecar file,", + .help2 = "so you can rotate the picture in post automatically.", + .works_best_in = DEP_PHOTO_MODE, + }, + #endif #ifdef FEATURE_BULB_TIMER { @@ -5631,6 +5646,168 @@ } #endif +#ifdef FEATURE_ELECTRONIC_LEVEL_LOGGING +static volatile int roll; +static volatile int pitch; +static volatile int roll_pitch_status = 1; +static volatile int roll_pitch_timestamp = 0; +static struct msg_queue * level_mq = 0; + +static void level_mq_init() +{ + level_mq = (void*) msg_queue_create("level_mq", 100); +} + +INIT_FUNC("level_mq", level_mq_init); + +struct rolling_pitching +{ + uint8_t status; + uint8_t cameraposture; + uint8_t roll_hi; + uint8_t roll_lo; + uint8_t pitch_hi; + uint8_t pitch_lo; +}; + +PROP_HANDLER(PROP_ROLLING_PITCHING_LEVEL) +{ + struct rolling_pitching * orientation = (struct rolling_pitching *) buf; + + static int first_time = 1; + if (!first_time) + roll_pitch_status = orientation->status; + first_time = 0; + + if (orientation->status == 2) + { + roll = orientation->roll_hi * 256 + orientation->roll_lo; + pitch = orientation->pitch_hi * 256 + orientation->pitch_lo; + + /* so we know whether the values are still valid */ + roll_pitch_timestamp = get_ms_clock_value(); + } +} + +static char electronic_level_last_msg[100]; + +static void electronic_level_save_sidecar_file_for_cr2(int file_number, int roll, int pitch) +{ + /* prefer -180.00 ... +180.00 range instead of 0.00 ... 360.00 */ + if (roll > 18000) roll -= 36000; + if (pitch > 18000) pitch -= 36000; + + char fn[100]; + snprintf(fn, sizeof(fn), "%s/%s%04d.LEV", get_dcim_dir(), get_file_prefix(), file_number); + FILE* f = FIO_CreateFileEx(fn); + if (f == INVALID_PTR) return; + snprintf(electronic_level_last_msg, sizeof(electronic_level_last_msg), + "Roll : %s%d.%02d\n" + "Pitch : %s%d.%02d\n", + FMT_FIXEDPOINT2S(roll), + FMT_FIXEDPOINT2S(pitch) + ); + my_fprintf(f, electronic_level_last_msg); + FIO_CloseFile(f); +} + +static void electronic_level_sidecar_task() +{ + /* the trigger is a bit too early */ + /* trial and error, rotate the camera at constant speed while taking a burst speed; + * adjust it until the systematic error disappears + */ + msleep(50); + + /* force an update */ + roll_pitch_timestamp = 0; + int iter = 0; + while (roll_pitch_timestamp == 0) + { + msleep(10); + iter++; + if (iter > 100) + { + /* something's wrong */ + snprintf(electronic_level_last_msg, sizeof(electronic_level_last_msg), + "Roll / pitch\nnot updated." + ); + beep(); + return; + } + } + + /* check sync (long exposures are best for this) */ + /* should trigger at the start of exposure */ + //~ beep(); + + /* put roll/pitch data into a message queue, for syncing with the files */ + msg_queue_post(level_mq, ((uint32_t)roll & 0xFFFF) | ((uint32_t)pitch << 16)); +} + +/* called from QR zebras */ +void electronic_level_sidecar_show_info() +{ + if (electronic_level_log && electronic_level_last_msg[0]) + { + bmp_printf(FONT_MED, 300, os.y_max - font_med.height * 2, electronic_level_last_msg); + electronic_level_last_msg[0] = 0; + } +} + +/* called from SCS task, at the start of exposure */ +void electronic_level_sidecar_trigger() +{ + if (electronic_level_log) + { + /* not a really good idea to slow down Canon picture taking task */ + task_create("level_task", 0x1c, 0x1000, electronic_level_sidecar_task, (void*) 0); + } +} + +static void electronic_level_sidecar_save_task(void* file_number) +{ + if (level_mq == 0) return; + uint32_t msg; + int err = msg_queue_receive(level_mq, (struct event**)&msg, 1000); + if (err == 0) + { + uint32_t roll = msg & 0xFFFF; + uint32_t pitch = msg >> 16; + electronic_level_save_sidecar_file_for_cr2((int)file_number, roll, pitch); + } + else + { + console_printf("%d: recv err\n", file_number); + } +} + +PROP_HANDLER(PROP_FILE_NUMBER_A) +{ + static int prev_file = -1; + int file = buf[0]; + + if (electronic_level_log && prev_file != file && prev_file != -1) + { + /* new CR2 file saved? get a measurement from the queue and save it to sidecar file */ + /* not a good idea to slow down the property task */ + task_create("level_save_task", 0x1c, 0x1000, electronic_level_sidecar_save_task, (void*) file); + } + prev_file = file; +} + +/* periodical check whether electronic level is still active */ +static void electronic_level_refresh() +{ + if (electronic_level_log && roll_pitch_status == 1) + { + GUI_SetRollingPitchingLevelStatus(0); + msleep(100); + } +} + +#endif + static struct msg_queue * shoot_task_mqueue = NULL; /* cause an immediate redraw of the shooting task infos. not used yet, but can be triggered by model-specific code */ @@ -5762,6 +5939,10 @@ module_exec_cbr(CBR_SHOOT_TASK); #endif +#ifdef FEATURE_ELECTRONIC_LEVEL_LOGGING + electronic_level_refresh(); +#endif + #ifdef FEATURE_MLU_HANDHELD_DEBUG if (mlu_handled_debug) big_bmp_printf(FONT_MED, 50, 100, "%s", mlu_msg); #endif diff -r 02d771ecb347 src/state-object.c --- a/src/state-object.c Sat Oct 12 09:19:57 2013 +0300 +++ b/src/state-object.c Mon Oct 14 09:58:07 2013 +0300 @@ -281,6 +281,24 @@ } #endif +#ifdef SCS_STATE +static int stateobj_scs_spy(struct state_object * self, int x, int input, int z, int t) +{ + int old_state = self->current_state; + int ans = StateTransition(self, x, input, z, t); + int new_state = self->current_state; + + #if defined(CONFIG_5D3) + #ifdef FEATURE_ELECTRONIC_LEVEL_LOGGING + if (old_state == 8 && input == 5 && (new_state == 9 || new_state == 12)) // scsReleaseStart + electronic_level_sidecar_trigger(); + #endif + #endif + + return ans; +} +#endif + static int stateobj_start_spy(struct state_object * stateobj, void* spy) { if (!StateTransition) @@ -323,6 +341,10 @@ #ifdef SDS_FRONT3_STATE stateobj_start_spy(SDS_FRONT3_STATE, stateobj_sdsf3_spy); #endif + + #ifdef SCS_STATE + stateobj_start_spy(SCS_STATE, stateobj_scs_spy); + #endif #ifdef CONFIG_550D display_is_on_550D = (DISPLAY_STATEOBJ->current_state != 0); diff -r 02d771ecb347 src/zebra.c --- a/src/zebra.c Sat Oct 12 09:19:57 2013 +0300 +++ b/src/zebra.c Mon Oct 14 09:58:07 2013 +0300 @@ -4131,6 +4131,10 @@ bvram_mirror_clear(); // may be filled with liveview cropmark / masking info, not needed in play mode clrscr(); + #ifdef FEATURE_ELECTRONIC_LEVEL_LOGGING + electronic_level_sidecar_show_info(); + #endif + #ifdef FEATURE_CROPMARKS cropmark_redraw(); #endif