diff options
Diffstat (limited to 'src/host/trxcon/include')
17 files changed, 1136 insertions, 0 deletions
diff --git a/src/host/trxcon/include/Makefile.am b/src/host/trxcon/include/Makefile.am new file mode 100644 index 00000000..9d963a02 --- /dev/null +++ b/src/host/trxcon/include/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = \ + osmocom \ + $(NULL) diff --git a/src/host/trxcon/include/osmocom/Makefile.am b/src/host/trxcon/include/osmocom/Makefile.am new file mode 100644 index 00000000..83c6385c --- /dev/null +++ b/src/host/trxcon/include/osmocom/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = \ + bb \ + $(NULL) diff --git a/src/host/trxcon/include/osmocom/bb/Makefile.am b/src/host/trxcon/include/osmocom/bb/Makefile.am new file mode 100644 index 00000000..4a575ffb --- /dev/null +++ b/src/host/trxcon/include/osmocom/bb/Makefile.am @@ -0,0 +1,9 @@ +SUBDIRS = \ + l1sched \ + trxcon \ + $(NULL) + +noinst_HEADERS = \ + l1ctl_proto.h \ + l1gprs.h \ + $(NULL) diff --git a/src/host/trxcon/include/osmocom/bb/l1ctl_proto.h b/src/host/trxcon/include/osmocom/bb/l1ctl_proto.h new file mode 120000 index 00000000..ee19b80e --- /dev/null +++ b/src/host/trxcon/include/osmocom/bb/l1ctl_proto.h @@ -0,0 +1 @@ +../../../../../../include/l1ctl_proto.h
\ No newline at end of file diff --git a/src/host/trxcon/include/osmocom/bb/l1gprs.h b/src/host/trxcon/include/osmocom/bb/l1gprs.h new file mode 120000 index 00000000..3bf85176 --- /dev/null +++ b/src/host/trxcon/include/osmocom/bb/l1gprs.h @@ -0,0 +1 @@ +../../../../../../include/l1gprs.h
\ No newline at end of file diff --git a/src/host/trxcon/include/osmocom/bb/l1sched/Makefile.am b/src/host/trxcon/include/osmocom/bb/l1sched/Makefile.am new file mode 100644 index 00000000..39c32ba0 --- /dev/null +++ b/src/host/trxcon/include/osmocom/bb/l1sched/Makefile.am @@ -0,0 +1,5 @@ +noinst_HEADERS = \ + l1sched.h \ + logging.h \ + prim.h \ + $(NULL) diff --git a/src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h b/src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h new file mode 100644 index 00000000..6c5a31e8 --- /dev/null +++ b/src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h @@ -0,0 +1,417 @@ +#pragma once + +#include <time.h> +#include <stdint.h> +#include <stdbool.h> + +#include <arpa/inet.h> + +#include <osmocom/core/bits.h> +#include <osmocom/core/utils.h> +#include <osmocom/gsm/protocol/gsm_04_08.h> +#include <osmocom/gsm/gsm_utils.h> +#include <osmocom/gsm/gsm0502.h> +#include <osmocom/core/linuxlist.h> +#include <osmocom/core/timer.h> + +#include <osmocom/bb/l1sched/prim.h> + +#define GPRS_L2_MAX_LEN 54 +#define EDGE_L2_MAX_LEN 155 + +#define L1SCHED_CH_LID_DEDIC 0x00 +#define L1SCHED_CH_LID_SACCH 0x40 + +/* Osmocom-specific extension for PTCCH (see 3GPP TS 45.002, section 3.3.4.2). + * Shall be used to distinguish PTCCH and PDTCH channels on a PDCH time-slot. */ +#define L1SCHED_CH_LID_PTCCH 0x80 + +/* Is a channel related to PDCH (GPRS) */ +#define L1SCHED_CH_FLAG_PDCH (1 << 0) +/* Should a channel be activated automatically */ +#define L1SCHED_CH_FLAG_AUTO (1 << 1) + +#define MAX_A5_KEY_LEN (128 / 8) +#define TRX_TS_COUNT 8 + +struct l1sched_lchan_state; +struct l1sched_meas_set; +struct l1sched_state; +struct l1sched_ts; + +enum l1sched_burst_type { + L1SCHED_BURST_GMSK, + L1SCHED_BURST_8PSK, +}; + +/** + * These types define the different channels on a multiframe. + * Each channel has queues and can be activated individually. + */ +enum l1sched_lchan_type { + L1SCHED_IDLE = 0, + L1SCHED_FCCH, + L1SCHED_SCH, + L1SCHED_BCCH, + L1SCHED_RACH, + L1SCHED_CCCH, + L1SCHED_TCHF, + L1SCHED_TCHH_0, + L1SCHED_TCHH_1, + L1SCHED_SDCCH4_0, + L1SCHED_SDCCH4_1, + L1SCHED_SDCCH4_2, + L1SCHED_SDCCH4_3, + L1SCHED_SDCCH8_0, + L1SCHED_SDCCH8_1, + L1SCHED_SDCCH8_2, + L1SCHED_SDCCH8_3, + L1SCHED_SDCCH8_4, + L1SCHED_SDCCH8_5, + L1SCHED_SDCCH8_6, + L1SCHED_SDCCH8_7, + L1SCHED_SACCHTF, + L1SCHED_SACCHTH_0, + L1SCHED_SACCHTH_1, + L1SCHED_SACCH4_0, + L1SCHED_SACCH4_1, + L1SCHED_SACCH4_2, + L1SCHED_SACCH4_3, + L1SCHED_SACCH8_0, + L1SCHED_SACCH8_1, + L1SCHED_SACCH8_2, + L1SCHED_SACCH8_3, + L1SCHED_SACCH8_4, + L1SCHED_SACCH8_5, + L1SCHED_SACCH8_6, + L1SCHED_SACCH8_7, + L1SCHED_PDTCH, + L1SCHED_PTCCH, + L1SCHED_SDCCH4_CBCH, + L1SCHED_SDCCH8_CBCH, + _L1SCHED_CHAN_MAX +}; + +/* Represents a burst to be transmitted */ +struct l1sched_burst_req { + uint32_t fn; + uint8_t tn; + uint8_t pwr; + + /* Internally used by the scheduler */ + uint8_t bid; + + ubit_t burst[GSM_NBITS_NB_8PSK_BURST]; + size_t burst_len; +}; + +/* Represents a received burst */ +struct l1sched_burst_ind { + uint32_t fn; + uint8_t tn; + + /*! ToA256 (Timing of Arrival, 1/256 of a symbol) */ + int16_t toa256; + /*! RSSI (Received Signal Strength Indication) */ + int8_t rssi; + + /* Internally used by the scheduler */ + uint8_t bid; + + sbit_t burst[GSM_NBITS_NB_8PSK_BURST]; + size_t burst_len; +}; + +/* Probed lchan is active */ +#define L1SCHED_PROBE_F_ACTIVE (1 << 0) + +/* RTR (Ready-to-Receive) probe */ +struct l1sched_probe { + uint32_t flags; /* see L1SCHED_PROBE_F_* above */ + uint32_t fn; + uint8_t tn; +}; + +typedef int l1sched_lchan_rx_func(struct l1sched_lchan_state *lchan, + const struct l1sched_burst_ind *bi); + +typedef int l1sched_lchan_tx_func(struct l1sched_lchan_state *lchan, + struct l1sched_burst_req *br); + +struct l1sched_lchan_desc { + /*! Human-readable name */ + const char *name; + /*! Human-readable description */ + const char *desc; + + /*! Channel Number (like in RSL) */ + uint8_t chan_nr; + /*! Link ID (like in RSL) */ + uint8_t link_id; + + /*! How much memory do we need to store bursts */ + size_t burst_buf_size; + /*! Channel specific flags */ + uint8_t flags; + + /*! Function to call when burst received from PHY */ + l1sched_lchan_rx_func *rx_fn; + /*! Function to call when data received from L2 */ + l1sched_lchan_tx_func *tx_fn; +}; + +struct l1sched_tdma_frame { + /*! Downlink channel (slot) type */ + enum l1sched_lchan_type dl_chan; + /*! Downlink block ID */ + uint8_t dl_bid; + /*! Uplink channel (slot) type */ + enum l1sched_lchan_type ul_chan; + /*! Uplink block ID */ + uint8_t ul_bid; +}; + +struct l1sched_tdma_multiframe { + /*! Channel combination */ + enum gsm_phys_chan_config chan_config; + /*! Human-readable name */ + const char *name; + /*! Repeats how many frames */ + uint8_t period; + /*! Applies to which timeslots */ + uint8_t slotmask; + /*! Contains which lchans */ + uint64_t lchan_mask; + /*! Pointer to scheduling structure */ + const struct l1sched_tdma_frame *frames; +}; + +struct l1sched_meas_set { + /*! TDMA frame number of the first burst this set belongs to */ + uint32_t fn; + /*! ToA256 (Timing of Arrival, 1/256 of a symbol) */ + int16_t toa256; + /*! RSSI (Received Signal Strength Indication) */ + int8_t rssi; +}; + +/* Simple ring buffer (up to 24 unique measurements) */ +struct l1sched_lchan_meas_hist { + struct l1sched_meas_set buf[24]; + struct l1sched_meas_set *head; +}; + +/* States each channel on a multiframe */ +struct l1sched_lchan_state { + /*! Channel type */ + enum l1sched_lchan_type type; + /*! Channel status */ + uint8_t active; + /*! Link to a list of channels */ + struct llist_head list; + + /*! Burst type: GMSK or 8PSK */ + enum l1sched_burst_type burst_type; + /*! Mask of received bursts */ + uint32_t rx_burst_mask; + /*! Mask of transmitted bursts */ + uint32_t tx_burst_mask; + /*! Burst buffer for RX */ + sbit_t *rx_bursts; + /*! Burst buffer for TX */ + ubit_t *tx_bursts; + + /*! Queue of Tx primitives */ + struct llist_head tx_prims; + /*! Tx primitive being sent */ + struct msgb *prim; + + /*! Mode for TCH channels (see GSM48_CMODE_*) */ + uint8_t tch_mode; + /*! Training Sequence Code */ + uint8_t tsc; + + /*! FACCH/H on downlink */ + bool dl_ongoing_facch; + /*! pending FACCH/H blocks on Uplink */ + uint8_t ul_facch_blocks; + + /*! Downlink measurements history */ + struct l1sched_lchan_meas_hist meas_hist; + /*! AVG measurements of the last received block */ + struct l1sched_meas_set meas_avg; + + /*! TDMA loss detection state */ + struct { + /*! Last processed TDMA frame number */ + uint32_t last_proc; + /*! Number of processed TDMA frames */ + unsigned long num_proc; + /*! Number of lost TDMA frames */ + unsigned long num_lost; + } tdma; + + /*! SACCH state */ + struct { + /*! Cached measurement report (last received) */ + uint8_t mr_cache[GSM_MACBLOCK_LEN]; + /*! Cache usage counter */ + uint8_t mr_cache_usage; + /*! Was a MR transmitted last time? */ + bool mr_tx_last; + } sacch; + + /* AMR specific */ + struct { + /*! 4 possible codecs for AMR */ + uint8_t codec[4]; + /*! Number of possible codecs */ + uint8_t codecs; + /*! Current uplink FT index */ + uint8_t ul_ft; + /*! Current downlink FT index */ + uint8_t dl_ft; + /*! Current uplink CMR index */ + uint8_t ul_cmr; + /*! Current downlink CMR index */ + uint8_t dl_cmr; + /*! If AMR loop is enabled */ + uint8_t amr_loop; + /*! Number of bit error rates */ + uint8_t ber_num; + /*! Sum of bit error rates */ + float ber_sum; + /* last received dtx frame type */ + uint8_t last_dtx; + } amr; + + /*! A5/X encryption state */ + struct { + uint8_t key[MAX_A5_KEY_LEN]; + uint8_t key_len; + uint8_t algo; + } a5; + + /* TS that this lchan belongs to */ + struct l1sched_ts *ts; +}; + +struct l1sched_ts { + /*! Timeslot index within a frame (0..7) */ + uint8_t index; + + /*! Pointer to multiframe layout */ + const struct l1sched_tdma_multiframe *mf_layout; + /*! Channel states for logical channels */ + struct llist_head lchans; + /*! Backpointer to the scheduler */ + struct l1sched_state *sched; +}; + +/*! Scheduler configuration */ +struct l1sched_cfg { + /*! Logging context (used as prefix for messages) */ + const char *log_prefix; +}; + +/*! One scheduler instance */ +struct l1sched_state { + /*! List of timeslots maintained by this scheduler */ + struct l1sched_ts *ts[TRX_TS_COUNT]; + /*! SACCH cache (common for all lchans) */ + uint8_t sacch_cache[GSM_MACBLOCK_LEN]; + /*! BSIC value learned from SCH bursts */ + uint8_t bsic; + /*! Logging context (used as prefix for messages) */ + const char *log_prefix; + /*! Some private data */ + void *priv; +}; + +extern const struct l1sched_lchan_desc l1sched_lchan_desc[_L1SCHED_CHAN_MAX]; +const struct l1sched_tdma_multiframe * +l1sched_mframe_layout(enum gsm_phys_chan_config config, uint8_t tn); + +/* Scheduler management functions */ +struct l1sched_state *l1sched_alloc(void *ctx, const struct l1sched_cfg *cfg, void *priv); +void l1sched_reset(struct l1sched_state *sched, bool reset_clock); +void l1sched_free(struct l1sched_state *sched); + +/* Timeslot management functions */ +struct l1sched_ts *l1sched_add_ts(struct l1sched_state *sched, int tn); +void l1sched_del_ts(struct l1sched_state *sched, int tn); +int l1sched_reset_ts(struct l1sched_state *sched, int tn); +int l1sched_configure_ts(struct l1sched_state *sched, int tn, + enum gsm_phys_chan_config config); +int l1sched_start_ciphering(struct l1sched_ts *ts, uint8_t algo, + const uint8_t *key, uint8_t key_len); + +/* Logical channel management functions */ +enum gsm_phys_chan_config l1sched_chan_nr2pchan_config(uint8_t chan_nr); + +void l1sched_deactivate_all_lchans(struct l1sched_ts *ts); +int l1sched_set_lchans(struct l1sched_ts *ts, uint8_t chan_nr, + int active, uint8_t tch_mode, uint8_t tsc); +int l1sched_lchan_set_amr_cfg(struct l1sched_lchan_state *lchan, + uint8_t codecs_bitmask, uint8_t start_codec); +int l1sched_activate_lchan(struct l1sched_ts *ts, enum l1sched_lchan_type chan); +int l1sched_deactivate_lchan(struct l1sched_ts *ts, enum l1sched_lchan_type chan); +struct l1sched_lchan_state *l1sched_find_lchan_by_type(struct l1sched_ts *ts, + enum l1sched_lchan_type type); +struct l1sched_lchan_state *l1sched_find_lchan_by_chan_nr(struct l1sched_state *sched, + uint8_t chan_nr, uint8_t link_id); + +#define L1SCHED_TCH_MODE_IS_SPEECH(mode) \ + (mode == GSM48_CMODE_SPEECH_V1 \ + || mode == GSM48_CMODE_SPEECH_EFR \ + || mode == GSM48_CMODE_SPEECH_AMR) + +#define L1SCHED_TCH_MODE_IS_DATA(mode) \ + (mode == GSM48_CMODE_DATA_14k5 \ + || mode == GSM48_CMODE_DATA_12k0 \ + || mode == GSM48_CMODE_DATA_6k0 \ + || mode == GSM48_CMODE_DATA_3k6) + +#define L1SCHED_CHAN_IS_TCH(chan) \ + (chan == L1SCHED_TCHF || chan == L1SCHED_TCHH_0 || chan == L1SCHED_TCHH_1) + +#define L1SCHED_CHAN_IS_SACCH(chan) \ + (l1sched_lchan_desc[chan].link_id & L1SCHED_CH_LID_SACCH) + +int l1sched_handle_rx_burst(struct l1sched_state *sched, + struct l1sched_burst_ind *bi); +int l1sched_handle_rx_probe(struct l1sched_state *sched, + struct l1sched_probe *probe); +int l1sched_handle_burst_req(struct l1sched_state *sched, + const struct l1sched_burst_req *br); + +/* Shared declarations for lchan handlers */ +extern const uint8_t l1sched_nb_training_bits[8][26]; + +const char *l1sched_burst_mask2str(const uint32_t *mask, int bits); + +/* Interleaved TCH/H block TDMA frame mapping */ +bool l1sched_tchh_block_map_fn(enum l1sched_lchan_type chan, + uint32_t fn, bool ul, bool facch, bool start); + +#define l1sched_tchh_traffic_start(chan, fn, ul) \ + l1sched_tchh_block_map_fn(chan, fn, ul, 0, 1) +#define l1sched_tchh_traffic_end(chan, fn, ul) \ + l1sched_tchh_block_map_fn(chan, fn, ul, 0, 0) + +#define l1sched_tchh_facch_start(chan, fn, ul) \ + l1sched_tchh_block_map_fn(chan, fn, ul, 1, 1) +#define l1sched_tchh_facch_end(chan, fn, ul) \ + l1sched_tchh_block_map_fn(chan, fn, ul, 1, 0) + +/* Measurement history */ +void l1sched_lchan_meas_push(struct l1sched_lchan_state *lchan, + const struct l1sched_burst_ind *bi); +void l1sched_lchan_meas_avg(struct l1sched_lchan_state *lchan, unsigned int n); + +/* Clock and Downlink scheduling trigger */ +int l1sched_clck_handle(struct l1sched_state *sched, uint32_t fn); +void l1sched_clck_reset(struct l1sched_state *sched); + +void l1sched_pull_burst(struct l1sched_state *sched, struct l1sched_burst_req *br); +void l1sched_pull_send_frame(struct l1sched_state *sched); diff --git a/src/host/trxcon/include/osmocom/bb/l1sched/logging.h b/src/host/trxcon/include/osmocom/bb/l1sched/logging.h new file mode 100644 index 00000000..21be9955 --- /dev/null +++ b/src/host/trxcon/include/osmocom/bb/l1sched/logging.h @@ -0,0 +1,37 @@ +#pragma once + +extern int l1sched_log_cat_common; +extern int l1sched_log_cat_data; + +void l1sched_logging_init(int log_cat_common, int log_cat_data); + +/* Messages using l1sched_state as the context */ +#define LOGP_SCHED_CAT(sched, cat, level, fmt, args...) \ + LOGP(l1sched_log_cat_##cat, level, "%s" fmt, \ + (sched)->log_prefix, ## args) + +/* Common messages using l1sched_state as the context */ +#define LOGP_SCHEDC(sched, level, fmt, args...) \ + LOGP_SCHED_CAT(sched, common, level, fmt, ## args) + +/* Data messages using l1sched_state as the context */ +#define LOGP_SCHEDD(sched, level, fmt, args...) \ + LOGP_SCHED_CAT(sched, data, level, fmt, ## args) + + +#define LOGP_LCHAN_NAME_FMT "TS%u-%s" +#define LOGP_LCHAN_NAME_ARGS(lchan) \ + (lchan)->ts->index, l1sched_lchan_desc[(lchan)->type].name + +/* Messages using l1sched_lchan_state as the context */ +#define LOGP_LCHAN_CAT(lchan, cat, level, fmt, args...) \ + LOGP_SCHED_CAT((lchan)->ts->sched, cat, level, LOGP_LCHAN_NAME_FMT " " fmt, \ + LOGP_LCHAN_NAME_ARGS(lchan), ## args) + +/* Common messages using l1sched_lchan_state as the context */ +#define LOGP_LCHANC(lchan, level, fmt, args...) \ + LOGP_LCHAN_CAT(lchan, common, level, fmt, ## args) + +/* Data messages using l1sched_lchan_state as the context */ +#define LOGP_LCHAND(lchan, level, fmt, args...) \ + LOGP_LCHAN_CAT(lchan, data, level, fmt, ## args) diff --git a/src/host/trxcon/include/osmocom/bb/l1sched/prim.h b/src/host/trxcon/include/osmocom/bb/l1sched/prim.h new file mode 100644 index 00000000..a9187c2a --- /dev/null +++ b/src/host/trxcon/include/osmocom/bb/l1sched/prim.h @@ -0,0 +1,132 @@ +#pragma once + +#include <stdint.h> +#include <stdbool.h> + +#include <osmocom/core/msgb.h> +#include <osmocom/core/prim.h> +#include <osmocom/core/utils.h> + +#define l1sched_prim_from_msgb(msg) \ + ((struct l1sched_prim *)(msg)->l1h) + +#define l1sched_prim_data_from_msgb(msg) \ + ((uint8_t *)msgb_l2(msg)) + +#define l1sched_prim_type_from_msgb(msg) \ + l1sched_prim_from_msgb(msg)->oph.primitive + +#define L1SCHED_PRIM_STR_FMT "%s.%s" +#define L1SCHED_PRIM_STR_ARGS(prim) \ + l1sched_prim_type_name((prim)->oph.primitive), \ + osmo_prim_operation_name((prim)->oph.operation) + +enum l1sched_prim_type { + L1SCHED_PRIM_T_DATA, /* Req | Ind | Cnf */ + L1SCHED_PRIM_T_RACH, /* Req | Cnf */ + L1SCHED_PRIM_T_SCH, /* Ind */ + L1SCHED_PRIM_T_PCHAN_COMB, /* Ind */ +}; + +extern const struct value_string l1sched_prim_type_names[]; +static inline const char *l1sched_prim_type_name(enum l1sched_prim_type val) +{ + return get_value_string(l1sched_prim_type_names, val); +} + +/*! Common header for L1SCHED_PRIM_T_{DATA,RACH} */ +struct l1sched_prim_chdr { + /*! TDMA Frame Number */ + uint32_t frame_nr; + /*! RSL Channel Number */ + uint8_t chan_nr; + /*! RSL Link Identifier */ + uint8_t link_id; + /*! Traffic or signalling */ + bool traffic; +}; + +/*! Payload of L1SCHED_PRIM_T_DATA | Ind */ +struct l1sched_prim_data_ind { + /*! Common sub-header */ + struct l1sched_prim_chdr chdr; + int16_t toa256; + int8_t rssi; + int n_errors; + int n_bits_total; +}; + +/*! Payload of L1SCHED_PRIM_T_RACH | {Req,Cnf} */ +struct l1sched_prim_rach { + /*! Common sub-header */ + struct l1sched_prim_chdr chdr; + /*! Training Sequence (only for 11-bit RA) */ + uint8_t synch_seq; + /*! Transmission offset (how many frames to skip) */ + uint8_t offset; + /*! RA value is 11 bit */ + bool is_11bit; + /*! RA value */ + uint16_t ra; +}; + +struct l1sched_prim { + /*! Primitive header */ + struct osmo_prim_hdr oph; + /*! Type specific header */ + union { + /*! L1SCHED_PRIM_T_DATA | Req */ + struct l1sched_prim_chdr data_req; + /*! L1SCHED_PRIM_T_DATA | Cnf */ + struct l1sched_prim_chdr data_cnf; + /*! L1SCHED_PRIM_T_DATA | Ind */ + struct l1sched_prim_data_ind data_ind; + + /*! L1SCHED_PRIM_T_RACH | Req */ + struct l1sched_prim_rach rach_req; + /*! L1SCHED_PRIM_T_RACH | Cnf */ + struct l1sched_prim_rach rach_cnf; + + /*! L1SCHED_PRIM_T_SCH | Ind */ + struct { + /*! TDMA frame number */ + uint32_t frame_nr; + /*! BSIC */ + uint8_t bsic; + } sch_ind; + + /*! L1SCHED_PRIM_T_PCHAN_COMB | Ind */ + struct { + /*! Timeslot number */ + uint8_t tn; + /*! Channel combination for a timeslot */ + enum gsm_phys_chan_config pchan; + } pchan_comb_ind; + }; +}; + + +struct l1sched_state; +struct l1sched_lchan_state; + +void l1sched_prim_init(struct msgb *msg, + enum l1sched_prim_type type, + enum osmo_prim_operation op); + +struct msgb *l1sched_prim_alloc(enum l1sched_prim_type type, + enum osmo_prim_operation op); + +bool l1sched_lchan_amr_prim_is_valid(struct l1sched_lchan_state *lchan, + struct msgb *msg, bool is_cmr); +struct msgb *l1sched_lchan_prim_dequeue_sacch(struct l1sched_lchan_state *lchan); +struct msgb *l1sched_lchan_prim_dequeue_tch(struct l1sched_lchan_state *lchan, bool facch); +struct msgb *l1sched_lchan_prim_dummy_lapdm(const struct l1sched_lchan_state *lchan); + +int l1sched_lchan_emit_data_ind(struct l1sched_lchan_state *lchan, + const uint8_t *data, size_t data_len, + int n_errors, int n_bits_total, bool traffic); +int l1sched_lchan_emit_data_cnf(struct l1sched_lchan_state *lchan, + struct msgb *msg, uint32_t fn); + +int l1sched_prim_from_user(struct l1sched_state *sched, struct msgb *msg); +int l1sched_prim_to_user(struct l1sched_state *sched, struct msgb *msg); diff --git a/src/host/trxcon/include/osmocom/bb/trxcon/Makefile.am b/src/host/trxcon/include/osmocom/bb/trxcon/Makefile.am new file mode 100644 index 00000000..ad1e89a0 --- /dev/null +++ b/src/host/trxcon/include/osmocom/bb/trxcon/Makefile.am @@ -0,0 +1,9 @@ +noinst_HEADERS = \ + l1ctl_server.h \ + l1ctl.h \ + phyif.h \ + trx_if.h \ + logging.h \ + trxcon.h \ + trxcon_fsm.h \ + $(NULL) diff --git a/src/host/trxcon/include/osmocom/bb/trxcon/l1ctl.h b/src/host/trxcon/include/osmocom/bb/trxcon/l1ctl.h new file mode 100644 index 00000000..7e2fa6a5 --- /dev/null +++ b/src/host/trxcon/include/osmocom/bb/trxcon/l1ctl.h @@ -0,0 +1,22 @@ +#pragma once + +#include <stdint.h> + +struct msgb; +struct trxcon_param_rx_data_ind; +struct trxcon_param_tx_data_cnf; +struct trxcon_param_tx_access_burst_cnf; + +int l1ctl_tx_fbsb_conf(struct trxcon_inst *trxcon, uint16_t band_arfcn, uint8_t bsic); +int l1ctl_tx_fbsb_fail(struct trxcon_inst *trxcon, uint16_t band_arfcn); +int l1ctl_tx_ccch_mode_conf(struct trxcon_inst *trxcon, uint8_t mode); +int l1ctl_tx_pm_conf(struct trxcon_inst *trxcon, uint16_t band_arfcn, int dbm, int last); +int l1ctl_tx_reset_conf(struct trxcon_inst *trxcon, uint8_t type); +int l1ctl_tx_reset_ind(struct trxcon_inst *trxcon, uint8_t type); + +int l1ctl_tx_dt_ind(struct trxcon_inst *trxcon, + const struct trxcon_param_rx_data_ind *ind); +int l1ctl_tx_dt_conf(struct trxcon_inst *trxcon, + const struct trxcon_param_tx_data_cnf *cnf); +int l1ctl_tx_rach_conf(struct trxcon_inst *trxcon, + const struct trxcon_param_tx_access_burst_cnf *cnf); diff --git a/src/host/trxcon/include/osmocom/bb/trxcon/l1ctl_server.h b/src/host/trxcon/include/osmocom/bb/trxcon/l1ctl_server.h new file mode 100644 index 00000000..83c61f02 --- /dev/null +++ b/src/host/trxcon/include/osmocom/bb/trxcon/l1ctl_server.h @@ -0,0 +1,67 @@ +#pragma once + +#include <stdint.h> + +#include <osmocom/core/write_queue.h> +#include <osmocom/core/select.h> +#include <osmocom/core/timer.h> +#include <osmocom/core/msgb.h> + +#define L1CTL_LENGTH 512 +#define L1CTL_HEADROOM 32 + +/** + * Each L1CTL message gets its own length pushed + * as two bytes in front before sending. + */ +#define L1CTL_MSG_LEN_FIELD 2 + +struct l1ctl_client; + +typedef int l1ctl_conn_data_func(struct l1ctl_client *, struct msgb *); +typedef void l1ctl_conn_state_func(struct l1ctl_client *); + +struct l1ctl_server_cfg { + /* UNIX socket path to listen on */ + const char *sock_path; + /* maximum number of connected clients */ + unsigned int num_clients_max; + /* functions to be called on various events */ + l1ctl_conn_data_func *conn_read_cb; /* mandatory */ + l1ctl_conn_state_func *conn_accept_cb; /* optional */ + l1ctl_conn_state_func *conn_close_cb; /* optional */ +}; + +struct l1ctl_server { + /* list of connected clients */ + struct llist_head clients; + /* number of connected clients */ + unsigned int num_clients; + /* used for client ID generation */ + unsigned int next_client_id; + /* socket on which we listen for connections */ + struct osmo_fd ofd; + /* server configuration */ + const struct l1ctl_server_cfg *cfg; +}; + +struct l1ctl_client { + /* list head in l1ctl_server.clients */ + struct llist_head list; + /* struct l1ctl_server we belong to */ + struct l1ctl_server *server; + /* client's write queue */ + struct osmo_wqueue wq; + /* logging context (used as prefix for messages) */ + const char *log_prefix; + /* unique client ID */ + unsigned int id; + /* some private data */ + void *priv; +}; + +struct l1ctl_server *l1ctl_server_alloc(void *ctx, const struct l1ctl_server_cfg *cfg); +void l1ctl_server_free(struct l1ctl_server *server); + +int l1ctl_client_send(struct l1ctl_client *client, struct msgb *msg); +void l1ctl_client_conn_close(struct l1ctl_client *client); diff --git a/src/host/trxcon/include/osmocom/bb/trxcon/logging.h b/src/host/trxcon/include/osmocom/bb/trxcon/logging.h new file mode 100644 index 00000000..ce149926 --- /dev/null +++ b/src/host/trxcon/include/osmocom/bb/trxcon/logging.h @@ -0,0 +1,16 @@ +#pragma once + +#include <osmocom/core/logging.h> + +enum { + DAPP, + DL1C, + DL1D, + DTRXC, + DTRXD, + DSCH, + DSCHD, + DGPRS, +}; + +int trxcon_logging_init(void *tall_ctx, const char *category_mask); diff --git a/src/host/trxcon/include/osmocom/bb/trxcon/phyif.h b/src/host/trxcon/include/osmocom/bb/trxcon/phyif.h new file mode 100644 index 00000000..2ad7a678 --- /dev/null +++ b/src/host/trxcon/include/osmocom/bb/trxcon/phyif.h @@ -0,0 +1,120 @@ +#pragma once + +#include <stdint.h> + +#include <osmocom/core/bits.h> + +/* PHYIF command type */ +enum trxcon_phyif_cmd_type { + TRXCON_PHYIF_CMDT_RESET, + TRXCON_PHYIF_CMDT_POWERON, + TRXCON_PHYIF_CMDT_POWEROFF, + TRXCON_PHYIF_CMDT_MEASURE, + TRXCON_PHYIF_CMDT_SETFREQ_H0, + TRXCON_PHYIF_CMDT_SETFREQ_H1, + TRXCON_PHYIF_CMDT_SETSLOT, + TRXCON_PHYIF_CMDT_SETTA, +}; + +/* param of TRXCON_PHYIF_CMDT_SETFREQ_H0 */ +struct trxcon_phyif_cmdp_setfreq_h0 { + uint16_t band_arfcn; +}; + +/* param of TRXCON_PHYIF_CMDT_SETFREQ_H1 */ +struct trxcon_phyif_cmdp_setfreq_h1 { + uint8_t hsn; + uint8_t maio; + const uint16_t *ma; + unsigned int ma_len; +}; + +/* param of TRXCON_PHYIF_CMDT_SETSLOT */ +struct trxcon_phyif_cmdp_setslot { + uint8_t tn; + uint8_t pchan; /* enum gsm_phys_chan_config */ +}; + +/* param of TRXCON_PHYIF_CMDT_SETTA */ +struct trxcon_phyif_cmdp_setta { + int8_t ta; /* intentionally signed */ +}; + +/* param of TRXCON_PHYIF_CMDT_MEASURE (command) */ +struct trxcon_phyif_cmdp_measure { + uint16_t band_arfcn; +}; + +/* param of TRXCON_PHYIF_CMDT_MEASURE (response) */ +struct trxcon_phyif_rspp_measure { + uint16_t band_arfcn; + int dbm; +}; + +struct trxcon_phyif_cmd { + enum trxcon_phyif_cmd_type type; + union { + struct trxcon_phyif_cmdp_setfreq_h0 setfreq_h0; + struct trxcon_phyif_cmdp_setfreq_h1 setfreq_h1; + struct trxcon_phyif_cmdp_setslot setslot; + struct trxcon_phyif_cmdp_setta setta; + struct trxcon_phyif_cmdp_measure measure; + } param; +}; + +struct trxcon_phyif_rsp { + enum trxcon_phyif_cmd_type type; + union { + struct trxcon_phyif_rspp_measure measure; + } param; +}; + +/* RTS.ind - Ready-to-Send indication */ +struct trxcon_phyif_rts_ind { + uint32_t fn; + uint8_t tn; +}; + +/* RTR.ind - Ready-to-Receive indicaton */ +struct trxcon_phyif_rtr_ind { + uint32_t fn; + uint8_t tn; +}; + +/* The probed lchan is active */ +#define TRXCON_PHYIF_RTR_F_ACTIVE (1 << 0) + +/* RTR.rsp - Ready-to-Receive response */ +struct trxcon_phyif_rtr_rsp { + uint32_t flags; /* see TRXCON_PHYIF_RTR_F_* above */ +}; + +/* BURST.req - a burst to be transmitted */ +struct trxcon_phyif_burst_req { + uint32_t fn; + uint8_t tn; + uint8_t pwr; + const ubit_t *burst; + unsigned int burst_len; +}; + +/* BURST.ind - a received burst */ +struct trxcon_phyif_burst_ind { + uint32_t fn; + uint8_t tn; + int16_t toa256; + int8_t rssi; + const sbit_t *burst; + unsigned int burst_len; +}; + +int trxcon_phyif_handle_burst_req(void *phyif, const struct trxcon_phyif_burst_req *br); +int trxcon_phyif_handle_burst_ind(void *priv, const struct trxcon_phyif_burst_ind *bi); + +int trxcon_phyif_handle_rts_ind(void *priv, const struct trxcon_phyif_rts_ind *rts); +int trxcon_phyif_handle_rtr_ind(void *priv, const struct trxcon_phyif_rtr_ind *ind, + struct trxcon_phyif_rtr_rsp *rsp); + +int trxcon_phyif_handle_cmd(void *phyif, const struct trxcon_phyif_cmd *cmd); +int trxcon_phyif_handle_rsp(void *priv, const struct trxcon_phyif_rsp *rsp); +void trxcon_phyif_close(void *phyif); diff --git a/src/host/trxcon/include/osmocom/bb/trxcon/trx_if.h b/src/host/trxcon/include/osmocom/bb/trxcon/trx_if.h new file mode 100644 index 00000000..e564fd8e --- /dev/null +++ b/src/host/trxcon/include/osmocom/bb/trxcon/trx_if.h @@ -0,0 +1,61 @@ +#pragma once + +#include <osmocom/core/linuxlist.h> +#include <osmocom/core/select.h> +#include <osmocom/core/timer.h> +#include <osmocom/core/fsm.h> + +#include <osmocom/bb/trxcon/phyif.h> + +#define TRXC_BUF_SIZE 1024 +#define TRXD_BUF_SIZE 512 + +enum trx_fsm_states { + TRX_STATE_OFFLINE = 0, + TRX_STATE_IDLE, + TRX_STATE_ACTIVE, + TRX_STATE_RSP_WAIT, +}; + +struct trx_instance { + struct osmo_fd trx_ofd_ctrl; + struct osmo_fd trx_ofd_data; + + struct osmo_timer_list trx_ctrl_timer; + struct llist_head trx_ctrl_list; + struct osmo_fsm_inst *fi; + uint32_t fn_advance; + + /* HACK: we need proper state machines */ + uint32_t prev_state; + bool powered_up; + + /* Some private data */ + void *priv; +}; + +struct trx_ctrl_msg { + struct llist_head list; + char cmd[TRXC_BUF_SIZE]; + int retry_cnt; + int critical; + int cmd_len; +}; + +struct trx_if_params { + const char *local_host; + const char *remote_host; + uint16_t base_port; + uint32_t fn_advance; + uint8_t instance; + + struct osmo_fsm_inst *parent_fi; + uint32_t parent_term_event; + void *priv; +}; + +struct trx_instance *trx_if_open(const struct trx_if_params *params); +void trx_if_close(struct trx_instance *trx); + +int trx_if_handle_phyif_burst_req(struct trx_instance *trx, const struct trxcon_phyif_burst_req *br); +int trx_if_handle_phyif_cmd(struct trx_instance *trx, const struct trxcon_phyif_cmd *cmd); diff --git a/src/host/trxcon/include/osmocom/bb/trxcon/trxcon.h b/src/host/trxcon/include/osmocom/bb/trxcon/trxcon.h new file mode 100644 index 00000000..ff54e785 --- /dev/null +++ b/src/host/trxcon/include/osmocom/bb/trxcon/trxcon.h @@ -0,0 +1,64 @@ +#pragma once + +#include <stdint.h> + +struct osmo_fsm_inst; +struct l1sched_state; +struct l1gprs_state; +struct msgb; + +struct trxcon_inst { + struct osmo_fsm_inst *fi; + unsigned int id; + + /* Logging context for sched and l1c */ + const char *log_prefix; + + /* GSMTAP instance (optional) */ + struct gsmtap_inst *gsmtap; + + /* The L1 scheduler */ + struct l1sched_state *sched; + /* GPRS state (MAC layer) */ + struct l1gprs_state *gprs; + + /* PHY interface (e.g. TRXC/TRXD) */ + void *phyif; + /* L2 interface (e.g. L1CTL) */ + void *l2if; + + /* State specific data of trxcon_fsm */ + void *fi_data; + + /* L1 parameters */ + struct { + uint16_t band_arfcn; + uint8_t tx_power; + uint8_t tsc; /* only valid for DCCH/PDCH */ + int8_t ta; + } l1p; + + /* PHY specific quirks */ + struct { + /* FBSB timeout extension (in TDMA FNs) */ + unsigned int fbsb_extend_fns; + } phy_quirks; +}; + +enum trxcon_log_cat { + TRXCON_LOGC_FSM, /* trxcon_fsm */ + TRXCON_LOGC_L1C, /* L1CTL control */ + TRXCON_LOGC_L1D, /* L1CTL data */ + TRXCON_LOGC_SCHC, /* l1sched control */ + TRXCON_LOGC_SCHD, /* l1sched data */ + TRXCON_LOGC_GPRS, /* l1gprs logging */ +}; + +void trxcon_set_log_cfg(const int *logc, unsigned int logc_num); + +struct trxcon_inst *trxcon_inst_alloc(void *ctx, unsigned int id); +void trxcon_inst_free(struct trxcon_inst *trxcon); + +int trxcon_l1ctl_receive(struct trxcon_inst *trxcon, struct msgb *msg); +int trxcon_l1ctl_send(struct trxcon_inst *trxcon, struct msgb *msg); +void trxcon_l1ctl_close(struct trxcon_inst *trxcon); diff --git a/src/host/trxcon/include/osmocom/bb/trxcon/trxcon_fsm.h b/src/host/trxcon/include/osmocom/bb/trxcon/trxcon_fsm.h new file mode 100644 index 00000000..9eba4fde --- /dev/null +++ b/src/host/trxcon/include/osmocom/bb/trxcon/trxcon_fsm.h @@ -0,0 +1,169 @@ +#pragma once + +#include <stdint.h> +#include <stdbool.h> + +#include <osmocom/core/fsm.h> + +extern struct osmo_fsm trxcon_fsm_def; + +enum trxcon_fsm_states { + TRXCON_ST_RESET, + TRXCON_ST_FULL_POWER_SCAN, + TRXCON_ST_FBSB_SEARCH, + TRXCON_ST_BCCH_CCCH, + TRXCON_ST_DEDICATED, + TRXCON_ST_PACKET_DATA, +}; + +enum trxcon_fsm_events { + TRXCON_EV_PHYIF_FAILURE, + TRXCON_EV_L2IF_FAILURE, + TRXCON_EV_RESET_FULL_REQ, + TRXCON_EV_RESET_SCHED_REQ, + TRXCON_EV_FULL_POWER_SCAN_REQ, + TRXCON_EV_FULL_POWER_SCAN_RES, + TRXCON_EV_FBSB_SEARCH_REQ, + TRXCON_EV_FBSB_SEARCH_RES, + TRXCON_EV_SET_CCCH_MODE_REQ, + TRXCON_EV_SET_TCH_MODE_REQ, + TRXCON_EV_SET_PHY_CONFIG_REQ, + TRXCON_EV_TX_ACCESS_BURST_REQ, + TRXCON_EV_TX_ACCESS_BURST_CNF, + TRXCON_EV_UPDATE_SACCH_CACHE_REQ, + TRXCON_EV_DCH_EST_REQ, + TRXCON_EV_DCH_REL_REQ, + TRXCON_EV_TX_DATA_REQ, + TRXCON_EV_TX_DATA_CNF, + TRXCON_EV_RX_DATA_IND, + TRXCON_EV_CRYPTO_REQ, + TRXCON_EV_GPRS_UL_TBF_CFG_REQ, /* param: L1CTL msgb */ + TRXCON_EV_GPRS_DL_TBF_CFG_REQ, /* param: L1CTL msgb */ + TRXCON_EV_GPRS_UL_BLOCK_REQ, /* param: L1CTL msgb */ +}; + +/* param of TRXCON_EV_FULL_POWER_SCAN_REQ */ +struct trxcon_param_full_power_scan_req { + uint16_t band_arfcn_start; + uint16_t band_arfcn_stop; +}; + +/* param of TRXCON_EV_FULL_POWER_SCAN_RES */ +struct trxcon_param_full_power_scan_res { + uint16_t band_arfcn; + int dbm; +}; + +/* param of TRXCON_EV_FBSB_SEARCH_REQ */ +struct trxcon_param_fbsb_search_req { + uint16_t band_arfcn; + uint16_t timeout_fns; /* in TDMA Fn periods */ + uint8_t pchan_config; +}; + +/* param of TRXCON_EV_SET_{CCCH,TCH}_MODE_REQ */ +struct trxcon_param_set_ccch_tch_mode_req { + uint8_t mode; + struct { + uint8_t start_codec; + uint8_t codecs_bitmask; + } amr; + bool applied; +}; + +/* param of TRXCON_EV_SET_PHY_CONFIG_REQ */ +struct trxcon_param_set_phy_config_req { + enum { + TRXCON_PHY_CFGT_PCHAN_COMB, + TRXCON_PHY_CFGT_TX_PARAMS, + } type; + union { + struct { + uint8_t tn; + uint8_t pchan; + } pchan_comb; + struct { + uint8_t timing_advance; + uint8_t tx_power; + } tx_params; + }; +}; + +/* param of TRXCON_EV_TX_DATA_REQ */ +struct trxcon_param_tx_data_req { + bool traffic; + uint8_t chan_nr; + uint8_t link_id; + size_t data_len; + const uint8_t *data; +}; + +/* param of TRXCON_EV_TX_DATA_CNF */ +struct trxcon_param_tx_data_cnf { + bool traffic; + uint8_t chan_nr; + uint8_t link_id; + uint16_t band_arfcn; + uint32_t frame_nr; + size_t data_len; + const uint8_t *data; +}; + +/* param of TRXCON_EV_RX_DATA_IND */ +struct trxcon_param_rx_data_ind { + bool traffic; + uint8_t chan_nr; + uint8_t link_id; + uint16_t band_arfcn; + uint32_t frame_nr; + int16_t toa256; + int8_t rssi; + int n_errors; + int n_bits_total; + size_t data_len; + const uint8_t *data; +}; + +/* param of TRXCON_EV_TX_ACCESS_BURST_REQ */ +struct trxcon_param_tx_access_burst_req { + uint8_t chan_nr; + uint8_t link_id; + uint8_t offset; + uint8_t synch_seq; + uint16_t ra; + bool is_11bit; +}; + +/* param of TRXCON_EV_TX_ACCESS_BURST_CNF */ +struct trxcon_param_tx_access_burst_cnf { + uint16_t band_arfcn; + uint32_t frame_nr; +}; + +/* param of TRXCON_EV_DCH_EST_REQ */ +struct trxcon_param_dch_est_req { + uint8_t chan_nr; + uint8_t tch_mode; + uint8_t tsc; + + bool hopping; + union { + struct { /* hopping=false */ + uint16_t band_arfcn; + } h0; + struct { /* hopping=true */ + uint8_t hsn; + uint8_t maio; + uint8_t n; + uint16_t ma[64]; + } h1; + }; +}; + +/* param of TRXCON_EV_CRYPTO_REQ */ +struct trxcon_param_crypto_req { + uint8_t chan_nr; + uint8_t a5_algo; /* 0 is A5/0 */ + uint8_t key_len; + const uint8_t *key; +}; |