aboutsummaryrefslogtreecommitdiffstats
path: root/src/osmo-bts-octphy/octphy_hw_api.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/osmo-bts-octphy/octphy_hw_api.c')
-rw-r--r--src/osmo-bts-octphy/octphy_hw_api.c364
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);
+}
+