summaryrefslogtreecommitdiffstats
path: root/src/host/layer23/src
diff options
context:
space:
mode:
Diffstat (limited to 'src/host/layer23/src')
-rw-r--r--src/host/layer23/src/mobile/script_lua.c277
1 files changed, 270 insertions, 7 deletions
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 <lauxlib.h>
#include <osmocom/bb/common/osmocom_data.h>
+#include <osmocom/bb/mobile/app_mobile.h>
#include <osmocom/bb/common/logging.h>
#include <osmocom/bb/mobile/primitives.h>
@@ -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);