aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMinh-Quang Nguyen <minh-quang.nguyen@nutaq.com>2016-06-09 16:24:36 -0400
committerHarald Welte <laforge@gnumonks.org>2016-06-15 09:45:02 +0000
commit58e4e18206501c3bffa65f0b876bbc5ebe175d6e (patch)
tree6784031872e8d6f90c018c2dfe1cd80e1ddb0ea4
parentcbbce0be0965c3160c4916384c3d3d5303c57ae2 (diff)
LC15: TRX nominal TX power can be used from EEPROM or from BTS configuration
-rw-r--r--include/osmo-bts/phy_link.h3
-rw-r--r--src/osmo-bts-litecell15/calib_file.c200
-rw-r--r--src/osmo-bts-litecell15/lc15bts_vty.c25
-rw-r--r--src/osmo-bts-litecell15/main.c2
4 files changed, 226 insertions, 4 deletions
diff --git a/include/osmo-bts/phy_link.h b/include/osmo-bts/phy_link.h
index edc6cc09..b3db4ce5 100644
--- a/include/osmo-bts/phy_link.h
+++ b/include/osmo-bts/phy_link.h
@@ -103,7 +103,8 @@ struct phy_instance {
/* configuration */
uint32_t dsp_trace_f;
char *calib_path;
-
+ int minTxPower;
+ int maxTxPower;
struct lc15l1_hdl *hdl;
} lc15;
} u;
diff --git a/src/osmo-bts-litecell15/calib_file.c b/src/osmo-bts-litecell15/calib_file.c
index c6be4f05..3bc788c4 100644
--- a/src/osmo-bts-litecell15/calib_file.c
+++ b/src/osmo-bts-litecell15/calib_file.c
@@ -42,7 +42,11 @@
#include "lc15bts.h"
#include "utils.h"
-
+/**
+ * * Maximum calibration data chunk size
+ * */
+#define MAX_CALIB_TBL_SIZE 65536
+#define CALIB_HDR_V1 0x01
struct calib_file_desc {
const char *fname;
@@ -83,9 +87,37 @@ static const struct calib_file_desc calib_files[] = {
},
};
+static struct calTbl_t
+{
+ union
+ {
+ struct
+ {
+ uint8_t u8Version; // Header version (1)
+ uint8_t u8Parity; // Parity byte (xor)
+ uint8_t u8Type; // Table type (0:TX Downlink, 1:RX-A Uplink, 2:RX-B Uplink)
+ uint8_t u8Band; // GSM Band (0:GSM-850, 1:EGSM-900, 2:DCS-1800, 3:PCS-1900)
+ uint32_t u32Len; // Table length in bytes including the header
+ struct
+ {
+ uint32_t u32DescOfst; // Description section offset
+ uint32_t u32DateOfst; // Date section offset
+ uint32_t u32StationOfst; // Calibration test station section offset
+ uint32_t u32FpgaFwVerOfst; // Calibration FPGA firmware version section offset
+ uint32_t u32DspFwVerOfst; // Calibration DSP firmware section offset
+ uint32_t u32DataOfst; // Calibration data section offset
+ } toc;
+ } v1;
+ } hdr;
+
+ uint8_t u8RawData[MAX_CALIB_TBL_SIZE - 32];
+};
+
static int calib_file_send(struct lc15l1_hdl *fl1h,
const struct calib_file_desc *desc);
+static int calib_verify(struct lc15l1_hdl *fl1h,
+ const struct calib_file_desc *desc);
/* determine next calibration file index based on supported bands */
static int get_next_calib_file_idx(struct lc15l1_hdl *fl1h, int last_idx)
@@ -203,6 +235,20 @@ static int calib_file_send(struct lc15l1_hdl *fl1h,
return 0;
}
+ rc = calib_verify(fl1h, desc);
+ if ( rc < 0 ) {
+ LOGP(DL1C, LOGL_ERROR, "Verify L1 calibration table %s -> failed (%d)\n", desc->fname, rc);
+ st->last_file_idx = get_next_calib_file_idx(fl1h, st->last_file_idx);
+
+ if (st->last_file_idx >= 0)
+ return calib_file_send(fl1h,
+ &calib_files[st->last_file_idx]);
+ return 0;
+
+ }
+
+ LOGP(DL1C, LOGL_INFO, "Verify L1 calibration table %s -> done\n", desc->fname);
+
return calib_file_send_next_chunk(fl1h);
}
@@ -258,3 +304,155 @@ int calib_load(struct lc15l1_hdl *fl1h)
return calib_file_send(fl1h, &calib_files[st->last_file_idx]);
}
+
+static int calib_verify(struct lc15l1_hdl *fl1h, const struct calib_file_desc *desc)
+{
+ int i, rc, sz;
+ struct calib_send_state *st = &fl1h->st;
+ struct phy_link *plink = fl1h->phy_inst->phy_link;
+ char *rbuf;
+ struct calTbl_t *calTbl;
+ char calChkSum ;
+
+
+ //calculate file size in bytes
+ fseek(st->fp, 0L, SEEK_END);
+ sz = ftell(st->fp);
+
+ //rewind read poiner
+ fseek(st->fp, 0L, SEEK_SET);
+
+ //read file
+ rbuf = (char *) malloc( sizeof(char) * sz );
+
+ rc = fread(rbuf, 1, sizeof(char) * sz, st->fp);
+ if ( rc != sz) {
+
+ LOGP(DL1C, LOGL_ERROR, "%s reading error\n", desc->fname);
+ free(rbuf);
+
+ //close file
+ rc = calib_file_close(fl1h);
+ if (rc < 0 ) {
+ LOGP(DL1C, LOGL_ERROR, "%s can not close\n", desc->fname);
+ return rc;
+ }
+
+ return -2;
+ }
+
+
+ calTbl = (struct calTbl_t*) rbuf;
+ //calcualte file checksum
+ calChkSum = 0;
+ while ( sz-- ) {
+ calChkSum ^= rbuf[sz];
+ }
+
+ //validate Tx calibration parity
+ if ( calChkSum ) {
+ LOGP(DL1C, LOGL_ERROR, "%s has invalid checksum %x.\n", desc->fname, calChkSum);
+ return -4;
+ }
+
+ //validate Tx calibration header
+ if ( calTbl->hdr.v1.u8Version != CALIB_HDR_V1 ) {
+ LOGP(DL1C, LOGL_ERROR, "%s has invalid header version %u.\n", desc->fname, calTbl->hdr.v1.u8Version);
+ return -5;
+ }
+
+ //validate calibration description
+ if ( calTbl->hdr.v1.toc.u32DescOfst == 0xFFFFFFFF ) {
+ LOGP(DL1C, LOGL_ERROR, "%s has invalid calibration description offset.\n", desc->fname);
+ return -6;
+ }
+
+ //validate calibration date
+ if ( calTbl->hdr.v1.toc.u32DateOfst == 0xFFFFFFFF ) {
+ LOGP(DL1C, LOGL_ERROR, "%s has invalid calibration date offset.\n", desc->fname);
+ return -7;
+ }
+
+ LOGP(DL1C, LOGL_INFO, "L1 calibration table %s created on %s\n",
+ desc->fname,
+ calTbl->u8RawData + calTbl->hdr.v1.toc.u32DateOfst);
+
+ //validate calibration station
+ if ( calTbl->hdr.v1.toc.u32StationOfst == 0xFFFFFFFF ) {
+ LOGP(DL1C, LOGL_ERROR, "%s has invalid calibration station ID offset.\n", desc->fname);
+ return -8;
+ }
+
+ //validate FPGA FW version
+ if ( calTbl->hdr.v1.toc.u32FpgaFwVerOfst == 0xFFFFFFFF ) {
+ LOGP(DL1C, LOGL_ERROR, "%s has invalid FPGA FW version offset.\n", desc->fname);
+ return -9;
+ }
+ //validate DSP FW version
+ if ( calTbl->hdr.v1.toc.u32DspFwVerOfst == 0xFFFFFFFF ) {
+ LOGP(DL1C, LOGL_ERROR, "%s has invalid DSP FW version offset.\n", desc->fname);
+ return -10;
+ }
+
+ //validate Tx calibration data offset
+ if ( calTbl->hdr.v1.toc.u32DataOfst == 0xFFFFFFFF ) {
+ LOGP(DL1C, LOGL_ERROR, "%s has invalid calibration data offset.\n", desc->fname);
+ return -11;
+ }
+
+ if ( !desc->rx ) {
+
+ //parse min/max Tx power
+ fl1h->phy_inst->u.lc15.minTxPower = calTbl->u8RawData[calTbl->hdr.v1.toc.u32DataOfst + (5 << 2)];
+ fl1h->phy_inst->u.lc15.maxTxPower = calTbl->u8RawData[calTbl->hdr.v1.toc.u32DataOfst + (6 << 2)];
+
+ //override nominal Tx power of given TRX if needed
+ if ( fl1h->phy_inst->trx->nominal_power > fl1h->phy_inst->u.lc15.maxTxPower) {
+ LOGP(DL1C, LOGL_INFO, "Set TRX %u nominal Tx power to %d dBm (%d)\n",
+ plink->num,
+ fl1h->phy_inst->u.lc15.maxTxPower,
+ fl1h->phy_inst->trx->nominal_power);
+
+ fl1h->phy_inst->trx->nominal_power = fl1h->phy_inst->u.lc15.maxTxPower;
+ }
+
+ if ( fl1h->phy_inst->trx->nominal_power < fl1h->phy_inst->u.lc15.minTxPower) {
+ LOGP(DL1C, LOGL_INFO, "Set TRX %u nominal Tx power to %d dBm (%d)\n",
+ plink->num,
+ fl1h->phy_inst->u.lc15.minTxPower,
+ fl1h->phy_inst->trx->nominal_power);
+
+ fl1h->phy_inst->trx->nominal_power = fl1h->phy_inst->u.lc15.minTxPower;
+ }
+
+ if ( fl1h->phy_inst->trx->power_params.trx_p_max_out_mdBm > to_mdB(fl1h->phy_inst->u.lc15.maxTxPower) ) {
+ LOGP(DL1C, LOGL_INFO, "Set TRX %u Tx power parameter to %d dBm (%d)\n",
+ plink->num,
+ to_mdB(fl1h->phy_inst->u.lc15.maxTxPower),
+ fl1h->phy_inst->trx->power_params.trx_p_max_out_mdBm);
+
+ fl1h->phy_inst->trx->power_params.trx_p_max_out_mdBm = to_mdB(fl1h->phy_inst->u.lc15.maxTxPower);
+ }
+
+ if ( fl1h->phy_inst->trx->power_params.trx_p_max_out_mdBm < to_mdB(fl1h->phy_inst->u.lc15.minTxPower) ) {
+ LOGP(DL1C, LOGL_INFO, "Set TRX %u Tx power parameter to %d dBm (%d)\n",
+ plink->num,
+ to_mdB(fl1h->phy_inst->u.lc15.minTxPower),
+ fl1h->phy_inst->trx->power_params.trx_p_max_out_mdBm);
+
+ fl1h->phy_inst->trx->power_params.trx_p_max_out_mdBm = to_mdB(fl1h->phy_inst->u.lc15.minTxPower);
+ }
+
+ LOGP(DL1C, LOGL_DEBUG, "%s: minTxPower=%d, maxTxPower=%d\n",
+ desc->fname,
+ fl1h->phy_inst->u.lc15.minTxPower,
+ fl1h->phy_inst->u.lc15.maxTxPower );
+ }
+
+ //rewind read poiner for subsequence tasks
+ fseek(st->fp, 0L, SEEK_SET);
+ free(rbuf);
+
+ return 0;
+}
+
diff --git a/src/osmo-bts-litecell15/lc15bts_vty.c b/src/osmo-bts-litecell15/lc15bts_vty.c
index d0288ab7..8c4364c4 100644
--- a/src/osmo-bts-litecell15/lc15bts_vty.c
+++ b/src/osmo-bts-litecell15/lc15bts_vty.c
@@ -218,6 +218,8 @@ DEFUN(show_sys_info, show_sys_info_cmd,
vty_out(vty, "%s ", gsm_band_name(1 << i));
}
vty_out(vty, "%s", VTY_NEWLINE);
+ vty_out(vty, "Min Tx Power: %d dBm%s", fl1h->phy_inst->u.lc15.minTxPower, VTY_NEWLINE);
+ vty_out(vty, "Max Tx Power: %d dBm%s", fl1h->phy_inst->u.lc15.maxTxPower, VTY_NEWLINE);
return CMD_SUCCESS;
}
@@ -246,8 +248,9 @@ DEFUN(activate_lchan, activate_lchan_cmd,
}
DEFUN(set_tx_power, set_tx_power_cmd,
- "trx <0-0> tx-power <-110-100>",
+ "trx nr <0-1> tx-power <-110-100>",
TRX_STR
+ "TRX number \n"
"Set transmit power (override BSC)\n"
"Transmit power in dBm\n")
{
@@ -298,6 +301,25 @@ DEFUN(no_loopback, no_loopback_cmd,
return CMD_SUCCESS;
}
+DEFUN(cfg_trx_nominal_power, cfg_trx_nominal_power_cmd,
+ "nominal-tx-power <0-40>",
+ "Set the nominal transmit output power in dBm\n"
+ "Nominal transmit output power level in dBm\n")
+{
+ int nominal_power = atoi(argv[0]);
+ struct gsm_bts_trx *trx = vty->index;
+
+ if (( nominal_power > 40 ) || ( nominal_power < 0 )) {
+ vty_out(vty, "Nominal Tx power level must be between 0 and 40 dBm (%d) %s",
+ nominal_power, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ trx->nominal_power = nominal_power;
+ trx->power_params.trx_p_max_out_mdBm = to_mdB(nominal_power);
+
+ return CMD_SUCCESS;
+}
void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts)
{
@@ -305,6 +327,7 @@ void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts)
void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx)
{
+ vty_out(vty, " nominal-tx-power %d%s", trx->nominal_power,VTY_NEWLINE);
}
static void write_phy_inst(struct vty *vty, struct phy_instance *pinst)
diff --git a/src/osmo-bts-litecell15/main.c b/src/osmo-bts-litecell15/main.c
index 2aaacd3c..352949b4 100644
--- a/src/osmo-bts-litecell15/main.c
+++ b/src/osmo-bts-litecell15/main.c
@@ -81,7 +81,7 @@ int bts_model_init(struct gsm_bts *bts)
}
llist_for_each_entry(trx, &bts->trx_list, list) {
- trx->nominal_power = 37;
+ trx->nominal_power = 40;
trx->power_params.trx_p_max_out_mdBm = to_mdB(bts->c0->nominal_power);
}