/** \file | |
* PTP handlers to extend Magic Lantern to the USB port. | |
* | |
* These handlers are registered to allow Magic Lantern to interact with | |
* a PTP client on the USB port. | |
*/ | |
#include "dryos.h" | |
#include "ptp.h" | |
#include "ptp-extra.h" | |
#include "tasks.h" | |
#include "menu.h" | |
#include "raw.h" | |
#include "bmp.h" | |
#include "property.h" | |
#include "module.h" | |
#include "lens.h" | |
#include "shoot.h" | |
#include "version.h" | |
#include "chdk-dng.h" | |
#include "powersave.h" | |
static PROP_INT(PROP_ISO, prop_iso); | |
static PROP_INT(PROP_SHUTTER, prop_shutter); | |
static void* my_single_frame; | |
static int get_a_frame = 0; | |
static void* get_lv() | |
{ | |
// See also silent_pic_take_fullres(int interactive) | |
force_liveview(); | |
raw_lv_request(); | |
msleep(50); | |
raw_lv_release(); | |
msleep(50); | |
raw_update_params(); | |
return &raw_info; | |
} | |
static int getBuffers(struct memSuite * hSuite) | |
{ | |
struct memChunk * hChunk = (void*) GetFirstChunkFromSuite(hSuite); | |
void* ptr = (void*) GetMemoryAddressOfMemoryChunk(hChunk); | |
while (1) | |
{ | |
void* ptr0 = (void*) GetMemoryAddressOfMemoryChunk(hChunk); | |
int size = GetSizeOfMemoryChunk(hChunk); | |
int used = ptr - ptr0; | |
int remain = size - used; | |
//~ printf("remain: %x\n", remain); | |
/* the EDMAC might write a bit more than that, | |
* so we'll use a small safety margin (2 extra lines) */ | |
if (remain < raw_info.frame_size + 2 * raw_info.pitch) | |
{ | |
/* move to next chunk */ | |
hChunk = GetNextMemoryChunk(hSuite, hChunk); | |
if (!hChunk) | |
{ | |
//~ printf("no more memory\n"); | |
break; | |
} | |
ptr = (void*) GetMemoryAddressOfMemoryChunk(hChunk); | |
//~ printf("next chunk: %x %x\n", hChunk, ptr); | |
continue; | |
} | |
else /* alright, a new frame fits here */ | |
{ | |
//~ printf("FRAME %d: hSuite=%x hChunk=%x ptr=%x\n", count, hSuite, hChunk, ptr); | |
my_single_frame = ptr; | |
return 0; | |
/*ptr = ptr + raw_info.frame_size; | |
if (count >= SP_BUFFER_SIZE) | |
{ | |
//~ printf("we have lots of RAM, lol\n"); | |
break; | |
} | |
*/ | |
} | |
} | |
return 1; | |
} | |
static void fill_uint32(char* data, uint32_t value) { | |
uint8_t* d = (uint8_t*)data; | |
*d = value & 0xFF; value >>= 8; d++; | |
*d = value & 0xFF; value >>= 8; d++; | |
*d = value & 0xFF; value >>= 8; d++; | |
*d = value & 0xFF; | |
} | |
PTP_HANDLER( PTP_EXTRA_CODE, 0 ) | |
{ | |
struct ptp_msg msg = { | |
.id = PTP_RC_OK, | |
.session = session, | |
.transaction = transaction, | |
.param_count = 4, | |
.param = { 1, 2, 0xdeadbeef, 3 }, | |
}; | |
// handle command | |
char* mydata = NULL; | |
size_t thumbnail_size = 0; | |
char* rawadr = NULL; | |
struct memSuite * hSuite1 = NULL; | |
switch ( param1 ) | |
{ | |
case PTP_EXTRA_HelloWorld: | |
msg.param_count = 2; | |
msg.param[0] = PTP_EXTRA_VERSION_MAJOR; | |
msg.param[1] = PTP_EXTRA_VERSION_MINOR; | |
break; | |
case PTP_EXTRA_TakePicture: | |
#if defined(CONFIG_EOSM) | |
call("Release"); | |
#endif | |
msg.param_count = 1; | |
msg.param[0] = 0; | |
break; | |
case PTP_EXTRA_GetLV: | |
hSuite1 = srm_malloc_suite(1); | |
if(!hSuite1) | |
{ | |
msg.id = PTP_RC_GeneralError; | |
msg.param[0] = 0; | |
} | |
int raw_flag = 1; | |
raw_lv_request(); | |
if (!raw_update_params()) | |
{ | |
msg.id = PTP_RC_GeneralError; | |
msg.param[0] = 1; | |
goto cleanup; | |
} | |
if(getBuffers(hSuite1)) | |
{ | |
msg.id = PTP_RC_GeneralError; | |
msg.param[0] = 2; | |
goto cleanup; | |
} | |
memset(my_single_frame, 0, raw_info.frame_size); | |
struct raw_info local_raw_info = raw_info; | |
get_a_frame = 1; | |
int loop_ctr = 0; | |
while(get_a_frame == 1) | |
{ | |
loop_ctr++; | |
msleep(20); | |
if (!lv) | |
{ | |
get_a_frame = 0; | |
break; | |
} | |
} | |
if(get_a_frame != 2) | |
{ | |
msg.id = PTP_RC_GeneralError; | |
msg.param[0] = 3; | |
get_a_frame = 0; | |
goto cleanup; | |
} | |
raw_lv_release(); raw_flag = 0; | |
//raw_force_aspect_ratio_1to1(); | |
// | |
local_raw_info.buffer = my_single_frame; | |
msg.param[0] = local_raw_info.jpeg.width; | |
msg.param[1] = local_raw_info.jpeg.height; | |
create_dng_header(&local_raw_info); | |
create_thumbnail(&local_raw_info); | |
thumbnail_size = dng_th_width*dng_th_height*3; | |
mydata = malloc(dng_header_buf_size + thumbnail_size + local_raw_info.frame_size ); | |
memcpy(mydata,dng_header_buf,dng_header_buf_size); | |
memcpy(mydata + dng_header_buf_size, thumbnail_buf,thumbnail_size); | |
rawadr = (void*) local_raw_info.buffer; | |
reverse_bytes_order(rawadr, local_raw_info.frame_size); | |
memcpy(mydata + dng_header_buf_size + thumbnail_size, rawadr, local_raw_info.frame_size); | |
srm_free_suite(hSuite1); | |
my_single_frame = NULL; | |
send_ptp_data(context, mydata, dng_header_buf_size + thumbnail_size + local_raw_info.frame_size); | |
free(mydata); | |
free_dng_header(); | |
redraw(); | |
cleanup: | |
if (raw_flag) | |
raw_lv_release(); | |
break; | |
/* | |
case PTP_EXTRA_GetLVFull: | |
prop_iso = lens_info.raw_iso; | |
if (shooting_mode != SHOOTMODE_M || (prop_iso == 0 || prop_shutter == 0)) | |
{ | |
msg.param_count = 1; | |
msg.param[0] = 1; | |
break; | |
} | |
if (!lv && !LV_PAUSED && gui_state != GUISTATE_QR) force_liveview(); | |
PauseLiveView(); | |
//gui_uilock(UILOCK_EVERYTHING); | |
//clrscr(); | |
vram_clear_lv(); | |
display_off(); | |
//struct JobClass * copy_job = 0; | |
//void* copy_buf = 0; | |
struct JobClass * job = (void*) call("FA_CreateTestImage"); | |
lens_info.job_state = 1; | |
info_led_on(); | |
//int t0 = get_ms_clock_value(); | |
call("FA_CaptureTestImage", job); | |
//int t1 = get_ms_clock_value(); | |
//int capture_time = t1 - t0; | |
info_led_off(); | |
lens_info.job_state = 0; | |
call("FA_DeleteTestImage", job); | |
msg.param[0] = raw_info.jpeg.width; | |
msg.param[1] = raw_info.jpeg.height; | |
create_dng_header(&raw_info); | |
create_thumbnail(&raw_info); | |
mydata = malloc(dng_header_buf_size + dng_th_width*dng_th_height*3 + raw_info.frame_size ); | |
memcpy(mydata,dng_header_buf,dng_header_buf_size); | |
size_t thumbnail_size = dng_th_width*dng_th_height*3; | |
memcpy(mydata + dng_header_buf_size, thumbnail_buf,thumbnail_size); | |
rawadr = (void*) raw_info.buffer; | |
reverse_bytes_order(rawadr, raw_info.frame_size); | |
memcpy(mydata + dng_header_buf_size + thumbnail_size, rawadr, raw_info.frame_size); | |
send_ptp_data(context, mydata, dng_header_buf_size + thumbnail_size + raw_info.frame_size); | |
free(mydata); | |
free_dng_header(); | |
break; | |
*/ | |
default: | |
msg.id = PTP_RC_ParameterNotSupported; | |
break; | |
} | |
context->send_resp( | |
context->handle, | |
&msg | |
); | |
return 0; | |
} | |
unsigned int get_single_frame(unsigned int ctx) | |
{ | |
if(get_a_frame != 1) | |
return 0; | |
if(my_single_frame == 0) | |
return 0; | |
raw_lv_redirect_edmac(my_single_frame); | |
get_a_frame=2; | |
return 0; | |
/* | |
if (!sp_running) return 0; | |
if (!sp_buffer_count) { sp_running = 0; return 0; }; | |
if (!raw_lv_settings_still_valid()) { sp_running = 0; return 0; } | |
if (silent_pic_mode == SILENT_PIC_MODE_SLITSCAN) | |
{ | |
silent_pic_raw_slitscan_vsync(); | |
return 0; | |
} | |
// are we done? | |
if ((sp_num_frames >= sp_min_frames && !get_halfshutter_pressed()) || sp_num_frames >= sp_max_frames) | |
{ | |
sp_running = 0; | |
return 0; | |
} | |
int next_slot = sp_num_frames % sp_buffer_count; | |
if (silent_pic_mode == SILENT_PIC_MODE_BEST_FOCUS) | |
{ | |
next_slot = silent_pic_raw_choose_next_slot(); | |
} | |
// Reprogram the raw EDMAC to output the data in our buffer (ptr) | |
raw_lv_redirect_edmac(sp_frames[next_slot % sp_buffer_count]); | |
sp_num_frames++; | |
bmp_printf(FONT_MED, 0, 60, "Capturing frame %d...", sp_num_frames); | |
return 0; | |
*/ | |
} | |
MODULE_CBRS_START() | |
MODULE_CBR(CBR_VSYNC, get_single_frame, 0) | |
MODULE_CBRS_END() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This comment has been minimized.
Hello natschil,
I would like to use your ML PTP extension for capturing silencing pictures via libgphoto2 for astrophotography.
Could you please upload also your ptp-extra.h?
Have you managed to make it work with libgphoto2 or libptp2?
Regards