sysmobts: Add support for reading calibration tables

'trx-calibration-path' is the new VTY command indicating the path
name where the calibration files can be found.

Calibration is only implemented for SUPERFEMTO API version 2.4.0 or
later.
This commit is contained in:
Harald Welte 2012-10-28 10:58:41 +01:00
parent 98a4404279
commit d1335d878b
6 changed files with 125 additions and 9 deletions

View File

@ -6,7 +6,7 @@ EXTRA_DIST = misc/sysmobts_mgr.h misc/sysmobts_misc.h misc/sysmobts_par.h misc/s
bin_PROGRAMS = sysmobts sysmobts-remote l1fwd-proxy sysmobts-mgr
COMMON_SOURCES = main.c femtobts.c l1_if.c oml.c sysmobts_vty.c tch.c hw_misc.c
COMMON_SOURCES = main.c femtobts.c l1_if.c oml.c sysmobts_vty.c tch.c hw_misc.c calib_file.c
sysmobts_SOURCES = $(COMMON_SOURCES) l1_transp_hw.c
sysmobts_LDADD = $(top_builddir)/src/common/libbts.a $(LDADD)

View File

@ -27,9 +27,13 @@
#include <osmocom/core/utils.h>
#include <osmo-bts/logging.h>
#include <sysmocom/femtobts/superfemto.h>
#include <sysmocom/femtobts/gsml1const.h>
#include "l1_if.h"
struct calib_file_desc {
const char *fname;
GsmL1_FreqBand_t band;
@ -104,7 +108,7 @@ static const struct calib_file_desc calib_files[] = {
static const unsigned int arrsize_by_band[] = {
[GsmL1_FreqBand_850] = 124,
[GsmL1_FreqBand_900] = 195,
[GsmL1_FreqBand_900] = 194,
[GsmL1_FreqBand_1800] = 374,
[GsmL1_FreqBand_1900] = 299
};
@ -129,18 +133,20 @@ int calib_file_read(const char *path, const struct calib_file_desc *desc,
{
FILE *in;
char fname[PATH_MAX];
int rc, i;
int i;
fname[0] = '\0';
rc = snprintf(fname, sizeof(fname)-1, "%s/%s", path, desc->fname);
snprintf(fname, sizeof(fname)-1, "%s/%s", path, desc->fname);
fname[sizeof(fname)-1] = '\0';
in = fopen(fname, "r");
if (!in)
return -1;
#if SUPERFEMTO_API_VERSION >= SUPERFEMTO_API(2,4,0)
if (desc->rx) {
SuperFemto_SetRxCalibTblReq_t *rx = &prim->u.setRxCalibTblReq;
memset(rx, 0, sizeof(*rx));
prim->id = SuperFemto_PrimId_SetRxCalibTblReq;
@ -156,13 +162,16 @@ int calib_file_read(const char *path, const struct calib_file_desc *desc,
for (i = 0; i < arrsize_by_band[desc->band]; i++)
rx->fRxRollOffCorr[i] = read_float(in);
rx->u8IqImbalMode = read_int(in);
for (i = 0; i < ARRAY_SIZE(rx->u16IqImbalCorr); i++)
rx->u16IqImbalCorr[i] = read_int(in);
if (desc->uplink) {
rx->u8IqImbalMode = read_int(in);
printf("%s: u8IqImbalMode=%d\n", desc->fname, rx->u8IqImbalMode);
for (i = 0; i < ARRAY_SIZE(rx->u16IqImbalCorr); i++)
rx->u16IqImbalCorr[i] = read_int(in);
}
} else {
SuperFemto_SetTxCalibTblReq_t *tx = &prim->u.setTxCalibTblReq;
memset(tx, 0, sizeof(*tx));
prim->id = SuperFemto_PrimId_SetTxCalibTblReq;
@ -179,12 +188,75 @@ int calib_file_read(const char *path, const struct calib_file_desc *desc,
for (i = 0; i < arrsize_by_band[desc->band]; i++)
tx->fTxRollOffCorr[i] = read_float(in);
}
#else
#warning Format of calibration tables before API version 2.4.0 not supported
#endif
fclose(in);
return 0;
}
/* iteratively download the calibration data into the L1 */
struct calib_send_state {
struct femtol1_hdl *fl1h;
const char *path;
int last_file_idx;
};
static int calib_send_compl_cb(struct msgb *l1_msg, void *data);
/* send the calibration table for a single specified file */
static int calib_file_send(struct femtol1_hdl *fl1h,
const struct calib_file_desc *desc, void *state)
{
struct msgb *msg;
int rc;
msg = sysp_msgb_alloc();
rc = calib_file_read(fl1h->calib_path, desc, msgb_sysprim(msg));
if (rc < 0) {
msgb_free(msg);
return rc;
}
return l1if_req_compl(fl1h, msg, 1, calib_send_compl_cb, state);
}
/* completion callback after every SetCalibTbl is confirmed */
static int calib_send_compl_cb(struct msgb *l1_msg, void *data)
{
struct calib_send_state *st = data;
LOGP(DL1C, LOGL_DEBUG, "L1 calibration table %s loaded\n",
calib_files[st->last_file_idx].fname);
st->last_file_idx++;
if (st->last_file_idx < ARRAY_SIZE(calib_files))
return calib_file_send(st->fl1h,
&calib_files[st->last_file_idx], st);
LOGP(DL1C, LOGL_INFO, "L1 calibration table loading complete!\n");
return 0;
}
int calib_load(struct femtol1_hdl *fl1h)
{
static struct calib_send_state st;
memset(&st, 0, sizeof(st));
st.fl1h = fl1h;
#if SUPERFEMTO_API_VERSION < SUPERFEMTO_API(2,4,0)
return -1;
#else
return calib_file_send(fl1h, &calib_files[0], &st);
#endif
}
#if 0

View File

@ -123,6 +123,16 @@ const struct value_string femtobts_sysprim_names[SuperFemto_PrimId_NUM+1] = {
{ SuperFemto_PrimId_RfClockSetupCnf, "RF-CLOCK-SETUP.conf" },
{ SuperFemto_PrimId_Layer1ResetReq, "LAYER1-RESET.req" },
{ SuperFemto_PrimId_Layer1ResetCnf, "LAYER1-RESET.conf" },
#if SUPERFEMTO_API_VERSION >= SUPERFEMTO_API(2,1,0)
{ SuperFemto_PrimId_GetTxCalibTblReq, "GET-TX-CALIB.req" },
{ SuperFemto_PrimId_GetTxCalibTblCnf, "GET-TX-CALIB.cnf" },
{ SuperFemto_PrimId_SetTxCalibTblReq, "SET-TX-CALIB.req" },
{ SuperFemto_PrimId_SetTxCalibTblCnf, "SET-TX-CALIB.cnf" },
{ SuperFemto_PrimId_GetRxCalibTblReq, "GET-RX-CALIB.req" },
{ SuperFemto_PrimId_GetRxCalibTblCnf, "GET-RX-CALIB.cnf" },
{ SuperFemto_PrimId_SetRxCalibTblReq, "SET-RX-CALIB.req" },
{ SuperFemto_PrimId_SetRxCalibTblCnf, "SET-RX-CALIB.cnf" },
#endif
{ 0, NULL }
};
@ -133,6 +143,12 @@ const SuperFemto_PrimId_t femtobts_sysprim_req2conf[SuperFemto_PrimId_NUM] = {
[SuperFemto_PrimId_RfClockInfoReq] = SuperFemto_PrimId_RfClockInfoCnf,
[SuperFemto_PrimId_RfClockSetupReq] = SuperFemto_PrimId_RfClockSetupCnf,
[SuperFemto_PrimId_Layer1ResetReq] = SuperFemto_PrimId_Layer1ResetCnf,
#if SUPERFEMTO_API_VERSION >= SUPERFEMTO_API(2,1,0)
[SuperFemto_PrimId_GetTxCalibTblReq] = SuperFemto_PrimId_GetTxCalibTblCnf,
[SuperFemto_PrimId_SetTxCalibTblReq] = SuperFemto_PrimId_SetTxCalibTblCnf,
[SuperFemto_PrimId_GetRxCalibTblReq] = SuperFemto_PrimId_GetRxCalibTblCnf,
[SuperFemto_PrimId_SetRxCalibTblReq] = SuperFemto_PrimId_SetRxCalibTblCnf,
#endif
};
const struct value_string femtobts_l1sapi_names[GsmL1_Sapi_NUM+1] = {

View File

@ -1074,6 +1074,14 @@ static int reset_compl_cb(struct msgb *resp, void *data)
/* obtain version information on DSP/FPGA and band capabilities */
l1if_get_info(fl1h);
#if SUPERFEMTO_API_VERSION >= SUPERFEMTO_API(2,1,0)
/* load calibration tables (if we know their path) */
if (fl1h->calib_path)
calib_load(fl1h);
else
#endif
LOGP(DL1C, LOGL_NOTICE, "Operating without calibration tables!\n");
/* otherwise, request activation of RF board */
l1if_activate_rf(fl1h, 1);

View File

@ -4,6 +4,7 @@
#include <osmocom/core/select.h>
#include <osmocom/core/write_queue.h>
#include <osmocom/core/gsmtap_util.h>
#include <osmocom/core/timer.h>
#include <osmocom/gsm/gsm_utils.h>
enum {
@ -32,6 +33,7 @@ struct femtol1_hdl {
uint32_t dsp_trace_f;
int clk_cal;
uint8_t clk_src;
char *calib_path;
struct llist_head wlc_list;
struct gsmtap_inst *gsmtap;

View File

@ -146,6 +146,21 @@ DEFUN(cfg_trx_clksrc, cfg_trx_clksrc_cmd,
return CMD_SUCCESS;
}
DEFUN(cfg_trx_cal_path, cfg_trx_cal_path_cmd,
"trx-calibration-path PATH",
"Set the path name to TRX calibration data\n" "Path name\n")
{
struct gsm_bts_trx *trx = vty->index;
struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx);
if (fl1h->calib_path)
talloc_free(fl1h->calib_path);
fl1h->calib_path = talloc_strdup(fl1h, argv[0]);
return CMD_SUCCESS;
}
/* runtime */
DEFUN(show_trx_clksrc, show_trx_clksrc_cmd,
@ -394,6 +409,8 @@ void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx)
vty_out(vty, " clock-calibration %d%s", fl1h->clk_cal,
VTY_NEWLINE);
vty_out(vty, " trx-calibration-path %s%s", fl1h->calib_path,
VTY_NEWLINE);
vty_out(vty, " clock-source %s%s",
get_value_string(femtobts_clksrc_names, fl1h->clk_src),
VTY_NEWLINE);
@ -455,6 +472,7 @@ int bts_model_vty_init(struct gsm_bts *bts)
install_element(TRX_NODE, &cfg_trx_clkcal_cmd);
install_element(TRX_NODE, &cfg_trx_clkcal_def_cmd);
install_element(TRX_NODE, &cfg_trx_clksrc_cmd);
install_element(TRX_NODE, &cfg_trx_cal_path_cmd);
install_element(TRX_NODE, &cfg_trx_gsmtap_sapi_cmd);
install_element(TRX_NODE, &cfg_trx_no_gsmtap_sapi_cmd);