ge0rg / samsung-nx-hacks

Firmware Hacks for the Linux-based Samsung NX mirrorless camera models (NX300, NX2000, ???)
118 stars 12 forks source link

Set intervalometer to 90s+ for astrophotography #34

Open FranchDressin opened 1 month ago

FranchDressin commented 1 month ago

Posting here because the intervalometer page is over 7 years old and I'm not sure where else would be better.

I want to use my NX300 for astrophotography, but need exposure times longer than 30s. The current Intervalometer hack uses the camera's selected exposure time, and you set the interval (time between shots) with the hack's menu.

Is there a way to modify it to use BULB mode to take 90s+ exposures with a short interval? (something like 3s) Currently if BULB is selected it only takes 1s exposures.

Thanks for any advice in advance, and here is the link to the source code for the intervalometer hack: https://github.com/HausnerR/nx300-hacks/blob/master/src/intervalometer/intervalometer.c

sithil94 commented 2 weeks ago

I haven't found any way to do bulb exposures with software, maybe the only way is to build an external intervalometer/shutter trigger with an arduino or smth.

ge0rg commented 2 weeks ago

The respective code in the intervalometer will only click the shutter, not hold it :

sprintf(buf, "while true; do st key push s1; st key click s2; st key release s1; sleep %d; done &", i);

This will, repeatedly:

The right sequence would be push s1, push s2, wait, release s2, release s1.

I've written a respective shell script, but it doesn't have a UI. I can upload it to a gist if so desired.

FranchDressin commented 2 weeks ago

Hey ge0rg, for my astrophotography purposes, I don't actually need a customizable interval, something like 3s to let the sensor cool between shots is fine. I attempted to make a modification of the code that replaces the UI interval value with the exposure length, so I can take exposures up to 4 minutes. I wasn't able to compile this due to some issues with me knowing nothing about coding or linux :)

I'd love to try your shell script, and I'll include my modified version of intervalometer.c that I think might work, and request if you could please compile it for me if you have the means (assuming it even works at all). Thank you for replying to my post :)

#include <Elementary.h>
#include <strings.h>
#include <Ecore.h>
#include <Ecore_Input.h>

Evas_Object *win, *bg, *box, *label, *input, *button_cancel, *button_ok;

static void ok_button_clicked(void *data, Evas_Object *obj, void *event_info)
{
    int press_duration = strtol(elm_object_text_get(input), NULL, 10);
    elm_exit();

    system("st lcd set 4");

    // Fixed interval of 3 seconds
    int interval = 3;

    // Start the shutter press sequence
    char* buf = (char *)malloc(200 * sizeof(char));
    sprintf(buf, "while true; do st key push s1; st key push s2; sleep %d; st key release s2; st key release s1; sleep %d; done &", press_duration, interval);
    system(buf);

    exit(0);
}

static void cancel_button_clicked(void *data, Evas_Object *obj, void *event_info)
{
    elm_exit();
    exit(255);
}

static Eina_Bool key_down_callback(void *data, int type, void *ev)
{
    Ecore_Event_Key *event = ev;

    if (!strcmp("KP_Enter", event->key))
    {
        ok_button_clicked(NULL, NULL, NULL);
    }

    if (!strcmp("Menu", event->key))
    {
        cancel_button_clicked(NULL, NULL, NULL);
    }

    if (!strcmp("KP_Up", event->key) || !strcmp("KP_Down", event->key))
    {
        int i = strtol(elm_object_text_get(input), NULL, 10);
        if (!strcmp("KP_Up", event->key) && i < 999) i++;
        if (!strcmp("KP_Down", event->key) && i > 0) i--;

        char* buf = (char *)malloc(3 * sizeof(char));
        sprintf(buf, "%d", i);
        elm_object_text_set(input, buf);
        elm_entry_cursor_pos_set(input, 10000);
    }

    return ECORE_CALLBACK_PASS_ON;
}

EAPI int
elm_main(int argc, char **argv)
{
    ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, key_down_callback, NULL);

    win = elm_win_add(NULL, "Info", ELM_WIN_BASIC);
    elm_win_rotation_set(win, 270); // NX300 have rotated interface!
    evas_object_move(win, 310, 80);
    elm_win_title_set(win, "Info");

    bg = elm_bg_add(win);
    elm_bg_color_set(bg, 230, 230, 230);
    elm_win_resize_object_add(win, bg);
    evas_object_show(bg);

    box = elm_box_add(win);
    elm_win_resize_object_add(win, box);
    evas_object_show(box);

    Evas_Object* table = elm_table_add(win);
    elm_box_pack_end(box, table);
    evas_object_show(table);

    label = elm_label_add(win);
    elm_object_text_set(label, "<align=center>Shutter Press Duration (s):</align>");
    evas_object_size_hint_min_set(label, 300, 40);
    evas_object_size_hint_padding_set(label, 10, 10, 20, 10);
    elm_table_pack(table, label, 1, 1, 1, 1);
    evas_object_show(label);

    static Elm_Entry_Filter_Limit_Size limit_size = {
        .max_char_count = 3,
        .max_byte_count = 0
    };

    input = elm_entry_add(win);
    elm_entry_entry_set(input, "1"); // Default to 1 second
    elm_entry_cursor_pos_set(input, 10000);
    elm_entry_single_line_set(input, EINA_TRUE);
    elm_entry_input_panel_layout_set(input, ELM_INPUT_PANEL_LAYOUT_NUMBERONLY);
    elm_entry_markup_filter_append(input, elm_entry_filter_limit_size, &limit_size);
    evas_object_size_hint_padding_set(input, 10, 10, 20, 10);
    elm_table_pack(table, input, 2, 1, 1, 1);
    evas_object_show(input);
    elm_object_focus_set(input, EINA_TRUE);

    button_cancel = elm_button_add(win);
    elm_object_text_set(button_cancel, "Cancel");
    evas_object_size_hint_min_set(button_cancel, 300, 75);
    evas_object_size_hint_padding_set(button_cancel, 10, 10, 10, 10);
    elm_table_pack(table, button_cancel, 1, 2, 1, 1);
    evas_object_smart_callback_add(button_cancel, "clicked", cancel_button_clicked, NULL);
    evas_object_show(button_cancel);

    button_ok = elm_button_add(win);
    elm_object_text_set(button_ok, "OK");
    evas_object_size_hint_min_set(button_ok, 300, 75);
    evas_object_size_hint_padding_set(button_ok, 10, 10, 10, 10);
    elm_table_pack(table, button_ok, 2, 2, 1, 1);
    evas_object_smart_callback_add(button_ok, "clicked", ok_button_clicked, NULL);
    evas_object_show(button_ok);

    evas_object_show(win);

    elm_run();

    return 0;
}
ELM_MAIN()
FranchDressin commented 1 week ago

The respective code in the intervalometer will only click the shutter, not hold it :

sprintf(buf, "while true; do st key push s1; st key click s2; st key release s1; sleep %d; done &", i);

This will, repeatedly:

* push s1 (half press the shutter)

* click s2 (fully press and half release the shutter)

* release s1 (fully release the shutter)

* wait the interval

The right sequence would be push s1, push s2, wait, release s2, release s1.

I've written a respective shell script, but it doesn't have a UI. I can upload it to a gist if so desired.

could you post that gist and potentially compile what I included in my above comment? Thanks