PicoC scripting

Started by wolf, December 06, 2012, 03:00:10 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

wolf

Hi there,
does anybody know if pymite is still supported. I think, after trying lua, which only operates at the moment with integer numbers, python would be the better scripting language.
When I try to compile ML with pymite=y :
make[1]: *** No rule to make target `script.o', needed by `magiclantern'.  Stop.

Thanks

a1ex

If anyone would like to port it, be my guest.

There was some success with PicoC on CHDK forum, but the patch disappeared due to a server error. It shouldn't be too hard to try to port it again. It uses quite a bit less RAM than Lua, so it may be a good idea.

wolf

PicoC sounds good to me. Porting a scripting language to ML is ways beyond my little programming skills. I guess a scripting language for ML is only used by a few people and therefore I like ML the way it is.
I wonder if Pico C would be fast enough to replace the timelapse function or motion detection and could it be able to handle the HDR automatic function?

a1ex

I'd say yes, worth giving it a try.

wolf

Found this patch of yours:
Forum site
http://chdk.setepontos.com/index.php?topic=6161.630
patch
chdk.setepontos.com/index.php?action=dlattach;topic=6161.0;attach=5339

Is this the missing patch?
I just compiled Picoc on my Linux box and it is really awesome. The code runs as a script and it could be compiled too. Amazing - with math lib and "normal" printf!

So now I wonder if it would be possible run a pico compiled code nativley on a EOS camera and would the code run faster?

a1ex


maxchen

I did a ugly picoc port to ML before, base on a very old version of ML.
Testing on my 50D is OK.

How can I upload an attachment ?


#ifdef CONFIG_PICOC
/* script functions */
#define SCRIPT_NUM 5
#define LINE_BUF_SIZE 30
#define PICOC_HEAP_SIZE (30*1024)

char *script_list[SCRIPT_NUM]={NULL};
int script_selected=0;
int script_cnt = 0;

/*
int * script_read_line(const char *script_source, char *buf, int line)
{
    int line_pos = 0;
    char *pos, *line_start;

    line_start = pos = script_source;
    while (*pos != '\0') {
        if (*pos == '\n') {
            if (++line_pos == line) {
                my_memcpy(buf, line_start,pos-line_start);
                buf[pos-line_start] = '\0';
                return pos-line_start;
            } else {
                line_start = pos + 1;
            }
        }
        pos++;
    }
   
    return 0;
}
*/

/* modify from is_valid_cropmark_filename */
int is_valid_script_filename(char* filename)
{
int n = strlen(filename);
if ((n > 2) && (streq(filename + n - 2, ".C") || streq(filename + n - 2, ".c")) && (filename[0] != '.') && (filename[0] != '_'))
return 1;
return 0;
}

static void find_scripts(void)
{
    char buf[LINE_BUF_SIZE];
struct fio_file file;
struct fio_dirent * dirent = FIO_FindFirstEx( CARD_DRIVE "scripts/", &file );
if( IS_ERROR(dirent) )
{
NotifyBox(2000, "Scripts dir missing" );
msleep(100);
NotifyBox(2000, "Please copy all ML files!" );
return;
}
script_cnt = 0;
do {
        if ((file.mode & 0x20) && is_valid_script_filename(file.name)) {
            /* get the full path of the script */
            snprintf(buf,LINE_BUF_SIZE,"%s%s%s%c",CARD_DRIVE,"scripts/",file.name,'\0');
            int len = strlen(buf);
            script_list[script_cnt] = (char *)AllocateMemory(len+1);
            strncpy(script_list[script_cnt], buf, len);
            script_list[script_cnt++][len] = '\0';

            if (script_cnt >= SCRIPT_NUM)
                break;
        }
} while( FIO_FindNextEx( dirent, &file ) == 0);
FIO_CleanupAfterFindNext_maybe(dirent);
}

static void
script_select_display( void * priv, int x, int y, int selected )
{
bmp_printf(
selected ? MENU_FONT_SEL : MENU_FONT,
x, y,
"Scripts(%d/%d): %s",script_selected,script_cnt,
script_selected==0?"OFF":(script_list[script_selected-1]+strlen(CARD_DRIVE"scripts/"))
);
}

static void script_select(void)
{
    if (script_cnt == 0)
        find_scripts();

    if (++script_selected > script_cnt)
        script_selected = 0;
}

void run_script(const char *script)
{
    extern int PicocExitBuf[];
    PicocInitialise(PICOC_HEAP_SIZE);
    PicocExitBuf[40] = 0;
    setjmp(PicocExitBuf);
    PlatformScanFile(script_list[script_selected-1]);
    PicocCleanup();
}

void script_run_fun(void)
{
    if (script_selected == 0)
        return;

task_create("run_script", 0x1c, 0, run_script, 0);
}

/* end script functions */
#endif

//for the menu
#ifdef CONFIG_PICOC
{
.priv = &script_selected,
.display = script_select_display,
.select = script_select,
},
{
.priv = "Run script",
.display = menu_print,
.select = script_run_fun,
},
#endif


wolf

Thanks for your reply and welcome.  :)
I guess you can upload changes as a patch or you can fork the official source code on
https://bitbucket.org/hudson/magic-lantern/src


a1ex

Tip: to get proper credit in the repo, the preferred way is to make a fork and create a pull request.

maxchen

Thanks for the tip, I will try to port picoc as a plugin.

a1ex

I think I've got it working fairly smoothly. Here's my test script:

Quote
printf("Hello from PicoC!\n");
msleep(3000);

int n = 3;
for (int i = 0; i < n; i++)
{
    printf("Taking pic %d of %d...\n", i+1, n);
    msleep(1000);
    shoot();
}

printf("Done :)\n");

The scripting API only has msleep and shoot, so it's not very useful right now.

To try it, enable CONFIG_PICOC = y and CONFIG_CONSOLE = y in Makefile.user and compile ML yourself.

Static memory usage: 43K (including GUI). If you want floating point support, that's 32K more. So it's probably small enough to include it in main builds in near future.

Suggestions for the scripting API?

wolf

Suggestions for the scripting API?

Very nice.

I, am a great fan of silent pics, cause the preserve the camera even if I haven't  figured out how to use them with a aperture (sticky button?).
So I suggest half button.
I also suggest  RTC to take a pic or shot a movie at a specific date and or time and setting aperture, time, focus, switch LV which could be interesting for sunset timelaps and the calculation  for example.
And change values inside a script would be awesome. But we can already do this with native(are the so called?) plugins.

I know it's a lot of...

gerk.raisen

Excellent work A1ex
Totally agree with wolf :)
Please add an API to interact with the sound dB level read from microphone (like the one used in Audio remoteshot), I have idead for interesting uses.

PS. Tried enabling picoc on my 60D: compile ok, camera starts but crash to err70 after a few second without doing nothing,


a1ex

Works for me on 60D, but there are only 8K of free RAM left for Canon firmware.

Disabling some unused features (from features.h) may help.

gerk.raisen

Thank you...solved
I have only disabled the GDB, old PLUGINS, and CONFIG_STRESS_TEST
leaving on all defaults plus PICOC, PTP-ML and FEATURE_SILENT_PIC_HIRES (work flawlessy on my 60D)
Now the hello.c and I have 21k free!

I can't wait for new API :)


wolf

Hello.c works, but I cant see any printed message on my 550D. (printf("Hello from PicoC!\n");)

and can't compile ML with CONFIG_PLUGINS  = y

...
[ CC       ]   plugin.o
In file included from ../../src/all_headers.h:11:0,
                 from ../../src/plugin.c:4:
../../src/console.h:5:1: error: expected identifier or '(' before '{' token
../../src/console.h:5:31: error: 'console_puts' undeclared here (not in a function)
../../src/console.h:7:1: error: expected identifier or '(' before '{' token
../../src/console.h:7:30: error: 'console_printf' undeclared here (not in a function)
make[1]: *** [plugin.o] Error 1
make[1]: Leaving directory `/home/wolf/magic-lantern/platform/60D.111'
make: *** [60D] Error 2

g3gg0

you have to enable CONFIG_CONSOLE too
Help us with datasheets - Help us with register dumps
magic lantern: 1Magic9991E1eWbGvrsx186GovYCXFbppY, server expenses: [email protected]
ONLY donate for things we have done, not for things you expect!

a1ex


wolf

Picoc works now for me on 550D :-)

Now I get this error when I try to compile my old plugins:

...
[ CC       ]   plugin.o
[ CC       ]   console.o
[ AR       ]   lib_a-setjmp.o
[ AR       ]   libstdio.a
[ LD       ]   magiclantern
plugin.o:(.plugin_commands+0x104): undefined reference to `sprintf'
collect2: ld returned 1 exit status
make[1]: *** [magiclantern] Error 1
make[1]: Leaving directory `/home/wolf/magic-lantern/platform/60D.111'
make: *** [60D] Error 2

with this enabled:
CONFIG_PYMITE       = n
CONFIG_RELOC        = n
CONFIG_TIMECODE     = n
CONFIG_PTP          = n
CONFIG_PTP_CHDK     = n
CONFIG_PTP_ML       = n
CONFIG_GDB          = n
CONFIG_GDBSTUB      = n
CONFIG_PLUGINS      = y
CONFIG_CONSOLE      = y
CONFIG_DEBUGMSG     = 0
CONFIG_CCACHE       = n
CONFIG_PICOC        = n


a1ex

Here's a small sketch of the scripting API:


    /** General-purpose functions */
    {LibMsleep,         "void msleep(int delay);"       },  // sleep X milliseconds
    {LibBeep,           "void beep();"                  },  // short beep sound
    {LibConsoleShow,    "void console_show();"          },  // show the script console
    {LibConsoleHide,    "void console_hide();"          },  // hide the script console

    /** Date/time */
    {LibGetTime,        "struct tm * get_time();"},     // get current date/time (hour, minute, second, year, month, day); the pointer is to a static structure

    /** Picture taking */
    {LibTakePic,        "void takepic();"               },  // take a picture
    {LibBulbPic,        "void bulbpic(int ms);"         },  // take a picture in bulb mode
   
    /** Video recording */
    {LibMovieStart,     "void movie_start();"           },  // start recording
    {LibMovieEnd,       "void movie_end();"             },  // stop recording

    /** Button press emulation */
    // LEFT, RIGHT, UP, DOWN, SET, MENU, PLAY, ERASE, Q, LV, INFO, ZOOM_IN, ZOOM_OUT
    // SHOOT_FULL, SHOOT_HALF
    {LibPress,          "void press(int button);"       },  // "press" a button
    {LibUnpress,        "void unpress(int button);"     },  // "unpress" a button
    {LibClick,          "void click(int button);"       },  // "press" and then "unpress" a button

    /** Exposure settings */
    // APEX units
#if 0 // not yet implemented
    {LibGetTv,        "float get_tv();"                 },
    {LibGetAv,        "float get_av();"                 },
    {LibGetSv,        "float get_sv();"                 },
    {LibSetTv,        "void set_tv(float tv);"          },
    {LibSetAv,        "void set_av(float av);"          },
    {LibSetSv,        "void set_sv(float av);"          },

    // Conventional units (ISO 100, 1.0/4000, 2.8)
    {LibGetISO,        "int get_iso();"                 },
    {LibGetShutter,    "float get_shutter();"           },
    {LibGetAperture,   "float get_aperture();"          },
    {LibSetISO,        "void set_iso(int iso);"         },
    {LibSetShutter,    "void set_shutter(float s);"     },
    {LibSetAperture,   "void set_aperture(float s);"    },

    // Raw units (1/8 EV steps)
    {LibGetRawISO,      "int get_rawiso();"             },
    {LibGetRawShutter,  "int get_rawshutter();"         },
    {LibGetRawAperture, "int get_rawaperture();"        },
    {LibSetRawISO,      "void set_rawiso(int raw);"     },
    {LibSetRawShutter,  "void set_rawshutter(int raw);" },
    {LibSetRawAperture, "void set_rawaperture(int raw);"},
   
    /** Exposure compensation (in EV) */
    {LibGetAE,          "float get_ae();"               },
    {LibGetFlashAE,     "float get_flash_ae();"         },
    {LibSetAE,          "void set_ae(float ae);"        },
    {LibSetFlashAE,     "void set_flash_ae(float ae);"  },

    /** White balance */
    {LibGetKelvin,      "int get_kelvin();"             },
    {LibGetGreen,       "int get_green();"              },
    {LibSetKelvin,      "void set_kelvin();"            },
    {LibSetGreen,       "void set_green();"             },

    /** MLU, HTP, misc settings */
    {LibGetMLU,         "int get_mlu();"                },
    {LibGetHTP,         "int get_htp();"                },

    /** Interaction with menus */
    { LibMenuOpen,       "void menu_open();"            },  // open ML menu
    { LibMenuSelect,     "void menu_select(char* tab, char* entry);"}, // select a menu tab and entry (e.g. Overlay, Focus Peak)
    { LibMenuClose,      "void menu_close();"           },  // close ML menu
   
    /** Image analysis */
    { LibGetPixelYUV,    "void get_pixel_yuv(int x, int y, int* Y, int* U, int* V);" },          // get the YUV components of a pixel from LiveView (720x480)
    { LibGetSpotYUV,     "void get_spot_yuv(int x, int y, int size, int* Y, int* U, int* V);" }, // spotmeter: average pixels from a (small) box and return average YUV
    { LibYUV2RGB,        "void yuv2rgb(int Y, int U, int V, int* R, int* G, int* B);"},          // convert from YUV to RGB
    { LibRGB2YUV,        "void rgb2yuv(int R, int G, int B, int* Y, int* U, int* V);"},          // convert from RGB to YUV
    { LibGetHistoRange,  "float get_histo_range(int from, int to);"},                            // percent of values between <from> and <to> in histogram data
   
    /** Audio stuff */
    { LibAudioGetLevel,  "int audio_get_level(int channel, int type);" }, // channel: 0/1; type: INSTANT, AVG, PEAK, PEAK_FAST
    { LibAudioLevelToDB, "int audio_level_to_db(int level)"            }, // conversion from 16-bit signed to dB
   
    /** Powersaving */
    { LibDisplayOn,     "void display_on();"           },
    { LibDisplayOff,    "void display_off();"          },
    { LibDisplayIsOn,   "int display_is_on();"         },

    { LibLVPause,       "void lv_pause();"             }, // pause LiveView without dropping the mirror
    { LibLVResume,      "void lv_resume();"            },
#endif


Not all of this is implemented; should be straightforward, but a bit time consuming. Anyone would like to help me?

https://bitbucket.org/hudson/magic-lantern/commits/5385081fee78

a1ex

We can now run custom bracketing sequences :)


set_aperture(1.8);
set_iso(3200);
set_shutter(1./10);
takepic();

set_aperture(8);
set_iso(100);
takepic();

set_shutter(1);
takepic();

set_shutter(10);
takepic();

wolf

This is really great. Thanks a lot.
Now we can calculate for example the sun position and set the values for the images depending on the RTC for timelaps ramping and much more.  :)


a1ex

PicoC scripting will be enabled in tomorrow's nightly build, maybe more people can try it. Simple scripts seems to work pretty well so far.

gerk.raisen

Great work a1lex.


A simple suggestion:
now when you press on a script a submenu appear with the options in this order:

-Show Script
-Run Script

I think that inverting it can be better, so that when you are on a script you can run it with a double click on SET button.
Now you have to click on a script and go down with the arrow before you can run.

Thank you.