diff options
author | Minh-Quang Nguyen <minh-quang.nguyen@nutaq.com> | 2016-06-09 16:24:36 -0400 |
---|---|---|
committer | Minh-Quang Nguyen <minh-quang.nguyen@nutaq.com> | 2016-06-09 16:24:36 -0400 |
commit | 8e7f07296cfcb381e8beb0a11481632bc7943cfd (patch) | |
tree | 2bc0c858e03ad514e9d2ace19a7cd9b1395d6ec1 | |
parent | c98f3cd12f5dad61d68c225bdc141045fcf30582 (diff) |
LC15: TRX nominal TX power can be used from EEPROM or from BTS configuration
Change-Id: Icb30c2533ab3e0f78a08667158a1681939fe86a8
-rw-r--r-- | include/osmo-bts/phy_link.h | 3 | ||||
-rw-r--r-- | src/osmo-bts-litecell15/calib_file.c | 200 | ||||
-rw-r--r-- | src/osmo-bts-litecell15/lc15bts_vty.c | 25 | ||||
-rw-r--r-- | src/osmo-bts-litecell15/main.c | 2 |
4 files changed, 226 insertions, 4 deletions
diff --git a/include/osmo-bts/phy_link.h b/include/osmo-bts/phy_link.h index a559aa3e..ab5409af 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); } |