Eric | c0f78a3 | 2023-05-12 13:00:14 +0200 | [diff] [blame] | 1 | #pragma once |
| 2 | /* |
| 3 | * (C) 2022 by sysmocom s.f.m.c. GmbH <info@sysmocom.de> |
| 4 | * All Rights Reserved |
| 5 | * |
| 6 | * Author: Eric Wild <ewild@sysmocom.de> |
| 7 | * |
| 8 | * This program is free software; you can redistribute it and/or modify |
| 9 | * it under the terms of the GNU Affero General Public License as published by |
| 10 | * the Free Software Foundation; either version 3 of the License, or |
| 11 | * (at your option) any later version. |
| 12 | * |
| 13 | * This program is distributed in the hope that it will be useful, |
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 16 | * GNU Affero General Public License for more details. |
| 17 | * |
| 18 | * You should have received a copy of the GNU Affero General Public License |
| 19 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 20 | * |
| 21 | */ |
| 22 | |
| 23 | #include <string> |
| 24 | #include <tuple> |
| 25 | |
| 26 | #include "Logger.h" |
| 27 | |
| 28 | extern "C" { |
| 29 | #include <osmocom/gsm/gsm_utils.h> |
| 30 | } |
| 31 | |
| 32 | template <typename powermapt, typename devmapt> |
| 33 | class band_manager { |
| 34 | using powerkeyt = typename powermapt::key_type; |
| 35 | using powermappedt = typename powermapt::mapped_type; |
| 36 | using devkeyt = typename devmapt::key_type; |
Eric | 242ceb2 | 2023-11-06 19:31:46 +0100 | [diff] [blame^] | 37 | devkeyt m_dev_type; |
Eric | c0f78a3 | 2023-05-12 13:00:14 +0200 | [diff] [blame] | 38 | const powermapt &m_power_map; |
| 39 | const devmapt &m_dev_map; |
| 40 | powerkeyt m_fallback; |
| 41 | enum gsm_band m_band; |
| 42 | powermappedt m_band_desc; |
| 43 | bool band_ass_curr_sess{}; /* true if "band" was set after last POWEROFF */ |
| 44 | |
| 45 | // looks up either first tuple element (->enum) or straight enum |
| 46 | template <typename T, typename std::enable_if<std::is_enum<T>::value>::type *dummy = nullptr> |
| 47 | auto key_helper(T &t) -> T |
| 48 | { |
| 49 | return t; |
| 50 | } |
| 51 | |
| 52 | template <typename T> |
| 53 | auto key_helper(T t) -> typename std::tuple_element<0, T>::type |
| 54 | { |
| 55 | return std::get<0>(t); |
| 56 | } |
| 57 | |
| 58 | void assign_band_desc(enum gsm_band req_band) |
| 59 | { |
| 60 | auto key = key_helper(m_dev_type); |
| 61 | auto fallback_key = key_helper(m_fallback); |
| 62 | auto it = m_power_map.find({ key, req_band }); |
| 63 | if (it == m_power_map.end()) { |
| 64 | auto desc = m_dev_map.at(m_dev_type); |
| 65 | LOGC(DDEV, ERROR) << "No Tx Power measurements exist for device " << desc.desc_str |
| 66 | << " on band " << gsm_band_name(req_band) << ", using fallback.."; |
| 67 | it = m_power_map.find({ fallback_key, req_band }); |
| 68 | } |
| 69 | OSMO_ASSERT(it != m_power_map.end()); |
| 70 | m_band_desc = it->second; |
| 71 | } |
| 72 | |
| 73 | bool set_band(enum gsm_band req_band) |
| 74 | { |
| 75 | if (band_ass_curr_sess && req_band != m_band) { |
| 76 | LOGC(DDEV, ALERT) << "Requesting band " << gsm_band_name(req_band) |
| 77 | << " different from previous band " << gsm_band_name(m_band); |
| 78 | return false; |
| 79 | } |
| 80 | |
| 81 | if (req_band != m_band) { |
| 82 | m_band = req_band; |
| 83 | assign_band_desc(m_band); |
| 84 | } |
| 85 | band_ass_curr_sess = true; |
| 86 | return true; |
| 87 | } |
| 88 | |
| 89 | public: |
| 90 | band_manager(const devkeyt &dev_type, const powermapt &power_map, const devmapt &dev_map, powerkeyt fallback) |
| 91 | : m_dev_type(dev_type), m_power_map(power_map), m_dev_map(dev_map), m_fallback(fallback), |
| 92 | m_band((enum gsm_band)0) |
| 93 | { |
| 94 | } |
| 95 | band_manager(const powermapt &power_map, const devmapt &dev_map) |
| 96 | : m_dev_type(dev_map.begin()->first), m_power_map(power_map), m_dev_map(dev_map), |
| 97 | m_fallback(m_power_map.begin()->first), m_band((enum gsm_band)0) |
| 98 | { |
| 99 | } |
| 100 | void band_reset() |
| 101 | { |
| 102 | band_ass_curr_sess = false; |
| 103 | } |
| 104 | |
Eric | 242ceb2 | 2023-11-06 19:31:46 +0100 | [diff] [blame^] | 105 | void update_band_dev(devkeyt dev_type) { |
| 106 | m_dev_type = dev_type; |
| 107 | } |
| 108 | |
Eric | c0f78a3 | 2023-05-12 13:00:14 +0200 | [diff] [blame] | 109 | void get_dev_band_desc(powermappedt &desc) |
| 110 | { |
| 111 | if (m_band == 0) { |
| 112 | LOGC(DDEV, ERROR) |
| 113 | << "Power parameters requested before Tx Frequency was set! Providing band 900 by default..."; |
| 114 | assign_band_desc(GSM_BAND_900); |
| 115 | } |
| 116 | desc = m_band_desc; |
| 117 | } |
| 118 | |
| 119 | bool update_band_from_freq(double wFreq, int chan, bool is_tx) |
| 120 | { |
| 121 | enum gsm_band req_band; |
| 122 | auto dirstr = is_tx ? "Tx" : "Rx"; |
| 123 | auto req_arfcn = gsm_freq102arfcn(wFreq / 1000 / 100, !is_tx); |
| 124 | if (req_arfcn == 0xffff) { |
| 125 | LOGCHAN(chan, DDEV, ALERT) |
| 126 | << "Unknown ARFCN for " << dirstr << " Frequency " << wFreq / 1000 << " kHz"; |
| 127 | return false; |
| 128 | } |
| 129 | if (gsm_arfcn2band_rc(req_arfcn, &req_band) < 0) { |
| 130 | LOGCHAN(chan, DDEV, ALERT) << "Unknown GSM band for " << dirstr << " Frequency " << wFreq |
| 131 | << " Hz (ARFCN " << req_arfcn << " )"; |
| 132 | return false; |
| 133 | } |
| 134 | |
| 135 | return set_band(req_band); |
| 136 | } |
| 137 | }; |