diff options
Diffstat (limited to 'src/osmo-bts-octphy/octphy_hw_api.c')
-rw-r--r-- | src/osmo-bts-octphy/octphy_hw_api.c | 364 |
1 files changed, 364 insertions, 0 deletions
diff --git a/src/osmo-bts-octphy/octphy_hw_api.c b/src/osmo-bts-octphy/octphy_hw_api.c new file mode 100644 index 0000000..5291742 --- /dev/null +++ b/src/osmo-bts-octphy/octphy_hw_api.c @@ -0,0 +1,364 @@ +/* Layer 1 (PHY) interface of osmo-bts OCTPHY integration */ + +/* Copyright (c) 2015 Harald Welte <laforge@gnumonks.org> + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +#include <stdint.h> +#include <errno.h> + +#include <osmocom/core/talloc.h> +#include <osmocom/core/utils.h> + +#include <osmo-bts/logging.h> + +#include "l1_if.h" +#include "l1_oml.h" +#include "l1_utils.h" + +#include <octphy/octvc1/octvc1_rc2string.h> +#include <octphy/octvc1/hw/octvc1_hw_api.h> +#include <octphy/octvc1/hw/octvc1_hw_api_swap.h> + +/* Chapter 12.1 */ +static int get_pcb_info_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) +{ + tOCTVC1_HW_MSG_PCB_INFO_RSP *pir = + (tOCTVC1_HW_MSG_PCB_INFO_RSP *) resp->l2h; + + mOCTVC1_HW_MSG_PCB_INFO_RSP_SWAP(pir); + + LOGP(DL1C, LOGL_INFO, "HW-PCB-INFO.resp: Name=%s %s, Serial=%s, " + "FileName=%s, InfoSource=%u, InfoState=%u, GpsName=%s, " + "WiFiName=%s\n", pir->szName, pir->ulDeviceId ? "SEC" : "PRI", + pir->szSerial, pir->szFilename, pir->ulInfoSource, + pir->ulInfoState, pir->szGpsName, pir->szWifiName); + + msgb_free(resp); + return 0; +} + +/* Chapter 12.1 */ +int octphy_hw_get_pcb_info(struct octphy_hdl *fl1h) +{ + struct msgb *msg = l1p_msgb_alloc(); + tOCTVC1_HW_MSG_PCB_INFO_CMD *pic; + + pic = (tOCTVC1_HW_MSG_PCB_INFO_CMD *) msgb_put(msg, sizeof(*pic)); + + l1if_fill_msg_hdr(&pic->Header, msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND, + cOCTVC1_HW_MSG_PCB_INFO_CID); + + mOCTVC1_HW_MSG_PCB_INFO_CMD_SWAP(pic); + + return l1if_req_compl(fl1h, msg, get_pcb_info_compl_cb, NULL); +} + +/* Chapter 12.9 */ +static int rf_port_info_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, + void *data) +{ + tOCTVC1_HW_MSG_RF_PORT_INFO_RSP *pir = + (tOCTVC1_HW_MSG_RF_PORT_INFO_RSP *) resp->l2h; + + mOCTVC1_HW_MSG_RF_PORT_INFO_RSP_SWAP(pir); + + LOGP(DL1C, LOGL_INFO, "RF-PORT-INFO.resp Idx=%u, InService=%u, " + "hOwner=0x%x, Id=%u, FreqMin=%u, FreqMax=%u\n", + pir->ulPortIndex, pir->ulInService, pir->hOwner, + pir->ulPortInterfaceId, pir->ulFrequencyMinKhz, + pir->ulFrequencyMaxKhz); + + msgb_free(resp); + return 0; +} + +/* Chapter 12.9 */ +int octphy_hw_get_rf_port_info(struct octphy_hdl *fl1h, uint32_t index) +{ + struct msgb *msg = l1p_msgb_alloc(); + tOCTVC1_HW_MSG_RF_PORT_INFO_CMD *pic; + + pic = (tOCTVC1_HW_MSG_RF_PORT_INFO_CMD *) msgb_put(msg, sizeof(*pic)); + + l1if_fill_msg_hdr(&pic->Header, msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND, + cOCTVC1_HW_MSG_RF_PORT_INFO_CID); + + pic->ulPortIndex = index; + + mOCTVC1_HW_MSG_RF_PORT_INFO_CMD_SWAP(pic); + + return l1if_req_compl(fl1h, msg, rf_port_info_compl_cb, NULL); +} + +static const struct value_string radio_std_vals[] = { + { cOCTVC1_RADIO_STANDARD_ENUM_GSM, "GSM" }, + { cOCTVC1_RADIO_STANDARD_ENUM_UMTS, "UMTS" }, + { cOCTVC1_RADIO_STANDARD_ENUM_LTE, "LTE" }, + { cOCTVC1_RADIO_STANDARD_ENUM_INVALID, "INVALID" }, + { 0, NULL } +}; + +/* Chapter 12.10 */ +static int rf_port_stats_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, + void *data) +{ + tOCTVC1_HW_MSG_RF_PORT_STATS_RSP *psr = + (tOCTVC1_HW_MSG_RF_PORT_STATS_RSP *) resp->l2h; + + mOCTVC1_HW_MSG_RF_PORT_STATS_RSP_SWAP(psr); + + LOGP(DL1C, LOGL_INFO, "RF-PORT-STATS.resp Idx=%u RadioStandard=%s, " + "Rx(Bytes=%u, Overflow=%u, AvgBps=%u, Period=%uus, Freq=%u) " + "Tx(Bytes=%i, Underflow=%u, AvgBps=%u, Period=%uus, Freq=%u)\n", + psr->ulPortIndex, + get_value_string(radio_std_vals, psr->ulRadioStandard), + psr->RxStats.ulRxByteCnt, psr->RxStats.ulRxOverflowCnt, + psr->RxStats.ulRxAverageBytePerSecond, + psr->RxStats.ulRxAveragePeriodUs, + psr->RxStats.ulFrequencyKhz, + psr->TxStats.ulTxByteCnt, psr->TxStats.ulTxUnderflowCnt, + psr->TxStats.ulTxAverageBytePerSecond, + psr->TxStats.ulTxAveragePeriodUs, + psr->TxStats.ulFrequencyKhz); + + msgb_free(resp); + return 0; +} + +/* Chapter 12.10 */ +int octphy_hw_get_rf_port_stats(struct octphy_hdl *fl1h, uint32_t index) +{ + struct msgb *msg = l1p_msgb_alloc(); + tOCTVC1_HW_MSG_RF_PORT_STATS_CMD *psc; + + psc = (tOCTVC1_HW_MSG_RF_PORT_STATS_CMD *) msgb_put(msg, sizeof(*psc)); + + l1if_fill_msg_hdr(&psc->Header, msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND, + cOCTVC1_HW_MSG_RF_PORT_STATS_CID); + + psc->ulPortIndex = index; + psc->ulResetStatsFlag = cOCT_FALSE; + + mOCTVC1_HW_MSG_RF_PORT_STATS_CMD_SWAP(psc); + + return l1if_req_compl(fl1h, msg, rf_port_stats_compl_cb, NULL); +} + +static const struct value_string rx_gain_mode_vals[] = { + { cOCTVC1_RADIO_RX_GAIN_CTRL_MODE_ENUM_MGC, "Manual" }, + { cOCTVC1_RADIO_RX_GAIN_CTRL_MODE_ENUM_AGC_FAST_ATK, "Automatic (fast)" }, + { cOCTVC1_RADIO_RX_GAIN_CTRL_MODE_ENUM_AGC_SLOW_ATK, "Automatic (slow)" }, + { 0, NULL } +}; + +/* Chapter 12.13 */ +static int rf_ant_rx_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, + void *data) +{ + tOCTVC1_HW_MSG_RF_PORT_INFO_ANTENNA_RX_CONFIG_RSP *arc = + (tOCTVC1_HW_MSG_RF_PORT_INFO_ANTENNA_RX_CONFIG_RSP *) resp->l2h; + + mOCTVC1_HW_MSG_RF_PORT_INFO_ANTENNA_RX_CONFIG_RSP_SWAP(arc); + + LOGP(DL1C, LOGL_INFO, "ANT-RX-CONFIG.resp(Port=%u, Ant=%u): %s, " + "Gain %d dB, GainCtrlMode=%s\n", + arc->ulPortIndex, arc->ulAntennaIndex, + arc->ulEnableFlag ? "Enabled" : "Disabled", + arc->lRxGaindB/512, + get_value_string(rx_gain_mode_vals, arc->ulRxGainMode)); + + msgb_free(resp); + return 0; +} + +/* Chapter 12.13 */ +int octphy_hw_get_rf_ant_rx_config(struct octphy_hdl *fl1h, uint32_t port_idx, + uint32_t ant_idx) +{ + struct msgb *msg = l1p_msgb_alloc(); + tOCTVC1_HW_MSG_RF_PORT_INFO_ANTENNA_RX_CONFIG_CMD *psc; + + psc = (tOCTVC1_HW_MSG_RF_PORT_INFO_ANTENNA_RX_CONFIG_CMD *) + msgb_put(msg, sizeof(*psc)); + + l1if_fill_msg_hdr(&psc->Header, msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND, + cOCTVC1_HW_MSG_RF_PORT_INFO_ANTENNA_RX_CONFIG_CID); + + psc->ulPortIndex = port_idx; + psc->ulAntennaIndex = ant_idx; + + mOCTVC1_HW_MSG_RF_PORT_INFO_ANTENNA_RX_CONFIG_CMD_SWAP(psc); + + return l1if_req_compl(fl1h, msg, rf_ant_rx_compl_cb, NULL); + +} + +/* Chapter 12.14 */ +static int rf_ant_tx_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, + void *data) +{ + tOCTVC1_HW_MSG_RF_PORT_INFO_ANTENNA_TX_CONFIG_RSP *atc = + (tOCTVC1_HW_MSG_RF_PORT_INFO_ANTENNA_TX_CONFIG_RSP *) resp->l2h; + + mOCTVC1_HW_MSG_RF_PORT_INFO_ANTENNA_TX_CONFIG_RSP_SWAP(atc); + + LOGP(DL1C, LOGL_INFO, "ANT-TX-CONFIG.resp(Port=%u, Ant=%u): %s, " + "Gain %d dB\n", + atc->ulPortIndex, atc->ulAntennaIndex, + atc->ulEnableFlag ? "Enabled" : "Disabled", + atc->lTxGaindB/512); + + msgb_free(resp); + return 0; +} + +/* Chapter 12.14 */ +int octphy_hw_get_rf_ant_tx_config(struct octphy_hdl *fl1h, uint32_t port_idx, + uint32_t ant_idx) +{ + struct msgb *msg = l1p_msgb_alloc(); + tOCTVC1_HW_MSG_RF_PORT_INFO_ANTENNA_TX_CONFIG_CMD *psc; + + psc = (tOCTVC1_HW_MSG_RF_PORT_INFO_ANTENNA_TX_CONFIG_CMD *) + msgb_put(msg, sizeof(*psc)); + + l1if_fill_msg_hdr(&psc->Header, msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND, + cOCTVC1_HW_MSG_RF_PORT_INFO_ANTENNA_RX_CONFIG_CID); + + psc->ulPortIndex = port_idx; + psc->ulAntennaIndex = ant_idx; + + mOCTVC1_HW_MSG_RF_PORT_INFO_ANTENNA_TX_CONFIG_CMD_SWAP(psc); + + return l1if_req_compl(fl1h, msg, rf_ant_tx_compl_cb, NULL); + +} + +static const struct value_string clocksync_source_vals[] = { + { cOCTVC1_HW_CLOCK_SYNC_MGR_SOURCE_ENUM_FREQ_1HZ, "1 Hz" }, + { cOCTVC1_HW_CLOCK_SYNC_MGR_SOURCE_ENUM_FREQ_10MHZ, "10 MHz" }, + { cOCTVC1_HW_CLOCK_SYNC_MGR_SOURCE_ENUM_FREQ_30_72MHZ, "30.72 MHz" }, + { cOCTVC1_HW_CLOCK_SYNC_MGR_SOURCE_ENUM_FREQ_1HZ_EXT, "1 Hz (ext)"}, + { cOCTVC1_HW_CLOCK_SYNC_MGR_SOURCE_ENUM_NONE, "None" }, + { 0, NULL } +}; + +static const struct value_string clocksync_sel_vals[] = { + { cOCTVC1_HW_CLOCK_SYNC_MGR_SOURCE_SELECTION_ENUM_AUTOSELECT, + "Autoselect" }, + { cOCTVC1_HW_CLOCK_SYNC_MGR_SOURCE_SELECTION_ENUM_CONFIG_FILE, + "Config File" }, + { cOCTVC1_HW_CLOCK_SYNC_MGR_SOURCE_SELECTION_ENUM_HOST_APPLICATION, + "Host Application" }, + { 0, NULL } +}; + +static const struct value_string clocksync_source_state_vals[] = { + { cOCTVC1_HW_CLOCK_SYNC_MGR_SOURCE_STATE_ENUM_INVALID, "Invalid" }, + { cOCTVC1_HW_CLOCK_SYNC_MGR_SOURCE_STATE_ENUM_VALID, "Valid" }, + { cOCTVC1_HW_CLOCK_SYNC_MGR_SOURCE_STATE_ENUM_UNSPECIFIED, + "Unspecified" }, + { 0, NULL } +}; + +static const struct value_string clocksync_state_vals[] = { + { cOCTVC1_HW_CLOCK_SYNC_MGR_STATE_ENUM_UNINITIALIZE, + "Uninitialized" }, + { cOCTVC1_HW_CLOCK_SYNC_MGR_STATE_ENUM_IDLE, "Idle" }, + { cOCTVC1_HW_CLOCK_SYNC_MGR_STATE_ENUM_NO_EXT_CLOCK, + "No External Clock" }, + { cOCTVC1_HW_CLOCK_SYNC_MGR_STATE_ENUM_LOCKED, "Locked" }, + { cOCTVC1_HW_CLOCK_SYNC_MGR_STATE_ENUM_UNLOCKED,"Unlocked" }, + { cOCTVC1_HW_CLOCK_SYNC_MGR_STATE_ENUM_ERROR, "Error" }, + { cOCTVC1_HW_CLOCK_SYNC_MGR_STATE_ENUM_DISABLE, "Disabled" }, + { cOCTVC1_HW_CLOCK_SYNC_MGR_STATE_ENUM_LOSS_EXT_CLOCK, + "Loss of Ext Clock" }, + { 0, NULL } +}; + +/* Chapter 12.15 */ +static int get_clock_sync_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, + void *data) +{ + tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_INFO_RSP *cir = + (tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_INFO_RSP *) resp->l2h; + + mOCTVC1_HW_MSG_CLOCK_SYNC_MGR_INFO_RSP_SWAP(cir); + + LOGP(DL1C, LOGL_INFO, "CLOCK-SYNC-MGR-INFO.resp Reference=%s ", + get_value_string(clocksync_source_vals, cir->ulClkSourceRef)); + LOGPC(DL1C, LOGL_INFO, "Selection=%s)\n", + get_value_string(clocksync_sel_vals, cir->ulClkSourceSelection)); + + msgb_free(resp); + return 0; +} + +/* Chapter 12.15 */ +int octphy_hw_get_clock_sync_info(struct octphy_hdl *fl1h) +{ + struct msgb *msg = l1p_msgb_alloc(); + tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_INFO_CMD *cic; + + cic = (tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_INFO_CMD *) + msgb_put(msg, sizeof(*cic)); + l1if_fill_msg_hdr(&cic->Header, msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND, + cOCTVC1_HW_MSG_CLOCK_SYNC_MGR_INFO_CID); + + mOCTVC1_HW_MSG_CLOCK_SYNC_MGR_INFO_CMD_SWAP(cic); + + return l1if_req_compl(fl1h, msg, get_clock_sync_compl_cb, NULL); +} + +/* Chapter 12.16 */ +static int get_clock_sync_stats_cb(struct gsm_bts_trx *trx, struct msgb *resp, + void *data) +{ + tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_STATS_RSP *csr = + (tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_STATS_RSP *) resp->l2h; + + mOCTVC1_HW_MSG_CLOCK_SYNC_MGR_STATS_RSP_SWAP(csr); + + LOGP(DL1C, LOGL_INFO, "CLOCK-SYNC-MGR-STATS.resp State=%s, " + "ClockError=%d DroppedCycles=%d, PllFreqHz=%u, PllFract=%u, " + "SlipCnt=%u SyncLosses=%u SourceState=%u, DacValue=%u\n", + get_value_string(clocksync_state_vals, csr->ulState), + csr->lClockError, csr->lDroppedCycles, csr->ulPllFreqHz, + csr->ulPllFractionalFreqHz, csr->ulSlipCnt, + csr->ulSyncLosseCnt, csr->ulSourceState, csr->ulDacValue); + + msgb_free(resp); + return 0; +} + +/* Chapter 12.16 */ +int octphy_hw_get_clock_sync_stats(struct octphy_hdl *fl1h) +{ + struct msgb *msg = l1p_msgb_alloc(); + tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_STATS_CMD *csc; + + csc = (tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_STATS_CMD *) + msgb_put(msg, sizeof(*csc)); + l1if_fill_msg_hdr(&csc->Header, msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND, + cOCTVC1_HW_MSG_CLOCK_SYNC_MGR_STATS_CID); + + mOCTVC1_HW_MSG_CLOCK_SYNC_MGR_STATS_CMD_SWAP(csc); + + return l1if_req_compl(fl1h, msg, get_clock_sync_stats_cb, NULL); +} + |