Ignore:
Timestamp:
03/23/11 04:41:29 (2 years ago)
Author:
reyalP
Message:

ptp script communication improvements, see http://chdk.setepontos.com/index.php?topic=4338.msg62725#msg62725
NOTE PTP protocol is updated, old clients will not be completely compatible

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/core/luascript.c

    r1036 r1101  
    1515#include "action_stack.h" 
    1616#include "motion_detector.h" 
     17#include "ptp.h" 
    1718 
    1819#include "../lib/lua/lstate.h"  // for L->nCcalls, baseCcalls 
     
    2021lua_State* L; 
    2122lua_State* Lt; 
    22 int lua_keep_result; 
    23  
    24 void *lua_consume_result() 
    25 { 
    26   lua_State* r = L; 
     23 
     24static int lua_script_is_ptp; 
     25 
     26static int yield_hook_enabled; 
     27 
     28static void lua_script_disable_yield_hook(void) { 
     29    yield_hook_enabled = 0; 
     30} 
     31static void lua_script_enable_yield_hook(void) { 
     32    yield_hook_enabled = 1; 
     33} 
     34 
     35#ifdef CAM_CHDK_PTP 
     36// create a ptp message from the given stack index 
     37// incompatible types will return a TYPE_UNSUPPORTED message 
     38static ptp_script_msg *lua_create_usb_msg( lua_State* L, int index, unsigned msgtype) { 
     39    // TODO maybe we should just pass the lua type constants 
     40    unsigned datatype, datasize = 4; 
     41    int ivalue = 0; 
     42    void *data = &ivalue; 
     43    int ltype = lua_type(L,index); 
     44    switch(ltype) { 
     45        case LUA_TNONE: 
     46            return NULL; // nothing on the stack, no message generated 
     47        break; 
     48        case LUA_TNIL: 
     49            datatype = PTP_CHDK_TYPE_NIL; 
     50        break; 
     51        case LUA_TBOOLEAN: 
     52            datatype = PTP_CHDK_TYPE_BOOLEAN; 
     53            ivalue = lua_toboolean(L,index); 
     54        break; 
     55        case LUA_TNUMBER: 
     56            datatype = PTP_CHDK_TYPE_INTEGER; 
     57            ivalue = lua_tonumber(L,index); 
     58        break; 
     59        case LUA_TSTRING: 
     60            datatype = PTP_CHDK_TYPE_STRING; 
     61            data = (char *)lua_tolstring(L,index,&datasize); 
     62        break; 
     63        // TODO this converts to a string and returns as STRING, format as described at  
     64        // http://chdk.setepontos.com/index.php?topic=4338.msg62606#msg62606 
     65        // for compatibility with current PTPCAM/PTPCAMGUI implementation 
     66        // later we should switch to a proper serialized table with it's own return type 
     67        case LUA_TTABLE:  
     68            lua_script_disable_yield_hook(); // don't want to yeild while converting 
     69            lua_getglobal(L, "usb_msg_table_to_string"); // push function 
     70            lua_pushvalue(L, index); // copy specified index to top of stack 
     71            lua_pcall(L,1,1,0); // this will leave an error message as a string on the stack if call fails 
     72            lua_script_enable_yield_hook(); 
     73            // an empty table will be returned as an empty string 
     74            // a non-string should never show up here 
     75            if ( !(lua_isstring(L,-1) /*&& ( lua_objlen(L,-1) > 0 )*/)) {  
     76                return NULL; 
     77            } 
     78            datatype = PTP_CHDK_TYPE_STRING; 
     79            data = (char *)lua_tolstring(L,-1,&datasize); 
     80            lua_pop(L,1); 
     81        break; 
     82        default: 
     83            datatype = PTP_CHDK_TYPE_UNSUPPORTED; 
     84            data = (char *)lua_typename(L,ltype); // return type name as message data 
     85            datasize = strlen(data); 
     86    } 
     87    return ptp_script_create_msg(msgtype,datatype,datasize,data); 
     88} 
     89 
     90void lua_script_error_ptp(int runtime, const char *err) { 
     91    if(runtime) { 
     92        ptp_script_write_error_msg(PTP_CHDK_S_ERRTYPE_RUN, err); 
     93        script_end(); 
     94    } else { 
     95        ptp_script_write_error_msg(PTP_CHDK_S_ERRTYPE_COMPILE, err); 
     96        lua_script_reset(); 
     97    } 
     98} 
     99#endif 
     100 
     101void lua_script_reset() 
     102{ 
     103  lua_close( L ); 
    27104  L = 0; 
    28   return r; 
    29 } 
    30  
    31 void lua_script_reset() 
    32 { 
    33   if ( !lua_keep_result ) 
    34   { 
    35     lua_close( L ); 
    36     L = 0; 
    37   } 
    38   Lt = 0; 
    39105} 
    40106 
    41107static void lua_count_hook(lua_State *L, lua_Debug *ar) 
    42108{ 
    43   if( L->nCcalls <= L->baseCcalls ) 
     109  if( L->nCcalls <= L->baseCcalls && yield_hook_enabled ) 
    44110    lua_yield( L, 0 ); 
    45111} 
    46112 
    47 int lua_script_start( char const* script ) 
    48 { 
    49   lua_keep_result = 0; 
     113void lua_script_error(lua_State *Lt,int runtime) 
     114{ 
     115    const char *err = lua_tostring( Lt, -1 ); 
     116    script_console_add_line( err ); 
     117    if(lua_script_is_ptp) { 
     118#ifdef CAM_CHDK_PTP 
     119        lua_script_error_ptp(runtime,err); 
     120#endif 
     121    } else { 
     122        if(runtime) { 
     123            if(conf.debug_lua_restart_on_error) { 
     124                lua_script_reset(); 
     125                script_start_gui(0); 
     126            } else { 
     127                script_wait_and_end(); 
     128            } 
     129        } else { 
     130            script_print_screen_end(); 
     131            script_wait_and_end(); 
     132        } 
     133    } 
     134} 
     135 
     136 
     137// TODO more stuff from script.c should be moved here 
     138void lua_script_finish(lua_State *L)  
     139{ 
     140#ifdef CAM_CHDK_PTP 
     141    if(lua_script_is_ptp) { 
     142        // send all return values as RET messages 
     143        int i,end = lua_gettop(L); 
     144        for(i=1;i<=end; i++) { 
     145            // if the queue is full return values will be silently discarded 
     146            // incompatible types will be returned as TYPE_UNSUPPORTED to preserve expected number and order of return values 
     147            ptp_script_write_msg(lua_create_usb_msg(L,i,PTP_CHDK_S_MSGTYPE_RET));  
     148        } 
     149    } 
     150#endif 
     151} 
     152 
     153int lua_script_start( char const* script, int ptp ) 
     154{ 
     155  lua_script_is_ptp = ptp; 
    50156  L = lua_open(); 
    51157  luaL_openlibs( L ); 
     
    55161  lua_setfield( L, LUA_REGISTRYINDEX, "Lt" ); 
    56162  if( luaL_loadstring( Lt, script ) != 0 ) { 
    57     script_console_add_line( lua_tostring( Lt, -1 ) ); 
    58     lua_script_reset(); 
     163    lua_script_error(Lt,0); 
    59164    return 0; 
    60165  } 
    61166  lua_sethook(Lt, lua_count_hook, LUA_MASKCOUNT, 1000 ); 
     167  lua_script_enable_yield_hook(); 
    62168  return 1; 
    63169} 
     
    13871493        return 1; 
    13881494} 
     1495 
     1496#ifdef CAM_CHDK_PTP 
     1497/* 
     1498msg = read_usb_msg([timeout]) 
     1499read a message from the CHDK ptp interface. 
     1500Returns the next available message as a string, or nil if no messages are available 
     1501If timeout is given and not zero, wait until a message is available or timeout expires 
     1502*/ 
     1503static int luaCB_read_usb_msg( lua_State* L ) 
     1504{ 
     1505  int timeout = luaL_optnumber( L, 1, 0 ); 
     1506  if(timeout) { 
     1507    action_push(timeout); 
     1508    action_push(AS_SCRIPT_READ_USB_MSG); 
     1509    return lua_yield( L, 0 ); 
     1510  } 
     1511  ptp_script_msg *msg = ptp_script_read_msg(); 
     1512  if(msg) { 
     1513    lua_pushlstring(L,msg->data,msg->size); 
     1514    return 1; 
     1515  } 
     1516  lua_pushnil(L); 
     1517  return 1; 
     1518} 
     1519 
     1520/* 
     1521status = write_usb_msg(msg,[timeout]) 
     1522writes a message to the CHDK ptp interface 
     1523msg may be nil, boolean, number, string or table (table has some restrictions, will be converted to string) 
     1524returns true if the message was queued successfully, otherwise false 
     1525if timeout is set and not zero, wait until message is written or timeout expires 
     1526NOTE strings will not include a terminating NULL, must be handled by recipient 
     1527*/ 
     1528static int luaCB_write_usb_msg( lua_State* L ) 
     1529{ 
     1530  ptp_script_msg *msg; 
     1531  int timeout = luaL_optnumber( L, 2, 0 ); 
     1532  // TODO would it be better to either ignore this or return nil ? 
     1533  // a write_usb_msg(function_which_returns_no_value()) is an error in this case 
     1534  // replacing with nil might be more luaish 
     1535  if(lua_gettop(L) < 1) { 
     1536    return luaL_error(L,"missing argument"); 
     1537  } 
     1538  msg=lua_create_usb_msg(L,1,PTP_CHDK_S_MSGTYPE_USER); 
     1539  // for user messages, trying to create a message from an incompatible type throws an error 
     1540  if(msg->subtype == PTP_CHDK_TYPE_UNSUPPORTED) { 
     1541    free(msg); 
     1542    return luaL_error(L,"unsupported type"); 
     1543  } 
     1544  if(!msg) { 
     1545    return luaL_error(L,"failed to create message"); 
     1546  } 
     1547  if(timeout) { 
     1548    action_push(timeout); 
     1549    action_push((int)msg); 
     1550    action_push(AS_SCRIPT_WRITE_USB_MSG); 
     1551    return lua_yield( L, 0 ); 
     1552  } 
     1553  lua_pushboolean(L,ptp_script_write_msg(msg));  
     1554  return 1; 
     1555} 
     1556#endif 
    13891557 
    13901558void register_lua_funcs( lua_State* L ) 
     
    15541722#endif 
    15551723   FUNC(reboot); 
    1556 } 
     1724#ifdef CAM_CHDK_PTP 
     1725   FUNC(read_usb_msg); 
     1726   FUNC(write_usb_msg); 
     1727   luaL_dostring(L,"function usb_msg_table_to_string(t)" 
     1728                    " local v2s=function(v)" 
     1729                        " local t=type(v)" 
     1730                        " if t=='string' then return v end" 
     1731                        " if t=='number' or t=='boolean' or t=='nil' then return tostring(v) end" 
     1732                        " return '' end" 
     1733                    " local r=''" 
     1734                    " for k,v in pairs(t) do" 
     1735                        " local s,vs=''" 
     1736                        " if type(v)=='table' then" 
     1737                            " for i=1,table.maxn(v) do" 
     1738                            " s=s..'\\t'..v2s(v[i]) end" 
     1739                        " else" 
     1740                            " vs=v2s(v)" 
     1741                            " if #vs then s=s..'\\t'..vs end" 
     1742                        " end" 
     1743                        " vs=v2s(k)" 
     1744                        " if #vs>0 and #s>0 then r=r..vs..s..'\\n' end" 
     1745                    " end" 
     1746                    " return r" 
     1747                   " end"); 
     1748 
     1749#endif 
     1750} 
Note: See TracChangeset for help on using the changeset viewer.