PicoC scripting API

Started by a1ex, January 26, 2013, 01:24:01 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.


Current nightly builds can now run PicoC scripts :)

General-purpose functions

void sleep(float seconds);                            // sleep X seconds
void beep();                                          // short beep sound
void beeps(int num);                                  // short consecutive beeps
void console_show();                                  // show the script console
void console_hide();                                  // hide the script console
void cls();                                           // clear the script console
void screenshot();                                    // take a screenshot (BMP+422)
unsigned int rand();                                  // random numbers



struct tm
     int hour;
     int minute;
     int second;
     int year;
     int month;
     int day;

struct tm * get_time();                               // get current date/time
float get_uptime();                                   // get uptime, in seconds, 1ms resolution (from DIGIC clock)


Picture taking

void takepic();                                       // take a picture
void bulbpic(float seconds);                          // take a picture in bulb mode
void take_fast_pics(int number);                      // take N pictures in burst mode

void wait_pic();                                      // waits until you take a picture (e.g. for starting a custom bracket sequence)


Video recording

void movie_start();                                   // start recording
void movie_end();                                     // stop recording


Key press emulation

Available button codes:
     Q, ZOOM_OUT (if present on your camera)
     UNPRESS (for key input only)

void press(int button);                               // "press" a button
void unpress(int button);                             // "unpress" a button
void click(int button);                               // "press" and then "unpress" a button


Key input

Two methods:
- blocking:      int key = wait_key();      // waits for key to be pressed, then returns the key code
- non-blocking:  int key = last_key();     // returns the last key code without waiting (or -1)

Keys are trapped when you call one of those, and also 1 second after. This lets you write loops like:

    int key = wait_key();

    // process the key
    if (key == SET) { ... }


    int key = last_key();

    // process the key
    if (key == SET) { ... }


int wait_key();                                       // waits until you press some key, then returns key code
int last_key();                                       // returns last key pressed, without waiting


Exposure settings

// APEX units
float get_tv();                                       
float get_av();                                       
float get_sv();                                       
void set_tv(float tv);                               
void set_av(float av);                               
void set_sv(float sv);                               

// Conventional units ( ISO 100, 1.0/4000, 2.8 )
int get_iso();                                       
float get_shutter();                                 
float get_aperture();                                 
void set_iso(int iso);                               
void set_shutter(float s);                           
void set_aperture(float s);                           

// Raw units (1/8 EV steps)
int get_rawiso();                                     
int get_rawshutter();                                 
int get_rawaperture();                               
void set_rawiso(int raw);                             
void set_rawshutter(int raw);                         
void set_rawaperture(int raw);                       


Exposure compensation (in EV)

float get_ae();                                       
void set_ae(float ae);                               


Flash functions

int get_flash();                                      // 1=enabled, 0=disabled, 2=auto
int set_flash(int enabled);                           
int pop_flash();                                      // pop-up built-in flash
float get_flash_ae();                                 
void set_flash_ae(float ae);                          // flash exposure compensation


White balance

int get_kelvin();                                     
int get_green();                                     
void set_kelvin(int k);                               // from 1500 to 15000
void set_green(int gm);                               // green-magenta shift, from -9 to 9



void focus(int steps);                                // move the focus ring by X steps
void focus_setup(int stepsize, int delay, int wait);  // see Focus -> Focus Settings menu
int get_focus_confirm();                              // return AF confirmation state (outside LiveView, with shutter halfway pressed)

void set_af(int af);                                  // enable or disable AF for half-shutter press
void reset_af(int af);                                // restore the original setting from Canon menu (CFn) (auto-called when script finishes)

int get_afma(int mode);                               // get AF microadjust value
void set_afma(int value, int mode);                   // set AF microadjust value

struct dof
     char* lens_name;
     int focal_len;
     int focus_dist;
     int dof; int far;
     int near;
     int hyperfocal;

struct dof * get_dof();                               


Low-level I/O

void mic_out(int value);                              // digital output via microphone jack, by toggling mic power
void set_led(int led, int value);                     // set LED state; 1 = card LED, 2 = blue LED



Graphics constants:


    FONT(fnt, fg, bg)

void clrscr();                                        // clear screen
int get_pixel(int x, int y);                         
void put_pixel(int x, int y, int color);             
void draw_line(int x1, int y1, int x2, int y2, int color);
void draw_line_polar(int x, int y, int radius, float angle, int color);
void draw_circle(int x, int y, int radius, int color);
void fill_circle(int x, int y, int radius, int color);
void draw_rect(int x, int y, int w, int h, int color);
void fill_rect(int x, int y, int w, int h, int color);


Text output

void bmp_printf(int fnt, int x, int y, char* fmt, ...);
void notify_box(float duration, char* fmt, ...);     


Interaction with Canon GUI

void set_canon_gui(int enabled);                      // allow disabling Canon graphics
void set_gui_mode(int mode);                          // set Canon GUI mode (current dialog, 0=idle, 1=play, 2=menu, others camera-specific)
int get_gui_mode();                                   


Interaction with ML menus

// Tip: to get a list with menus and possible values, go to Prefs -> Config File -> Export as PicoC script
// You can also use these functions to create custom presets.
void menu_open();                                     // open ML menu
void menu_close();                                    // close ML menu
void menu_select(char* tab, char* entry);             // select a menu tab and entry (e.g. Overlay, Focus Peak)
int menu_get(char* tab, char* entry);                 // return the raw (integer) value from a menu entry
int menu_set(char* tab, char* entry, int value);      // set a menu entry to some arbitrary value; 1 = success, 0 = failure
char* menu_get_str(char* tab, char* entry);           // return the displayed (string) value from a menu entry
int menu_set_str(char* tab, char* entry, char* value); // set a menu entry to some arbitrary string value (cycles until it gets it); 1 = success, 0 = failure


Image analysis

Don't expect too much; it's quite slow to operate at pixel level due to interpreter overhead.
Consider using plain C for this task.

Functions that operate on larger data sets (e.g. spotmeter, histogram analysis) should be fast enough.

struct yuv
     int Y; // 0...255
     int U; // -128...127
     int V; // -128...127

struct rgb
     int R; // 0...255
     int G; // 0...255
     int B; // 0...255

// The following functions operate on normalized coordinates (720x480)
// This means they should work on external monitors without extra care, for example.
// Details: http://magiclantern.wikia.com/wiki/VRAM/Geometry
struct yuv * get_pixel_yuv(int x, int y);             // get the YUV components of a pixel from LiveView buffer
struct rgb * get_pixel_rgb(int x, int y);             // similar for RGB
struct yuv * get_spot_yuv(int x, int y, int size);    // spotmeter: average pixels from a (small) box and return average YUV.
struct rgb * get_spot_rgb(int x, int y, int size);    // similar for RGB

For low-level image processing

struct vram
     void* buffer;
     int width;
     int pitch;
     int height;
struct vram * get_lv_vram();                          // get LiveView image buffer
struct vram * get_hd_vram();                          // get LiveView recording buffer



void display_on();                                   
void display_off();                                   
int display_is_on();                                 

void lv_pause();                                      // pause LiveView without dropping the mirror
void lv_resume();                                     


Cache hacking

unsigned int cache_locked();                         
void cache_lock();                                   
void cache_unlock();                                 
void cache_fake(unsigned int address, unsigned int data, unsigned int type);


Camera info

char* get_model();                                   
char* get_firmware();                                 


Sample scripts
hello.c - first steps
brack.c - custom bracketing sequence
keys.c - key press demo
test.c - API tests, and usage example for each function
sokoban.c - a simple game

To create a script, just place it in the ML/SCRIPTS directory, with the C extension, and they will be autodetected. Use short 8.3 names. You can place max 15 scripts there.

Startup script
If one of the scripts is named AUTORUN.C, it will be executed at startup, automatically.

Looking forward to see what you can do with these scripts. You can use this forum section to share them.

- Extend the API (and keep it clean). Here I'd like to see your suggestions. Feel free to implement the todo list (commented APIs) from picoc/library_ml.c.
- [DONE] Edit script parameters (like CHDK).
- In-camera script editing (so you can change small things in the field).
- Compile a desktop PicoC interpreter (so you can try the scripts offline). ML will run in QEMU
- etc


No clue on how easy it would be to implement this and if PicoC would allow something like it. But how about parameters? When executing a script, a few parameters can be defined by the user. Would be very useful and make the In-Camera editor (which would be allot of work to implement as well) sort of needless.

But otherwise I really welcome this addition. PicoC is very easy to learn and many might benefit from this.

GUI stuff: print(); or even set_pixel(); get_pixel();?
Focus stuff: get_af(); set_focus_distance(); get_focus_distance();

EDIT: I'm blind, you even mention parameters in the ToDo list..


still pushes my bins over 500K, couldn't we just increase bin size and  allocate more memory? 500k not enough if you use o2 or o3


On 60D there is ~480K in the small buffer (currently 430K for ML and 50K free). There's no space to load ML on the large one (1MB left, but Canon code requires it). 600D/1100D aren't much better. I wouldn't increase binary size in the main tree, but if you have a lot of free RAM you can experiment with it.

If you compile with O2/O3, you can optimize only the modules you need.


How about close consolle after script execution? On 600D after the script has ended only way to go back to camera is halfshutter, other buttons are working normally buy dialog screens can't be seen since console is over all.
When console is opened to show the script (so we stay in ML menu screen) console goes away pressing any button and is better

EDIT: Also focus peak is broke now (like wrong image size seems), only for me? Fix worked
I'm using ML2.3 for photography with:
EOS 600DML | EOS 400Dplus | EOS 5D MLbeta5- EF 100mm f/2.8 USM Macro  - EF-S 17-85mm f4-5.6 IS USM - EF 70-200mm f/4 L USM - 580EXII - OsX, PS, LR, RawTherapee, LightZone -no video experience-


Is it possible to extend the API to add a new menu entry with

menu_add( "NewMenu", New_menus, COUNT(New_menus) );

The menu is already made for changing values and does it very good. This routine sets even the icons automatically.
The menu panel could also serve as a console.
I can imagine that it's not that easy and there is no menu_go_away() function.


AFAIK menus are statically compiled into ML (the MENU_ADD is actually a pre-processor macro)
EOS 1100D | EOS 650 (No, I didn't forget the D) | Ye Olde Canon EF Lenses ('87): 50 f/1.8 - 28 f/2.8 - 70-210 f/4 | EF-S 18-55 f/3.5-5.6 | Metz 36 AF-5


I think it's dynamically. I changed the testplug.c and it's possible to add a menu after ML has started.


Check the latest changeset: now each script has its own menu entry and its own submenu, and script parameters could be added there.

Creating menus on the fly it's a bit tricky, I prefer to avoid it.


I've tried hello script and was only 1 pic left of space on card so the script got hang and no way to stop it, can we add a stop script option in the script submenu? I can see it showing script going on right now.
I'm using ML2.3 for photography with:
EOS 600DML | EOS 400Dplus | EOS 5D MLbeta5- EF 100mm f/2.8 USM Macro  - EF-S 17-85mm f4-5.6 IS USM - EF 70-200mm f/4 L USM - 580EXII - OsX, PS, LR, RawTherapee, LightZone -no video experience-


Regarding extending scripting functions/calls, as a CHDK user as well as a ML user, would it be a good start to emulate some of the CHDK scripting functionality. For instance, I have an autobracketing script that runs in CHDK where i access a CHDK histogram call to get the histogram at a 12bit level, ie the level my S95 and G11 operates at. This page gives an example of the functions http://chdk.wikia.com/wiki/CHDK_Scripting_Cross_Reference_Page

Just a thought, as the CHDK community have done a lot for scripting of P&S cameras, so why reinvent the wheel, lets bootstrap!


Yes, CHDK is a good starting point. But achieving 100% compatibility is not very easy (histogram here is 8 bit, EV values are not in 1/96 EV steps, but in 1/8 and so on.

Some things are easy to port (draw_line, draw_pixel, reboot,  set_backlight,  set_led).



Some of the CHDK community have sent time pushing the limits. For instance, as I say, I use a histo call that covers 12bits, and it could be extended to 14bit. It is achieved by sampling  the sensor RAW. Also all the exposure calls work in APEX 96 space.

What is was suggesting is that at least we look at where CHDK is as we construct an ML requirements set of functions. For instance, I know one of the CHDK community has added in functions in CHDK few sensor level exposure reading such that in camera  holly grail timelapse can be smoothly achieved.

Obviously some of the ML functions will be unique to ML, eg mirror up functions, if possible, however, any will and I suggest should be common.

Bottom line: whatever the ML. Developers, such as yourself, can do will be great; IMHO there could be beneficial if the ML community took stock of the CHDK scripting status, especially in the 1.2 developers trunk.


QuoteIf you compile with O2/O3, you can optimize only the modules you need.

Still a bit too big. on 6D there seems to be more ram. wish i could have both scripts and optimization. camera i much snappier with the opts


Script parameters seem to work :)

They use CHDK syntax: @title, @param, @default and @range. They are not yet saved to config file (you can only change them in RAM).

@wolf, can you try to port your timelapse script, and see what's missing?


Is there a possibilty to display a string which can be updated?

I try to change it to picoc runable without displaying the lasting time human readable.

        .name = "Duration",
        .priv = &v,
        .max = 0,
        .choices = (const char *[]) {time_str},
        .help = "",
char* sec_to_time(int seconds)
    int minutes, hours;
    hours=seconds % 86400 / 3600;
    minutes=seconds % 3600 / 60;
    seconds=seconds % 60;
    const char colon[] = ":";
    snprintf(time_str,sizeof(time_str), "%02d%s%02d%s%02d",hours,colon,minutes,colon,seconds );
    return time_str;


You can't interact with the menu, but you can print it at the console, with plain printf.


Only for design reasons, is it very unlikely that the menu could be interactive one day? I am very happy with ML the way it is right now.

And do you think "bmp_printf" should be added to the API, I guess it's not that hard.
In my plugin I print some info with small letters in the corner.


I just thought while trying picoc, if it would be better to change the menu items and add an exit option when selecting a script instead of open a submenu.

QuoteCreating menus on the fly it's a bit tricky, I prefer to avoid it.
also changing?

The benefit of it would  be that the selected script would be already present when switching back to ML after LV for example.

The main reason for my timelaps script was , that I wanted to know the duration of the timelaps and to play with ML.  ;)
But I am not sure if interactivity is that important,  I guess in most scripts it's not needed. If it is needed, it can be already done!

My first script: I always wanted to take a picture at a specific time!
@title Shoot at a time
@param h Hour
@range h 0 23
@param m Minute
@range m 0 59
@param s Second
@range s 0 59
struct tm * t = get_time();
int hour,minute,second;
while ((hour != h) ||  (minute != m) ||  (second != s))
    t = get_time();
    hour = t->hour;
    minute = t-> minute;
    second = t->second;
printf("Done :)\n");


On 600D I can't see the options pictured in the OP to enable the test.c script
I'm using ML2.3 for photography with:
EOS 600DML | EOS 400Dplus | EOS 5D MLbeta5- EF 100mm f/2.8 USM Macro  - EF-S 17-85mm f4-5.6 IS USM - EF 70-200mm f/4 L USM - 580EXII - OsX, PS, LR, RawTherapee, LightZone -no video experience-


Does anybody know if the letters of @param have to be in alphabetical order? I get incorrect Parameter Text when letters aren't in order.


Fixed. I wonder why CHDK guys didn't notice it, since it was from their code.


what about this program http://www.zenoshrdlu.com/kapstuff/zubdb.html will it work with ML scripts? only ubasic
I'm using ML2.3 for photography with:
EOS 600DML | EOS 400Dplus | EOS 5D MLbeta5- EF 100mm f/2.8 USM Macro  - EF-S 17-85mm f4-5.6 IS USM - EF 70-200mm f/4 L USM - 580EXII - OsX, PS, LR, RawTherapee, LightZone -no video experience-


Wrote a very basic and rough picoc-ml parser bash script to try and test a script outside the camera. I just implemented the functions I needed lately.
Usage: ml_picoc_parser.sh "script-file"


# ml_picoc_parser.sh
echo "//temporary file just delete me" > foo.c
echo "#include<ml_functions.h>" >> foo.c
while read line;do
        a=( $line )
        if [ "${a[0]}" = "@param" ];then
                echo "int ${a[1]};" >> foo.c
        if [ "${a[0]}" = "@default" ];then
                echo "${a[1]}=${a[2]};" >> foo.c
done < "$FILE"
cat $1>>foo.c

picoc -s foo.c

ml_functions.h can be easily extended

// ml_functions.h

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>

#define SHOOT_HALF 0
#define SHOOT_FULL 1

void beep()

void sleep(float n)

void click(int x)
if (x==0)
if (x==1)

void console_show()

void console_hide()

void display_on()

void display_off()

void lv_pause()

void lv_resume()


Imho this is an important feature, so it'd be a pitty if the development should stall - I suggest a script option for triggering ml features: void start_ml_shooting(int feature) for things like focus stack, bracketing or intervalometer to enable this http://www.magiclantern.fm/forum/index.php?topic=4622.0 ... or are these ml features supposed to be started with keypress emulation?