Skip to content

Instantly share code, notes, and snippets.

@natschil
Created November 19, 2019 11:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save natschil/800920c9adbf30d375494c73a7676377 to your computer and use it in GitHub Desktop.
Save natschil/800920c9adbf30d375494c73a7676377 to your computer and use it in GitHub Desktop.
/** \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()
@andreok
Copy link

andreok commented Dec 5, 2019

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment