blob: 5d53221a6616529d7dac8e6eddd96b19a374daec [file] [log] [blame]
Eric2c12b302022-07-19 21:12:58 +02001/*
2 * (C) 2022 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
3 * All Rights Reserved
4 *
5 * Author: Eric Wild <ewild@sysmocom.de>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include "sigProcLib.h"
23#include "syncthing.h"
Eric2c12b302022-07-19 21:12:58 +020024#include <signalVector.h>
25#include <radioVector.h>
26#include <radioInterface.h>
27#include "grgsm_vitac/grgsm_vitac.h"
Eric2c12b302022-07-19 21:12:58 +020028#include "ms_rx_upper.h"
29
30extern "C" {
Eric70bd9412022-10-27 15:22:34 +020031#include <osmocom/core/select.h>
Eric2c12b302022-07-19 21:12:58 +020032#include "sch.h"
33#include "convolve.h"
34#include "convert.h"
35#include "proto_trxd.h"
36
37void __lsan_do_recoverable_leak_check();
38}
39
Eric2ecd9f62022-10-31 15:01:26 +010040namespace trxcon
41{
42extern "C" {
43#include <trxcon/trx_if.h>
44}
45trx_instance *trxcon_instance; // local handle
46static tx_queue_t txq;
47} // namespace trxcon
48
Eric2c12b302022-07-19 21:12:58 +020049#ifdef LOG
50#undef LOG
51#define LOG(...) upper_trx::dummy_log()
52#endif
53
54void upper_trx::start_threads()
55{
Eric2c12b302022-07-19 21:12:58 +020056 thr_control = std::thread([this] {
57 set_name_aff_sched("upper_ctrl", 1, SCHED_RR, sched_get_priority_max(SCHED_RR));
58 while (1) {
59 driveControl();
60 pthread_testcancel();
61 }
62 });
63 msleep(1);
64 thr_tx = std::thread([this] {
65 set_name_aff_sched("upper_tx", 1, SCHED_FIFO, sched_get_priority_max(SCHED_FIFO) - 1);
66
67 while (1) {
68 driveTx();
69 pthread_testcancel();
70 }
71 });
72
Eric70bd9412022-10-27 15:22:34 +020073 // atomic ensures data is not written to q until loop reads
74 start_ms();
75
76 set_name_aff_sched("upper_rx", 1, SCHED_FIFO, sched_get_priority_max(SCHED_RR) - 5);
77 while (1) {
78 // set_upper_ready(true);
79 driveReceiveFIFO();
80 pthread_testcancel();
81 osmo_select_main(1);
82 }
83
Eric2c12b302022-07-19 21:12:58 +020084 // std::thread([this] {
85 // set_name_aff_sched("leakcheck", 1, SCHED_FIFO, sched_get_priority_max(SCHED_FIFO) - 10);
86
87 // while (1) {
88 // std::this_thread::sleep_for(std::chrono::seconds{ 5 });
89 // __lsan_do_recoverable_leak_check();
90 // }
91 // }).detach();
92}
93
94void upper_trx::start_ms()
95{
96 ms_trx::start();
97}
98
Eric2c12b302022-07-19 21:12:58 +020099SoftVector *upper_trx::pullRadioVector(GSM::Time &wTime, int &RSSI, int &timingOffset) __attribute__((optnone))
100{
101 float pow, avg = 1.0;
102 static SoftVector bits(148);
103 static complex workbuf[40 + 625 + 40];
104 static signalVector sv(workbuf, 40, 625);
105
106 GSM::Time burst_time;
107 auto ss = reinterpret_cast<std::complex<float> *>(&workbuf[40]);
108
109 memset((void *)&workbuf[0], 0, sizeof(workbuf));
110 // assert(sv.begin() == &workbuf[40]);
111
112 one_burst e;
113 unsigned char outbin[148];
114
115 std::stringstream dbgout;
116
117 while (!rxqueue.spsc_pop(&e)) {
118 rxqueue.spsc_prep_pop();
119 }
120
121 burst_time = e.gsmts;
122 wTime = burst_time;
123
124 auto is_sch = (burst_time.TN() == 0 && gsm_sch_check_fn(burst_time.FN()));
125 auto is_fcch = (burst_time.TN() == 0 && gsm_fcch_check_fn(burst_time.FN()));
126
127 if (is_fcch) {
128 // return trash
129 // fprintf(stderr, "c %d\n",burst_time.FN());
130 return &bits;
131 }
132
133 if (is_sch) {
134 for (int i = 0; i < 148; i++)
135 (bits)[i] = (!e.sch_bits[i]) < 1 ? -1 : 1;
136 RSSI = 10;
137 timingOffset = 0;
138 // fprintf(stderr, "s %d\n", burst_time.FN());
139 return &bits;
140 }
141
Eric2ecd9f62022-10-31 15:01:26 +0100142 auto ts = trxcon::trxcon_instance->ts_list[burst_time.TN()];
143 if (ts == NULL || ts->mf_layout == NULL)
144 return 0;
Eric2c12b302022-07-19 21:12:58 +0200145
146 convert_and_scale<float, int16_t>(ss, e.burst, ONE_TS_BURST_LEN * 2, 1.f / float(rxFullScale));
147
148 pow = energyDetect(sv, 20 * rx_sps);
149 if (pow < -1) {
150 LOG(ALERT) << "Received empty burst";
Eric2ecd9f62022-10-31 15:01:26 +0100151 return NULL;
Eric2c12b302022-07-19 21:12:58 +0200152 }
153
154 avg = sqrt(pow);
Eric2ecd9f62022-10-31 15:01:26 +0100155 {
Eric2c12b302022-07-19 21:12:58 +0200156 float ncmax, dcmax;
157 std::complex<float> chan_imp_resp[CHAN_IMP_RESP_LENGTH * d_OSR];
158 std::complex<float> chan_imp_resp2[CHAN_IMP_RESP_LENGTH * d_OSR];
159 auto normal_burst_start = get_norm_chan_imp_resp(ss, &chan_imp_resp[0], &ncmax, mTSC);
160 auto dummy_burst_start = get_norm_chan_imp_resp(ss, &chan_imp_resp2[0], &dcmax, TS_DUMMY);
161 auto is_nb = ncmax > dcmax;
162
163 // std::cerr << " U " << (is_nb ? "NB" : "DB") << "@ o nb: " << normal_burst_start
164 // << " o db: " << dummy_burst_start << std::endl;
165
166 normal_burst_start = normal_burst_start < 39 ? normal_burst_start : 39;
167 normal_burst_start = normal_burst_start > -39 ? normal_burst_start : -39;
168
169 // fprintf(stderr, "%s %d\n", (is_nb ? "N":"D"), burst_time.FN());
170 // if (is_nb)
171 detect_burst(ss, &chan_imp_resp[0], normal_burst_start, outbin);
172 // else
173 // detect_burst(ss, &chan_imp_resp2[0], dummy_burst_start, outbin);
174
175 for (int i = 0; i < 148; i++)
176 (bits)[i] = (outbin[i]) < 1 ? -1 : 1;
177 }
Eric2c12b302022-07-19 21:12:58 +0200178 RSSI = (int)floor(20.0 * log10(rxFullScale / avg));
179 timingOffset = (int)round(0);
180
181 return &bits;
Eric2c12b302022-07-19 21:12:58 +0200182}
183
184void upper_trx::driveReceiveFIFO()
185{
186 int RSSI;
187 int TOA; // in 1/256 of a symbol
188 GSM::Time burstTime;
Eric2c12b302022-07-19 21:12:58 +0200189
190 if (!mOn)
191 return;
192
Eric70bd9412022-10-27 15:22:34 +0200193 SoftVector *rxBurst = pullRadioVector(burstTime, RSSI, TOA);
Eric2c12b302022-07-19 21:12:58 +0200194
Eric2c12b302022-07-19 21:12:58 +0200195 if (rxBurst) {
Eric2ecd9f62022-10-31 15:01:26 +0100196 trxd_from_trx response;
197 response.ts = burstTime.TN();
198 response.fn = htonl(burstTime.FN());
199 response.rssi = RSSI;
200 response.toa = htons(TOA);
201
Eric2c12b302022-07-19 21:12:58 +0200202 SoftVector::const_iterator burstItr = rxBurst->begin();
203 if (burstTime.TN() == 0 && gsm_sch_check_fn(burstTime.FN())) {
204 clamp_array(rxBurst->begin(), 148, 1.5f);
205 for (unsigned int i = 0; i < gSlotLen; i++) {
206 auto val = *burstItr++;
207 auto vval = isnan(val) ? 0 : val;
208 ((int8_t *)response.symbols)[i] = round((vval - 0.5) * 64.0);
209 }
210 } else {
211 // invert and fix to +-127 sbits
212 for (int i = 0; i < 148; i++)
213 ((int8_t *)response.symbols)[i] = *burstItr++ > 0.0f ? -127 : 127;
214 }
Eric2ecd9f62022-10-31 15:01:26 +0100215 trxcon::trx_data_rx_handler(trxcon::trxcon_instance, (uint8_t *)&response);
Eric2c12b302022-07-19 21:12:58 +0200216 }
Eric2c12b302022-07-19 21:12:58 +0200217}
218
219void upper_trx::driveTx()
220{
Eric2ecd9f62022-10-31 15:01:26 +0100221 trxd_to_trx e;
222 while (!trxcon::txq.spsc_pop(&e)) {
223 trxcon::txq.spsc_prep_pop();
Eric2c12b302022-07-19 21:12:58 +0200224 }
Eric2c12b302022-07-19 21:12:58 +0200225
Eric2ecd9f62022-10-31 15:01:26 +0100226 trxd_to_trx *burst = &e;
Eric2c12b302022-07-19 21:12:58 +0200227
Eric2c12b302022-07-19 21:12:58 +0200228 auto proper_fn = ntohl(burst->fn);
229 // std::cerr << "got burst!" << proper_fn << ":" << burst->ts
230 // << " current: " << timekeeper.gsmtime().FN()
231 // << " dff: " << (int64_t)((int64_t)timekeeper.gsmtime().FN() - (int64_t)proper_fn)
232 // << std::endl;
233
234 auto currTime = GSM::Time(proper_fn, burst->ts);
235 int RSSI = (int)burst->txlev;
236
237 static BitVector newBurst(gSlotLen);
238 BitVector::iterator itr = newBurst.begin();
239 auto *bufferItr = burst->symbols;
240 while (itr < newBurst.end())
241 *itr++ = *bufferItr++;
242
243 auto txburst = modulateBurst(newBurst, 8 + (currTime.TN() % 4 == 0), 4);
244 scaleVector(*txburst, txFullScale * 0.7 /* * pow(10, -RSSI / 10)*/);
245
246 // float -> int16
247 blade_sample_type burst_buf[txburst->size()];
248 convert_and_scale<int16_t, float>(burst_buf, txburst->begin(), txburst->size() * 2, 1);
249
250 // auto check = signalVector(txburst->size(), 40);
251 // convert_and_scale<float, int16_t, 1>(check.begin(), burst_buf, txburst->size() * 2);
252 // estim_burst_params ebp;
253 // auto d = detectAnyBurst(check, 2, 4, 4, CorrType::RACH, 40, &ebp);
254 // if(d)
255 // std::cerr << "RACH D! " << ebp.toa << std::endl;
256 // else
257 // std::cerr << "RACH NOOOOOOOOOO D! " << ebp.toa << std::endl;
258
259 // memory read --binary --outfile /tmp/mem.bin &burst_buf[0] --count 2500 --force
260
261 submit_burst(burst_buf, txburst->size(), currTime);
262 delete txburst;
Eric2c12b302022-07-19 21:12:58 +0200263}
264
Eric2c12b302022-07-19 21:12:58 +0200265int trxc_main(int argc, char *argv[])
266{
267 pthread_setname_np(pthread_self(), "main_trxc");
268
269 convolve_init();
270 convert_init();
271 sigProcLibSetup();
272 initvita();
273
274 int status = 0;
275 auto trx = new upper_trx();
276 trx->do_auto_gain = true;
277
278 status = trx->init_dev_and_streams(0, 0);
279 trx->start_threads();
280
281 return status;
282}
283
Eric2ecd9f62022-10-31 15:01:26 +0100284extern "C" {
285void init_external_transceiver(struct trx_instance *trx, int argc, char **argv)
Eric2c12b302022-07-19 21:12:58 +0200286{
Eric2ecd9f62022-10-31 15:01:26 +0100287 trxcon::trxcon_instance = (trxcon::trx_instance *)trx;
Eric2c12b302022-07-19 21:12:58 +0200288 std::cout << "init?" << std::endl;
289 trxc_main(argc, argv);
290}
291
Eric2ecd9f62022-10-31 15:01:26 +0100292void close_external_transceiver(int argc, char **argv)
Eric2c12b302022-07-19 21:12:58 +0200293{
294 std::cout << "Shutting down transceiver..." << std::endl;
295}
Eric2ecd9f62022-10-31 15:01:26 +0100296
297void tx_external_transceiver(uint8_t *burst)
298{
299 trxcon::txq.spsc_push((trxd_to_trx *)burst);
300}
301}