/* VTY interface for osmo-bts OCTPHY integration */ /* (C) 2015-2016 by Harald Welte * * 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 . * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "l1_if.h" #include "l1_utils.h" #include "octphy_hw_api.h" #define TRX_STR "Transceiver related commands\n" "TRX number\n" #define SHOW_TRX_STR \ SHOW_STR \ TRX_STR #define OCT_STR "OCTPHY Um interface\n" static struct gsm_bts *vty_bts; /* configuration */ DEFUN(cfg_phy_hwaddr, cfg_phy_hwaddr_cmd, "octphy hw-addr HWADDR", OCT_STR "Configure the hardware address of the OCTPHY\n" "hardware address in aa:bb:cc:dd:ee:ff format\n") { struct phy_link *plink = vty->index; int rc; if (plink->state != PHY_LINK_SHUTDOWN) { vty_out(vty, "Can only reconfigure a PHY link that is down%s", VTY_NEWLINE); return CMD_WARNING; } rc = osmo_macaddr_parse(plink->u.octphy.phy_addr.sll_addr, argv[0]); if (rc < 0) return CMD_WARNING; return CMD_SUCCESS; } DEFUN(cfg_phy_netdev, cfg_phy_netdev_cmd, "octphy net-device NAME", OCT_STR "Configure the hardware device towards the OCTPHY\n" "Ethernet device name\n") { struct phy_link *plink = vty->index; if (plink->state != PHY_LINK_SHUTDOWN) { vty_out(vty, "Can only reconfigure a PHY link that is down%s", VTY_NEWLINE); return CMD_WARNING; } if (plink->u.octphy.netdev_name) talloc_free(plink->u.octphy.netdev_name); plink->u.octphy.netdev_name = talloc_strdup(plink, argv[0]); return CMD_SUCCESS; } DEFUN(cfg_phy_rf_port_idx, cfg_phy_rf_port_idx_cmd, "octphy rf-port-index <0-255>", OCT_STR "Configure the RF Port for this TRX\n" "RF Port Index\n") { struct phy_link *plink = vty->index; if (plink->state != PHY_LINK_SHUTDOWN) { vty_out(vty, "Can only reconfigure a PHY link that is down%s", VTY_NEWLINE); return CMD_WARNING; } plink->u.octphy.rf_port_index = atoi(argv[0]); return CMD_SUCCESS; } #if OCTPHY_USE_ANTENNA_ID == 1 DEFUN(cfg_phy_rx_ant_id, cfg_phy_rx_ant_id_cmd, "octphy rx-ant-id <0-1>", OCT_STR "Configure the RX Antenna for this TRX\n" "RX Antenna Id\n") { struct phy_link *plink = vty->index; if (plink->state != PHY_LINK_SHUTDOWN) { vty_out(vty, "Can only reconfigure a PHY link that is down%s", VTY_NEWLINE); return CMD_WARNING; } plink->u.octphy.rx_ant_id = atoi(argv[0]); return CMD_SUCCESS; } DEFUN(cfg_phy_tx_ant_id, cfg_phy_tx_ant_id_cmd, "octphy tx-ant-id <0-1>", OCT_STR "Configure the TX Antenna for this TRX\n" "TX Antenna Id\n") { struct phy_link *plink = vty->index; if (plink->state != PHY_LINK_SHUTDOWN) { vty_out(vty, "Can only reconfigure a PHY link that is down%s", VTY_NEWLINE); return CMD_WARNING; } plink->u.octphy.tx_ant_id = atoi(argv[0]); return CMD_SUCCESS; } #endif DEFUN(cfg_phy_rx_gain_db, cfg_phy_rx_gain_db_cmd, "octphy rx-gain <0-73>", OCT_STR "Configure the Rx Gain in dB\n" "Rx gain in dB\n") { struct phy_link *plink = vty->index; if (plink->state != PHY_LINK_SHUTDOWN) { vty_out(vty, "Can only reconfigure a PHY link that is down%s", VTY_NEWLINE); return CMD_WARNING; } plink->u.octphy.rx_gain_db = atoi(argv[0]); return CMD_SUCCESS; } DEFUN(cfg_phy_tx_atten_db, cfg_phy_tx_atten_db_cmd, "octphy tx-attenuation (oml|<0-359>)", OCT_STR "Set attenuation on transmitted RF\n" "Use tx-attenuation according to OML instructions from BSC\n" "Fixed tx-attenuation in quarter-dB\n") { struct phy_link *plink = vty->index; if (plink->state != PHY_LINK_SHUTDOWN) { vty_out(vty, "Can only reconfigure a PHY link that is down%s", VTY_NEWLINE); return CMD_WARNING; } if (strcmp(argv[0], "oml") == 0) { plink->u.octphy.tx_atten_flag = false; } else { plink->u.octphy.tx_atten_db = atoi(argv[0]); plink->u.octphy.tx_atten_flag = true; } return CMD_SUCCESS; } #if OCTPHY_USE_16X_OVERSAMPLING == 1 DEFUN(cfg_phy_over_sample_16x, cfg_phy_over_sample_16x_cmd, "octphy over-sample-16x <0-1>", OCT_STR "Configure 16x over sampling rate for this TRX (restart required)\n" "Over Sampling Rate\n") { struct phy_link *plink = vty->index; if (plink->state != PHY_LINK_SHUTDOWN) { vty_out(vty, "Can only reconfigure a PHY link that is down%s", VTY_NEWLINE); return CMD_WARNING; } if(atoi(argv[0])) plink->u.octphy.over_sample_16x = true; else plink->u.octphy.over_sample_16x = false; return CMD_SUCCESS; } #endif void show_rf_port_stats_cb(struct msgb *resp, void *data) { struct vty *vty = (struct vty*) data; tOCTVC1_HW_MSG_RF_PORT_STATS_RSP *psr; if (sizeof(tOCTVC1_HW_MSG_RF_PORT_STATS_RSP) != msgb_l2len(resp)) { vty_out(vty, "invalid msgb size (%d bytes, expected %zu bytes)%s", msgb_l2len(resp), sizeof(tOCTVC1_HW_MSG_RF_PORT_STATS_RSP), VTY_NEWLINE); return; } psr = (tOCTVC1_HW_MSG_RF_PORT_STATS_RSP *) msgb_l2(resp); vty_out(vty, "%s", VTY_NEWLINE); vty_out(vty, "RF-PORT-STATS:%s", VTY_NEWLINE); vty_out(vty, "Idx=%d%s", psr->ulPortIndex, VTY_NEWLINE); vty_out(vty, "RadioStandard=%s%s", get_value_string(radio_std_vals, psr->ulRadioStandard), VTY_NEWLINE); vty_out(vty, "Rx Bytes=%u%s", psr->RxStats.ulRxByteCnt, VTY_NEWLINE); vty_out(vty, "Rx Overflow=%u%s", psr->RxStats.ulRxOverflowCnt, VTY_NEWLINE); vty_out(vty, "Rx AvgBps=%u%s", psr->RxStats.ulRxAverageBytePerSecond, VTY_NEWLINE); vty_out(vty, "Rx Period=%u%s", psr->RxStats.ulRxAveragePeriodUs, VTY_NEWLINE); #if OCTPHY_USE_FREQUENCY == 1 vty_out(vty, "Rx Freq=%u%s", psr->RxStats.Frequency.ulValue, VTY_NEWLINE); #else vty_out(vty, "Rx Freq=%u%s", psr->RxStats.ulFrequencyKhz, VTY_NEWLINE); #endif vty_out(vty, "Tx Bytes=%u%s", psr->TxStats.ulTxByteCnt, VTY_NEWLINE); vty_out(vty, "Tx Underflow=%u%s", psr->TxStats.ulTxUnderflowCnt, VTY_NEWLINE); vty_out(vty, "Tx AvgBps=%u%s", psr->TxStats.ulTxAverageBytePerSecond, VTY_NEWLINE); vty_out(vty, "Tx Period=%u%s", psr->TxStats.ulTxAveragePeriodUs, VTY_NEWLINE); #if OCTPHY_USE_FREQUENCY == 1 vty_out(vty, "Tx Freq=%u%s", psr->TxStats.Frequency.ulValue, VTY_NEWLINE); #else vty_out(vty, "Tx Freq=%u%s", psr->TxStats.ulFrequencyKhz, VTY_NEWLINE); #endif } DEFUN(show_rf_port_stats, show_rf_port_stats_cmd, "show phy <0-255> rf-port-stats <0-1>", "Show statistics for the RF Port\n" "RF Port Number\n") { int phy_nr = atoi(argv[0]); struct phy_link *plink = phy_link_by_num(phy_nr); static struct octphy_hw_get_cb_data cb_data; cb_data.cb = show_rf_port_stats_cb; cb_data.data = vty; octphy_hw_get_rf_port_stats(plink->u.octphy.hdl, atoi(argv[1]), &cb_data); return CMD_SUCCESS; } void show_clk_sync_stats_cb(struct msgb *resp, void *data) { struct vty *vty = (struct vty*) data; tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_STATS_RSP *csr; if (sizeof(tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_STATS_RSP) != msgb_l2len(resp)) { vty_out(vty, "invalid msgb size (%d bytes, expected %zu bytes)%s", msgb_l2len(resp), sizeof(tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_STATS_RSP), VTY_NEWLINE); return; } csr = (tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_STATS_RSP *) msgb_l2(resp); vty_out(vty, "%s", VTY_NEWLINE); vty_out(vty, "CLOCK-SYNC-MGR-STATS:%s", VTY_NEWLINE); vty_out(vty, "State=%s%s", get_value_string(clocksync_state_vals, csr->ulState), VTY_NEWLINE); #if OCTPHY_USE_CLOCK_SYNC_MGR_STATS_CLOCK_ERROR == 1 vty_out(vty, "ClockError=%d%s", csr->lClockError, VTY_NEWLINE); #endif #if OCTPHY_USE_CLOCK_SYNC_MGR_STATS_DROPPED_CYCLES == 1 vty_out(vty, "DroppedCycles=%d%s", csr->lDroppedCycles, VTY_NEWLINE); #endif #if OCTPHY_USE_CLOCK_SYNC_MGR_STATS_PLL_FREQ_HZ == 1 vty_out(vty, "PllFreqHz=%u%s", csr->ulPllFreqHz, VTY_NEWLINE); #endif #if OCTPHY_USE_CLOCK_SYNC_MGR_STATS_PLL_FRACTIONAL_FREQ_HZ == 1 vty_out(vty, "PllFract=%u%s", csr->ulPllFractionalFreqHz, VTY_NEWLINE); #endif #if OCTPHY_USE_CLOCK_SYNC_MGR_STATS_SLIP_CNT == 1 vty_out(vty, "SlipCnt=%u%s", csr->ulSlipCnt, VTY_NEWLINE); #endif #if OCTPHY_USE_CLOCK_SYNC_MGR_STATS_SYNC_LOSS_CNT == 1 vty_out(vty, "SyncLosses=%u%s", csr->ulSyncLossCnt, VTY_NEWLINE); #endif #if OCTPHY_USE_CLOCK_SYNC_MGR_STATS_SYNC_LOSSE_CNT == 1 vty_out(vty, "SyncLosses=%u%s", csr->ulSyncLosseCnt, VTY_NEWLINE); #endif #if OCTPHY_USE_CLOCK_SYNC_MGR_STATS_SOURCE_STATE == 1 vty_out(vty, "SourceState=%u%s", csr->ulSourceState, VTY_NEWLINE); #endif vty_out(vty, "DacValue=%u%s", csr->ulDacValue, VTY_NEWLINE); #if OCTPHY_USE_CLOCK_SYNC_MGR_STATS_DAC_STATE == 1 vty_out(vty, "CLOCK-SYNC-MGR-STATS.resp State=%s%s", get_value_string(clocksync_dac_vals, csr->ulDacState), VTY_NEWLINE); #endif vty_out(vty, "LOCK-SYNC-MGR-USR-PROCESS.resp State=%s%s", get_value_string(usr_process_id, csr->ulOwnerProcessUid), VTY_NEWLINE); vty_out(vty, "DacValue=%u%s", csr->ulDacValue, VTY_NEWLINE); #if OCTPHY_USE_CLOCK_SYNC_MGR_STATS_DRIFT_ELAPSE_TIME_US == 1 vty_out(vty, "DriftElapseTime=%u Us%s", csr->ulDriftElapseTimeUs, VTY_NEWLINE); #endif } DEFUN(show_clk_sync_stats, show_clk_sync_stats_cmd, "show phy <0-255> clk-sync-stats", "Obtain statistics for the Clock Sync Manager\n") { int phy_nr = atoi(argv[0]); struct phy_link *plink = phy_link_by_num(phy_nr); static struct octphy_hw_get_cb_data cb_data; cb_data.cb = show_clk_sync_stats_cb; cb_data.data = vty; octphy_hw_get_clock_sync_stats(plink->u.octphy.hdl, &cb_data); return CMD_SUCCESS; } void bts_model_config_write_phy(struct vty *vty, const struct phy_link *plink) { if (plink->u.octphy.netdev_name) vty_out(vty, " octphy net-device %s%s", plink->u.octphy.netdev_name, VTY_NEWLINE); vty_out(vty, " octphy hw-addr %02x:%02x:%02x:%02x:%02x:%02x%s", plink->u.octphy.phy_addr.sll_addr[0], plink->u.octphy.phy_addr.sll_addr[1], plink->u.octphy.phy_addr.sll_addr[2], plink->u.octphy.phy_addr.sll_addr[3], plink->u.octphy.phy_addr.sll_addr[4], plink->u.octphy.phy_addr.sll_addr[5], VTY_NEWLINE); vty_out(vty, " octphy rx-gain %u%s", plink->u.octphy.rx_gain_db, VTY_NEWLINE); if (plink->u.octphy.tx_atten_flag) { vty_out(vty, " octphy tx-attenuation %u%s", plink->u.octphy.tx_atten_db, VTY_NEWLINE); } else vty_out(vty, " octphy tx-attenuation oml%s", VTY_NEWLINE); vty_out(vty, " octphy rf-port-index %u%s", plink->u.octphy.rf_port_index, VTY_NEWLINE); #if OCTPHY_USE_ANTENNA_ID == 1 vty_out(vty, " octphy tx-ant-id %u%s", plink->u.octphy.tx_ant_id, VTY_NEWLINE); vty_out(vty, " octphy rx-ant-id %u%s", plink->u.octphy.rx_ant_id, VTY_NEWLINE); #endif #if OCTPHY_USE_16X_OVERSAMPLING == 1 vty_out(vty, " octphy over-sample-16x %u%s", plink->u.octphy.over_sample_16x, VTY_NEWLINE); #endif } void bts_model_config_write_phy_inst(struct vty *vty, const struct phy_instance *pinst) { } void bts_model_config_write_bts(struct vty *vty, const struct gsm_bts *bts) { } void bts_model_config_write_trx(struct vty *vty, const struct gsm_bts_trx *trx) { } DEFUN(show_sys_info, show_sys_info_cmd, "show phy <0-255> system-information", SHOW_TRX_STR "Display information about system\n") { int phy_nr = atoi(argv[0]); struct phy_link *plink = phy_link_by_num(phy_nr); struct octphy_hdl *fl1h; if (!plink) { vty_out(vty, "Cannot find PHY number %u%s", phy_nr, VTY_NEWLINE); return CMD_WARNING; } fl1h = plink->u.octphy.hdl; vty_out(vty, "System Platform: '%s', Version: '%s'%s", fl1h->info.system.platform, fl1h->info.system.version, VTY_NEWLINE); vty_out(vty, "Application Name: '%s', Description: '%s', Version: '%s'%s", fl1h->info.app.name, fl1h->info.app.description, fl1h->info.app.version, VTY_NEWLINE); return CMD_SUCCESS; } int bts_model_vty_init(struct gsm_bts *bts) { vty_bts = bts; install_element(PHY_NODE, &cfg_phy_hwaddr_cmd); install_element(PHY_NODE, &cfg_phy_netdev_cmd); install_element(PHY_NODE, &cfg_phy_rf_port_idx_cmd); #if OCTPHY_USE_ANTENNA_ID == 1 install_element(PHY_NODE, &cfg_phy_rx_ant_id_cmd); install_element(PHY_NODE, &cfg_phy_tx_ant_id_cmd); #endif install_element(PHY_NODE, &cfg_phy_rx_gain_db_cmd); install_element(PHY_NODE, &cfg_phy_tx_atten_db_cmd); #if OCTPHY_USE_16X_OVERSAMPLING == 1 install_element(PHY_NODE, &cfg_phy_over_sample_16x_cmd); #endif install_element_ve(&show_rf_port_stats_cmd); install_element_ve(&show_clk_sync_stats_cmd); install_element_ve(&show_sys_info_cmd); return 0; } int bts_model_ctrl_cmds_install(struct gsm_bts *bts) { return 0; }