From 50869b91469122a82554c34dc7a83025c7a2d1dd Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 13 Nov 2017 10:36:18 +0100 Subject: mobile: Create "ms" singleton for struct osmocom_ms Make the MS the script is associated with accessible to lua. Provide access to IMSI and IMEI. The IMSI might not be available at the given time and just return an empty string. Example lua usage: print(osmo.ms():imsi()); print(osmo.ms():imei()); print(osmo.ms():shutdown_state()) print(osmo.ms():started()) function ms_started_cb(started) print("MS started", started) end function ms_shutdown_cb(old_state, new_state) print("MS shutdown", old_state, "->", new_state) end function sms_cb(sms, cause, valid) print("SMS data cb", sms, cause, valid) for i, v in pairs(sms) do print(i, v) end end function mm_cb(new_state, new_substate, old_substate) if new_state == 19 and new_substate == 1 then osmo.ms():sms_send_simple("1234", "21321324", "fooooooo", 23) end end local cbs = { Started=ms_started_cb, Shutdown=ms_shutdown_cb, Sms=sms_cb, Mm=mm_cb } timer = osmo.timeout(20, function() print("Timeout occurred after 20s") end) osmo.ms():register(cbs) # Can fail. Best to wait for state changes... print(osmo.ms().start()) print(osmo.ms().stop(true)) Change-Id: Ia3ace33d6ba4e904b1ff8e271a02d67777334a58 --- .../include/osmocom/bb/common/osmocom_data.h | 1 + src/host/layer23/src/mobile/script_lua.c | 277 ++++++++++++++++++++- 2 files changed, 271 insertions(+), 7 deletions(-) diff --git a/src/host/layer23/include/osmocom/bb/common/osmocom_data.h b/src/host/layer23/include/osmocom/bb/common/osmocom_data.h index 8f5cdc33..486c36d0 100644 --- a/src/host/layer23/include/osmocom/bb/common/osmocom_data.h +++ b/src/host/layer23/include/osmocom/bb/common/osmocom_data.h @@ -87,6 +87,7 @@ struct osmocom_ms { struct llist_head trans_list; void *lua_state; + int lua_cb_ref; char *lua_script; }; diff --git a/src/host/layer23/src/mobile/script_lua.c b/src/host/layer23/src/mobile/script_lua.c index cd7e8bca..cbba0708 100644 --- a/src/host/layer23/src/mobile/script_lua.c +++ b/src/host/layer23/src/mobile/script_lua.c @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -94,6 +95,30 @@ static const struct luaL_Reg global_runtime[] = { { NULL, NULL }, }; +/* Push table and function. Stack+=2 */ +static bool load_cb(lua_State *L, int ref, const char *cb_name) +{ + lua_rawgeti(L, LUA_REGISTRYINDEX, ref); + lua_pushstring(L, cb_name); + lua_gettable(L, -2); + if (lua_isnil(L, -1)) { + LOGP(DLUA, LOGL_DEBUG, "No handler for %s\n", cb_name); + lua_pop(L, 2); + return false; + } + return true; +} + +/* Call callback. Stack-=func + args. func/args popped by lua_pcall */ +static void call_cb(lua_State *L, int args) +{ + int err = lua_pcall(L, args, 0, 0); + if (err) { + LOGP(DLUA, LOGL_ERROR, "lua error: %s\n", lua_tostring(L, -1)); + lua_pop(L, 2); + } +} + static void handle_timeout(struct mobile_prim_intf *intf, struct mobile_timer_param *param) { struct timer_userdata *timer = (void *)(intptr_t) param->timer_id; @@ -110,6 +135,109 @@ static void handle_timeout(struct mobile_prim_intf *intf, struct mobile_timer_pa } } +static void handle_started(struct mobile_prim_intf *intf, struct mobile_started_param *param) +{ + lua_State *L = intf->ms->lua_state; + + if (intf->ms->lua_cb_ref == LUA_REFNIL) + return; + + if (!load_cb(L, intf->ms->lua_cb_ref, "Started")) + return; + + lua_pushinteger(L, param->started); + + call_cb(L, 1); + lua_pop(L, 1); +} + +static void handle_shutdown(struct mobile_prim_intf *intf, struct mobile_shutdown_param *param) +{ + lua_State *L = intf->ms->lua_state; + + if (intf->ms->lua_cb_ref == LUA_REFNIL) + return; + + if (!load_cb(L, intf->ms->lua_cb_ref, "Shutdown")) + return; + + lua_pushinteger(L, param->old_state); + lua_pushinteger(L, param->new_state); + + call_cb(L, 2); + lua_pop(L, 1); +} + +static void handle_sms(struct mobile_prim_intf *intf, struct mobile_sms_param *param) +{ + lua_State *L = intf->ms->lua_state; + + if (intf->ms->lua_cb_ref == LUA_REFNIL) + return; + + if (!load_cb(L, intf->ms->lua_cb_ref, "Sms")) + return; + + lua_createtable(L, 0, 11); + + lua_pushinteger(L, param->sms.validity_minutes); + lua_setfield(L, -2, "validity_minutes"); + + lua_pushinteger(L, param->sms.reply_path_req); + lua_setfield(L, -2, "reply_path_req"); + + lua_pushinteger(L, param->sms.status_rep_req); + lua_setfield(L, -2, "status_rep_req"); + + lua_pushinteger(L, param->sms.ud_hdr_ind); + lua_setfield(L, -2, "ud_hdr_ind"); + + lua_pushinteger(L, param->sms.protocol_id); + lua_setfield(L, -2, "protocol_id"); + + lua_pushinteger(L, param->sms.data_coding_scheme); + lua_setfield(L, -2, "data_coding_scheme"); + + lua_pushinteger(L, param->sms.msg_ref); + lua_setfield(L, -2, "msg_ref"); + + lua_pushstring(L, param->sms.address); + lua_setfield(L, -2, "address"); + + lua_pushinteger(L, param->sms.time); + lua_setfield(L, -2, "time"); + + lua_pushlstring(L, (char *) param->sms.user_data, param->sms.user_data_len); + lua_setfield(L, -2, "user_data"); + + lua_pushstring(L, param->sms.text); + lua_setfield(L, -2, "text"); + + lua_pushinteger(L, param->cause_valid); + lua_pushinteger(L, param->cause); + + call_cb(L, 3); + lua_pop(L, 1); +} + +static void handle_mm(struct mobile_prim_intf *intf, struct mobile_mm_param *param) +{ + lua_State *L = intf->ms->lua_state; + + if (intf->ms->lua_cb_ref == LUA_REFNIL) + return; + + if (!load_cb(L, intf->ms->lua_cb_ref, "Mm")) + return; + + lua_pushinteger(L, param->state); + lua_pushinteger(L, param->substate); + lua_pushinteger(L, param->prev_substate); + + call_cb(L, 3); + lua_pop(L, 1); +} + static int lua_osmo_timeout(lua_State *L) { struct mobile_prim *prim; @@ -164,8 +292,125 @@ static const struct luaL_Reg timer_funcs[] = { { NULL, NULL }, }; +static int lua_osmo_ms(lua_State *L) +{ + lua_pushlightuserdata(L, get_primitive(L)->ms); + luaL_getmetatable(L, "MS"); + lua_setmetatable(L, -2); + + return 1; +} + +static int lua_ms_imei(lua_State *L) +{ + struct osmocom_ms *ms = get_primitive(L)->ms; + + luaL_argcheck(L, lua_isuserdata(L, -1), 1, "No userdata"); + lua_pushstring(L, ms->settings.imei); + return 1; +} +static int lua_ms_imsi(lua_State *L) +{ + struct osmocom_ms *ms = get_primitive(L)->ms; + + luaL_argcheck(L, lua_isuserdata(L, -1), 1, "No userdata"); + lua_pushstring(L, ms->subscr.imsi); + return 1; +} + +static int lua_ms_shutdown_state(lua_State *L) +{ + struct osmocom_ms *ms = get_primitive(L)->ms; + + lua_pushinteger(L, ms->shutdown); + return 1; +} + +static int lua_ms_started(lua_State *L) +{ + struct osmocom_ms *ms = get_primitive(L)->ms; + + lua_pushinteger(L, ms->started); + return 1; +} + +static int lua_ms_register(lua_State *L) +{ + struct osmocom_ms *ms = get_primitive(L)->ms; + + /* callbacks must be a table */ + luaL_checktype(L, 2, LUA_TTABLE); + + if (ms->lua_cb_ref != LUA_REFNIL) + luaL_unref(L, LUA_REGISTRYINDEX, ms->lua_cb_ref); + ms->lua_cb_ref = luaL_ref(L, LUA_REGISTRYINDEX); + return 0; +} + +static int lua_ms_no_shutdown(lua_State *L) +{ + struct osmocom_ms *ms = get_primitive(L)->ms; + char *name; + int res; + + res = mobile_start(ms, &name); + lua_pushinteger(L, res); + return 1; +} + +static int lua_ms_shutdown(lua_State *L) +{ + struct osmocom_ms *ms = get_primitive(L)->ms; + int argc = lua_gettop(L); + int force = 0; + int res; + + if (argc >= 1) { + luaL_argcheck(L, lua_isboolean(L, -1), 1, "Force"); + force = lua_toboolean(L, -1); + } + + res = mobile_stop(ms, force); + lua_pushinteger(L, res); + return 1; +} + +static int lua_ms_sms_send_simple(lua_State *L) +{ + const char *sms_sca, *number, *text; + int msg_ref, rc; + + luaL_argcheck(L, lua_isnumber(L, -1), 4, "msg_ref needs to be a number"); + luaL_argcheck(L, lua_isstring(L, -2), 3, "text must be a string"); + luaL_argcheck(L, lua_isstring(L, -3), 2, "number must be a string"); + luaL_argcheck(L, lua_isstring(L, -4), 1, "sms_sca must be a string"); + + msg_ref = (int) lua_tonumber(L, -1); + text = lua_tostring(L, -2); + number = lua_tostring(L, -3); + sms_sca = lua_tostring(L, -4); + + rc = sms_send(get_primitive(L)->ms, sms_sca, number, text, msg_ref); + lua_pushinteger(L, rc); + return 1; +} + +static const struct luaL_Reg ms_funcs[] = { + { "imsi", lua_ms_imsi }, + { "imei", lua_ms_imei }, + { "shutdown_state", lua_ms_shutdown_state }, + { "started", lua_ms_started }, + { "register", lua_ms_register }, + { "start", lua_ms_no_shutdown }, + { "stop", lua_ms_shutdown }, + { "sms_send_simple", lua_ms_sms_send_simple }, + { NULL, NULL }, +}; + + static const struct luaL_Reg osmo_funcs[] = { { "timeout", lua_osmo_timeout }, + { "ms", lua_osmo_ms }, { NULL, NULL }, }; @@ -175,6 +420,18 @@ static void lua_prim_ind(struct mobile_prim_intf *intf, struct mobile_prim *prim case OSMO_PRIM(PRIM_MOB_TIMER, PRIM_OP_INDICATION): handle_timeout(intf, (struct mobile_timer_param *) &prim->u.timer); break; + case OSMO_PRIM(PRIM_MOB_STARTED, PRIM_OP_INDICATION): + handle_started(intf, (struct mobile_started_param *) &prim->u.started); + break; + case OSMO_PRIM(PRIM_MOB_SHUTDOWN, PRIM_OP_INDICATION): + handle_shutdown(intf, (struct mobile_shutdown_param *) &prim->u.shutdown); + break; + case OSMO_PRIM(PRIM_MOB_SMS, PRIM_OP_INDICATION): + handle_sms(intf, (struct mobile_sms_param *) &prim->u.sms); + break; + case OSMO_PRIM(PRIM_MOB_MM, PRIM_OP_INDICATION): + handle_mm(intf, (struct mobile_mm_param *) &prim->u.mm); + break; default: LOGP(DLUA, LOGL_ERROR, "Unknown primitive: %d\n", OSMO_PRIM_HDR(&prim->hdr)); }; @@ -196,6 +453,16 @@ static void add_globals(lua_State *L) lua_pop(L, 1); } +static void create_meta_table(lua_State *L, const char *name, const luaL_Reg *regs) +{ + luaL_newmetatable(L, name); + lua_pushliteral(L, "__index"); + lua_pushvalue(L, -2); + lua_rawset(L, -3); + luaL_setfuncs(L, regs, 0); + lua_pop(L, 1); +} + static void add_runtime(lua_State *L, struct mobile_prim_intf *intf) { add_globals(L); @@ -206,13 +473,8 @@ static void add_runtime(lua_State *L, struct mobile_prim_intf *intf) lua_setglobal(L, "osmo"); /* Create metatables so we can GC objects... */ - luaL_newmetatable(L, "Timer"); - lua_pushliteral(L, "__index"); - lua_pushvalue(L, -2); - lua_rawset(L, -3); - luaL_setfuncs(L, timer_funcs, 0); - lua_pop(L, 1); - + create_meta_table(L, "Timer", timer_funcs); + create_meta_table(L, "MS", ms_funcs); /* Remember the primitive pointer... store it in the registry */ lua_pushlightuserdata(L, lua_prim_key); @@ -251,6 +513,7 @@ int script_lua_load(struct vty *vty, struct osmocom_ms *ms, const char *filename if (!ms->lua_state) return -1; + ms->lua_cb_ref = LUA_REFNIL; luaL_openlibs(ms->lua_state); intf = mobile_prim_intf_alloc(ms); -- cgit v1.2.3