/*
* Copyright 2008 Free Software Foundation, Inc.
*
* SPDX-License-Identifier: GPL-3.0+
*
* This software is distributed under the terms of the GNU Public License.
* See the COPYING file in the main directory for details.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU 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 General Public License for more details.
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see .
*/
#include "radioInterface.h"
#include "Interthread.h"
#include "GSMCommon.h"
#include 
#include 
extern "C" {
#include 
#include 
#include "config_defs.h"
}
class Transceiver;
extern Transceiver *transceiver;
/** Channel descriptor for transceiver object and channel number pair */
struct TrxChanThParams {
	Transceiver *trx;
	size_t num;
};
/** Internal transceiver state variables */
struct TransceiverState {
  TransceiverState();
  ~TransceiverState();
  /* Initialize a multiframe slot in the filler table */
  bool init(FillerType filler, size_t sps, float scale, size_t rtsc, unsigned rach_delay);
  int chanType[8];
  /* Last timestamp of each timeslot's channel estimate */
  GSM::Time chanEstimateTime[8];
  /* The filler table */
  signalVector *fillerTable[102][8];
  int fillerModulus[8];
  FillerType mFiller;
  bool mRetrans;
  /* Most recent channel estimate of all timeslots */
  signalVector *chanResponse[8];
  /* Most recent DFE feedback filter of all timeslots */
  signalVector *DFEForward[8];
  signalVector *DFEFeedback[8];
  /* Most recent SNR, timing, and channel amplitude estimates */
  float SNRestimate[8];
  float chanRespOffset[8];
  complex chanRespAmplitude[8];
  /* Received noise energy levels */
  float mNoiseLev;
  avgVector mNoises;
  /* Shadowed downlink attenuation */
  int mPower;
  /* RF emission and reception disabled, as per NM Administrative State Locked */
  bool mMuted;
  /* counters */
  struct trx_counters ctrs;
  /* Used to keep track of lost and out of order frames */
  bool first_dl_fn_rcv[8];
  GSM::Time last_dl_time_rcv[8];
};
/** The Transceiver class, responsible for physical layer of basestation */
class Transceiver {
public:
  /** Transceiver constructor
      @param cfg VTY populated config
      @param wTransmitLatency initial setting of transmit latency
      @param radioInterface associated radioInterface object
  */
  Transceiver(const struct trx_cfg *cfg,
              GSM::Time wTransmitLatency,
              RadioInterface *wRadioInterface);
  /** Destructor */
  ~Transceiver();
  /** Start the control loop */
  bool init(void);
  /** attach the radioInterface receive FIFO */
  bool receiveFIFO(VectorFIFO *wFIFO, size_t chan)
  {
    if (chan >= mReceiveFIFO.size())
      return false;
    mReceiveFIFO[chan] = wFIFO;
    return true;
  }
  /** accessor for number of channels */
  size_t numChans() const { return cfg->num_chans; };
  /** Codes for channel combinations */
  typedef enum {
    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,               ///< Channel is inactive, default
    LOOPBACK            ///< similar go VII, used in loopback testing
  } ChannelCombination;
private:
  size_t mChans;
struct ctrl_msg {
  char data[101];
  ctrl_msg() {};
};
struct ctrl_sock_state {
  osmo_fd conn_bfd;
  std::deque txmsgqueue;
  ctrl_sock_state() {
      conn_bfd.fd =  -1;
  }
  ~ctrl_sock_state() {
      if(conn_bfd.fd >= 0) {
          osmo_fd_unregister(&conn_bfd);
          close(conn_bfd.fd);
          conn_bfd.fd = -1;
      }
  }
};
  const struct trx_cfg *cfg;	///< VTY populated config
  std::vector mDataSockets;  ///< socket for writing to/reading from GSM core
  std::vector mCtrlSockets;  ///< socket for writing/reading control commands from GSM core
  int mClockSocket;               ///< socket for writing clock updates to GSM core
  std::vector mTxPriorityQueues;   ///< priority queue of transmit bursts received from GSM core
  std::vector  mReceiveFIFO;      ///< radioInterface FIFO of receive bursts
  std::vector mRxServiceLoopThreads;  ///< thread to pull bursts into receive FIFO
  Thread *mRxLowerLoopThread;                   ///< thread to pull bursts into receive FIFO
  Thread *mTxLowerLoopThread;                   ///< thread to push bursts into transmit FIFO
  std::vector mTxPriorityQueueServiceLoopThreads; ///< thread to process transmit bursts from GSM core
  GSM::Time mTransmitLatency;             ///< latency between basestation clock and transmit deadline clock
  GSM::Time mLatencyUpdateTime;           ///< last time latency was updated
  GSM::Time mTransmitDeadlineClock;       ///< deadline for pushing bursts into transmit FIFO
  GSM::Time mLastClockUpdateTime;         ///< last time clock update was sent up to core
  RadioInterface *mRadioInterface;	  ///< associated radioInterface object
  double txFullScale;                     ///< full scale input to radio
  double rxFullScale;                     ///< full scale output to radio
  /** modulate and add a burst to the transmit queue */
  void addRadioVector(size_t chan, BitVector &bits,
                      int RSSI, GSM::Time &wTime);
  /** Update filler table */
  void updateFillerTable(size_t chan, radioVector *burst);
  /** Push modulated burst into transmit FIFO corresponding to a particular timestamp */
  void pushRadioVector(GSM::Time &nowTime);
  /** Pull and demodulate a burst from the receive FIFO */
  int pullRadioVector(size_t chan, struct trx_ul_burst_ind *ind);
  /** Set modulus for specific timeslot */
  void setModulus(size_t timeslot, size_t chan);
  /** return the expected burst type for the specified timestamp */
  CorrType expectedCorrType(GSM::Time currTime, size_t chan);
  /** send messages over the clock socket */
  bool writeClockInterface(void);
  static int ctrl_sock_cb(struct osmo_fd *bfd, unsigned int flags);
  int ctrl_sock_write(int chan);
  void ctrl_sock_send(ctrl_msg& m, int chan);
  /** drive handling of control messages from GSM core */
  int ctrl_sock_handle_rx(int chan);
  bool mOn;	                           ///< flag to indicate that transceiver is powered on
  bool mForceClockInterface;           ///< flag to indicate whether IND CLOCK shall be sent unconditionally after transceiver is started
  bool mHandover[8][8];                ///< expect handover to the timeslot/subslot
  double mTxFreq;                      ///< the transmit frequency
  double mRxFreq;                      ///< the receive frequency
  unsigned mTSC;                       ///< the midamble sequence code
  unsigned mMaxExpectedDelayAB;        ///< maximum expected time-of-arrival offset in GSM symbols for Access Bursts (RACH)
  unsigned mMaxExpectedDelayNB;        ///< maximum expected time-of-arrival offset in GSM symbols for Normal Bursts
  unsigned mWriteBurstToDiskMask;      ///< debug: bitmask to indicate which timeslots to dump to disk
  std::vector mVersionTRXD;  ///< Format version to use for TRXD protocol communication, per channel
  std::vector mStates;
  /** Start and stop I/O threads through the control socket API */
  bool start();
  void stop();
  /** Protect destructor accessible stop call */
  Mutex mLock;
protected:
  /** drive lower receive I/O and burst generation */
  bool driveReceiveRadio();
  /** drive demodulation of GSM bursts */
  bool driveReceiveFIFO(size_t chan);
  /** drive transmission of GSM bursts */
  void driveTxFIFO();
  /**
    drive modulation and sorting of GSM bursts from GSM core
    @return true if a burst was transferred successfully
  */
  bool driveTxPriorityQueue(size_t chan);
  friend void *RxUpperLoopAdapter(TrxChanThParams *params);
  friend void *TxUpperLoopAdapter(TrxChanThParams *params);
  friend void *RxLowerLoopAdapter(Transceiver *transceiver);
  friend void *TxLowerLoopAdapter(Transceiver *transceiver);
  double rssiOffset(size_t chan);
  void reset();
  void logRxBurst(size_t chan, const struct trx_ul_burst_ind *bi);
};
void *RxUpperLoopAdapter(TrxChanThParams *params);
/** Main drive threads */
void *RxLowerLoopAdapter(Transceiver *transceiver);
void *TxLowerLoopAdapter(Transceiver *transceiver);
/** transmit queueing thread loop */
void *TxUpperLoopAdapter(TrxChanThParams *params);