static int set_clock_info(struct ctrl_cmd *cmd, void *data) { struct gsm_bts_trx *trx = cmd->node; struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); struct msgb *msg = sysp_msgb_alloc(); SuperFemto_Prim_t *sysp = msgb_sysprim(msg); struct ctrl_cmd_def *cd; /* geneate a deferred control command */ cd = ctrl_cmd_def_make(fl1h, cmd, NULL, 10); /* Set GPS/PPS as reference */ sysp->id = SuperFemto_PrimId_RfClockSetupReq; sysp->u.rfClockSetupReq.rfTrx.iClkCor = fl1h->clk_cal; /* !!! use get_clk_cal */ sysp->u.rfClockSetupReq.rfTrx.clkSrc = fl1h->clk_src; sysp->u.rfClockSetupReq.rfTrxClkCal.clkSrc = SuperFemto_ClkSrcId_GpsPps; l1if_req_compl(fl1h, msg, clock_setup_cb, NULL); /* Reset the error counters */ msg = sysp_msgb_alloc(); sysp = msgb_sysprim(msg); sysp->id = SuperFemto_PrimId_RfClockInfoReq; sysp->u.rfClockInfoReq.u8RstClkCal = 1; l1if_req_compl(fl1h, msg, ctrl_set_clkinfo_cb, cd); return CTRL_CMD_HANDLED; }
static int get_clock_info(struct ctrl_cmd *cmd, void *data) { struct gsm_bts_trx *trx = cmd->node; struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); struct msgb *msg = sysp_msgb_alloc(); SuperFemto_Prim_t *sysp = msgb_sysprim(msg); struct ctrl_cmd_def *cd; /* geneate a deferred control command */ cd = ctrl_cmd_def_make(fl1h, cmd, NULL, 10); sysp->id = SuperFemto_PrimId_RfClockInfoReq; sysp->u.rfClockInfoReq.u8RstClkCal = 0; return l1if_req_compl(fl1h, msg, ctrl_clkinfo_cb, cd); }
static int ctrl_get_clkcorr_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) { SuperFemto_Prim_t *sysp = msgb_sysprim(resp); struct ctrl_cmd_def *cd = data; struct ctrl_cmd *cmd = cd->cmd; if (ctrl_cmd_def_is_zombie(cd)) { msgb_free(resp); return 0; } cmd->reply = talloc_asprintf(cmd, "%d", sysp->u.rfClockInfoCnf.rfTrx.iClkCor); ctrl_cmd_def_send(cd); msgb_free(resp); return 0; }
static int set_clock_corr(struct ctrl_cmd *cmd, void *data) { struct gsm_bts_trx *trx = cmd->node; struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); struct msgb *msg = sysp_msgb_alloc(); SuperFemto_Prim_t *sysp = msgb_sysprim(msg); struct ctrl_cmd_def *cd; fl1h->clk_cal = atoi(cmd->value); /* geneate a deferred control command */ cd = ctrl_cmd_def_make(fl1h, cmd, NULL, 10); sysp->id = SuperFemto_PrimId_RfClockSetupReq; sysp->u.rfClockSetupReq.rfTrx.iClkCor = fl1h->clk_cal; sysp->u.rfClockSetupReq.rfTrx.clkSrc = fl1h->clk_src; sysp->u.rfClockSetupReq.rfTrxClkCal.clkSrc = SuperFemto_ClkSrcId_GpsPps; l1if_req_compl(fl1h, msg, ctrl_set_clkcorr_cb, cd); return CTRL_CMD_HANDLED; }
static int get_clock_corr(struct ctrl_cmd *cmd, void *data) { struct gsm_bts_trx *trx = cmd->node; struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); struct msgb *msg = sysp_msgb_alloc(); SuperFemto_Prim_t *sysp = msgb_sysprim(msg); struct ctrl_cmd_def *cd; /* we could theoretically simply respond with a cached value, but I * prefer to to ask the actual L1 about the currently used value to * avoid any mistakes */ /* geneate a deferred control command */ cd = ctrl_cmd_def_make(fl1h, cmd, NULL, 10); sysp->id = SuperFemto_PrimId_RfClockInfoReq; sysp->u.rfClockInfoReq.u8RstClkCal = 0; l1if_req_compl(fl1h, msg, ctrl_get_clkcorr_cb, cd); return CTRL_CMD_HANDLED; }
static int ctrl_clkinfo_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) { SuperFemto_Prim_t *sysp = msgb_sysprim(resp); struct ctrl_cmd_def *cd = data; struct ctrl_cmd *cmd = cd->cmd; LOGP(DL1C, LOGL_NOTICE, "RfClockInfo iClkCor=%d/clkSrc=%s Err=%d/ErrRes=%d/clkSrc=%s\n", sysp->u.rfClockInfoCnf.rfTrx.iClkCor, get_value_string(femtobts_clksrc_names, sysp->u.rfClockInfoCnf.rfTrx.clkSrc), sysp->u.rfClockInfoCnf.rfTrxClkCal.iClkErr, sysp->u.rfClockInfoCnf.rfTrxClkCal.iClkErrRes, get_value_string(femtobts_clksrc_names, sysp->u.rfClockInfoCnf.rfTrxClkCal.clkSrc)); if (ctrl_cmd_def_is_zombie(cd)) { msgb_free(resp); return 0; } cmd->reply = talloc_asprintf(cmd, "%d,%s,%d,%d,%s", sysp->u.rfClockInfoCnf.rfTrx.iClkCor, get_value_string(femtobts_clksrc_names, sysp->u.rfClockInfoCnf.rfTrx.clkSrc), sysp->u.rfClockInfoCnf.rfTrxClkCal.iClkErr, sysp->u.rfClockInfoCnf.rfTrxClkCal.iClkErrRes, get_value_string(femtobts_clksrc_names, sysp->u.rfClockInfoCnf.rfTrxClkCal.clkSrc)); ctrl_cmd_def_send(cd); msgb_free(resp); return 0; }
static int ctrl_set_clkcorr_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) { SuperFemto_Prim_t *sysp = msgb_sysprim(resp); struct ctrl_cmd_def *cd = data; struct ctrl_cmd *cmd = cd->cmd; if (ctrl_cmd_def_is_zombie(cd)) { msgb_free(resp); return 0; } if (sysp->u.rfClockSetupCnf.status != GsmL1_Status_Success) { cmd->type = CTRL_CMD_ERROR; cmd->reply = "Error setting new correction value."; } else cmd->reply = "success"; ctrl_cmd_def_send(cd); msgb_free(resp); return 0; }
static int _l1if_req_compl(struct lc15l1_hdl *fl1h, struct msgb *msg, int is_system_prim, l1if_compl_cb *cb, void *data) { struct wait_l1_conf *wlc; struct osmo_wqueue *wqueue; unsigned int timeout_secs; /* allocate new wsc and store reference to mutex and conf_id */ wlc = talloc_zero(fl1h, struct wait_l1_conf); wlc->cb = cb; wlc->cb_data = data; /* Make sure we actually have received a REQUEST type primitive */ if (is_system_prim == 0) { GsmL1_Prim_t *l1p = msgb_l1prim(msg); LOGP(DL1P, LOGL_INFO, "Tx L1 prim %s\n", get_value_string(lc15bts_l1prim_names, l1p->id)); if (lc15bts_get_l1prim_type(l1p->id) != L1P_T_REQ) { LOGP(DL1C, LOGL_ERROR, "L1 Prim %s is not a Request!\n", get_value_string(lc15bts_l1prim_names, l1p->id)); talloc_free(wlc); return -EINVAL; } wlc->is_sys_prim = 0; wlc->conf_prim_id = lc15bts_get_l1prim_conf(l1p->id); wlc->conf_hLayer3 = l1p_get_hLayer3(l1p); wqueue = &fl1h->write_q[MQ_L1_WRITE]; timeout_secs = 30; } else { Litecell15_Prim_t *sysp = msgb_sysprim(msg); LOGP(DL1C, LOGL_INFO, "Tx SYS prim %s\n", get_value_string(lc15bts_sysprim_names, sysp->id)); if (lc15bts_get_sysprim_type(sysp->id) != L1P_T_REQ) { LOGP(DL1C, LOGL_ERROR, "SYS Prim %s is not a Request!\n", get_value_string(lc15bts_sysprim_names, sysp->id)); talloc_free(wlc); return -EINVAL; } wlc->is_sys_prim = 1; wlc->conf_prim_id = lc15bts_get_sysprim_conf(sysp->id); wqueue = &fl1h->write_q[MQ_SYS_WRITE]; timeout_secs = 30; } /* enqueue the message in the queue and add wsc to list */ if (osmo_wqueue_enqueue(wqueue, msg) != 0) { /* So we will get a timeout but the log message might help */ LOGP(DL1C, LOGL_ERROR, "Write queue for %s full. dropping msg.\n", is_system_prim ? "system primitive" : "gsm"); msgb_free(msg); } llist_add(&wlc->list, &fl1h->wlc_list); /* schedule a timer for timeout_secs seconds. If DSP fails to respond, we terminate */ wlc->timer.data = wlc; wlc->timer.cb = l1if_req_timeout; osmo_timer_schedule(&wlc->timer, timeout_secs, 0); return 0; }