trcon<->l1 data if without sockets

direct call of UL rx receive data handler + sched check if ts is active
tx dir call stub for for tx thread queue.

Change-Id: I5911004db58742cf39b968fcf87bc1243f7a374a
This commit is contained in:
Eric Wild 2022-10-31 15:01:26 +01:00
parent 70bd9415a2
commit 2ecd9f698f
8 changed files with 65 additions and 359 deletions

View File

@ -191,7 +191,6 @@ noinst_HEADERS += \
ms/bladerf_specific.h \ ms/bladerf_specific.h \
ms/uhd_specific.h \ ms/uhd_specific.h \
ms/ms_rx_upper.h \ ms/ms_rx_upper.h \
ms/ms_state.h \
itrq.h itrq.h
# -fsanitize=address,undefined -shared-libsan -O0 # -fsanitize=address,undefined -shared-libsan -O0
# #

View File

@ -20,10 +20,8 @@
*/ */
#include <radioInterface.h> #include <radioInterface.h>
#include "l1if.h"
#include "ms_rx_upper.h" #include "ms_rx_upper.h"
#include "syncthing.h" #include "syncthing.h"
#include "ms_state.h"
void upper_trx::driveControl() void upper_trx::driveControl()
{ {
@ -199,8 +197,6 @@ void upper_trx::commandhandler(char *buffer, char *response)
sprintf(response, "RSP SETSLOT 1 %d %d", timeslot, corrCode); sprintf(response, "RSP SETSLOT 1 %d %d", timeslot, corrCode);
return; return;
} }
mStates.chanType[timeslot] = (ChannelCombination)corrCode;
mStates.setModulus(timeslot);
sprintf(response, "RSP SETSLOT 0 %d %d", timeslot, corrCode); sprintf(response, "RSP SETSLOT 0 %d %d", timeslot, corrCode);
} else if (!strcmp(command, "SETRXMASK")) { } else if (!strcmp(command, "SETRXMASK")) {
int slot; int slot;
@ -214,7 +210,6 @@ void upper_trx::commandhandler(char *buffer, char *response)
} }
} else if (!strcmp(command, "SYNC")) { } else if (!strcmp(command, "SYNC")) {
// msleep(10); // msleep(10);
mStates.mode = trx_mode::TRX_MODE_MS_TRACK;
sprintf(response, "RSP SYNC 0"); sprintf(response, "RSP SYNC 0");
mMaxExpectedDelay = 48; mMaxExpectedDelay = 48;
// setRxGain(30); // setRxGain(30);

View File

@ -21,12 +21,10 @@
#include "sigProcLib.h" #include "sigProcLib.h"
#include "syncthing.h" #include "syncthing.h"
#include "l1if.h"
#include <signalVector.h> #include <signalVector.h>
#include <radioVector.h> #include <radioVector.h>
#include <radioInterface.h> #include <radioInterface.h>
#include "grgsm_vitac/grgsm_vitac.h" #include "grgsm_vitac/grgsm_vitac.h"
#include "ms_state.h"
#include "ms_rx_upper.h" #include "ms_rx_upper.h"
extern "C" { extern "C" {
@ -39,6 +37,15 @@ extern "C" {
void __lsan_do_recoverable_leak_check(); void __lsan_do_recoverable_leak_check();
} }
namespace trxcon
{
extern "C" {
#include <trxcon/trx_if.h>
}
trx_instance *trxcon_instance; // local handle
static tx_queue_t txq;
} // namespace trxcon
#ifdef LOG #ifdef LOG
#undef LOG #undef LOG
#define LOG(...) upper_trx::dummy_log() #define LOG(...) upper_trx::dummy_log()
@ -89,35 +96,6 @@ void upper_trx::start_ms()
ms_trx::start(); ms_trx::start();
} }
/* Detect SCH synchronization sequence within a burst */
bool upper_trx::detectSCH(ms_TransceiverState *state, signalVector &burst, struct estim_burst_params *ebp)
{
int shift;
sch_detect_type full;
float mag, threshold = 4.0;
full = (state->mode == trx_mode::TRX_MODE_MS_TRACK) ? sch_detect_type::SCH_DETECT_NARROW :
sch_detect_type::SCH_DETECT_FULL;
if (!detectSCHBurst(burst, threshold, rx_sps, full, ebp))
return false;
std::clog << "SCH : Timing offset " << ebp->toa << " symbols" << std::endl;
mag = fabsf(ebp->toa);
if (mag < 1.0f)
return true;
shift = (int)(mag / 2.0f);
if (!shift)
shift++;
shift = ebp->toa > 0 ? shift : -shift;
std::clog << "SCH : shift -> " << shift << " symbols" << std::endl;
// mRadioInterface->applyOffset(shift);
return false;
}
SoftVector *upper_trx::pullRadioVector(GSM::Time &wTime, int &RSSI, int &timingOffset) __attribute__((optnone)) SoftVector *upper_trx::pullRadioVector(GSM::Time &wTime, int &RSSI, int &timingOffset) __attribute__((optnone))
{ {
float pow, avg = 1.0; float pow, avg = 1.0;
@ -161,50 +139,20 @@ SoftVector *upper_trx::pullRadioVector(GSM::Time &wTime, int &RSSI, int &timingO
return &bits; return &bits;
} }
CorrType type = TSC; auto ts = trxcon::trxcon_instance->ts_list[burst_time.TN()];
if (ts == NULL || ts->mf_layout == NULL)
// tickle UL by returning null bursts if demod is skipped due to unused TS return 0;
switch (mStates.mode) {
case trx_mode::TRX_MODE_MS_TRACK:
if (mStates.chanType[burst_time.TN()] == ChannelCombination::NONE_INACTIVE) {
type = OFF;
goto release;
} else if (is_sch)
type = SCH;
else if (!is_fcch) // all ts0, but not fcch or sch..
type = TSC;
break;
case trx_mode::TRX_MODE_OFF:
default:
goto release;
}
convert_and_scale<float, int16_t>(ss, e.burst, ONE_TS_BURST_LEN * 2, 1.f / float(rxFullScale)); convert_and_scale<float, int16_t>(ss, e.burst, ONE_TS_BURST_LEN * 2, 1.f / float(rxFullScale));
pow = energyDetect(sv, 20 * rx_sps); pow = energyDetect(sv, 20 * rx_sps);
if (pow < -1) { if (pow < -1) {
LOG(ALERT) << "Received empty burst"; LOG(ALERT) << "Received empty burst";
goto release; return NULL;
} }
avg = sqrt(pow); avg = sqrt(pow);
{
if (type == SCH) {
std::complex<float> chan_imp_resp[CHAN_IMP_RESP_LENGTH * d_OSR];
int d_c0_burst_start = get_sch_chan_imp_resp(ss, &chan_imp_resp[0]);
detect_burst(ss, &chan_imp_resp[0], d_c0_burst_start, outbin);
for (int i = 0; i < 148; i++)
(bits)[i] = (!outbin[i]) < 1 ? -1 : 1;
// auto rv = decode_sch(bits->begin(), false);
// dbgout << "U SCH@"
// << " " << e.gsmts.FN() << ":" << e.gsmts.TN() << " " << d_c0_burst_start
// << " DECODE:" << (rv ? "yes" : "---") << std::endl;
// std::cerr << dbgout.str();
} else {
float ncmax, dcmax; float ncmax, dcmax;
std::complex<float> chan_imp_resp[CHAN_IMP_RESP_LENGTH * d_OSR]; std::complex<float> chan_imp_resp[CHAN_IMP_RESP_LENGTH * d_OSR];
std::complex<float> chan_imp_resp2[CHAN_IMP_RESP_LENGTH * d_OSR]; std::complex<float> chan_imp_resp2[CHAN_IMP_RESP_LENGTH * d_OSR];
@ -227,14 +175,10 @@ SoftVector *upper_trx::pullRadioVector(GSM::Time &wTime, int &RSSI, int &timingO
for (int i = 0; i < 148; i++) for (int i = 0; i < 148; i++)
(bits)[i] = (outbin[i]) < 1 ? -1 : 1; (bits)[i] = (outbin[i]) < 1 ? -1 : 1;
} }
RSSI = (int)floor(20.0 * log10(rxFullScale / avg)); RSSI = (int)floor(20.0 * log10(rxFullScale / avg));
timingOffset = (int)round(0); timingOffset = (int)round(0);
return &bits; return &bits;
release:
return NULL;
} }
void upper_trx::driveReceiveFIFO() void upper_trx::driveReceiveFIFO()
@ -248,12 +192,13 @@ void upper_trx::driveReceiveFIFO()
SoftVector *rxBurst = pullRadioVector(burstTime, RSSI, TOA); SoftVector *rxBurst = pullRadioVector(burstTime, RSSI, TOA);
trxd_from_trx response;
response.ts = burstTime.TN();
response.fn = htonl(burstTime.FN());
response.rssi = RSSI;
response.toa = htons(TOA);
if (rxBurst) { if (rxBurst) {
trxd_from_trx response;
response.ts = burstTime.TN();
response.fn = htonl(burstTime.FN());
response.rssi = RSSI;
response.toa = htons(TOA);
SoftVector::const_iterator burstItr = rxBurst->begin(); SoftVector::const_iterator burstItr = rxBurst->begin();
if (burstTime.TN() == 0 && gsm_sch_check_fn(burstTime.FN())) { if (burstTime.TN() == 0 && gsm_sch_check_fn(burstTime.FN())) {
clamp_array(rxBurst->begin(), 148, 1.5f); clamp_array(rxBurst->begin(), 148, 1.5f);
@ -267,45 +212,19 @@ void upper_trx::driveReceiveFIFO()
for (int i = 0; i < 148; i++) for (int i = 0; i < 148; i++)
((int8_t *)response.symbols)[i] = *burstItr++ > 0.0f ? -127 : 127; ((int8_t *)response.symbols)[i] = *burstItr++ > 0.0f ? -127 : 127;
} }
trxcon::trx_data_rx_handler(trxcon::trxcon_instance, (uint8_t *)&response);
} }
#ifdef IPCIF
push_d(response);
#else
int rv = sendto(mDataSockets, &response, sizeof(trxd_from_trx), 0, (struct sockaddr *)&datadest,
sizeof(struct sockaddr_in));
if (rv < 0) {
std::cerr << "fuck, send?" << std::endl;
exit(0);
}
#endif
} }
void upper_trx::driveTx() void upper_trx::driveTx()
{ {
#ifdef IPCIF trxd_to_trx e;
auto burst = pop_d(); while (!trxcon::txq.spsc_pop(&e)) {
if (!burst) { trxcon::txq.spsc_prep_pop();
// std::cerr << "wtf no tx burst?" << std::endl;
// exit(0);
continue;
} }
#else
trxd_to_trx buffer;
socklen_t addr_len = sizeof(datasrc); trxd_to_trx *burst = &e;
int rdln = recvfrom(mDataSockets, (void *)&buffer, sizeof(trxd_to_trx), 0, &datasrc, &addr_len);
if (rdln < 0 && errno == EAGAIN) {
std::cerr << "fuck, rcv?" << std::endl;
exit(0);
}
if(rdln < sizeof(buffer)) // nope ind has len 6 or something like that
return;
trxd_to_trx *burst = &buffer;
#endif
auto proper_fn = ntohl(burst->fn); auto proper_fn = ntohl(burst->fn);
// std::cerr << "got burst!" << proper_fn << ":" << burst->ts // std::cerr << "got burst!" << proper_fn << ":" << burst->ts
// << " current: " << timekeeper.gsmtime().FN() // << " current: " << timekeeper.gsmtime().FN()
@ -341,30 +260,8 @@ void upper_trx::driveTx()
submit_burst(burst_buf, txburst->size(), currTime); submit_burst(burst_buf, txburst->size(), currTime);
delete txburst; delete txburst;
#ifdef IPCIF
free(burst);
#endif
} }
// __attribute__((xray_always_instrument)) static void *rx_stream_callback(struct bladerf *dev,
// struct bladerf_stream *stream,
// struct bladerf_metadata *meta, void *samples,
// size_t num_samples, void *user_data)
// {
// struct ms_trx *trx = (struct ms_trx *)user_data;
// return trx->rx_cb(dev, stream, meta, samples, num_samples, user_data);
// }
// __attribute__((xray_always_instrument)) static void *tx_stream_callback(struct bladerf *dev,
// struct bladerf_stream *stream,
// struct bladerf_metadata *meta, void *samples,
// size_t num_samples, void *user_data)
// {
// struct ms_trx *trx = (struct ms_trx *)user_data;
// return BLADERF_STREAM_NO_DATA;
// }
int trxc_main(int argc, char *argv[]) int trxc_main(int argc, char *argv[])
{ {
pthread_setname_np(pthread_self(), "main_trxc"); pthread_setname_np(pthread_self(), "main_trxc");
@ -384,14 +281,21 @@ int trxc_main(int argc, char *argv[])
return status; return status;
} }
extern "C" volatile bool gshutdown = false; extern "C" {
extern "C" void init_external_transceiver(int argc, char **argv) void init_external_transceiver(struct trx_instance *trx, int argc, char **argv)
{ {
trxcon::trxcon_instance = (trxcon::trx_instance *)trx;
std::cout << "init?" << std::endl; std::cout << "init?" << std::endl;
trxc_main(argc, argv); trxc_main(argc, argv);
} }
extern "C" void stop_trx() void close_external_transceiver(int argc, char **argv)
{ {
std::cout << "Shutting down transceiver..." << std::endl; std::cout << "Shutting down transceiver..." << std::endl;
} }
void tx_external_transceiver(uint8_t *burst)
{
trxcon::txq.spsc_push((trxd_to_trx *)burst);
}
}

View File

@ -28,13 +28,12 @@
#include "GSMCommon.h" #include "GSMCommon.h"
#include "radioClock.h" #include "radioClock.h"
#include "syncthing.h" #include "syncthing.h"
#include "ms_state.h" #include "l1if.h"
using tx_queue_t = spsc_cond<8 * 1, trxd_to_trx, true, false>;
class upper_trx : public ms_trx { class upper_trx : public ms_trx {
int rx_sps, tx_sps; int rx_sps, tx_sps;
ms_TransceiverState mStates;
bool mOn; ///< flag to indicate that transceiver is powered on bool mOn; ///< flag to indicate that transceiver is powered on
double mTxFreq; ///< the transmit frequency double mTxFreq; ///< the transmit frequency
double mRxFreq; ///< the receive frequency double mRxFreq; ///< the receive frequency
@ -42,9 +41,6 @@ class upper_trx : public ms_trx {
unsigned mMaxExpectedDelay; ///< maximum TOA offset in GSM symbols unsigned mMaxExpectedDelay; ///< maximum TOA offset in GSM symbols
unsigned long long mRxSlotMask[8]; ///< MS - enabled multiframe slot mask unsigned long long mRxSlotMask[8]; ///< MS - enabled multiframe slot mask
int mDataSockets;
sockaddr_in datadest;
sockaddr datasrc;
int mCtrlSockets; int mCtrlSockets;
sockaddr_in ctrldest; sockaddr_in ctrldest;
sockaddr ctrlsrc; sockaddr ctrlsrc;
@ -98,8 +94,6 @@ class upper_trx : public ms_trx {
SoftVector *pullRadioVector(GSM::Time &wTime, int &RSSI, int &timingOffset); SoftVector *pullRadioVector(GSM::Time &wTime, int &RSSI, int &timingOffset);
bool detectSCH(ms_TransceiverState *state, signalVector &burst, struct estim_burst_params *ebp);
std::thread thr_control, thr_rx, thr_tx; std::thread thr_control, thr_rx, thr_tx;
public: public:
@ -110,12 +104,8 @@ class upper_trx : public ms_trx {
{ {
auto c_srcport = 6700 + 2 * 0 + 1; auto c_srcport = 6700 + 2 * 0 + 1;
auto c_dstport = 6700 + 2 * 0 + 101; auto c_dstport = 6700 + 2 * 0 + 101;
auto d_srcport = 6700 + 2 * 0 + 2;
auto d_dstport = 6700 + 2 * 0 + 102;
openudp(&mCtrlSockets, c_srcport, "127.0.0.1"); openudp(&mCtrlSockets, c_srcport, "127.0.0.1");
openudp(&mDataSockets, d_srcport, "127.0.0.1");
resolveAddress(&ctrldest, "127.0.0.1", c_dstport); resolveAddress(&ctrldest, "127.0.0.1", c_dstport);
resolveAddress(&datadest, "127.0.0.1", d_dstport);
}; };
}; };

View File

@ -1,175 +0,0 @@
#pragma once
#include <radioVector.h>
#include <signalVector.h>
enum class trx_mode {
TRX_MODE_OFF,
TRX_MODE_BTS,
TRX_MODE_MS_ACQUIRE,
TRX_MODE_MS_TRACK,
};
enum class ChannelCombination {
FILL, ///< Channel is transmitted, but unused
I, ///< TCH/FS
II, ///< TCH/HS, idle every other slot
III, ///< TCH/HS
IV, ///< FCCH+SCH+CCCH+BCCH, uplink RACH
V, ///< FCCH+SCH+CCCH+BCCH+SDCCH/4+SACCH/4, uplink RACH+SDCCH/4
VI, ///< CCCH+BCCH, uplink RACH
VII, ///< SDCCH/8 + SACCH/8
VIII, ///< TCH/F + FACCH/F + SACCH/M
IX, ///< TCH/F + SACCH/M
X, ///< TCH/FD + SACCH/MD
XI, ///< PBCCH+PCCCH+PDTCH+PACCH+PTCCH
XII, ///< PCCCH+PDTCH+PACCH+PTCCH
XIII, ///< PDTCH+PACCH+PTCCH
NONE_INACTIVE, ///< Channel is inactive, default
LOOPBACK ///< similar go VII, used in loopback testing
};
struct ms_TransceiverState {
ms_TransceiverState() : mFreqOffsets(10), mode(trx_mode::TRX_MODE_OFF)
{
for (int i = 0; i < 8; i++) {
chanType[i] = ChannelCombination::NONE_INACTIVE;
fillerModulus[i] = 26;
for (int n = 0; n < 102; n++)
fillerTable[n][i] = nullptr;
}
}
~ms_TransceiverState()
{
for (int i = 0; i < 8; i++) {
for (int n = 0; n < 102; n++)
delete fillerTable[n][i];
}
}
void setModulus(size_t timeslot)
{
switch (chanType[timeslot]) {
case ChannelCombination::NONE_INACTIVE:
case ChannelCombination::I:
case ChannelCombination::II:
case ChannelCombination::III:
case ChannelCombination::FILL:
fillerModulus[timeslot] = 26;
break;
case ChannelCombination::IV:
case ChannelCombination::VI:
case ChannelCombination::V:
fillerModulus[timeslot] = 51;
break;
//case V:
case ChannelCombination::VII:
fillerModulus[timeslot] = 102;
break;
case ChannelCombination::XIII:
fillerModulus[timeslot] = 52;
break;
default:
break;
}
}
CorrType expectedCorrType(GSM::Time currTime, unsigned long long *mRxSlotMask)
{
unsigned burstTN = currTime.TN();
unsigned burstFN = currTime.FN();
if (mode == trx_mode::TRX_MODE_MS_TRACK) {
/* 102 modulus case currently unhandled */
if (fillerModulus[burstTN] > 52)
return OFF;
int modFN = burstFN % fillerModulus[burstTN];
unsigned long long reg = (unsigned long long)1 << modFN;
if (reg & mRxSlotMask[burstTN])
return TSC;
else
return OFF;
}
switch (chanType[burstTN]) {
case ChannelCombination::NONE_INACTIVE:
return OFF;
break;
case ChannelCombination::FILL:
return IDLE;
break;
case ChannelCombination::I:
return TSC;
/*if (burstFN % 26 == 25)
return IDLE;
else
return TSC;*/
break;
case ChannelCombination::II:
return TSC;
break;
case ChannelCombination::III:
return TSC;
break;
case ChannelCombination::IV:
case ChannelCombination::VI:
return RACH;
break;
case ChannelCombination::V: {
int mod51 = burstFN % 51;
if ((mod51 <= 36) && (mod51 >= 14))
return RACH;
else if ((mod51 == 4) || (mod51 == 5))
return RACH;
else if ((mod51 == 45) || (mod51 == 46))
return RACH;
else
return TSC;
break;
}
case ChannelCombination::VII:
if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
return IDLE;
else
return TSC;
break;
case ChannelCombination::XIII: {
int mod52 = burstFN % 52;
if ((mod52 == 12) || (mod52 == 38))
return RACH;
else if ((mod52 == 25) || (mod52 == 51))
return IDLE;
else
return TSC;
break;
}
case ChannelCombination::LOOPBACK:
if ((burstFN % 51 <= 50) && (burstFN % 51 >= 48))
return IDLE;
else
return TSC;
break;
default:
return OFF;
break;
}
}
/* Initialize a multiframe slot in the filler table */
void init(size_t slot, signalVector *burst, bool fill);
ChannelCombination chanType[8];
/* The filler table */
signalVector *fillerTable[102][8];
int fillerModulus[8];
/* Received noise energy levels */
avgVector mFreqOffsets;
/* Transceiver mode */
trx_mode mode;
};

View File

@ -602,32 +602,9 @@ rsp_error:
static int trx_data_rx_cb(struct osmo_fd *ofd, unsigned int what) static int trx_data_rx_cb(struct osmo_fd *ofd, unsigned int what)
{ {
struct trx_instance *trx = ofd->data; struct trx_instance *trx = ofd->data;
struct trx_meas_set meas;
uint8_t buf[TRXD_BUF_SIZE]; uint8_t buf[TRXD_BUF_SIZE];
sbit_t bits[148];
int8_t rssi, tn;
int16_t toa256;
uint32_t fn;
ssize_t read_len; ssize_t read_len;
#ifdef IPCIF
struct trxd_from_trx* rcvd = trxif_from_trx_d();
if (!rcvd) {
LOGP(DTRX, LOGL_ERROR, "read() failed with rc=%zd\n", rcvd);
return rcvd;
}
tn = rcvd->ts;
fn = rcvd->fn;
rssi = -(int8_t) rcvd->rssi;
toa256 = (int16_t) rcvd->toa;
/* Copy and convert bits {254..0} to sbits {-127..127} */
//osmo_ubit2sbit(bits, rcvd->symbols, 148);
memcpy(bits, rcvd->symbols, 148);
free(rcvd);
#else
read_len = read(ofd->fd, buf, sizeof(buf)); read_len = read(ofd->fd, buf, sizeof(buf));
if (read_len <= 0) { if (read_len <= 0) {
LOGP(DTRXD, LOGL_ERROR, "read() failed with rc=%zd\n", read_len); LOGP(DTRXD, LOGL_ERROR, "read() failed with rc=%zd\n", read_len);
@ -641,7 +618,18 @@ static int trx_data_rx_cb(struct osmo_fd *ofd, unsigned int what)
read_len); read_len);
return -EINVAL; return -EINVAL;
} }
#endif
return trx_data_rx_handler(trx, buf);
}
int trx_data_rx_handler(struct trx_instance *trx, uint8_t *buf)
{
struct trx_meas_set meas;
sbit_t bits[148];
int8_t rssi, tn;
int16_t toa256;
uint32_t fn;
tn = buf[0]; tn = buf[0];
fn = osmo_load32be(buf + 1); fn = osmo_load32be(buf + 1);
rssi = -(int8_t)buf[5]; rssi = -(int8_t)buf[5];
@ -681,6 +669,8 @@ static int trx_data_rx_cb(struct osmo_fd *ofd, unsigned int what)
return 0; return 0;
} }
extern void tx_external_transceiver(uint8_t *burst) __attribute__((weak));
int trx_if_tx_burst(struct trx_instance *trx, uint8_t tn, uint32_t fn, int trx_if_tx_burst(struct trx_instance *trx, uint8_t tn, uint32_t fn,
uint8_t pwr, const ubit_t *bits) uint8_t pwr, const ubit_t *bits)
{ {
@ -719,7 +709,10 @@ int trx_if_tx_burst(struct trx_instance *trx, uint8_t tn, uint32_t fn,
memcpy(buf + 6, bits, 148); memcpy(buf + 6, bits, 148);
/* Send data to transceiver */ /* Send data to transceiver */
send(trx->trx_ofd_data.fd, buf, 154, 0); if (tx_external_transceiver)
tx_external_transceiver(buf);
else
send(trx->trx_ofd_data.fd, buf, 154, 0);
#endif #endif
return 0; return 0;

View File

@ -84,3 +84,4 @@ int trx_if_cmd_measure(struct trx_instance *trx,
int trx_if_tx_burst(struct trx_instance *trx, uint8_t tn, uint32_t fn, int trx_if_tx_burst(struct trx_instance *trx, uint8_t tn, uint32_t fn,
uint8_t pwr, const ubit_t *bits); uint8_t pwr, const ubit_t *bits);
int trx_data_rx_handler(struct trx_instance *trx, uint8_t *buf);

View File

@ -271,9 +271,8 @@ static void signal_handler(int signum)
} }
} }
extern void init_external_transceiver(int argc, char **argv); extern void init_external_transceiver(struct trx_instance *trx, int argc, char **argv) __attribute__((weak));
extern void stop_trx(); extern void close_external_transceiver(int argc, char **argv) __attribute__((weak));
extern volatile bool gshutdown;
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
@ -372,14 +371,14 @@ int main(int argc, char **argv)
/* Initialize pseudo-random generator */ /* Initialize pseudo-random generator */
srand(time(NULL)); srand(time(NULL));
init_external_transceiver(argc, argv); if (init_external_transceiver)
init_external_transceiver(app_data.trx, argc, argv);
// while (!app_data.quit) else
// osmo_select_main(0); while (!app_data.quit)
osmo_select_main(0);
gshutdown = true;
stop_trx();
if (close_external_transceiver)
close_external_transceiver(argc, argv);
exit: exit:
/* Close active connections */ /* Close active connections */