sysmobts: Provide VTY routines to do clock calibrations

The sysmoBTS2050 does not have a OCXO and we should not rely
on the GPS module to always have a fix. Instead use the TCXO
by default and from time to time (and we know we have a fix
calibrate the TCXO). This can be done by:

  trx 0 rf-clock-info reset
  wait...
  trx 0 rf-clock-info correct
  write

The output is currently only written to the log as the VTY
connection might go away during the operation. The reset will
set the approriate reference clock and the correct will attempt
to determine and apply the correction. The write terminal will
make sure that next on start a known good value will be used.
This commit is contained in:
Holger Hans Peter Freyther 2014-07-25 14:37:47 +02:00
parent bac0ff7f6d
commit bc24955e91
3 changed files with 150 additions and 2 deletions

View File

@ -1,6 +1,7 @@
/* Interface handler for Sysmocom L1 */
/* (C) 2011 by Harald Welte <laforge@gnumonks.org>
* (C) 2014 by Holger Hans Peter Freyther
*
* All Rights Reserved
*
@ -1486,8 +1487,9 @@ struct femtol1_hdl *l1if_open(void *priv)
#if SUPERFEMTO_API_VERSION >= SUPERFEMTO_API(2,1,0)
if (fl1h->hw_info.model_nr == 2050) {
/* On the sysmoBTS 2050, we don't have an OCXO but
* always slave our clock to the GPS receiver */
fl1h->clk_src = SuperFemto_ClkSrcId_GpsPps;
* start with the TCXO and will sync it with the PPS
* of the GPS in case there is a fix. */
fl1h->clk_src = SuperFemto_ClkSrcId_Tcxo;
LOGP(DL1C, LOGL_INFO, "Clock source defaulting to GPS 1PPS "
"on sysmoBTS 2050\n");
} else {
@ -1524,3 +1526,117 @@ int l1if_close(struct femtol1_hdl *fl1h)
l1if_transport_close(MQ_SYS_WRITE, fl1h);
return 0;
}
#ifdef HW_SYSMOBTS_V1
int l1if_rf_clock_info_reset(struct femtol1_hdl *fl1h)
{
LOGP(DL1C, LOGL_ERROR, "RfClock calibration not supported on v1 hw.\n");
return -ENOTSUP;
}
int l1if_rf_clock_info_correct(struct femtol1_hdl *fl1h)
{
LOGP(DL1C, LOGL_ERROR, "RfClock calibration not supported on v1 hw.\n");
return -ENOTSUP;
}
#else
static int clock_reset_cb(struct gsm_bts_trx *trx, struct msgb *resp)
{
msgb_free(resp);
return 0;
}
static int clock_setup_cb(struct gsm_bts_trx *trx, struct msgb *resp)
{
SuperFemto_Prim_t *sysp = msgb_sysprim(resp);
if (sysp->u.rfClockSetupCnf.status != GsmL1_Status_Success)
LOGP(DL1C, LOGL_ERROR, "Rx RfClockSetupConf failed with: %d\n",
sysp->u.rfClockSetupCnf.status);
msgb_free(resp);
return 0;
}
static int clock_correct_info_cb(struct gsm_bts_trx *trx, struct msgb *resp)
{
struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx);
SuperFemto_Prim_t *sysp = msgb_sysprim(resp);
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 (sysp->u.rfClockInfoCnf.rfTrx.clkSrc == SuperFemto_ClkSrcId_GpsPps) {
LOGP(DL1C, LOGL_ERROR,
"Calibrating GPS against GPS doesn not make sense.\n");
msgb_free(resp);
return -1;
}
if (sysp->u.rfClockInfoCnf.rfTrxClkCal.clkSrc == SuperFemto_ClkSrcId_None) {
LOGP(DL1C, LOGL_ERROR,
"No reference clock set. Please reset first.\n");
msgb_free(resp);
return -1;
}
if (sysp->u.rfClockInfoCnf.rfTrxClkCal.iClkErrRes == 0) {
LOGP(DL1C, LOGL_ERROR,
"Couldn't determine the clock difference.\n");
msgb_free(resp);
return -1;
}
fl1h->clk_cal = sysp->u.rfClockInfoCnf.rfTrxClkCal.iClkErr;
fl1h->clk_use_eeprom = 0;
msgb_free(resp);
/*
* Let's reset the counter and this will lead to applying the
* new calibration.
*/
l1if_rf_clock_info_reset(fl1h);
return 0;
}
int l1if_rf_clock_info_reset(struct femtol1_hdl *fl1h)
{
struct msgb *msg = sysp_msgb_alloc();
SuperFemto_Prim_t *sysp = msgb_sysprim(msg);
/* Set GPS/PPS as reference */
sysp->id = SuperFemto_PrimId_RfClockSetupReq;
sysp->u.rfClockSetupReq.rfTrx.iClkCor = get_clk_cal(fl1h);
sysp->u.rfClockSetupReq.rfTrx.clkSrc = fl1h->clk_src;
sysp->u.rfClockSetupReq.rfTrxClkCal.clkSrc = SuperFemto_ClkSrcId_GpsPps;
l1if_req_compl(fl1h, msg, clock_setup_cb);
/* Reset the error counters */
msg = sysp_msgb_alloc();
sysp = msgb_sysprim(msg);
sysp->id = SuperFemto_PrimId_RfClockInfoReq;
sysp->u.rfClockInfoReq.u8RstClkCal = 1;
return l1if_req_compl(fl1h, msg, clock_reset_cb);
}
int l1if_rf_clock_info_correct(struct femtol1_hdl *fl1h)
{
struct msgb *msg = sysp_msgb_alloc();
SuperFemto_Prim_t *sysp = msgb_sysprim(msg);
sysp->id = SuperFemto_PrimId_RfClockInfoReq;
sysp->u.rfClockInfoReq.u8RstClkCal = 0;
return l1if_req_compl(fl1h, msg, clock_correct_info_cb);
}
#endif

View File

@ -120,4 +120,8 @@ int l1if_set_ciphering(struct femtol1_hdl *fl1h,
/* calibration loading */
int calib_load(struct femtol1_hdl *fl1h);
/* on-line re-calibration */
int l1if_rf_clock_info_reset(struct femtol1_hdl *fl1h);
int l1if_rf_clock_info_correct(struct femtol1_hdl *fl1h);
#endif /* _FEMTO_L1_H */

View File

@ -426,6 +426,32 @@ DEFUN(set_tx_power, set_tx_power_cmd,
return CMD_SUCCESS;
}
DEFUN(reset_rf_clock_ctr, reset_rf_clock_ctr_cmd,
"trx <0-0> rf-clock-info reset",
TRX_STR
"RF Clock Information\n" "Reset the counter\n")
{
int trx_nr = atoi(argv[0]);
struct gsm_bts_trx *trx = gsm_bts_trx_num(vty_bts, trx_nr);
struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx);
l1if_rf_clock_info_reset(fl1h);
return CMD_SUCCESS;
}
DEFUN(correct_rf_clock_ctr, correct_rf_clock_ctr_cmd,
"trx <0-0> rf-clock-info correct",
TRX_STR
"RF Clock Information\n" "Apply\n")
{
int trx_nr = atoi(argv[0]);
struct gsm_bts_trx *trx = gsm_bts_trx_num(vty_bts, trx_nr);
struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx);
l1if_rf_clock_info_correct(fl1h);
return CMD_SUCCESS;
}
DEFUN(loopback, loopback_cmd,
"trx <0-0> <0-7> loopback <0-1>",
TRX_STR
@ -576,6 +602,8 @@ int bts_model_vty_init(struct gsm_bts *bts)
install_element(ENABLE_NODE, &activate_lchan_cmd);
install_element(ENABLE_NODE, &set_tx_power_cmd);
install_element(ENABLE_NODE, &reset_rf_clock_ctr_cmd);
install_element(ENABLE_NODE, &correct_rf_clock_ctr_cmd);
install_element(ENABLE_NODE, &loopback_cmd);
install_element(ENABLE_NODE, &no_loopback_cmd);