diff --git a/srslte/include/srslte/common/bcd_helpers.h b/srslte/include/srslte/common/bcd_helpers.h new file mode 100644 index 000000000..d44a66483 --- /dev/null +++ b/srslte/include/srslte/common/bcd_helpers.h @@ -0,0 +1,118 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef BCD_HELPERS +#define BCD_HELPERS + +#include +#include +#include + +namespace srslte { + +/****************************************************************************** + * Convert between string and BCD-coded MCC. + * Digits are represented by 4-bit nibbles. Unused nibbles are filled with 0xF. + * MCC 001 results in 0xF001 + *****************************************************************************/ +inline bool string_to_mcc(std::string str, uint16_t *mcc) +{ + uint32_t len = str.size(); + if(len != 3) { + return false; + } + if(!isdigit(str[0]) || !isdigit(str[1]) || !isdigit(str[2])) { + return false; + } + *mcc = 0xF000; + *mcc |= ((uint8_t)(str[0]-'0') << 8); + *mcc |= ((uint8_t)(str[1]-'0') << 4); + *mcc |= ((uint8_t)(str[2]-'0')); + return true; +} + +inline bool mcc_to_string(uint16_t mcc, std::string *str) +{ + if((mcc & 0xF000) != 0xF000) { + return false; + } + *str = ""; + *str += ((mcc & 0x0F00) >> 8) + '0'; + *str += ((mcc & 0x00F0) >> 4) + '0'; + *str += (mcc & 0x000F) + '0'; + return true; +} + +/****************************************************************************** + * Convert between string and BCD-coded MNC. + * Digits are represented by 4-bit nibbles. Unused nibbles are filled with 0xF. + * MNC 001 results in 0xF001 + * MNC 01 results in 0xFF01 + *****************************************************************************/ +inline bool string_to_mnc(std::string str, uint16_t *mnc) +{ + uint32_t len = str.size(); + if(len != 3 && len != 2) { + return false; + } + if(len == 3) { + if(!isdigit(str[0]) || !isdigit(str[1]) || !isdigit(str[2])) { + return false; + } + *mnc = 0xF000; + *mnc |= ((uint8_t)(str[0]-'0') << 8); + *mnc |= ((uint8_t)(str[1]-'0') << 4); + *mnc |= ((uint8_t)(str[2]-'0')); + } + if(len == 2) { + if(!isdigit(str[0]) || !isdigit(str[1])) { + return false; + } + *mnc = 0xFF00; + *mnc |= ((uint8_t)(str[0]-'0') << 4); + *mnc |= ((uint8_t)(str[1]-'0')); + } + + return true; +} + +inline bool mnc_to_string(uint16_t mnc, std::string *str) +{ + if((mnc & 0xF000) != 0xF000) { + return false; + } + *str = ""; + if((mnc & 0xFF00) != 0xFF00) { + *str += ((mnc & 0x0F00) >> 8) + '0'; + } + *str += ((mnc & 0x00F0) >> 4) + '0'; + *str += (mnc & 0x000F) + '0'; + return true; +} + +} // namespace srslte + +#endif // BCD_HELPERS diff --git a/srslte/include/srslte/common/block_queue.h b/srslte/include/srslte/common/block_queue.h new file mode 100644 index 000000000..b4b312b60 --- /dev/null +++ b/srslte/include/srslte/common/block_queue.h @@ -0,0 +1,97 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef BLOCK_QUEUE +#define BLOCK_QUEUE + +#include +#include +#include +#include +#include +namespace srslte { + +template +class block_queue { + +public: + block_queue() { + pthread_mutex_init(&mutex, NULL); + pthread_cond_init(&cvar, NULL); + } + void push(const myobj& value) { + pthread_mutex_lock(&mutex); + q.push(value); + pthread_cond_signal(&cvar); + pthread_mutex_unlock(&mutex); + } + + bool try_pop(myobj *value) { + pthread_mutex_lock(&mutex); + if (q.empty()) { + pthread_mutex_unlock(&mutex); + return false; + } + if (value) { + *value = q.front(); + q.pop(); + } + pthread_mutex_unlock(&mutex); + return true; + } + + myobj wait_pop() { // blocking pop + pthread_mutex_lock(&mutex); + while(q.empty()) { + pthread_cond_wait(&cvar, &mutex); + } + myobj value = q.front(); + q.pop(); + pthread_mutex_unlock(&mutex); + return value; + } + + bool empty() const { // queue is empty? + pthread_mutex_lock(&mutex); + bool ret = q.empty(); + pthread_mutex_unlock(&mutex); + return ret; + } + + void clear() { // remove all items + myobj item; + while (try_pop(item)); + } + +private: + std::queue q; + pthread_mutex_t mutex; + pthread_cond_t cvar; +}; + +} + +#endif \ No newline at end of file diff --git a/srslte/include/srslte/common/buffer_pool.h b/srslte/include/srslte/common/buffer_pool.h new file mode 100644 index 000000000..231afefe0 --- /dev/null +++ b/srslte/include/srslte/common/buffer_pool.h @@ -0,0 +1,151 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef BUFFER_POOL_H +#define BUFFER_POOL_H + +#include +#include +#include +#include + +/******************************************************************************* + INCLUDES +*******************************************************************************/ + +#include "common/common.h" + +namespace srslte { + +/****************************************************************************** + * Buffer pool + * + * Preallocates a large number of buffer_t and provides allocate and + * deallocate functions. Provides quick object creation and deletion as well + * as object reuse. + * Singleton class of byte_buffer_t (but other pools of different type can be created) + *****************************************************************************/ + +template +class buffer_pool{ +public: + + // non-static methods + buffer_pool(uint32_t nof_buffers = POOL_SIZE) + { + pthread_mutex_init(&mutex, NULL); + for(int i=0;i 0) + { + b = available.top(); + used.push_back(b); + available.pop(); + + if (available.size() < capacity/20) { + printf("Warning buffer pool capacity is %f %%\n", (float) available.size()/capacity); + } + + } else { + printf("Error - buffer pool is empty\n"); + } + + pthread_mutex_unlock(&mutex); + return b; + } + + bool deallocate(buffer_t *b) + { + bool ret = false; + pthread_mutex_lock(&mutex); + typename std::vector::iterator elem = std::find(used.begin(), used.end(), b); + if (elem != used.end()) { + used.erase(elem); + available.push(b); + ret = true; + } else { + printf("Error deallocating from buffer pool: buffer not created in this pool.\n"); + } + pthread_mutex_unlock(&mutex); + return ret; + } + + +private: + static const int POOL_SIZE = 2048; + std::stack available; + std::vector used; + pthread_mutex_t mutex; + uint32_t capacity; +}; + + +class byte_buffer_pool { +public: + // Singleton static methods + static byte_buffer_pool *instance; + static byte_buffer_pool* get_instance(void); + static void cleanup(void); + byte_buffer_pool() { + pool = new buffer_pool; + } + ~byte_buffer_pool() { + delete pool; + } + byte_buffer_t* allocate() { + return pool->allocate(); + } + void deallocate(byte_buffer_t *b) { + b->reset(); + pool->deallocate(b); + } +private: + buffer_pool *pool; +}; + + +} // namespace srsue + +#endif // BUFFER_POOL_H diff --git a/srslte/include/srslte/common/common.h b/srslte/include/srslte/common/common.h new file mode 100644 index 000000000..93bca6577 --- /dev/null +++ b/srslte/include/srslte/common/common.h @@ -0,0 +1,224 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef COMMON_H +#define COMMON_H + +/******************************************************************************* + INCLUDES +*******************************************************************************/ + +#include +#include + +/******************************************************************************* + DEFINES +*******************************************************************************/ + +#define SRSUE_UE_CATEGORY 4 + +#define SRSUE_N_SRB 3 +#define SRSUE_N_DRB 8 +#define SRSUE_N_RADIO_BEARERS 11 + +// Cat 3 UE - Max number of DL-SCH transport block bits received within a TTI +// 3GPP 36.306 Table 4.1.1 +#define SRSUE_MAX_BUFFER_SIZE_BITS 102048 +#define SRSUE_MAX_BUFFER_SIZE_BYTES 12756 +#define SRSUE_BUFFER_HEADER_OFFSET 1024 + +#include "srslte/srslte.h" + +/******************************************************************************* + TYPEDEFS +*******************************************************************************/ + +namespace srslte { + +typedef enum{ + ERROR_NONE = 0, + ERROR_INVALID_PARAMS, + ERROR_INVALID_COMMAND, + ERROR_OUT_OF_BOUNDS, + ERROR_CANT_START, + ERROR_ALREADY_STARTED, + ERROR_N_ITEMS, +}error_t; +static const char error_text[ERROR_N_ITEMS][20] = { "None", + "Invalid parameters", + "Invalid command", + "Out of bounds", + "Can't start", + "Already started"}; + +typedef enum{ + RB_ID_SRB0 = 0, + RB_ID_SRB1, + RB_ID_SRB2, + RB_ID_DRB1, + RB_ID_DRB2, + RB_ID_DRB3, + RB_ID_DRB4, + RB_ID_DRB5, + RB_ID_DRB6, + RB_ID_DRB7, + RB_ID_DRB8, + RB_ID_N_ITEMS, +}rb_id_t; +static const char rb_id_text[RB_ID_N_ITEMS][20] = { "SRB0", + "SRB1", + "SRB2", + "DRB1", + "DRB2", + "DRB3", + "DRB4", + "DRB5", + "DRB6", + "DRB7", + "DRB8"}; + +/****************************************************************************** + * Byte and Bit buffers + * + * Generic buffers with headroom to accommodate packet headers and custom + * copy constructors & assignment operators for quick copying. Byte buffer + * holds a next pointer to support linked lists. + *****************************************************************************/ +class byte_buffer_t{ +public: + uint32_t N_bytes; + uint8_t buffer[SRSUE_MAX_BUFFER_SIZE_BYTES]; + uint8_t *msg; + + byte_buffer_t():N_bytes(0) + { + timestamp_is_set = false; + msg = &buffer[SRSUE_BUFFER_HEADER_OFFSET]; + next = NULL; + } + byte_buffer_t(const byte_buffer_t& buf) + { + N_bytes = buf.N_bytes; + memcpy(msg, buf.msg, N_bytes); + } + byte_buffer_t & operator= (const byte_buffer_t & buf) + { + N_bytes = buf.N_bytes; + memcpy(msg, buf.msg, N_bytes); + } + void reset() + { + msg = &buffer[SRSUE_BUFFER_HEADER_OFFSET]; + N_bytes = 0; + timestamp_is_set = false; + } + uint32_t get_headroom() + { + return msg-buffer; + } + long get_latency_us() + { + if(!timestamp_is_set) + return 0; + gettimeofday(×tamp[2], NULL); + get_time_interval(timestamp); + return timestamp[0].tv_usec; + } + + void set_timestamp() + { + gettimeofday(×tamp[1], NULL); + timestamp_is_set = true; + } + +private: + + + void get_time_interval(struct timeval * tdata) { + + tdata[0].tv_sec = tdata[2].tv_sec - tdata[1].tv_sec; + tdata[0].tv_usec = tdata[2].tv_usec - tdata[1].tv_usec; + if (tdata[0].tv_usec < 0) { + tdata[0].tv_sec--; + tdata[0].tv_usec += 1000000; + } + } + + + struct timeval timestamp[3]; + bool timestamp_is_set; + byte_buffer_t *next; +}; + +struct bit_buffer_t{ + uint32_t N_bits; + uint8_t buffer[SRSUE_MAX_BUFFER_SIZE_BITS]; + uint8_t *msg; + + bit_buffer_t():N_bits(0) + { + msg = &buffer[SRSUE_BUFFER_HEADER_OFFSET]; + } + bit_buffer_t(const bit_buffer_t& buf){ + N_bits = buf.N_bits; + memcpy(msg, buf.msg, N_bits); + } + bit_buffer_t & operator= (const bit_buffer_t & buf){ + N_bits = buf.N_bits; + memcpy(msg, buf.msg, N_bits); + } + void reset() + { + msg = &buffer[SRSUE_BUFFER_HEADER_OFFSET]; + N_bits = 0; + timestamp_is_set = false; + } + uint32_t get_headroom() + { + return msg-buffer; + } + long get_latency_us() + { + if(!timestamp_is_set) + return 0; + gettimeofday(×tamp[2], NULL); + return timestamp[0].tv_usec; + } + void set_timestamp() + { + gettimeofday(×tamp[1], NULL); + timestamp_is_set = true; + } + +private: + struct timeval timestamp[3]; + bool timestamp_is_set; + +}; + +} // namespace srsue + +#endif // COMMON_H diff --git a/srslte/include/srslte/common/config.h b/srslte/include/srslte/common/config.h new file mode 100644 index 000000000..3231355fa --- /dev/null +++ b/srslte/include/srslte/common/config.h @@ -0,0 +1,57 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef CONFIG_H +#define CONFIG_H + +// Generic helper definitions for shared library support +#if defined _WIN32 || defined __CYGWIN__ + #define SRSAPPS_IMPORT __declspec(dllimport) + #define SRSAPPS_EXPORT __declspec(dllexport) + #define SRSAPPS_LOCAL +#else + #if __GNUC__ >= 4 + #define SRSAPPS_IMPORT __attribute__ ((visibility ("default"))) + #define SRSAPPS_EXPORT __attribute__ ((visibility ("default"))) + #else + #define SRSAPPS_IMPORT + #define SRSAPPS_EXPORT + #define SRSAPPS_LOCAL + #endif +#endif + +// Define SRSAPPS_API +// is used for the public API symbols. +#ifdef SRSAPPS_DLL_EXPORTS // defined if we are building the SRSAPPS DLL (instead of using it) + #define SRSAPPS_EXPORT +#else + #define SRSAPPS_IMPORT +#endif + +// cf_t definition +typedef _Complex float cf_t; + +#endif // CONFIG_H diff --git a/srslte/include/srslte/common/interfaces.h b/srslte/include/srslte/common/interfaces.h new file mode 100644 index 000000000..1853da67d --- /dev/null +++ b/srslte/include/srslte/common/interfaces.h @@ -0,0 +1,234 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +/****************************************************************************** + * File: interfaces.h + * Description: Abstract base class interfaces provided by layers + * to other layers. + *****************************************************************************/ + +#ifndef INTERFACES_H +#define INTERFACES_H + +#include "liblte_rrc.h" +#include "common/interfaces_common.h" +#include "common/common.h" +#include "common/security.h" +#include "mac_interface.h" +#include "phy_interface.h" + +namespace srsue { + +// UE interface +class ue_interface +{ +}; + +// USIM interface for NAS +class usim_interface_nas +{ +public: + virtual void get_imsi_vec(uint8_t* imsi_, uint32_t n) = 0; + virtual void get_imei_vec(uint8_t* imei_, uint32_t n) = 0; + virtual void generate_authentication_response(uint8_t *rand, + uint8_t *autn_enb, + uint16_t mcc, + uint16_t mnc, + bool *net_valid, + uint8_t *res) = 0; + virtual void generate_nas_keys(uint8_t *k_nas_enc, + uint8_t *k_nas_int, + CIPHERING_ALGORITHM_ID_ENUM cipher_algo, + INTEGRITY_ALGORITHM_ID_ENUM integ_algo) = 0; +}; + +// USIM interface for RRC +class usim_interface_rrc +{ +public: + virtual void generate_as_keys(uint32_t count_ul, + uint8_t *k_rrc_enc, + uint8_t *k_rrc_int, + uint8_t *k_up_enc, + uint8_t *k_up_int, + CIPHERING_ALGORITHM_ID_ENUM cipher_algo, + INTEGRITY_ALGORITHM_ID_ENUM integ_algo) = 0; +}; + +// GW interface for NAS +class gw_interface_nas +{ +public: + virtual srslte::error_t setup_if_addr(uint32_t ip_addr, char *err_str) = 0; +}; + +// GW interface for PDCP +class gw_interface_pdcp +{ +public: + virtual void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu) = 0; +}; + +// NAS interface for RRC +class nas_interface_rrc +{ +public: + virtual bool is_attached() = 0; + virtual void notify_connection_setup() = 0; + virtual void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu) = 0; + virtual uint32_t get_ul_count() = 0; + virtual bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) = 0; +}; + +// RRC interface for MAC +class rrc_interface_mac +{ +public: + virtual void release_pucch_srs() = 0; + virtual void ra_problem() = 0; +}; + +// RRC interface for PHY +class rrc_interface_phy +{ +public: + virtual void in_sync() = 0; + virtual void out_of_sync() = 0; +}; + +// RRC interface for NAS +class rrc_interface_nas +{ +public: + virtual void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0; + virtual uint16_t get_mcc() = 0; + virtual uint16_t get_mnc() = 0; + virtual void enable_capabilities() = 0; +}; + +// RRC interface for GW +class rrc_interface_gw +{ +public: + virtual bool rrc_connected() = 0; + virtual void rrc_connect() = 0; + virtual bool have_drb() = 0; +}; + +// RRC interface for PDCP +class rrc_interface_pdcp +{ +public: + virtual void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu) = 0; + virtual void write_pdu_bcch_bch(srslte::byte_buffer_t *pdu) = 0; + virtual void write_pdu_bcch_dlsch(srslte::byte_buffer_t *pdu) = 0; + virtual void write_pdu_pcch(srslte::byte_buffer_t *pdu) = 0; +}; + +// RRC interface for RLC +class rrc_interface_rlc +{ +public: + virtual void max_retx_attempted() = 0; +}; + +// PDCP interface for GW +class pdcp_interface_gw +{ +public: + virtual void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0; +}; + +// PDCP interface for RRC +class pdcp_interface_rrc +{ +public: + virtual void reset() = 0; + virtual void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0; + virtual void add_bearer(uint32_t lcid, LIBLTE_RRC_PDCP_CONFIG_STRUCT *cnfg=NULL) = 0; + virtual void config_security(uint32_t lcid, + uint8_t *k_rrc_enc_, + uint8_t *k_rrc_int_, + CIPHERING_ALGORITHM_ID_ENUM cipher_algo_, + INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) = 0; +}; + +// PDCP interface for RLC +class pdcp_interface_rlc +{ +public: + /* RLC calls PDCP to push a PDCP PDU. */ + virtual void write_pdu(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0; + virtual void write_pdu_bcch_bch(srslte::byte_buffer_t *sdu) = 0; + virtual void write_pdu_bcch_dlsch(srslte::byte_buffer_t *sdu) = 0; + virtual void write_pdu_pcch(srslte::byte_buffer_t *sdu) = 0; +}; + +// RLC interface for RRC +class rlc_interface_rrc +{ +public: + virtual void reset() = 0; + virtual void add_bearer(uint32_t lcid) = 0; + virtual void add_bearer(uint32_t lcid, LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg) = 0; +}; + +// RLC interface for PDCP +class rlc_interface_pdcp +{ +public: + /* PDCP calls RLC to push an RLC SDU. SDU gets placed into the RLC buffer and MAC pulls + * RLC PDUs according to TB size. */ + virtual void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0; +}; + +//RLC interface for MAC +class rlc_interface_mac : public srslte::read_pdu_interface +{ +public: + /* MAC calls RLC to get buffer state for a logical channel. + * This function should return quickly. */ + virtual uint32_t get_buffer_state(uint32_t lcid) = 0; + virtual uint32_t get_total_buffer_state(uint32_t lcid) = 0; + + + const static int MAX_PDU_SEGMENTS = 20; + + /* MAC calls RLC to get RLC segment of nof_bytes length. + * Segmentation happens in this function. RLC PDU is stored in payload. */ + virtual int read_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) = 0; + + /* MAC calls RLC to push an RLC PDU. This function is called from an independent MAC thread. + * PDU gets placed into the buffer and higher layer thread gets notified. */ + virtual void write_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) = 0; + virtual void write_pdu_bcch_bch(uint8_t *payload, uint32_t nof_bytes) = 0; + virtual void write_pdu_bcch_dlsch(uint8_t *payload, uint32_t nof_bytes) = 0; + virtual void write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes) = 0; +}; + +} // namespace srsue + +#endif // INTERFACES_H diff --git a/srslte/include/srslte/common/interfaces_common.h b/srslte/include/srslte/common/interfaces_common.h new file mode 100644 index 000000000..3c3085e55 --- /dev/null +++ b/srslte/include/srslte/common/interfaces_common.h @@ -0,0 +1,27 @@ + +#include "common/timers.h" + +#ifndef INTERFACE_COMMON_H +#define INTERFACE_COMMON_H + +namespace srslte { + +class mac_interface_timers +{ +public: + /* Timer services with ms resolution. + * timer_id must be lower than MAC_NOF_UPPER_TIMERS + */ + virtual timers::timer* get(uint32_t timer_id) = 0; + virtual uint32_t get_unique_id() = 0; +}; + +class read_pdu_interface +{ +public: + virtual int read_pdu(uint32_t lcid, uint8_t *payload, uint32_t requested_bytes) = 0; +}; + +} + +#endif diff --git a/srslte/include/srslte/common/log.h b/srslte/include/srslte/common/log.h new file mode 100644 index 000000000..9bec779df --- /dev/null +++ b/srslte/include/srslte/common/log.h @@ -0,0 +1,127 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +/****************************************************************************** + * File: log.h + * + * Description: Abstract logging service + * + * Reference: + *****************************************************************************/ + +#ifndef LOG_H +#define LOG_H + +#include +#include + +namespace srslte { + +typedef enum { + LOG_LEVEL_NONE = 0, + LOG_LEVEL_ERROR, + LOG_LEVEL_WARNING, + LOG_LEVEL_INFO, + LOG_LEVEL_DEBUG, + LOG_LEVEL_N_ITEMS +} LOG_LEVEL_ENUM; +static const char log_level_text[LOG_LEVEL_N_ITEMS][16] = {"None ", + "Error ", + "Warning", + "Info ", + "Debug "}; + +class log +{ +public: + + log() { + service_name = ""; + tti = 0; + level = LOG_LEVEL_NONE; + hex_limit = 0; + } + + log(std::string service_name_) { + service_name = service_name_; + tti = 0; + level = LOG_LEVEL_NONE; + hex_limit = 0; + } + + // This function shall be called at the start of every tti for printing tti + void step(uint32_t tti_) { + tti = tti_; + } + uint32_t get_tti() { + return tti; + } + + void set_level(LOG_LEVEL_ENUM l) { + level = l; + } + LOG_LEVEL_ENUM get_level() { + return level; + } + + void set_hex_limit(int limit) { + hex_limit = limit; + } + int get_hex_limit() { + return hex_limit; + } + + // Pure virtual methods for logging + virtual void console(std::string message, ...) = 0; + virtual void error(std::string message, ...) = 0; + virtual void warning(std::string message, ...) = 0; + virtual void info(std::string message, ...) = 0; + virtual void debug(std::string message, ...) = 0; + + // Same with hex dump + virtual void error_hex(uint8_t *hex, int size, std::string message, ...){error("error_hex not implemented.\n");} + virtual void warning_hex(uint8_t *hex, int size, std::string message, ...){error("warning_hex not implemented.\n");} + virtual void info_hex(uint8_t *hex, int size, std::string message, ...){error("info_hex not implemented.\n");} + virtual void debug_hex(uint8_t *hex, int size, std::string message, ...){error("debug_hex not implemented.\n");} + + // Same with line and file info + virtual void error_line(std::string file, int line, std::string message, ...){error("error_line not implemented.\n");} + virtual void warning_line(std::string file, int line, std::string message, ...){error("warning_line not implemented.\n");} + virtual void info_line(std::string file, int line, std::string message, ...){error("info_line not implemented.\n");} + virtual void debug_line(std::string file, int line, std::string message, ...){error("debug_line not implemented.\n");} + +protected: + std::string get_service_name() { return service_name; } + uint32_t tti; + LOG_LEVEL_ENUM level; + int hex_limit; + std::string service_name; +}; + +} // namespace srslte + +#endif // LOG_H + diff --git a/srslte/include/srslte/common/log_filter.h b/srslte/include/srslte/common/log_filter.h new file mode 100644 index 000000000..3ee728690 --- /dev/null +++ b/srslte/include/srslte/common/log_filter.h @@ -0,0 +1,83 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +/****************************************************************************** + * File: log_filter.h + * Description: Log filter for a specific layer or element. + * Performs filtering based on log level, generates + * timestamped log strings and passes them to the + * common logger object. + *****************************************************************************/ + +#ifndef LOG_FILTER_H +#define LOG_FILTER_H + +#include +#include +#include +#include "logger.h" + +namespace srslte { + +class log_filter : public srslte::log +{ +public: + + log_filter(); + log_filter(std::string layer, logger *logger_, bool tti=false); + + void init(std::string layer, logger *logger_, bool tti=false); + + void console(std::string message, ...); + void error(std::string message, ...); + void warning(std::string message, ...); + void info(std::string message, ...); + void debug(std::string message, ...); + + void error_hex(uint8_t *hex, int size, std::string message, ...); + void warning_hex(uint8_t *hex, int size, std::string message, ...); + void info_hex(uint8_t *hex, int size, std::string message, ...); + void debug_hex(uint8_t *hex, int size, std::string message, ...); + + void error_line(std::string file, int line, std::string message, ...); + void warning_line(std::string file, int line, std::string message, ...); + void info_line(std::string file, int line, std::string message, ...); + void debug_line(std::string file, int line, std::string message, ...); + +private: + logger *logger_h; + bool do_tti; + + void all_log(srslte::LOG_LEVEL_ENUM level, uint32_t tti, char *msg); + void all_log(srslte::LOG_LEVEL_ENUM level, uint32_t tti, char *msg, uint8_t *hex, int size); + void all_log_line(srslte::LOG_LEVEL_ENUM level, uint32_t tti, std::string file, int line, char *msg); + std::string now_time(); + std::string hex_string(uint8_t *hex, int size); +}; + +} // namespace srsue + +#endif // LOG_FILTER_H diff --git a/srslte/include/srslte/common/log_stdout.h b/srslte/include/srslte/common/log_stdout.h new file mode 100644 index 000000000..51e000ecc --- /dev/null +++ b/srslte/include/srslte/common/log_stdout.h @@ -0,0 +1,82 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +/****************************************************************************** + * File: log_stout.h + * + * Description: Logging service through standard output. Inherits log interface + * + * Reference: + *****************************************************************************/ + +#ifndef LOGSTDOUT_H +#define LOGSTDOUT_H + +#include +#include +#include + +namespace srslte { + +class log_stdout : public log +{ +public: + + log_stdout(std::string service_name_) : log(service_name_) { } + + void console(std::string message, ...); + void error(std::string message, ...); + void warning(std::string message, ...); + void info(std::string message, ...); + void debug(std::string message, ...); + + // Same with hex dump + void error_hex(uint8_t *hex, int size, std::string message, ...); + void warning_hex(uint8_t *hex, int size, std::string message, ...); + void info_hex(uint8_t *hex, int size, std::string message, ...); + void debug_hex(uint8_t *hex, int size, std::string message, ...); + + // Same with line and file info + void error_line(std::string file, int line, std::string message, ...); + void warning_line(std::string file, int line, std::string message, ...); + void info_line(std::string file, int line, std::string message, ...); + void debug_line(std::string file, int line, std::string message, ...); + +private: + void printlog(srslte::LOG_LEVEL_ENUM level, uint32_t tti, std::string file, int line, std::string message, va_list args); + void printlog(srslte::LOG_LEVEL_ENUM level, uint32_t tti, std::string message, va_list args); + + void all_log(srslte::LOG_LEVEL_ENUM level, uint32_t tti, char *msg); + void all_log(srslte::LOG_LEVEL_ENUM level, uint32_t tti, char *msg, uint8_t *hex, int size); + void all_log_line(srslte::LOG_LEVEL_ENUM level, uint32_t tti, std::string file, int line, char *msg); + std::string now_time(); + std::string hex_string(uint8_t *hex, int size); +}; + +} + +#endif + diff --git a/srslte/include/srslte/common/logger.h b/srslte/include/srslte/common/logger.h new file mode 100644 index 000000000..6420ab6ca --- /dev/null +++ b/srslte/include/srslte/common/logger.h @@ -0,0 +1,74 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +/****************************************************************************** + * File: logger.h + * Description: Common log object. Maintains a queue of log messages + * and runs a thread to read messages and write to file. + * Multiple producers, single consumer. If full, producers + * increase queue size. If empty, consumer blocks. + *****************************************************************************/ + +#ifndef LOGGER_H +#define LOGGER_H + +#include +#include +#include +#include "common/threads.h" + +namespace srslte { + +typedef std::string* str_ptr; + +class logger : public thread +{ +public: + logger(); + logger(std::string file); + ~logger(); + void init(std::string file); + void log(const char *msg); + void log(str_ptr msg); + +private: + void run_thread(); + void flush(); + + FILE* logfile; + bool inited; + bool not_done; + std::string filename; + pthread_cond_t not_empty; + pthread_cond_t not_full; + pthread_mutex_t mutex; + pthread_t thread; + std::deque buffer; +}; + +} // namespace srsue + +#endif // LOGGER_H diff --git a/srslte/include/srslte/common/mac_interface.h b/srslte/include/srslte/common/mac_interface.h new file mode 100644 index 000000000..9a7128bd9 --- /dev/null +++ b/srslte/include/srslte/common/mac_interface.h @@ -0,0 +1,177 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +/****************************************************************************** + * File: mac_interface.h + * Description: LTE MAC layer interface + * Reference: + *****************************************************************************/ + +#ifndef MAC_INTERFACE_H +#define MAC_INTERFACE_H + +#include +#include +#include "srslte/srslte.h" + +#include "common/interfaces_common.h" +#include "common/timers.h" + +#include "liblte_rrc.h" + +namespace srsue { + +/* Interface PHY -> MAC */ +class mac_interface_phy +{ +public: + + typedef struct { + uint32_t pid; + uint32_t tti; + uint32_t last_tti; + bool ndi; + bool last_ndi; + uint32_t n_bytes; + int rv; + uint16_t rnti; + bool is_from_rar; + bool is_sps_release; + bool has_cqi_request; + srslte_rnti_type_t rnti_type; + srslte_phy_grant_t phy_grant; + } mac_grant_t; + + typedef struct { + bool decode_enabled; + int rv; + uint16_t rnti; + bool generate_ack; + bool default_ack; + // If non-null, called after tb_decoded_ok to determine if ack needs to be sent + bool (*generate_ack_callback)(void*); + void *generate_ack_callback_arg; + uint8_t *payload_ptr; + srslte_softbuffer_rx_t *softbuffer; + srslte_phy_grant_t phy_grant; + } tb_action_dl_t; + + typedef struct { + bool tx_enabled; + bool expect_ack; + uint32_t rv; + uint16_t rnti; + uint32_t current_tx_nb; + srslte_softbuffer_tx_t *softbuffer; + srslte_phy_grant_t phy_grant; + uint8_t *payload_ptr; + } tb_action_ul_t; + + /* Indicate reception of UL grant. + * payload_ptr points to memory where MAC PDU must be written by MAC layer */ + virtual void new_grant_ul(mac_grant_t grant, tb_action_ul_t *action) = 0; + + /* Indicate reception of UL grant + HARQ information throught PHICH in the same TTI. */ + virtual void new_grant_ul_ack(mac_grant_t grant, bool ack, tb_action_ul_t *action) = 0; + + /* Indicate reception of HARQ information only through PHICH. */ + virtual void harq_recv(uint32_t tti, bool ack, tb_action_ul_t *action) = 0; + + /* Indicate reception of DL grant. */ + virtual void new_grant_dl(mac_grant_t grant, tb_action_dl_t *action) = 0; + + /* Indicate successfull decoding of PDSCH TB. */ + virtual void tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid) = 0; + + /* Indicate successfull decoding of BCH TB through PBCH */ + virtual void bch_decoded_ok(uint8_t *payload, uint32_t len) = 0; + + /* Indicate successfull decoding of PCH TB through PDSCH */ + virtual void pch_decoded_ok(uint32_t len) = 0; + + /* Function called every start of a subframe (TTI). Warning, this function is called + * from a high priority thread and should terminate asap + */ + virtual void tti_clock(uint32_t tti) = 0; + +}; + + +/* Interface RRC -> MAC */ +class mac_interface_rrc +{ +public: + + typedef struct { + LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT main; + LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT rach; + LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT sr; + uint32_t prach_config_index; + } mac_cfg_t; + + + // Class to handle UE specific RNTIs between RRC and MAC + typedef struct { + uint16_t crnti; + uint16_t temp_rnti; + uint16_t tpc_rnti; + uint16_t sps_rnti; + uint64_t contention_id; + } ue_rnti_t; + + /* Instructs the MAC to start receiving BCCH */ + virtual void bcch_start_rx() = 0; + virtual void bcch_stop_rx() = 0; + virtual void bcch_start_rx(int si_window_start, int si_window_length) = 0; + + /* Instructs the MAC to start receiving PCCH */ + virtual void pcch_start_rx() = 0; + virtual void pcch_stop_rx() = 0; + + /* RRC configures a logical channel */ + virtual void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD) = 0; + + virtual uint32_t get_current_tti() = 0; + + virtual void set_config(mac_cfg_t *mac_cfg) = 0; + virtual void set_config_main(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT *main_cfg) = 0; + virtual void set_config_rach(LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT *rach_cfg, uint32_t prach_config_index) = 0; + virtual void set_config_sr(LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT *sr_cfg) = 0; + virtual void get_config(mac_cfg_t *mac_cfg) = 0; + + virtual void get_rntis(ue_rnti_t *rntis) = 0; + virtual void set_contention_id(uint64_t uecri) = 0; + + + virtual void reconfiguration() = 0; + virtual void reset() = 0; +}; + +} + + +#endif + diff --git a/srslte/include/srslte/common/mac_pcap.h b/srslte/include/srslte/common/mac_pcap.h new file mode 100644 index 000000000..f5f971546 --- /dev/null +++ b/srslte/include/srslte/common/mac_pcap.h @@ -0,0 +1,61 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef MACPCAP_H +#define MACPCAP_H + +#include +#include "common/pcap.h" + +namespace srslte { + +class mac_pcap +{ +public: + mac_pcap() {enable_write=false; ue_id=0; pcap_file = NULL; }; + void enable(bool en); + void open(const char *filename, uint32_t ue_id = 0); + void close(); + void write_ul_crnti(uint8_t *pdu, uint32_t pdu_len_bytes, uint16_t crnti, uint32_t reTX, uint32_t tti); + void write_dl_crnti(uint8_t *pdu, uint32_t pdu_len_bytes, uint16_t crnti, bool crc_ok, uint32_t tti); + void write_dl_ranti(uint8_t *pdu, uint32_t pdu_len_bytes, uint16_t ranti, bool crc_ok, uint32_t tti); + + // SI and BCH only for DL + void write_dl_sirnti(uint8_t *pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti); + void write_dl_bch(uint8_t *pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti); + void write_dl_pch(uint8_t *pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti); + +private: + bool enable_write; + FILE *pcap_file; + uint32_t ue_id; + void pack_and_write(uint8_t* pdu, uint32_t pdu_len_bytes, uint32_t reTX, bool crc_ok, uint32_t tti, + uint16_t crnti_, uint8_t direction, uint8_t rnti_type); +}; + +} // namespace srsue + +#endif // MACPCAP_H diff --git a/srslte/include/srslte/common/metrics_hub.h b/srslte/include/srslte/common/metrics_hub.h new file mode 100644 index 000000000..17786e37f --- /dev/null +++ b/srslte/include/srslte/common/metrics_hub.h @@ -0,0 +1,61 @@ + +/****************************************************************************** + * File: metrics_hub.h + * Description: Centralizes metrics interfaces to allow different metrics clients + * to get metrics + *****************************************************************************/ + +#ifndef METRICS_HUB_H +#define METRICS_HUB_H + +#include +#include "common/threads.h" + +namespace srslte { + +template +class metrics_interface +{ +public: + virtual bool get_metrics(metrics_t &m) = 0; +}; + +template +class metrics_listener +{ +public: + virtual void set_metrics(metrics_t &m) = 0; +}; + +template +class metrics_hub : public periodic_thread +{ +public: + bool init(metrics_interface *m_, float report_period_secs=1.0) { + m = m_; + start_periodic(report_period_secs*1e6); + } + void stop() { + thread_cancel(); + } + + void add_listener(metrics_listener *listener) { + listeners.push_back(listener); + } + +private: + void run_period() { + metrics_t metric; + m->get_metrics(metric); + for (int i=0;iset_metrics(metric); + } + } + metrics_interface *m; + std::vector*> listeners; + +}; + +} // namespace srslte + +#endif // METRICS_HUB_H diff --git a/srslte/include/srslte/common/msg_queue.h b/srslte/include/srslte/common/msg_queue.h new file mode 100644 index 000000000..58228cfe3 --- /dev/null +++ b/srslte/include/srslte/common/msg_queue.h @@ -0,0 +1,152 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +/****************************************************************************** + * File: msg_queue.h + * Description: Thread-safe bounded circular buffer of srsue_byte_buffer pointers. + * Reference: + *****************************************************************************/ + +#ifndef MSG_QUEUE_H +#define MSG_QUEUE_H + +#include "common/common.h" +#include + +namespace srslte { + +class msg_queue +{ +public: + msg_queue(uint32_t capacity_ = 128) + :head(0) + ,tail(0) + ,unread(0) + ,unread_bytes(0) + ,capacity(capacity_) + { + buf = new byte_buffer_t*[capacity]; + pthread_mutex_init(&mutex, NULL); + pthread_cond_init(¬_empty, NULL); + pthread_cond_init(¬_full, NULL); + } + + ~msg_queue() + { + delete [] buf; + } + + void write(byte_buffer_t *msg) + { + pthread_mutex_lock(&mutex); + while(is_full()) { + pthread_cond_wait(¬_full, &mutex); + } + buf[head] = msg; + head = (head+1)%capacity; + unread++; + unread_bytes += msg->N_bytes; + + pthread_cond_signal(¬_empty); + pthread_mutex_unlock(&mutex); + } + + void read(byte_buffer_t **msg) + { + pthread_mutex_lock(&mutex); + while(is_empty()) { + pthread_cond_wait(¬_empty, &mutex); + } + *msg = buf[tail]; + tail = (tail+1)%capacity; + unread--; + unread_bytes -= (*msg)->N_bytes; + + pthread_cond_signal(¬_full); + pthread_mutex_unlock(&mutex); + } + + bool try_read(byte_buffer_t **msg) + { + pthread_mutex_lock(&mutex); + if(is_empty()) + { + pthread_mutex_unlock(&mutex); + return false; + }else{ + *msg = buf[tail]; + tail = (tail+1)%capacity; + unread--; + unread_bytes -= (*msg)->N_bytes; + pthread_cond_signal(¬_full); + pthread_mutex_unlock(&mutex); + return true; + } + } + + uint32_t size() + { + pthread_mutex_lock(&mutex); + uint32_t r = unread; + pthread_mutex_unlock(&mutex); + return r; + } + + uint32_t size_bytes() + { + pthread_mutex_lock(&mutex); + uint32_t r = unread_bytes; + pthread_mutex_unlock(&mutex); + return r; + } + + uint32_t size_tail_bytes() + { + pthread_mutex_lock(&mutex); + uint32_t r = buf[tail]->N_bytes; + pthread_mutex_unlock(&mutex); + return r; + } + +private: + bool is_empty() const { return unread == 0; } + bool is_full() const { return unread == capacity; } + + pthread_cond_t not_empty; + pthread_cond_t not_full; + pthread_mutex_t mutex; + byte_buffer_t **buf; + uint32_t capacity; + uint32_t unread; + uint32_t unread_bytes; + uint32_t head; + uint32_t tail; +}; + +} // namespace srsue + + +#endif // MSG_QUEUE_H diff --git a/srslte/include/srslte/common/pcap.h b/srslte/include/srslte/common/pcap.h new file mode 100644 index 000000000..d9937c060 --- /dev/null +++ b/srslte/include/srslte/common/pcap.h @@ -0,0 +1,218 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef UEPCAP_H +#define UEPCAP_H + +#include +#include +#include +#include + +#define MAC_LTE_DLT 147 + + +/* This structure gets written to the start of the file */ +typedef struct pcap_hdr_s { + unsigned int magic_number; /* magic number */ + unsigned short version_major; /* major version number */ + unsigned short version_minor; /* minor version number */ + unsigned int thiszone; /* GMT to local correction */ + unsigned int sigfigs; /* accuracy of timestamps */ + unsigned int snaplen; /* max length of captured packets, in octets */ + unsigned int network; /* data link type */ +} pcap_hdr_t; + +/* This structure precedes each packet */ +typedef struct pcaprec_hdr_s { + unsigned int ts_sec; /* timestamp seconds */ + unsigned int ts_usec; /* timestamp microseconds */ + unsigned int incl_len; /* number of octets of packet saved in file */ + unsigned int orig_len; /* actual length of packet */ +} pcaprec_hdr_t; + + +/* radioType */ +#define FDD_RADIO 1 +#define TDD_RADIO 2 + +/* Direction */ +#define DIRECTION_UPLINK 0 +#define DIRECTION_DOWNLINK 1 + +/* rntiType */ +#define NO_RNTI 0 /* Used for BCH-BCH */ +#define P_RNTI 1 +#define RA_RNTI 2 +#define C_RNTI 3 +#define SI_RNTI 4 +#define SPS_RNTI 5 +#define M_RNTI 6 + +#define MAC_LTE_START_STRING "mac-lte" + +#define MAC_LTE_RNTI_TAG 0x02 +/* 2 bytes, network order */ + +#define MAC_LTE_UEID_TAG 0x03 +/* 2 bytes, network order */ + +#define MAC_LTE_SUBFRAME_TAG 0x04 +/* 2 bytes, network order */ + +#define MAC_LTE_PREDFINED_DATA_TAG 0x05 +/* 1 byte */ + +#define MAC_LTE_RETX_TAG 0x06 +/* 1 byte */ + +#define MAC_LTE_CRC_STATUS_TAG 0x07 +/* 1 byte */ + +/* MAC PDU. Following this tag comes the actual MAC PDU (there is no length, the PDU + continues until the end of the frame) */ +#define MAC_LTE_PAYLOAD_TAG 0x01 + + +/* Context information for every MAC PDU that will be logged */ +typedef struct MAC_Context_Info_t { + unsigned short radioType; + unsigned char direction; + unsigned char rntiType; + unsigned short rnti; + unsigned short ueid; + unsigned char isRetx; + unsigned char crcStatusOK; + + unsigned short sysFrameNumber; + unsigned short subFrameNumber; + +} MAC_Context_Info_t; + + + + +/**************************************************************************/ +/* API functions for opening/writing/closing MAC-LTE PCAP files */ + +/* Open the file and write file header */ +inline FILE *MAC_LTE_PCAP_Open(const char *fileName) +{ + pcap_hdr_t file_header = + { + 0xa1b2c3d4, /* magic number */ + 2, 4, /* version number is 2.4 */ + 0, /* timezone */ + 0, /* sigfigs - apparently all tools do this */ + 65535, /* snaplen - this should be long enough */ + MAC_LTE_DLT /* Data Link Type (DLT). Set as unused value 147 for now */ + }; + + FILE *fd = fopen(fileName, "w"); + if (fd == NULL) { + printf("Failed to open file \"%s\" for writing\n", fileName); + return NULL; + } + + /* Write the file header */ + fwrite(&file_header, sizeof(pcap_hdr_t), 1, fd); + + return fd; +} + +/* Write an individual PDU (PCAP packet header + mac-context + mac-pdu) */ +inline int MAC_LTE_PCAP_WritePDU(FILE *fd, MAC_Context_Info_t *context, + const unsigned char *PDU, unsigned int length) +{ + pcaprec_hdr_t packet_header; + char context_header[256]; + int offset = 0; + unsigned short tmp16; + + /* Can't write if file wasn't successfully opened */ + if (fd == NULL) { + printf("Error: Can't write to empty file handle\n"); + return 0; + } + + /*****************************************************************/ + /* Context information (same as written by UDP heuristic clients */ + context_header[offset++] = context->radioType; + context_header[offset++] = context->direction; + context_header[offset++] = context->rntiType; + + /* RNTI */ + context_header[offset++] = MAC_LTE_RNTI_TAG; + tmp16 = htons(context->rnti); + memcpy(context_header+offset, &tmp16, 2); + offset += 2; + + /* UEId */ + context_header[offset++] = MAC_LTE_UEID_TAG; + tmp16 = htons(context->ueid); + memcpy(context_header+offset, &tmp16, 2); + offset += 2; + + /* Subframe number */ + context_header[offset++] = MAC_LTE_SUBFRAME_TAG; + tmp16 = htons(context->subFrameNumber); + memcpy(context_header+offset, &tmp16, 2); + offset += 2; + + /* CRC Status */ + context_header[offset++] = MAC_LTE_CRC_STATUS_TAG; + context_header[offset++] = context->crcStatusOK; + + /* Data tag immediately preceding PDU */ + context_header[offset++] = MAC_LTE_PAYLOAD_TAG; + + + /****************************************************************/ + /* PCAP Header */ + struct timeval t; + gettimeofday(&t, NULL); + packet_header.ts_sec = t.tv_sec; + packet_header.ts_usec = t.tv_usec; + packet_header.incl_len = offset + length; + packet_header.orig_len = offset + length; + + /***************************************************************/ + /* Now write everything to the file */ + fwrite(&packet_header, sizeof(pcaprec_hdr_t), 1, fd); + fwrite(context_header, 1, offset, fd); + fwrite(PDU, 1, length, fd); + + return 1; +} + +/* Close the PCAP file */ +inline void MAC_LTE_PCAP_Close(FILE *fd) +{ + if(fd) + fclose(fd); +} + +#endif /* UEPCAP_H */ \ No newline at end of file diff --git a/srslte/include/srslte/common/pdu.h b/srslte/include/srslte/common/pdu.h new file mode 100644 index 000000000..e882be49f --- /dev/null +++ b/srslte/include/srslte/common/pdu.h @@ -0,0 +1,339 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef MACPDU_H +#define MACPDU_H + +#include +#include "common/log.h" +#include "common/interfaces_common.h" +#include +#include + +/* MAC PDU Packing/Unpacking functions. Section 6 of 36.321 */ + + +namespace srslte { + +template +class pdu +{ +public: + + pdu(uint32_t max_subheaders_) : subheaders(max_subheaders_) { + max_subheaders = max_subheaders_; + nof_subheaders = 0; + cur_idx = -1; + pdu_len = 0; + rem_len = 0; + last_sdu_idx = -1; + pdu_is_ul = false; + buffer_tx = NULL; + total_sdu_len = 0; + } + + void fprint(FILE *stream) { + fprintf(stream, "Number of Subheaders: %d\n", nof_subheaders); + for (int i=0;i 0) { + nof_subheaders++; + next(); + return true; + } else { + return false; + } + } + + bool next() { + if (cur_idx < nof_subheaders - 1) { + cur_idx++; + return true; + } else { + return false; + } + } + + void del_subh() { + if (nof_subheaders > 0) { + nof_subheaders--; + } + if (cur_idx > 0) { + cur_idx--; + } + } + + SubH* get() { + if (cur_idx >= 0) { + return &subheaders[cur_idx]; + } else { + return NULL; + } + } + + bool is_ul() { + return pdu_is_ul; + } + + uint8_t* get_current_sdu_ptr() { + return &buffer_tx[total_sdu_len+sdu_offset_start]; + } + + void add_sdu(uint32_t sdu_sz) { + total_sdu_len += sdu_sz; + } + + // Section 6.1.2 + void parse_packet(uint8_t *ptr) { + uint8_t *init_ptr = ptr; + nof_subheaders = 0; + while(subheaders[nof_subheaders].read_subheader(&ptr)) { + nof_subheaders++; + } + nof_subheaders++; + for (int i=0;i subheaders; + uint32_t pdu_len; + uint32_t rem_len; + int cur_idx; + int nof_subheaders; + uint32_t max_subheaders; + bool pdu_is_ul; + uint8_t* buffer_tx; + uint32_t total_sdu_len; + uint32_t sdu_offset_start; + int last_sdu_idx; + +private: + + /* Prepares the PDU for parsing or writing by setting the number of subheaders to 0 and the pdu length */ + void init_(uint8_t *buffer_tx_ptr, uint32_t pdu_len_bytes, bool is_ulsch) { + nof_subheaders = 0; + pdu_len = pdu_len_bytes; + rem_len = pdu_len; + pdu_is_ul = is_ulsch; + buffer_tx = buffer_tx_ptr; + sdu_offset_start = max_subheaders*2 + 13; // Assuming worst-case 2 bytes per sdu subheader + all possible CE + total_sdu_len = 0; + last_sdu_idx = -1; + reset(); + for (int i=0;i +class subh +{ +public: + + virtual bool read_subheader(uint8_t** ptr) = 0; + virtual void read_payload(uint8_t **ptr) = 0; + virtual void write_subheader(uint8_t** ptr, bool is_last) = 0; + virtual void write_payload(uint8_t **ptr) = 0; + virtual void fprint(FILE *stream) = 0; + + pdu* parent; +private: + virtual void init() = 0; +}; + + + +class sch_subh : public subh +{ + +public: + + typedef enum { + PHR_REPORT = 26, + CRNTI = 27, + CON_RES_ID = 28, + TRUNC_BSR = 28, + TA_CMD = 29, + SHORT_BSR = 29, + DRX_CMD = 30, + LONG_BSR = 30, + PADDING = 31, + SDU = 0 + } cetype; + + // Size of MAC CEs + const static int MAC_CE_CONTRES_LEN = 6; + + // Reading functions + bool is_sdu(); + cetype ce_type(); + uint32_t size_plus_header(); + void set_payload_size(uint32_t size); + + bool read_subheader(uint8_t** ptr); + void read_payload(uint8_t **ptr); + uint32_t get_sdu_lcid(); + uint32_t get_payload_size(); + uint32_t get_header_size(bool is_last); + uint8_t* get_sdu_ptr(); + + uint16_t get_c_rnti(); + uint64_t get_con_res_id(); + uint8_t get_ta_cmd(); + float get_phr(); + int get_bsr(uint32_t buff_size[4]); + + // Writing functions + void write_subheader(uint8_t** ptr, bool is_last); + void write_payload(uint8_t **ptr); + int set_sdu(uint32_t lcid, uint32_t nof_bytes, uint8_t *payload); + int set_sdu(uint32_t lcid, uint32_t requested_bytes, read_pdu_interface *sdu_itf); + bool set_c_rnti(uint16_t crnti); + bool set_bsr(uint32_t buff_size[4], sch_subh::cetype format); + bool set_con_res_id(uint64_t con_res_id); + bool set_ta_cmd(uint8_t ta_cmd); + bool set_phr(float phr); + void set_padding(); + void set_padding(uint32_t padding_len); + + void init(); + void fprint(FILE *stream); + + +private: + static const int MAX_CE_PAYLOAD_LEN = 8; + uint32_t lcid; + int nof_bytes; + uint8_t* payload; + uint8_t w_payload_ce[8]; + bool F_bit; + uint32_t sizeof_ce(uint32_t lcid, bool is_ul); + static uint8_t buff_size_table(uint32_t buffer_size); + static uint8_t phr_report_table(float phr_value); +}; + +class sch_pdu : public pdu +{ +public: + + sch_pdu(uint32_t max_subh) : pdu(max_subh) {} + + void parse_packet(uint8_t *ptr); + uint8_t* write_packet(); + uint8_t* write_packet(srslte::log *log_h); + bool has_space_ce(uint32_t nbytes); + bool has_space_sdu(uint32_t nbytes); + int get_pdu_len(); + int rem_size(); + int get_sdu_space(); + + static uint32_t size_header_sdu(uint32_t nbytes); + bool update_space_ce(uint32_t nbytes); + bool update_space_sdu(uint32_t nbytes); + void fprint(FILE *stream); +}; + +class rar_subh : public subh +{ +public: + + static const uint32_t RAR_GRANT_LEN = 20; + + // Reading functions + bool read_subheader(uint8_t** ptr); + void read_payload(uint8_t** ptr); + uint32_t get_rapid(); + uint32_t get_ta_cmd(); + uint16_t get_temp_crnti(); + void get_sched_grant(uint8_t grant[RAR_GRANT_LEN]); + + // Writing functoins + void write_subheader(uint8_t** ptr, bool is_last); + void write_payload(uint8_t** ptr); + void set_rapid(uint32_t rapid); + void set_ta_cmd(uint32_t ta); + void set_temp_crnti(uint16_t temp_rnti); + void set_sched_grant(uint8_t grant[RAR_GRANT_LEN]); + + void init(); + void fprint(FILE *stream); + +private: + uint8_t grant[RAR_GRANT_LEN]; + uint32_t ta; + uint16_t temp_rnti; + uint32_t preamble; +}; + +class rar_pdu : public pdu +{ +public: + + rar_pdu(uint32_t max_rars = 16); + + void set_backoff(uint8_t bi); + bool has_backoff(); + uint8_t get_backoff(); + + bool write_packet(uint8_t* ptr); + void fprint(FILE *stream); + +private: + bool has_backoff_indicator; + uint8_t backoff_indicator; +}; + +} // namespace srsue + +#endif // MACPDU_H diff --git a/srslte/include/srslte/common/pdu_queue.h b/srslte/include/srslte/common/pdu_queue.h new file mode 100644 index 000000000..b5853254a --- /dev/null +++ b/srslte/include/srslte/common/pdu_queue.h @@ -0,0 +1,80 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef PDUPROC_H +#define PDUPROC_H + +#include "common/log.h" +#include "common/block_queue.h" +#include "common/buffer_pool.h" +#include "common/timers.h" +#include "common/pdu.h" + +/* Logical Channel Demultiplexing and MAC CE dissassemble */ + + +namespace srslte { + +class pdu_queue +{ +public: + class process_callback + { + public: + virtual void process_pdu(uint8_t *buff, uint32_t len) = 0; + }; + + pdu_queue(uint32_t pool_size = DEFAULT_POOL_SIZE) : pool(pool_size), callback(NULL), log_h(NULL) {} + void init(process_callback *callback, log* log_h_); + + uint8_t* request(uint32_t len); + void deallocate(uint8_t* pdu); + void push(uint8_t *ptr, uint32_t len); + + bool process_pdus(); + +private: + const static int DEFAULT_POOL_SIZE = 64; // Number of PDU buffers in total + const static int MAX_PDU_LEN = 150*1024/8; // ~ 150 Mbps + + typedef struct { + uint8_t ptr[MAX_PDU_LEN]; + uint32_t len; + } pdu_t; + + block_queue pdu_q; + buffer_pool pool; + + process_callback *callback; + log *log_h; +}; + +} // namespace srslte + +#endif // PDUPROC_H + + + diff --git a/srslte/include/srslte/common/phy_interface.h b/srslte/include/srslte/common/phy_interface.h new file mode 100644 index 000000000..108390709 --- /dev/null +++ b/srslte/include/srslte/common/phy_interface.h @@ -0,0 +1,156 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +/****************************************************************************** + * File: phy_interface.h + * Description: PHY layer interfaces provided to other layers + * Reference: + *****************************************************************************/ + +#ifndef PHY_INTERFACE_H +#define PHY_INTERFACE_H + +#include +#include +#include "srslte/srslte.h" + +#include "liblte_rrc.h" + +namespace srsue { + + +typedef struct { + bool ul_pwr_ctrl_en; + float prach_gain; + int pdsch_max_its; + bool attach_enable_64qam; + int nof_phy_threads; + + int worker_cpu_mask; + int sync_cpu_affinity; + + uint32_t nof_rx_ant; + std::string equalizer_mode; + int cqi_max; + int cqi_fixed; + float snr_ema_coeff; + std::string snr_estim_alg; + bool cfo_integer_enabled; + float cfo_correct_tol_hz; + int time_correct_period; + bool sfo_correct_disable; + std::string sss_algorithm; + float estimator_fil_w; + bool rssi_sensor_enabled; +} phy_args_t; + +/* Interface MAC -> PHY */ +class phy_interface_mac +{ +public: + /* Configure PRACH using parameters written by RRC */ + virtual void configure_prach_params() = 0; + + /* Start synchronization with strongest cell in the current carrier frequency */ + virtual void sync_start() = 0; + virtual void sync_stop() = 0; + + /* Sets a C-RNTI allowing the PHY to pregenerate signals if necessary */ + virtual void set_crnti(uint16_t rnti) = 0; + + virtual void prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm) = 0; + virtual int prach_tx_tti() = 0; + + /* Indicates the transmission of a SR signal in the next opportunity */ + virtual void sr_send() = 0; + virtual int sr_last_tx_tti() = 0; + + /* Time advance commands */ + virtual void set_timeadv_rar(uint32_t ta_cmd) = 0; + virtual void set_timeadv(uint32_t ta_cmd) = 0; + + /* Sets RAR grant payload */ + virtual void set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN]) = 0; + + /* Instruct the PHY to decode PDCCH with the CRC scrambled with given RNTI */ + virtual void pdcch_ul_search(srslte_rnti_type_t rnti_type, uint16_t rnti, int tti_start = -1, int tti_end = -1) = 0; + virtual void pdcch_dl_search(srslte_rnti_type_t rnti_type, uint16_t rnti, int tti_start = -1, int tti_end = -1) = 0; + virtual void pdcch_ul_search_reset() = 0; + virtual void pdcch_dl_search_reset() = 0; + + virtual uint32_t get_current_tti() = 0; + + virtual float get_phr() = 0; + virtual float get_pathloss_db() = 0; + +}; + +class phy_interface_rrc +{ +public: + + typedef struct { + LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT prach_cnfg; + LIBLTE_RRC_PDSCH_CONFIG_COMMON_STRUCT pdsch_cnfg; + LIBLTE_RRC_PUSCH_CONFIG_COMMON_STRUCT pusch_cnfg; + LIBLTE_RRC_PHICH_CONFIG_STRUCT phich_cnfg; + LIBLTE_RRC_PUCCH_CONFIG_COMMON_STRUCT pucch_cnfg; + LIBLTE_RRC_SRS_UL_CONFIG_COMMON_STRUCT srs_ul_cnfg; + LIBLTE_RRC_UL_POWER_CONTROL_COMMON_STRUCT ul_pwr_ctrl; + LIBLTE_RRC_TDD_CONFIG_STRUCT tdd_cnfg; + LIBLTE_RRC_ANTENNA_PORTS_COUNT_ENUM ant_info; + } phy_cfg_common_t; + + typedef struct { + LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT dedicated; + phy_cfg_common_t common; + bool enable_64qam; + } phy_cfg_t; + + virtual void get_current_cell(srslte_cell_t *cell) = 0; + virtual void get_config(phy_cfg_t *phy_cfg) = 0; + virtual void set_config(phy_cfg_t *phy_cfg) = 0; + virtual void set_config_dedicated(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *dedicated) = 0; + virtual void set_config_common(phy_cfg_common_t *common) = 0; + virtual void set_config_tdd(LIBLTE_RRC_TDD_CONFIG_STRUCT *tdd) = 0; + virtual void set_config_64qam_en(bool enable) = 0; + + /* Is the PHY downlink synchronized? */ + virtual bool status_is_sync() = 0; + + /* Configure UL using parameters written with set_param() */ + virtual void configure_ul_params(bool pregen_disabled = false) = 0; + + virtual void reset() = 0; + + virtual void resync_sfn() = 0; + +}; + +} + +#endif + diff --git a/srslte/include/srslte/common/security.h b/srslte/include/srslte/common/security.h new file mode 100644 index 000000000..1d775fb40 --- /dev/null +++ b/srslte/include/srslte/common/security.h @@ -0,0 +1,151 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef SECURITY_H +#define SECURITY_H + +/****************************************************************************** + * Common security header - wraps ciphering/integrity check algorithms. + *****************************************************************************/ + + +#include "common/common.h" + + +#define SECURITY_DIRECTION_UPLINK 0 +#define SECURITY_DIRECTION_DOWNLINK 1 + +namespace srsue{ + +typedef enum{ + CIPHERING_ALGORITHM_ID_EEA0 = 0, + CIPHERING_ALGORITHM_ID_128_EEA1, + CIPHERING_ALGORITHM_ID_128_EEA2, + CIPHERING_ALGORITHM_ID_N_ITEMS, +}CIPHERING_ALGORITHM_ID_ENUM; +static const char ciphering_algorithm_id_text[CIPHERING_ALGORITHM_ID_N_ITEMS][20] = {"EEA0", + "128-EEA1", + "128-EEA2"}; +typedef enum{ + INTEGRITY_ALGORITHM_ID_EIA0 = 0, + INTEGRITY_ALGORITHM_ID_128_EIA1, + INTEGRITY_ALGORITHM_ID_128_EIA2, + INTEGRITY_ALGORITHM_ID_N_ITEMS, +}INTEGRITY_ALGORITHM_ID_ENUM; +static const char integrity_algorithm_id_text[INTEGRITY_ALGORITHM_ID_N_ITEMS][20] = {"EIA0", + "128-EIA1", + "128-EIA2"}; + + +/****************************************************************************** + * Key Generation + *****************************************************************************/ + +uint8_t security_generate_k_asme( uint8_t *ck, + uint8_t *ik, + uint8_t *ak, + uint8_t *sqn, + uint16_t mcc, + uint16_t mnc, + uint8_t *k_asme); + +uint8_t security_generate_k_enb( uint8_t *k_asme, + uint32_t nas_count, + uint8_t *k_enb); + +uint8_t security_generate_k_nas( uint8_t *k_asme, + CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, + INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, + uint8_t *k_nas_enc, + uint8_t *k_nas_int); + +uint8_t security_generate_k_rrc( uint8_t *k_enb, + CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, + INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, + uint8_t *k_rrc_enc, + uint8_t *k_rrc_int); + +uint8_t security_generate_k_up( uint8_t *k_enb, + CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, + INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, + uint8_t *k_up_enc, + uint8_t *k_up_int); + +/****************************************************************************** + * Integrity Protection + *****************************************************************************/ + +uint8_t security_128_eia1( uint8_t *key, + uint32_t count, + uint8_t bearer, + uint8_t direction, + uint8_t *msg, + uint32_t msg_len, + uint8_t *mac); + +uint8_t security_128_eia2( uint8_t *key, + uint32_t count, + uint8_t bearer, + uint8_t direction, + uint8_t *msg, + uint32_t msg_len, + uint8_t *mac); + +/****************************************************************************** + * Authentication + *****************************************************************************/ + +uint8_t security_milenage_f1( uint8_t *k, + uint8_t *op, + uint8_t *rand, + uint8_t *sqn, + uint8_t *amf, + uint8_t *mac_a); + +uint8_t security_milenage_f1_star( uint8_t *k, + uint8_t *op, + uint8_t *rand, + uint8_t *sqn, + uint8_t *amf, + uint8_t *mac_s); + +uint8_t security_milenage_f2345( uint8_t *k, + uint8_t *op, + uint8_t *rand, + uint8_t *res, + uint8_t *ck, + uint8_t *ik, + uint8_t *ak); + +uint8_t security_milenage_f5_star( uint8_t *k, + uint8_t *op, + uint8_t *rand, + uint8_t *ak); + + +} // namespace srsue + +#endif // SECURITY_H diff --git a/srslte/include/srslte/common/snow_3g.h b/srslte/include/srslte/common/snow_3g.h new file mode 100644 index 000000000..c20e6a626 --- /dev/null +++ b/srslte/include/srslte/common/snow_3g.h @@ -0,0 +1,71 @@ +/*--------------------------------------------------------- +* snow_3g.h +* +* Adapted from ETSI/SAGE specifications: +* "Specification of the 3GPP Confidentiality and +* Integrity Algorithms UEA2 & UIA2. +* Document 1: UEA2 and UIA2 Specification" +* "Specification of the 3GPP Confidentiality +* and Integrity Algorithms UEA2 & UIA2. +* Document 2: SNOW 3G Specification" +*---------------------------------------------------------*/ + +#include +#include +#include +#include + +typedef unsigned char u8; +typedef unsigned int u32; +typedef unsigned long long u64; + +/* Initialization. +* Input k[4]: Four 32-bit words making up 128-bit key. +* Input IV[4]: Four 32-bit words making 128-bit initialization variable. +* Output: All the LFSRs and FSM are initialized for key generation. +* See Section 4.1. +*/ + +void snow3g_initialize(u32 k[4], u32 IV[4]); + +/* Generation of Keystream. +* input n: number of 32-bit words of keystream. +* input z: space for the generated keystream, assumes +* memory is allocated already. +* output: generated keystream which is filled in z +* See section 4.2. +*/ + +void snow3g_generate_keystream(u32 n, u32 *z); + +/* f8. +* Input key: 128 bit Confidentiality Key. +* Input count:32-bit Count, Frame dependent input. +* Input bearer: 5-bit Bearer identity (in the LSB side). +* Input dir:1 bit, direction of transmission. +* Input data: length number of bits, input bit stream. +* Input length: 32 bit Length, i.e., the number of bits to be encrypted or +* decrypted. +* Output data: Output bit stream. Assumes data is suitably memory +* allocated. +* Encrypts/decrypts blocks of data between 1 and 2^32 bits in length as +* defined in Section 3. +*/ + +void snow3g_f8( u8 *key, u32 count, u32 bearer, u32 dir, \ + u8 *data, u32 length ); + +/* f9. +* Input key: 128 bit Integrity Key. +* Input count:32-bit Count, Frame dependent input. +* Input fresh: 32-bit Random number. +* Input dir:1 bit, direction of transmission (in the LSB). +* Input data: length number of bits, input bit stream. +* Input length: 64 bit Length, i.e., the number of bits to be MAC'd. +* Output : 32 bit block used as MAC +* Generates 32-bit MAC using UIA2 algorithm as defined in Section 4. +*/ + +u8* snow3g_f9( u8* key, u32 count, u32 fresh, u32 dir, \ + u8 *data, u64 length); + diff --git a/srslte/include/srslte/common/task_dispatcher.h b/srslte/include/srslte/common/task_dispatcher.h new file mode 100644 index 000000000..9c6eb9665 --- /dev/null +++ b/srslte/include/srslte/common/task_dispatcher.h @@ -0,0 +1,61 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +/****************************************************************************** + * File: task_dispatcher.h + * Description: + * Reference: + *****************************************************************************/ + +#ifndef TASK_DISPATCHER_H +#define TASK_DISPATCHER_H + +#include +#include +#include +#include +#include "common/threads.h" + +namespace srslte { + +class task_dispatcher : public thread +{ +public: + task_dispatcher(uint32_t max_pending_tasks); + ~task_dispatcher(); + void push_task(uint32_t task_code); + virtual void run_task(uint32_t task_code) = 0; +private: + std::queue pending_tasks; + void run_thread(); + pthread_mutex_t mutex; + pthread_cond_t cvar; + bool running; +}; + +} // namespace srsue + +#endif // TASK_DISPATCHER_H diff --git a/srslte/include/srslte/common/thread_pool.h b/srslte/include/srslte/common/thread_pool.h new file mode 100644 index 000000000..bde8a1d3d --- /dev/null +++ b/srslte/include/srslte/common/thread_pool.h @@ -0,0 +1,105 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +/****************************************************************************** + * File: thread_pool.h + * Description: Implements a pool of threads. Pending tasks to execute are + * identified by a pointer. + * Reference: + *****************************************************************************/ + +#ifndef THREAD_POOL_H +#define THREAD_POOL_H + +#include +#include +#include +#include + +#include "common/threads.h" + +namespace srslte { + +class thread_pool +{ +public: + + class worker : public thread + { + public: + void setup(uint32_t id, thread_pool *parent, uint32_t prio=0, uint32_t mask = 255); + void stop(); + uint32_t get_id(); + void release(); + protected: + virtual void work_imp() = 0; + private: + uint32_t my_id; + thread_pool *my_parent; + bool running; + void run_thread(); + void wait_to_start(); + void finished(); + }; + + + thread_pool(uint32_t nof_workers); + void init_worker(uint32_t id, worker*, uint32_t prio = 0, uint32_t mask = 255); + void stop(); + worker* wait_worker(); + worker* wait_worker(uint32_t tti); + worker* wait_worker_nb(uint32_t tti); + void start_worker(worker*); + void start_worker(uint32_t id); + worker* get_worker(uint32_t id); + uint32_t get_nof_workers(); + + +private: + + bool find_finished_worker(uint32_t tti, uint32_t *id); + + typedef enum { + IDLE, + START_WORK, + WORKER_READY, + WORKING + }worker_status; + + std::vector workers; + uint32_t nof_workers; + uint32_t max_workers; + bool running; + pthread_cond_t cvar_queue; + pthread_mutex_t mutex_queue; + std::vector status; + std::vector cvar; + std::vector mutex; + std::stack available_workers; +}; +} + +#endif diff --git a/srslte/include/srslte/common/threads.h b/srslte/include/srslte/common/threads.h new file mode 100644 index 000000000..a8807ba9b --- /dev/null +++ b/srslte/include/srslte/common/threads.h @@ -0,0 +1,151 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus + extern "C" { +#endif // __cplusplus + + bool threads_new_rt(pthread_t *thread, void *(*start_routine) (void*), void *arg); + bool threads_new_rt_prio(pthread_t *thread, void *(*start_routine) (void*), void *arg, int prio_offset); + bool threads_new_rt_cpu(pthread_t *thread, void *(*start_routine) (void*), void *arg, int cpu, int prio_offset); + bool threads_new_rt_mask(pthread_t *thread, void *(*start_routine) (void*), void *arg, int mask, int prio_offset); + void threads_print_self(); + +#ifdef __cplusplus +} + +#ifndef THREADS_ +#define THREADS_ + +class thread +{ +public: + bool start(int prio = -1) { + return threads_new_rt_prio(&_thread, thread_function_entry, this, prio); + } + bool start_cpu(int prio, int cpu) { + return threads_new_rt_cpu(&_thread, thread_function_entry, this, cpu, prio); + } + bool start_cpu_mask(int prio, int mask){ + return threads_new_rt_mask(&_thread, thread_function_entry, this, mask, prio); +} + void print_priority() { + threads_print_self(); + } + void wait_thread_finish() { + pthread_join(_thread, NULL); + } + void thread_cancel() { + pthread_cancel(_thread); + } +protected: + virtual void run_thread() = 0; +private: + static void *thread_function_entry(void *_this) { ((thread*) _this)->run_thread(); return NULL; } + pthread_t _thread; +}; + +class periodic_thread : public thread +{ +public: + void start_periodic(int period_us_, int priority = -1) { + period_us = period_us_; + start(priority); + } +protected: + virtual void run_period() = 0; +private: + int wakeups_missed; + int timer_fd; + int period_us; + void run_thread() { + if (make_periodic()) { + return; + } + while(1) { + run_period(); + wait_period(); + } + } + int make_periodic() { + int ret = -1; + unsigned int ns; + unsigned int sec; + struct itimerspec itval; + + /* Create the timer */ + ret = timerfd_create (CLOCK_MONOTONIC, 0); + wakeups_missed = 0; + timer_fd = ret; + if (ret > 0) { + /* Make the timer periodic */ + sec = period_us/1e6; + ns = (period_us - (sec * 1000000)) * 1000; + itval.it_interval.tv_sec = sec; + itval.it_interval.tv_nsec = ns; + itval.it_value.tv_sec = sec; + itval.it_value.tv_nsec = ns; + ret = timerfd_settime (timer_fd, 0, &itval, NULL); + if (ret < 0) { + perror("timerfd_settime"); + } + } else { + perror("timerfd_create"); + } + return ret; + } + void wait_period() { + unsigned long long missed; + int ret; + + /* Wait for the next timer event. If we have missed any the + number is written to "missed" */ + ret = read (timer_fd, &missed, sizeof (missed)); + if (ret == -1) + { + perror ("read timer"); + return; + } + + /* "missed" should always be >= 1, but just to be sure, check it is not 0 anyway */ + if (missed > 0) { + wakeups_missed += (missed - 1); + } + } +}; + + + +#endif // THREADS_ + +#endif // __cplusplus + diff --git a/srslte/include/srslte/common/timeout.h b/srslte/include/srslte/common/timeout.h new file mode 100644 index 000000000..2c9560729 --- /dev/null +++ b/srslte/include/srslte/common/timeout.h @@ -0,0 +1,124 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +/****************************************************************************** + * File: timeout.h + * Description: Millisecond resolution timeouts. Uses a dedicated thread to + * call an optional callback function upon timeout expiry. + * Reference: + *****************************************************************************/ + +#ifndef TIMEOUT_H +#define TIMEOUT_H + +#include +#include +#include +#include +#include "srslte/srslte.h" + +namespace srslte { + +class timeout_callback +{ + public: + virtual void timeout_expired(uint32_t timeout_id) = 0; +}; + +class timeout +{ +public: + timeout():running(false),callback(NULL), thread(0), timeout_id(0) {} + ~timeout() + { + if(running && callback) + pthread_join(thread, NULL); + } + void start(int duration_msec_, uint32_t timeout_id_=0,timeout_callback *callback_=NULL) + { + if(duration_msec_ < 0) + return; + reset(); + gettimeofday(&start_time[1], NULL); + duration_msec = duration_msec_; + running = true; + timeout_id = timeout_id_; + callback = callback_; + if(callback) + pthread_create(&thread, NULL, &thread_start, this); + } + void reset() + { + if(callback) + pthread_cancel(thread); + running = false; + } + static void* thread_start(void *t_) + { + timeout *t = (timeout*)t_; + t->thread_func(); + return NULL; + } + void thread_func() + { + + // substract time elapsed until now from timer duration + gettimeofday(&start_time[2], NULL); + get_time_interval(start_time); + + int32_t usec = duration_msec*1000-start_time[0].tv_usec; + if(usec > 0) + usleep(usec); + if(callback && running) + callback->timeout_expired(timeout_id); + } + bool expired() + { + if(running) { + gettimeofday(&start_time[2], NULL); + get_time_interval(start_time); + return start_time[0].tv_usec > duration_msec*1000; + } else { + return false; + } + } + bool is_running() + { + return running; + } + +private: + struct timeval start_time[3]; + pthread_t thread; + uint32_t timeout_id; + timeout_callback *callback; + bool running; + int duration_msec; +}; + +} // namespace srsue + +#endif // TIMEOUT_H diff --git a/srslte/include/srslte/common/timers.h b/srslte/include/srslte/common/timers.h new file mode 100644 index 000000000..bd77f0b19 --- /dev/null +++ b/srslte/include/srslte/common/timers.h @@ -0,0 +1,151 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + + +/****************************************************************************** + * File: timers.h + * Description: Manually incremented timers. Call a callback function upon + * expiry. + * Reference: + *****************************************************************************/ + +#ifndef TIMERS_H +#define TIMERS_H + +#include +#include +#include +#include + +namespace srslte { + +class timer_callback +{ + public: + virtual void timer_expired(uint32_t timer_id) = 0; +}; + +class timers +{ +public: + class timer + { + public: + timer(uint32_t id_=0) {id = id_; counter = 0; timeout = 0; running = false; callback = NULL; } + void set(timer_callback *callback_, uint32_t timeout_) { + callback = callback_; + timeout = timeout_; + reset(); + } + bool is_running() { + return (counter < timeout) && running; + } + bool is_expired() { + return callback && (counter >= timeout || !running); + } + uint32_t get_timeout() { + return timeout; + } + void reset() { + counter = 0; + } + void step() { + if (running) { + counter++; + if (is_expired()) { + running = false; + if (callback) { + callback->timer_expired(id); + } + } + } + } + void stop() { + running = false; + } + void run() { + running = true; + } + uint32_t id; + private: + timer_callback *callback; + uint32_t timeout; + uint32_t counter; + bool running; + }; + + timers(uint32_t nof_timers_) : timer_list(nof_timers_) { + nof_timers = nof_timers_; + next_timer = 0; + for (uint32_t i=0;istep(); + } + } + void stop_all() { + for (int i=0;istop(); + } + } + void run_all() { + for (int i=0;irun(); + } + } + void reset_all() { + for (int i=0;ireset(); + } + } + timer *get(uint32_t i) { + if (i < nof_timers) { + return &timer_list[i]; + } else { + printf("Error accessing invalid timer %d (Only %d timers available)\n", i, nof_timers); + return NULL; + } + } + uint32_t get_unique_id() { + if (next_timer == nof_timers){ + printf("No more unique timer ids (Only %d timers available)\n", nof_timers); + next_timer = 0; + } + return next_timer++; + } +private: + uint32_t nof_timers; + uint32_t next_timer; + std::vector timer_list; +}; + +} // namespace srslte + +#endif // TIMERS_H diff --git a/srslte/include/srslte/common/trace.h b/srslte/include/srslte/common/trace.h new file mode 100644 index 000000000..64d55e460 --- /dev/null +++ b/srslte/include/srslte/common/trace.h @@ -0,0 +1,101 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +/****************************************************************************** + * File: trace.h + * Description: + * Reference: + *****************************************************************************/ + +#ifndef TRACE_H +#define TRACE_H + +#include +#include +#include + +namespace srslte { + +template +class trace +{ +public: + + trace(uint32_t nof_elems_) : tti(nof_elems_), data(nof_elems_) { + rpm=0; + nof_elems=nof_elems_; + wrapped = false; + }; + void push_cur_time_us(uint32_t cur_tti) { + struct timeval t; + gettimeofday(&t, NULL); + elemType us = t.tv_sec*1e6+t.tv_usec; + push(cur_tti, us); + } + void push(uint32_t value_tti, elemType value) { + tti[rpm] = value_tti; + data[rpm] = value; + rpm++; + if (rpm >= nof_elems) { + rpm = 0; + wrapped = true; + } + } + bool writeToBinary(std::string filename) { + FILE *f = fopen(filename.c_str(), "w"); + if (f != NULL) { + uint32_t st=wrapped?(rpm+1):0; + do { + writeToBinaryValue(f, st++); + if (st >= nof_elems) { + st=0; + } + } while(st!=rpm); + fclose(f); + return true; + } else { + perror("fopen"); + return false; + } + } + +private: + std::vector tti; + std::vector data; + uint32_t rpm; + uint32_t nof_elems; + bool wrapped; + + void writeToBinaryValue(FILE *f, uint32_t idx) { + fwrite(&tti[idx], 1, sizeof(uint32_t), f); + fwrite(&data[idx], 1, sizeof(elemType), f); + } + +}; + +} // namespace srslte + +#endif // TRACE_H diff --git a/srslte/include/srslte/common/tti_sync.h b/srslte/include/srslte/common/tti_sync.h new file mode 100644 index 000000000..23061ea2d --- /dev/null +++ b/srslte/include/srslte/common/tti_sync.h @@ -0,0 +1,78 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +/****************************************************************************** + * File: tti_synch.h + * Description: Interface used for PHY-MAC synchronization + * (producer-consumer model). The consumer waits while its + * counter is lower than the producer counter. + * The PHY is the consumer. The MAC is the producer. + * Reference: + *****************************************************************************/ + +#ifndef TTISYNC_H +#define TTISYNC_H + +#include + +namespace srslte { + +class tti_sync +{ + public: + tti_sync(uint32_t modulus_) + { + modulus = modulus_; + increment = 1; + init_counters(0); + } + virtual void increase() = 0; + virtual void resync() = 0; + virtual uint32_t wait() = 0; + virtual void set_producer_cntr(uint32_t) = 0; + uint32_t get_producer_cntr() { return producer_cntr; } + uint32_t get_consumer_cntr() { return consumer_cntr; } + void set_increment(uint32_t increment_) { + increment = increment_; + } + protected: + void increase_producer() { producer_cntr = (producer_cntr + increment)%modulus; } + void increase_consumer() { consumer_cntr = (consumer_cntr + increment)%modulus; } + bool wait_condition() { return producer_cntr == consumer_cntr; } + void init_counters(uint32_t val) + { + consumer_cntr = val; + producer_cntr = val; + } + uint32_t increment; + uint32_t modulus; + uint32_t producer_cntr; + uint32_t consumer_cntr; +}; + +} // namespace srsue + +#endif // TTISYNC_H diff --git a/srslte/include/srslte/common/tti_sync_cv.h b/srslte/include/srslte/common/tti_sync_cv.h new file mode 100644 index 000000000..68fc6df0b --- /dev/null +++ b/srslte/include/srslte/common/tti_sync_cv.h @@ -0,0 +1,58 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +/****************************************************************************** + * File: tti_synch_cv.h + * Description: Implements tti_sync interface with condition variables. + * Reference: + *****************************************************************************/ + +#ifndef TTISYNC_CV_H +#define TTISYNC_CV_H + +#include +#include "common/tti_sync.h" + +namespace srslte { + +class tti_sync_cv : public tti_sync +{ + public: + tti_sync_cv(uint32_t modulus = 10240); + ~tti_sync_cv(); + void increase(); + uint32_t wait(); + void resync(); + void set_producer_cntr(uint32_t producer_cntr); + + private: + pthread_cond_t cond; + pthread_mutex_t mutex; +}; + +} // namespace srsue + +#endif // TTISYNC_CV_H diff --git a/srslte/lib/common/CMakeLists.txt b/srslte/lib/common/CMakeLists.txt new file mode 100644 index 000000000..037a6351e --- /dev/null +++ b/srslte/lib/common/CMakeLists.txt @@ -0,0 +1,25 @@ +# +# Copyright 2013-2015 Software Radio Systems Limited +# +# This file is part of the srsLTE library. +# +# srsLTE is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# srsLTE 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 Affero General Public License for more details. +# +# A copy of the GNU Affero General Public License can be found in +# the LICENSE file in the top-level directory of this distribution +# and at http://www.gnu.org/licenses/. +# + +file(GLOB CXX_SOURCES "*.cc") +file(GLOB C_SOURCES "*.c") +add_library(srslte_common SHARED ${C_SOURCES} ${CXX_SOURCES}) +INSTALL(TARGETS srslte_common DESTINATION ${LIBRARY_DIR}) +SRSLTE_SET_PIC(srslte_common) diff --git a/srslte/lib/common/buffer_pool.cc b/srslte/lib/common/buffer_pool.cc new file mode 100644 index 000000000..306184b38 --- /dev/null +++ b/srslte/lib/common/buffer_pool.cc @@ -0,0 +1,65 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + + +#include +#include "common/buffer_pool.h" +#include +#include + +namespace srslte{ + +byte_buffer_pool *byte_buffer_pool::instance = NULL; +pthread_mutex_t instance_mutex = PTHREAD_MUTEX_INITIALIZER; + +byte_buffer_pool* byte_buffer_pool::get_instance(void) +{ + pthread_mutex_lock(&instance_mutex); + if(NULL == instance) + instance = new byte_buffer_pool(); + pthread_mutex_unlock(&instance_mutex); + return instance; +} + +void byte_buffer_pool::cleanup(void) +{ + pthread_mutex_lock(&instance_mutex); + if(NULL != instance) + { + delete instance; + instance = NULL; + } + pthread_mutex_unlock(&instance_mutex); +} + + + + + + + + +} // namespace srsue diff --git a/srslte/lib/common/log_filter.cc b/srslte/lib/common/log_filter.cc new file mode 100644 index 000000000..052f4b051 --- /dev/null +++ b/srslte/lib/common/log_filter.cc @@ -0,0 +1,316 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "common/log_filter.h" + +namespace srslte{ + +log_filter::log_filter() +{ + do_tti = false; +} + +log_filter::log_filter(std::string layer, logger *logger_, bool tti) +{ + init(layer, logger_, tti); +} + +void log_filter::init(std::string layer, logger *logger_, bool tti) +{ + service_name = layer; + logger_h = logger_; + do_tti = tti; +} + +void log_filter::all_log(srslte::LOG_LEVEL_ENUM level, + uint32_t tti, + char *msg) +{ + if(logger_h) { + std::stringstream ss; + + ss << now_time() << " "; + ss << "[" <log(s_ptr); + } +} + +void log_filter::all_log(srslte::LOG_LEVEL_ENUM level, + uint32_t tti, + char *msg, + uint8_t *hex, + int size) +{ + if(logger_h) { + std::stringstream ss; + + ss << now_time() << " "; + ss << "[" < 0) { + ss << hex_string(hex, size); + } + str_ptr s_ptr(new std::string(ss.str())); + logger_h->log(s_ptr); + } +} + +void log_filter::all_log_line(srslte::LOG_LEVEL_ENUM level, + uint32_t tti, + std::string file, + int line, + char *msg) +{ + if(logger_h) { + std::stringstream ss; + + ss << now_time() << " "; + ss << "[" <log(s_ptr); + } +} + +void log_filter::console(std::string message, ...) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + printf("%s",args_msg); // Print directly to stdout + va_end(args); + free(args_msg); +} + +void log_filter::error(std::string message, ...) { + if (level >= LOG_LEVEL_ERROR) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + all_log(LOG_LEVEL_ERROR, tti, args_msg); + va_end(args); + free(args_msg); + } +} +void log_filter::warning(std::string message, ...) { + if (level >= LOG_LEVEL_WARNING) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + all_log(LOG_LEVEL_WARNING, tti, args_msg); + va_end(args); + free(args_msg); + } +} +void log_filter::info(std::string message, ...) { + if (level >= LOG_LEVEL_INFO) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + all_log(LOG_LEVEL_INFO, tti, args_msg); + va_end(args); + free(args_msg); + } +} +void log_filter::debug(std::string message, ...) { + if (level >= LOG_LEVEL_DEBUG) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + all_log(LOG_LEVEL_DEBUG, tti, args_msg); + va_end(args); + free(args_msg); + } +} + +void log_filter::error_hex(uint8_t *hex, int size, std::string message, ...) { + if (level >= LOG_LEVEL_ERROR) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + all_log(LOG_LEVEL_ERROR, tti, args_msg, hex, size); + va_end(args); + free(args_msg); + } +} +void log_filter::warning_hex(uint8_t *hex, int size, std::string message, ...) { + if (level >= LOG_LEVEL_WARNING) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + all_log(LOG_LEVEL_WARNING, tti, args_msg, hex, size); + va_end(args); + free(args_msg); + } +} +void log_filter::info_hex(uint8_t *hex, int size, std::string message, ...) { + if (level >= LOG_LEVEL_INFO) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + all_log(LOG_LEVEL_INFO, tti, args_msg, hex, size); + va_end(args); + free(args_msg); + } +} +void log_filter::debug_hex(uint8_t *hex, int size, std::string message, ...) { + if (level >= LOG_LEVEL_DEBUG) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + all_log(LOG_LEVEL_DEBUG, tti, args_msg, hex, size); + va_end(args); + free(args_msg); + } +} + +void log_filter::error_line(std::string file, int line, std::string message, ...) +{ + if (level >= LOG_LEVEL_ERROR) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + all_log_line(LOG_LEVEL_ERROR, tti, file, line, args_msg); + va_end(args); + free(args_msg); + } +} + +void log_filter::warning_line(std::string file, int line, std::string message, ...) +{ + if (level >= LOG_LEVEL_WARNING) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + all_log_line(LOG_LEVEL_WARNING, tti, file, line, args_msg); + va_end(args); + free(args_msg); + } +} + +void log_filter::info_line(std::string file, int line, std::string message, ...) +{ + if (level >= LOG_LEVEL_INFO) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + all_log_line(LOG_LEVEL_INFO, tti, file, line, args_msg); + va_end(args); + free(args_msg); + } +} + +void log_filter::debug_line(std::string file, int line, std::string message, ...) +{ + if (level >= LOG_LEVEL_DEBUG) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + all_log_line(LOG_LEVEL_DEBUG, tti, file, line, args_msg); + va_end(args); + free(args_msg); + } +} + + + +std::string log_filter::now_time() +{ + struct timeval rawtime; + struct tm * timeinfo; + char buffer[64]; + char us[16]; + + gettimeofday(&rawtime, NULL); + timeinfo = localtime(&rawtime.tv_sec); + + strftime(buffer,64,"%H:%M:%S",timeinfo); + strcat(buffer,"."); + snprintf(us,16,"%06ld",rawtime.tv_usec); + strcat(buffer,us); + + return std::string(buffer); +} + +std::string log_filter::hex_string(uint8_t *hex, int size) +{ + std::stringstream ss; + int c = 0; + + ss << std::hex << std::setfill('0'); + if(hex_limit >= 0) { + size = (size > hex_limit) ? hex_limit : size; + } + while(c < size) { + ss << " " << std::setw(4) << static_cast(c) << ": "; + int tmp = (size-c < 16) ? size-c : 16; + for(int i=0;i(hex[c++]) << " "; + } + ss << "\n"; + } + return ss.str(); +} + +} // namespace srsue diff --git a/srslte/lib/common/log_stdout.cc b/srslte/lib/common/log_stdout.cc new file mode 100644 index 000000000..6b46b4880 --- /dev/null +++ b/srslte/lib/common/log_stdout.cc @@ -0,0 +1,290 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common/log_stdout.h" + + +using namespace std; + +namespace srslte { + +void log_stdout::all_log(srslte::LOG_LEVEL_ENUM level, + uint32_t tti, + char *msg) +{ + std::stringstream ss; + + ss << now_time() << " "; + ss << "[" < 0); + printf("%s",args_msg); // Print directly to stdout + va_end(args); + free(args_msg); +} + +void log_stdout::error(std::string message, ...) { + if (level >= LOG_LEVEL_ERROR) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0); + all_log(LOG_LEVEL_ERROR, tti, args_msg); + va_end(args); + free(args_msg); + } +} +void log_stdout::warning(std::string message, ...) { + if (level >= LOG_LEVEL_WARNING) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0); + all_log(LOG_LEVEL_WARNING, tti, args_msg); + va_end(args); + free(args_msg); + } +} +void log_stdout::info(std::string message, ...) { + if (level >= LOG_LEVEL_INFO) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0); + all_log(LOG_LEVEL_INFO, tti, args_msg); + va_end(args); + free(args_msg); + } +} +void log_stdout::debug(std::string message, ...) { + if (level >= LOG_LEVEL_DEBUG) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0); + all_log(LOG_LEVEL_DEBUG, tti, args_msg); + va_end(args); + free(args_msg); + } +} + +void log_stdout::error_hex(uint8_t *hex, int size, std::string message, ...) { + if (level >= LOG_LEVEL_ERROR) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0); + all_log(LOG_LEVEL_ERROR, tti, args_msg, hex, size); + va_end(args); + free(args_msg); + } +} +void log_stdout::warning_hex(uint8_t *hex, int size, std::string message, ...) { + if (level >= LOG_LEVEL_WARNING) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0); + all_log(LOG_LEVEL_WARNING, tti, args_msg, hex, size); + va_end(args); + free(args_msg); + } +} +void log_stdout::info_hex(uint8_t *hex, int size, std::string message, ...) { + if (level >= LOG_LEVEL_INFO) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0); + all_log(LOG_LEVEL_INFO, tti, args_msg, hex, size); + va_end(args); + free(args_msg); + } +} +void log_stdout::debug_hex(uint8_t *hex, int size, std::string message, ...) { + if (level >= LOG_LEVEL_DEBUG) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0); + all_log(LOG_LEVEL_DEBUG, tti, args_msg, hex, size); + va_end(args); + free(args_msg); + } +} + +void log_stdout::error_line(std::string file, int line, std::string message, ...) +{ + if (level >= LOG_LEVEL_ERROR) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0); + all_log_line(LOG_LEVEL_ERROR, tti, file, line, args_msg); + va_end(args); + free(args_msg); + } +} + +void log_stdout::warning_line(std::string file, int line, std::string message, ...) +{ + if (level >= LOG_LEVEL_WARNING) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0); + all_log_line(LOG_LEVEL_WARNING, tti, file, line, args_msg); + va_end(args); + free(args_msg); + } +} + +void log_stdout::info_line(std::string file, int line, std::string message, ...) +{ + if (level >= LOG_LEVEL_INFO) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0); + all_log_line(LOG_LEVEL_INFO, tti, file, line, args_msg); + va_end(args); + free(args_msg); + } +} + +void log_stdout::debug_line(std::string file, int line, std::string message, ...) +{ + if (level >= LOG_LEVEL_DEBUG) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0); + all_log_line(LOG_LEVEL_DEBUG, tti, file, line, args_msg); + va_end(args); + free(args_msg); + } +} + + + +std::string log_stdout::now_time() +{ + struct timeval rawtime; + struct tm * timeinfo; + char buffer[64]; + char us[16]; + + gettimeofday(&rawtime, NULL); + timeinfo = localtime(&rawtime.tv_sec); + + strftime(buffer,64,"%H:%M:%S",timeinfo); + strcat(buffer,"."); + snprintf(us,16,"%ld",rawtime.tv_usec); + strcat(buffer,us); + + return std::string(buffer); +} + +std::string log_stdout::hex_string(uint8_t *hex, int size) +{ + std::stringstream ss; + int c = 0; + + ss << std::hex << std::setfill('0'); + if(hex_limit >= 0) { + size = (size > hex_limit) ? hex_limit : size; + } + while(c < size) { + ss << " " << std::setw(4) << static_cast(c) << ": "; + int tmp = (size-c < 16) ? size-c : 16; + for(int i=0;i(hex[c++]) << " "; + } + ss << "\n"; + } + return ss.str(); +} + +} + + diff --git a/srslte/lib/common/logger.cc b/srslte/lib/common/logger.cc new file mode 100644 index 000000000..bf6ab8e63 --- /dev/null +++ b/srslte/lib/common/logger.cc @@ -0,0 +1,103 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + + +#define LOG_BUFFER_SIZE 1024*32 + +#include "common/logger.h" + +using namespace std; + +namespace srslte{ + +logger::logger() + :inited(false) + ,not_done(true) +{} + +logger::~logger() { + not_done = false; + log("Closing log"); + if(inited) { + wait_thread_finish(); + flush(); + fclose(logfile); + } +} + +void logger::init(std::string file) { + pthread_mutex_init(&mutex, NULL); + pthread_cond_init(¬_empty, NULL); + pthread_cond_init(¬_full, NULL); + filename = file; + logfile = fopen(filename.c_str(), "w"); + if(logfile==NULL) { + printf("Error: could not create log file, no messages will be logged"); + } + start(); + inited = true; +} + +void logger::log(const char *msg) { + str_ptr s_ptr(new std::string(msg)); + log(s_ptr); +} + +void logger::log(str_ptr msg) { + pthread_mutex_lock(&mutex); + buffer.push_back(msg); + pthread_cond_signal(¬_empty); + pthread_mutex_unlock(&mutex); +} + +void logger::run_thread() { + while(not_done) { + pthread_mutex_lock(&mutex); + while(buffer.empty()) { + pthread_cond_wait(¬_empty, &mutex); + } + str_ptr s = buffer.front(); + pthread_cond_signal(¬_full); + if(logfile) + fprintf(logfile, "%s", s->c_str()); + delete s; + buffer.pop_front(); + pthread_mutex_unlock(&mutex); + } +} + +void logger::flush() { + std::deque::iterator it; + for(it=buffer.begin();it!=buffer.end();it++) + { + str_ptr s = *it; + if(logfile) + fprintf(logfile, "%s", s->c_str()); + delete s; + } +} + +} // namespace srsue diff --git a/srslte/lib/common/mac_pcap.cc b/srslte/lib/common/mac_pcap.cc new file mode 100644 index 000000000..9651de0d5 --- /dev/null +++ b/srslte/lib/common/mac_pcap.cc @@ -0,0 +1,99 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + + +#include +#include "srslte/srslte.h" +#include "common/pcap.h" +#include "common/mac_pcap.h" + + + +namespace srslte { + +void mac_pcap::enable(bool en) +{ + enable_write = true; +} +void mac_pcap::open(const char* filename, uint32_t ue_id) +{ + pcap_file = MAC_LTE_PCAP_Open(filename); + ue_id = ue_id; + enable_write = true; +} +void mac_pcap::close() +{ + fprintf(stdout, "Saving PCAP file\n"); + MAC_LTE_PCAP_Close(pcap_file); +} + +void mac_pcap::pack_and_write(uint8_t* pdu, uint32_t pdu_len_bytes, uint32_t reTX, bool crc_ok, uint32_t tti, + uint16_t crnti, uint8_t direction, uint8_t rnti_type) +{ + if (enable_write) { + MAC_Context_Info_t context = + { + FDD_RADIO, direction, rnti_type, + crnti, /* RNTI */ + ue_id, /* UEId */ + reTX, /* Retx */ + crc_ok, /* CRC Stsatus (i.e. OK) */ + tti/10, /* Sysframe number */ + tti%10 /* Subframe number */ + }; + if (pdu) { + MAC_LTE_PCAP_WritePDU(pcap_file, &context, pdu, pdu_len_bytes); + } + } +} + +void mac_pcap::write_dl_crnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, bool crc_ok, uint32_t tti) +{ + pack_and_write(pdu, pdu_len_bytes, 0, crc_ok, tti, rnti, DIRECTION_DOWNLINK, C_RNTI); +} +void mac_pcap::write_dl_ranti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, bool crc_ok, uint32_t tti) +{ + pack_and_write(pdu, pdu_len_bytes, 0, crc_ok, tti, rnti, DIRECTION_DOWNLINK, RA_RNTI); +} +void mac_pcap::write_ul_crnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint32_t reTX, uint32_t tti) +{ + pack_and_write(pdu, pdu_len_bytes, reTX, true, tti, rnti, DIRECTION_UPLINK, C_RNTI); +} +void mac_pcap::write_dl_bch(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti) +{ + pack_and_write(pdu, pdu_len_bytes, 0, crc_ok, tti, 0, DIRECTION_DOWNLINK, NO_RNTI); +} +void mac_pcap::write_dl_pch(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti) +{ + pack_and_write(pdu, pdu_len_bytes, 0, crc_ok, tti, SRSLTE_PRNTI, DIRECTION_DOWNLINK, P_RNTI); +} +void mac_pcap::write_dl_sirnti(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti) +{ + pack_and_write(pdu, pdu_len_bytes, 0, crc_ok, tti, SRSLTE_SIRNTI, DIRECTION_DOWNLINK, SI_RNTI); +} + + +} diff --git a/srslte/lib/common/pdu.cc b/srslte/lib/common/pdu.cc new file mode 100644 index 000000000..df498d313 --- /dev/null +++ b/srslte/lib/common/pdu.cc @@ -0,0 +1,1000 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include + +#include "common/pdu.h" +#include "srslte/srslte.h" + +// Table 6.1.3.1-1 Buffer size levels for BSR +static uint32_t btable[64] = { + 0, 5, 10, 12, 14, 17, 19, 22, 26, 31, 36, 42, 49, 57, 67, 78, 91, 107, 125, 146, 171, 200, 234, 274, 321, 376, 440, 515, 603, 706, 826, 967, 1132, + 1326, 1552, 1817, 2127, 2490, 2915, 3413, 3995, 4667, 5476, 6411, 7505, 8787, 10287, 12043, 14099, 16507, 19325, 22624, 26487, 31009, 36304, + 42502, 49759, 58255, 68201, 79846, 93479, 109439, 128125, 150000}; + + + +namespace srslte { + + +void sch_pdu::fprint(FILE* stream) +{ + fprintf(stream, "MAC SDU for UL/DL-SCH. "); + pdu::fprint(stream); +} + +void sch_subh::fprint(FILE* stream) +{ + if (is_sdu()) { + fprintf(stream, "SDU LCHID=%d, SDU nof_bytes=%d\n", lcid, nof_bytes); + } else { + if (parent->is_ul()) { + switch(lcid) { + case CRNTI: + fprintf(stream, "C-RNTI CE\n"); + break; + case PHR_REPORT: + fprintf(stream, "PHR\n"); + break; + case TRUNC_BSR: + fprintf(stream, "Truncated BSR CE\n"); + break; + case SHORT_BSR: + fprintf(stream, "Short BSR CE\n"); + break; + case LONG_BSR: + fprintf(stream, "Long BSR CE\n"); + break; + case PADDING: + fprintf(stream, "PADDING\n"); + } + } else { + switch(lcid) { + case CON_RES_ID: + fprintf(stream, "Contention Resolution ID CE: 0x%lx\n", get_con_res_id()); + break; + case TA_CMD: + fprintf(stream, "Time Advance Command CE: %d\n", get_ta_cmd()); + break; + case DRX_CMD: + fprintf(stream, "DRX Command CE: Not implemented\n"); + break; + case PADDING: + fprintf(stream, "PADDING\n"); + } + } + } +} + +void sch_pdu::parse_packet(uint8_t *ptr) +{ + + pdu::parse_packet(ptr); + + // Correct size for last SDU + if (nof_subheaders > 0) { + uint32_t read_len = 0; + for (int i=0;i= 0) { + subheaders[nof_subheaders-1].set_payload_size(pdu_len-read_len-1); + } else { + fprintf(stderr,"Reading MAC PDU: negative payload for last subheader\n"); + } + } +} + +uint8_t* sch_pdu::write_packet() { + return write_packet(NULL); +} + +/* Writes the MAC PDU in the packet, including the MAC headers and CE payload. Section 6.1.2 */ +uint8_t* sch_pdu::write_packet(srslte::log *log_h) +{ + int init_rem_len=rem_len; + sch_subh padding; + padding.set_padding(); + + if (init_rem_len < 0) { + log_h->error("init_rem_len=%d\n", init_rem_len); + return NULL; + } + + /* If last SDU has zero payload, remove it. FIXME: Why happens this?? */ + if (subheaders[nof_subheaders-1].get_payload_size() == 0) { + del_subh(); + } + + /* Determine if we are transmitting CEs only. */ + bool ce_only = last_sdu_idx<0?true:false; + + /* Determine if we will need multi-byte padding or 1/2 bytes padding */ + bool multibyte_padding = false; + uint32_t onetwo_padding = 0; + if (rem_len > 2) { + multibyte_padding = true; + // Add 1 header for padding + rem_len--; + // Add the header for the last SDU + if (!ce_only) { + rem_len -= (subheaders[last_sdu_idx].get_header_size(false)-1); // Becuase we were assuming it was the one + } + } else if (rem_len > 0) { + onetwo_padding = rem_len; + rem_len = 0; + } + + /* Determine the header size and CE payload size */ + uint32_t header_sz = 0; + uint32_t ce_payload_sz = 0; + for (int i=0;i= sdu_offset_start) { + fprintf(stderr, "Writting PDU: header sz + ce_payload_sz >= sdu_offset_start (%d>=%d). pdu_len=%d, total_sdu_len=%d\n", + header_sz + ce_payload_sz, sdu_offset_start, pdu_len, total_sdu_len); + return NULL; + } + + /* Start writting header and CE payload before the start of the SDU payload */ + uint8_t *ptr = &buffer_tx[sdu_offset_start-header_sz-ce_payload_sz]; + uint8_t *pdu_start_ptr = ptr; + + // Add single/two byte padding first + for (int i=0;i 0) { + bzero(&pdu_start_ptr[pdu_len-rem_len], rem_len*sizeof(uint8_t)); + } + + /* Sanity check and print if error */ + if (log_h) { + log_h->debug("Wrote PDU: pdu_len=%d, header_and_ce=%d (%d+%d), nof_subh=%d, last_sdu=%d, sdu_len=%d, onepad=%d, multi=%d\n", + pdu_len, header_sz+ce_payload_sz, header_sz, ce_payload_sz, + nof_subheaders, last_sdu_idx, total_sdu_len, onetwo_padding, rem_len); + } else { + printf("Wrote PDU: pdu_len=%d, header_and_ce=%d (%d+%d), nof_subh=%d, last_sdu=%d, sdu_len=%d, onepad=%d, multi=%d, init_rem_len=%d\n", + pdu_len, header_sz+ce_payload_sz, header_sz, ce_payload_sz, + nof_subheaders, last_sdu_idx, total_sdu_len, onetwo_padding, rem_len, init_rem_len); + } + + if (rem_len + header_sz + ce_payload_sz + total_sdu_len != pdu_len) { + printf("\n------------------------------\n"); + for (int i=0;ierror("Wrote PDU: pdu_len=%d, header_and_ce=%d (%d+%d), nof_subh=%d, last_sdu=%d, sdu_len=%d, onepad=%d, multi=%d, init_rem_len=%d\n", + pdu_len, header_sz+ce_payload_sz, header_sz, ce_payload_sz, + nof_subheaders, last_sdu_idx, total_sdu_len, onetwo_padding, rem_len, init_rem_len); + + } + + return NULL; + } + + if (header_sz + ce_payload_sz != (int) (ptr - pdu_start_ptr)) { + fprintf(stderr, "Expected a header and CE payload of %d bytes but wrote %d\n", + header_sz+ce_payload_sz,(int) (ptr - pdu_start_ptr)); + return NULL; + } + + return pdu_start_ptr; +} + +int sch_pdu::rem_size() { + return rem_len; +} + +int sch_pdu::get_pdu_len() +{ + return pdu_len; +} + +uint32_t sch_pdu::size_header_sdu(uint32_t nbytes) +{ + if (nbytes < 128) { + return 2; + } else { + return 3; + } +} +bool sch_pdu::has_space_ce(uint32_t nbytes) +{ + if (rem_len >= nbytes + 1) { + return true; + } else { + return false; + } +} + +bool sch_pdu::update_space_ce(uint32_t nbytes) +{ + if (has_space_ce(nbytes)) { + rem_len -= nbytes + 1; + return true; + } else { + return false; + } +} + +bool sch_pdu::has_space_sdu(uint32_t nbytes) +{ + return get_sdu_space() >= nbytes; +} + +bool sch_pdu::update_space_sdu(uint32_t nbytes) +{ + int init_rem = rem_len; + if (has_space_sdu(nbytes)) { + if (last_sdu_idx < 0) { + rem_len -= (nbytes+1); + } else { + rem_len -= (nbytes+1 + (size_header_sdu(subheaders[last_sdu_idx].get_payload_size())-1)); + } + last_sdu_idx = cur_idx; + return true; + } else { + return false; + } +} + +int sch_pdu::get_sdu_space() +{ + int ret; + if (last_sdu_idx < 0) { + ret = rem_len - 1; + } else { + ret = rem_len - (size_header_sdu(subheaders[last_sdu_idx].get_payload_size())-1) - 1; + } + return ret; +} + +void sch_subh::init() +{ + lcid = 0; + nof_bytes = 0; + payload = NULL; +} + +sch_subh::cetype sch_subh::ce_type() +{ + if (lcid >= PHR_REPORT) { + return (cetype) lcid; + } else { + return SDU; + } +} + +void sch_subh::set_payload_size(uint32_t size) { + nof_bytes = size; +} + +uint32_t sch_subh::size_plus_header() { + if (is_sdu()) { + return sch_pdu::size_header_sdu(nof_bytes) + nof_bytes; + } else { + return nof_bytes + 1; + } +} + +uint32_t sch_subh::sizeof_ce(uint32_t lcid, bool is_ul) +{ + if (is_ul) { + switch(lcid) { + case PHR_REPORT: + return 1; + case CRNTI: + return 2; + case TRUNC_BSR: + return 1; + case SHORT_BSR: + return 1; + case LONG_BSR: + return 3; + case PADDING: + return 0; + } + } else { + switch(lcid) { + case CON_RES_ID: + return 6; + case TA_CMD: + return 1; + case DRX_CMD: + return 0; + case PADDING: + return 0; + } + } + return 0; +} +bool sch_subh::is_sdu() +{ + return ce_type() == SDU; +} +uint16_t sch_subh::get_c_rnti() +{ + if (payload) { + return (uint16_t) payload[0]<<8 | payload[1]; + } else { + return (uint16_t) w_payload_ce[0]<<8 | w_payload_ce[1]; + } +} +uint64_t sch_subh::get_con_res_id() +{ + if (payload) { + return ((uint64_t) payload[5]) | (((uint64_t) payload[4])<<8) | (((uint64_t) payload[3])<<16) | (((uint64_t) payload[2])<<24) | + (((uint64_t) payload[1])<<32) | (((uint64_t) payload[0])<<40); + } else { + return ((uint64_t) w_payload_ce[5]) | (((uint64_t) w_payload_ce[4])<<8) | (((uint64_t) w_payload_ce[3])<<16) | (((uint64_t) w_payload_ce[2])<<24) | + (((uint64_t) w_payload_ce[1])<<32) | (((uint64_t) w_payload_ce[0])<<40); + return 0; + } +} +float sch_subh::get_phr() +{ + if (payload) { + return (float) (payload[0]&0x3f) - 23; + } else { + return (float) (w_payload_ce[0]&0x3f) - 23; + } +} + +int sch_subh::get_bsr(uint32_t buff_size[4]) +{ + if (payload) { + uint32_t nonzero_lcg = 0; + if (ce_type()==LONG_BSR) { + buff_size[0] = (payload[0]&0xFC) >> 2; + buff_size[1] = (payload[0]&0x03) << 4 | (payload[1]&0xF0) >> 4; + buff_size[2] = (payload[1]&0x0F) << 4 | (payload[1]&0xC0) >> 6; + buff_size[3] = (payload[2]&0x3F); + } else { + uint32_t nonzero_lcg = (payload[0]&0xc0) >> 6; + buff_size[nonzero_lcg%4] = payload[0]&0x3f; + } + for (int i=0;i<4;i++) { + if (buff_size[i]) { + buff_size[i] = btable[buff_size[i]%64]; + } + } + return nonzero_lcg; + } else { + return -1; + } +} + +uint8_t sch_subh::get_ta_cmd() +{ + if (payload) { + return (uint8_t) payload[0]&0x3f; + } else { + return 0; + } +} +uint32_t sch_subh::get_sdu_lcid() +{ + return lcid; +} +uint32_t sch_subh::get_payload_size() +{ + return nof_bytes; +} +uint32_t sch_subh::get_header_size(bool is_last) { + if (!is_last) { + // For all subheaders, size can be 1, 2 or 3 bytes + if (is_sdu()) { + return sch_pdu::size_header_sdu(get_payload_size()); + } else { + return 1; + } + } else { + // Last subheader (CE or SDU) has always 1 byte header + return 1; + } +} +uint8_t* sch_subh::get_sdu_ptr() +{ + return payload; +} +void sch_subh::set_padding(uint32_t padding_len) +{ + lcid = PADDING; + nof_bytes = padding_len; +} +void sch_subh::set_padding() +{ + set_padding(0); +} + + +bool sch_subh::set_bsr(uint32_t buff_size[4], sch_subh::cetype format) +{ + uint32_t nonzero_lcg=0; + for (int i=0;i<4;i++) { + if (buff_size[i]) { + nonzero_lcg=i; + } + } + uint32_t ce_size = format==LONG_BSR?3:1; + if (((sch_pdu*)parent)->has_space_ce(ce_size)) { + if (format==LONG_BSR) { + w_payload_ce[0] = (buff_size_table(buff_size[0])&0x3f) << 2 | (buff_size_table(buff_size[1])&0xc0)>>6; + w_payload_ce[1] = (buff_size_table(buff_size[1])&0xf) << 4 | (buff_size_table(buff_size[2])&0xf0)>>4; + w_payload_ce[2] = (buff_size_table(buff_size[2])&0x3) << 6 | (buff_size_table(buff_size[3])&0x3f); + } else { + w_payload_ce[0] = (nonzero_lcg&0x3)<<6 | buff_size_table(buff_size[nonzero_lcg])&0x3f; + } + lcid = format; + ((sch_pdu*)parent)->update_space_ce(ce_size); + nof_bytes = ce_size; + return true; + } else { + return false; + } +} + +bool sch_subh::set_c_rnti(uint16_t crnti) +{ + if (((sch_pdu*)parent)->has_space_ce(2)) { + w_payload_ce[0] = (uint8_t) (crnti&0xff00)>>8; + w_payload_ce[1] = (uint8_t) (crnti&0x00ff); + lcid = CRNTI; + ((sch_pdu*)parent)->update_space_ce(2); + nof_bytes = 2; + return true; + } else { + return false; + } +} +bool sch_subh::set_con_res_id(uint64_t con_res_id) +{ + if (((sch_pdu*)parent)->has_space_ce(6)) { + w_payload_ce[0] = (uint8_t) ((con_res_id&0xff0000000000)>>40); + w_payload_ce[1] = (uint8_t) ((con_res_id&0x00ff00000000)>>32); + w_payload_ce[2] = (uint8_t) ((con_res_id&0x0000ff000000)>>24); + w_payload_ce[3] = (uint8_t) ((con_res_id&0x000000ff0000)>>16); + w_payload_ce[4] = (uint8_t) ((con_res_id&0x00000000ff00)>>8); + w_payload_ce[5] = (uint8_t) ((con_res_id&0x0000000000ff)); + lcid = CON_RES_ID; + ((sch_pdu*)parent)->update_space_ce(6); + nof_bytes = 6; + return true; + } else { + return false; + } +} +bool sch_subh::set_phr(float phr) +{ + if (((sch_pdu*)parent)->has_space_ce(1)) { + w_payload_ce[0] = phr_report_table(phr)&0x3f; + lcid = PHR_REPORT; + ((sch_pdu*)parent)->update_space_ce(1); + nof_bytes = 1; + return true; + } else { + return false; + } +} + +bool sch_subh::set_ta_cmd(uint8_t ta_cmd) +{ + if (((sch_pdu*)parent)->has_space_ce(1)) { + w_payload_ce[0] = ta_cmd&0x3f; + lcid = TA_CMD; + ((sch_pdu*)parent)->update_space_ce(1); + nof_bytes = 1; + return true; + } else { + return false; + } +} + +int sch_subh::set_sdu(uint32_t lcid_, uint32_t requested_bytes, read_pdu_interface *sdu_itf) +{ + if (((sch_pdu*)parent)->has_space_sdu(requested_bytes)) { + lcid = lcid_; + + payload = ((sch_pdu*)parent)->get_current_sdu_ptr(); + // Copy data and get final number of bytes written to the MAC PDU + int sdu_sz = sdu_itf->read_pdu(lcid, payload, requested_bytes); + + if (sdu_sz < 0 || sdu_sz > requested_bytes) { + return -1; + } + if (sdu_sz == 0) { + return 0; + } + + // Save final number of written bytes + nof_bytes = sdu_sz; + + ((sch_pdu*)parent)->add_sdu(nof_bytes); + ((sch_pdu*)parent)->update_space_sdu(nof_bytes); + return nof_bytes; + } else { + return -1; + } +} + +int sch_subh::set_sdu(uint32_t lcid_, uint32_t nof_bytes_, uint8_t *payload) +{ + if (((sch_pdu*)parent)->has_space_sdu(nof_bytes_)) { + lcid = lcid_; + + memcpy(((sch_pdu*)parent)->get_current_sdu_ptr(), payload, nof_bytes_); + + ((sch_pdu*)parent)->add_sdu(nof_bytes_); + ((sch_pdu*)parent)->update_space_sdu(nof_bytes_); + nof_bytes = nof_bytes_; + + return (int) nof_bytes; + } else { + return -1; + } +} + + +// Section 6.2.1 +void sch_subh::write_subheader(uint8_t** ptr, bool is_last) +{ + *(*ptr) = (uint8_t) (is_last?0:(1<<5)) | ((uint8_t) lcid & 0x1f); + *ptr += 1; + if (is_sdu()) { + // MAC SDU: R/R/E/LCID/F/L subheader + // 2nd and 3rd octet + if (!is_last) { + if (nof_bytes >= 128) { + *(*ptr) = (uint8_t) 1<<7 | ((nof_bytes & 0x7f00) >> 8); + *ptr += 1; + *(*ptr) = (uint8_t) (nof_bytes & 0xff); + *ptr += 1; + } else { + *(*ptr) = (uint8_t) (nof_bytes & 0x7f); + *ptr += 1; + } + } + } +} + +void sch_subh::write_payload(uint8_t** ptr) +{ + if (is_sdu()) { + // SDU is written directly during subheader creation + } else { + nof_bytes = sizeof_ce(lcid, parent->is_ul()); + memcpy(*ptr, w_payload_ce, nof_bytes*sizeof(uint8_t)); + } + *ptr += nof_bytes; +} + +bool sch_subh::read_subheader(uint8_t** ptr) +{ + // Skip R + bool e_bit = (bool) (*(*ptr) & 0x20)?true:false; + lcid = (uint8_t) *(*ptr) & 0x1f; + *ptr += 1; + if (is_sdu()) { + if (e_bit) { + F_bit = (bool) (*(*ptr) & 0x80)?true:false; + nof_bytes = (uint32_t)*(*ptr) & 0x7f; + *ptr += 1; + if (F_bit) { + nof_bytes = nof_bytes<<8 | (uint32_t) *(*ptr) & 0xff; + *ptr += 1; + } + } else { + nof_bytes = 0; + F_bit = 0; + } + } else { + nof_bytes = sizeof_ce(lcid, parent->is_ul()); + } + return e_bit; +} +void sch_subh::read_payload(uint8_t** ptr) +{ + payload = *ptr; + *ptr += nof_bytes; +} + +uint8_t sch_subh::buff_size_table(uint32_t buffer_size) { + if (buffer_size == 0) { + return 0; + } else if (buffer_size > 150000) { + return 63; + } else { + for (int i=0;i<61;i++) { + if (buffer_size < btable[i+2]) { + return 1+i; + } + } + return 62; + } +} + +// Implements Table 9.1.8.4-1 Power headroom report mapping (36.133) +uint8_t sch_subh::phr_report_table(float phr_value) +{ + if (phr_value < -23) { + phr_value = -23; + } + if (phr_value > 40) { + phr_value = 40; + } + return (uint8_t) floor(phr_value+23); +} + + + + + + + +void rar_pdu::fprint(FILE* stream) +{ + fprintf(stream, "MAC PDU for RAR. "); + if (has_backoff_indicator) { + fprintf(stream, "Backoff Indicator %d. ", backoff_indicator); + } + pdu::fprint(stream); +} + + +void rar_subh::fprint(FILE* stream) +{ + fprintf(stream, "RAPID: %d, Temp C-RNTI: %d, TA: %d, UL Grant: ", preamble, temp_rnti, ta); + srslte_vec_fprint_hex(stream, grant, 20); +} + +rar_pdu::rar_pdu(uint32_t max_rars_) : pdu(max_rars_) +{ + backoff_indicator = 0; + has_backoff_indicator = false; +} +uint8_t rar_pdu::get_backoff() +{ + return backoff_indicator; +} +bool rar_pdu::has_backoff() +{ + return has_backoff_indicator; +} +void rar_pdu::set_backoff(uint8_t bi) +{ + has_backoff_indicator = true; + backoff_indicator = bi; +} + +// Section 6.1.5 +bool rar_pdu::write_packet(uint8_t* ptr) +{ + // Write Backoff Indicator, if any + if (has_backoff_indicator) { + *(ptr) = backoff_indicator&0xf; + if (nof_subheaders > 0) { + *(ptr) = 1<<7; + } + ptr++; + } + + // Write RAR subheaders + for (int i=0;i>4; + *(*ptr + 1) = (uint8_t) ((ta&0xf) <<4) | (grant[0]<<3) | (grant[1]<<2) | (grant[2]<<1) | grant[3]; + uint8_t *x = &grant[4]; + *(*ptr + 2) = (uint8_t) srslte_bit_pack(&x, 8); + *(*ptr + 3) = (uint8_t) srslte_bit_pack(&x, 8); + *(*ptr + 4) = (uint8_t) ((temp_rnti&0xff00) >> 8); + *(*ptr + 5) = (uint8_t) (temp_rnti&0x00ff); + *ptr += 6; +} + +void rar_subh::read_payload(uint8_t** ptr) +{ + ta = ((uint32_t) *(*ptr + 0)&0x7f)<<4 | (*(*ptr + 1)&0xf0)>>4; + grant[0] = *(*ptr + 1)&0x8?1:0; + grant[1] = *(*ptr + 1)&0x4?1:0; + grant[2] = *(*ptr + 1)&0x2?1:0; + grant[3] = *(*ptr + 1)&0x1?1:0; + uint8_t *x = &grant[4]; + srslte_bit_unpack(*(*ptr+2), &x, 8); + srslte_bit_unpack(*(*ptr+3), &x, 8); + temp_rnti = ((uint16_t) *(*ptr + 4))<<8 | *(*ptr + 5); + *ptr += 6; +} + +bool rar_subh::read_subheader(uint8_t** ptr) +{ + bool e_bit = *(*ptr) & 0x80?true:false; + bool type = *(*ptr) & 0x40?true:false; + if (type) { + preamble = *(*ptr) & 0x3f; + } else { + ((rar_pdu*)parent)->set_backoff(*(*ptr) & 0xf); + } + *ptr += 1; + return e_bit; +} + +} + + + +//int main() +//{ +// /* Test 1st message: CCCH + Short BSR + PHR */ +// uint8_t buffer[10240]; +// uint8_t ccch_payload[6] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60}; +// uint32_t bsr_st[4] = {1, 2, 3, 4}; +// srsue::sch_pdu pdu(10); +// uint8_t *ptr; + +// printf("------- CCCH + Short BSR + PHR no padding ----------\n"); +// bzero(buffer, 10240); +// pdu.init_tx(buffer, 11, true); +// printf("Available space: %d\n", pdu.rem_size()); +// pdu.new_subh(); +// pdu.get()->set_sdu(0,6,ccch_payload); +// pdu.new_subh(); +// pdu.get()->set_phr(10); +// pdu.new_subh(); +// pdu.get()->set_bsr(bsr_st, srsue::sch_subh::SHORT_BSR); +// printf("Remaining space: %d\n", pdu.rem_size()); +// ptr = pdu.write_packet(); +// srslte_vec_fprint_byte(stdout, ptr, pdu.get_pdu_len()); +// printf("\n"); + +// /* Test single SDU: SDU 15 + 1 byte header */ +// printf("------- Single SDU no padding ----------\n"); +// uint8_t dlsch_payload[15] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; +// bzero(buffer, 10240); +// pdu.init_tx(buffer, 16, true); +// printf("Available space: %d\n", pdu.rem_size()); +// pdu.new_subh(); +// pdu.get()->set_sdu(1, 15, dlsch_payload); +// printf("Remaining space: %d\n", pdu.rem_size()); +// ptr = pdu.write_packet(); +// srslte_vec_fprint_byte(stdout, ptr, pdu.get_pdu_len()); +// printf("\n"); + +// /* Test multiple SDU + multiword padding: SDU 8 + SDU 2 byte*/ +// printf("------- Multiple SDU + multiword padding ----------\n"); +// uint8_t dlsch_payload1[8] = {1,2,3,4,5,6,7,8}; +// uint8_t dlsch_payload2[2] = {0xA, 0xB}; +// bzero(buffer, 10240); +// pdu.init_tx(buffer, 18, true); +// printf("Available space: %d\n", pdu.rem_size()); +// pdu.new_subh(); +// pdu.get()->set_sdu(2, 8, dlsch_payload1); +// pdu.new_subh(); +// pdu.get()->set_sdu(3, 2, dlsch_payload2); +// printf("Remaining space: %d\n", pdu.rem_size()); +// ptr = pdu.write_packet(); +// srslte_vec_fprint_byte(stdout, ptr, pdu.get_pdu_len()); +// printf("\n"); + +// printf("------- Multiple SDU + 2word padding ----------\n"); +// bzero(buffer, 10240); +// pdu.init_tx(buffer, 15, true); +// printf("Available space: %d\n", pdu.rem_size()); +// pdu.new_subh(); +// pdu.get()->set_sdu(2, 8, dlsch_payload1); +// pdu.new_subh(); +// pdu.get()->set_sdu(3, 2, dlsch_payload2); +// printf("Remaining space: %d\n", pdu.rem_size()); +// ptr = pdu.write_packet(); +// srslte_vec_fprint_byte(stdout, ptr, pdu.get_pdu_len()); +// printf("\n"); + +// printf("------- Multiple SDU + 1word padding ----------\n"); +// bzero(buffer, 10240); +// pdu.init_tx(buffer, 14, true); +// printf("Available space: %d\n", pdu.rem_size()); +// pdu.new_subh(); +// pdu.get()->set_sdu(2, 8, dlsch_payload1); +// pdu.new_subh(); +// pdu.get()->set_sdu(3, 2, dlsch_payload2); +// printf("Remaining space: %d\n", pdu.rem_size()); +// ptr = pdu.write_packet(); +// srslte_vec_fprint_byte(stdout, ptr, pdu.get_pdu_len()); +// printf("\n"); + +// printf("------- Multiple SDU + 0word padding ----------\n"); +// bzero(buffer, 10240); +// pdu.init_tx(buffer, 13, true); +// printf("Available space: %d\n", pdu.rem_size()); +// pdu.new_subh(); +// pdu.get()->set_sdu(2, 8, dlsch_payload1); +// pdu.new_subh(); +// pdu.get()->set_sdu(3, 2, dlsch_payload2); +// printf("Remaining space: %d\n", pdu.rem_size()); +// ptr = pdu.write_packet(); +// srslte_vec_fprint_byte(stdout, ptr, pdu.get_pdu_len()); +// printf("\n"); + +// printf("------- Multiple SDU + no space ----------\n"); +// bzero(buffer, 10240); +// pdu.init_tx(buffer, 12, true); +// printf("Available space: %d\n", pdu.rem_size()); +// pdu.new_subh(); +// pdu.get()->set_sdu(2, 8, dlsch_payload1); +// pdu.new_subh(); +// if (pdu.get()->set_sdu(3, 2, dlsch_payload2) < 0) { +// pdu.del_subh(); +// } +// printf("Remaining space: %d\n", pdu.rem_size()); +// ptr = pdu.write_packet(); +// srslte_vec_fprint_byte(stdout, ptr, pdu.get_pdu_len()); +// printf("\n"); + +// /* CE only */ +// printf("------- CE only ----------\n"); +// bzero(buffer, 10240); +// pdu.init_tx(buffer, 125, true); +// printf("Available space: %d\n", pdu.rem_size()); +// pdu.new_subh(); +// pdu.get()->set_phr(15); +// pdu.new_subh(); +// pdu.get()->set_bsr(bsr_st, srsue::sch_subh::SHORT_BSR); +// printf("Remaining space: %d\n", pdu.rem_size()); +// ptr = pdu.write_packet(); +// srslte_vec_fprint_byte(stdout, ptr, pdu.get_pdu_len()); +// printf("\n"); + +// /* Another test */ +// printf("------- Another test ----------\n"); +// uint8_t dlsch_payload3[602]; +// bzero(buffer, 10240); +// pdu.init_tx(buffer, 75, true); +// printf("Available space: %d\n", pdu.rem_size()); +// pdu.new_subh(); +// pdu.get()->set_bsr(bsr_st, srsue::sch_subh::SHORT_BSR); +// pdu.new_subh(); +// pdu.get()->set_sdu(3, 2, dlsch_payload3); +// pdu.new_subh(); +// pdu.get()->set_sdu(3, 66, dlsch_payload3); +// pdu.new_subh(); +// printf("Remaining space: %d\n", pdu.rem_size()); +// ptr = pdu.write_packet(); +// //srslte_vec_fprint_byte(stdout, ptr, pdu.get_pdu_len()); +// printf("\n"); + +// return 0; +//} + + + diff --git a/srslte/lib/common/pdu_queue.cc b/srslte/lib/common/pdu_queue.cc new file mode 100644 index 000000000..5be6d94ac --- /dev/null +++ b/srslte/lib/common/pdu_queue.cc @@ -0,0 +1,108 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + + +#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) + +#include "common/pdu_queue.h" + + +namespace srslte { + + +void pdu_queue::init(process_callback *callback_, log* log_h_) +{ + callback = callback_; + log_h = log_h_; +} + +uint8_t* pdu_queue::request(uint32_t len) +{ + if (len > MAX_PDU_LEN) { + fprintf(stderr, "Error request buffer of invalid size %d. Max bytes %d\n", len, MAX_PDU_LEN); + return NULL; + } + pdu_t *pdu = pool.allocate(); + if (!pdu) { + if (log_h) { + log_h->error("Not enough buffers for MAC PDU\n"); + } + fprintf(stderr, "Not enough buffers for MAC PDU\n"); + } + if ((void*) pdu->ptr != (void*) pdu) { + fprintf(stderr, "Fatal error in memory alignment in struct pdu_queue::pdu_t\n"); + exit(-1); + } + + return pdu->ptr; +} + +void pdu_queue::deallocate(uint8_t* pdu) +{ + if (!pool.deallocate((pdu_t*) pdu)) { + log_h->warning("Error deallocating from buffer pool: buffer not created in this pool.\n"); + } +} + +/* Demultiplexing of logical channels and dissassemble of MAC CE + * This function enqueues the packet and returns quicly because ACK + * deadline is important here. + */ +void pdu_queue::push(uint8_t *ptr, uint32_t len) +{ + pdu_t *pdu = (pdu_t*) ptr; + pdu->len = len; + pdu_q.push(pdu); +} + +bool pdu_queue::process_pdus() +{ + bool have_data = false; + uint32_t cnt = 0; + pdu_t *pdu; + while(pdu_q.try_pop(&pdu)) { + if (callback) { + callback->process_pdu(pdu->ptr, pdu->len); + } + if (!pool.deallocate(pdu)) { + log_h->warning("Error deallocating from buffer pool: buffer not created in this pool.\n"); + } + cnt++; + have_data = true; + } + if (cnt > 20) { + if (log_h) { + log_h->warning("PDU queue dispatched %d packets\n", cnt); + } + printf("Warning PDU queue dispatched %d packets\n", cnt); + } + return have_data; +} + +} diff --git a/srslte/lib/common/security.cc b/srslte/lib/common/security.cc new file mode 100644 index 000000000..1f3cfc30a --- /dev/null +++ b/srslte/lib/common/security.cc @@ -0,0 +1,214 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + + +#include "common/security.h" +#include "liblte_security.h" +#include "common/snow_3g.h" + +using namespace srslte; + +namespace srsue{ + +/****************************************************************************** + * Key Generation + *****************************************************************************/ + +uint8_t security_generate_k_asme( uint8_t *ck, + uint8_t *ik, + uint8_t *ak, + uint8_t *sqn, + uint16_t mcc, + uint16_t mnc, + uint8_t *k_asme) +{ + return liblte_security_generate_k_asme(ck, + ik, + ak, + sqn, + mcc, + mnc, + k_asme); +} + +uint8_t security_generate_k_enb( uint8_t *k_asme, + uint32_t nas_count, + uint8_t *k_enb) +{ + return liblte_security_generate_k_enb(k_asme, + nas_count, + k_enb); +} + +uint8_t security_generate_k_nas( uint8_t *k_asme, + CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, + INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, + uint8_t *k_nas_enc, + uint8_t *k_nas_int) +{ + return liblte_security_generate_k_nas( k_asme, + (LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_ENUM)enc_alg_id, + (LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_ENUM)int_alg_id, + k_nas_enc, + k_nas_int); +} + +uint8_t security_generate_k_rrc( uint8_t *k_enb, + CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, + INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, + uint8_t *k_rrc_enc, + uint8_t *k_rrc_int) +{ + return liblte_security_generate_k_rrc(k_enb, + (LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_ENUM)enc_alg_id, + (LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_ENUM)int_alg_id, + k_rrc_enc, + k_rrc_int); +} + +uint8_t security_generate_k_up( uint8_t *k_enb, + CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, + INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, + uint8_t *k_up_enc, + uint8_t *k_up_int) +{ + return liblte_security_generate_k_up(k_enb, + (LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_ENUM)enc_alg_id, + (LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_ENUM)int_alg_id, + k_up_enc, + k_up_int); +} + +/****************************************************************************** + * Integrity Protection + *****************************************************************************/ + +uint8_t security_128_eia1( uint8_t *key, + uint32_t count, + uint8_t bearer, + uint8_t direction, + uint8_t *msg, + uint32_t msg_len, + uint8_t *mac) +{ + uint32_t msg_len_bits; + uint32_t i; + uint8_t *m_ptr; + + msg_len_bits = msg_len*8; + m_ptr = snow3g_f9(key, + count, + bearer, + direction, + msg, + msg_len_bits); + for(i=0; i<4; i++) { + mac[i] = m_ptr[i]; + } + return ERROR_NONE; +} + +uint8_t security_128_eia2( uint8_t *key, + uint32_t count, + uint8_t bearer, + uint8_t direction, + uint8_t *msg, + uint32_t msg_len, + uint8_t *mac) +{ + return liblte_security_128_eia2(key, + count, + bearer, + direction, + msg, + msg_len, + mac); +} + +/****************************************************************************** + * Authentication + *****************************************************************************/ + +uint8_t security_milenage_f1( uint8_t *k, + uint8_t *op, + uint8_t *rand, + uint8_t *sqn, + uint8_t *amf, + uint8_t *mac_a) +{ + return liblte_security_milenage_f1(k, + op, + rand, + sqn, + amf, + mac_a); +} + +uint8_t security_milenage_f1_star( uint8_t *k, + uint8_t *op, + uint8_t *rand, + uint8_t *sqn, + uint8_t *amf, + uint8_t *mac_s) +{ + return liblte_security_milenage_f1_star(k, + op, + rand, + sqn, + amf, + mac_s); +} + +uint8_t security_milenage_f2345( uint8_t *k, + uint8_t *op, + uint8_t *rand, + uint8_t *res, + uint8_t *ck, + uint8_t *ik, + uint8_t *ak) +{ + return liblte_security_milenage_f2345(k, + op, + rand, + res, + ck, + ik, + ak); +} + +uint8_t security_milenage_f5_star( uint8_t *k, + uint8_t *op, + uint8_t *rand, + uint8_t *ak) +{ + return liblte_security_milenage_f5_star(k, + op, + rand, + ak); +} + + +} // namespace srsue diff --git a/srslte/lib/common/snow_3g.cc b/srslte/lib/common/snow_3g.cc new file mode 100644 index 000000000..f9e08fc59 --- /dev/null +++ b/srslte/lib/common/snow_3g.cc @@ -0,0 +1,577 @@ +/*------------------------------------------------------------------------ +* snow_3g.c +* +* Adapted from ETSI/SAGE specifications: +* "Specification of the 3GPP Confidentiality and +* Integrity Algorithms UEA2 & UIA2. +* Document 1: UEA2 and UIA2 Specification" +* "Specification of the 3GPP Confidentiality +* and Integrity Algorithms UEA2 & UIA2. +* Document 2: SNOW 3G Specification" +*------------------------------------------------------------------------*/ + +#include "common/snow_3g.h" + +/* LFSR */ + +u32 LFSR_S0 = 0x00; +u32 LFSR_S1 = 0x00; +u32 LFSR_S2 = 0x00; +u32 LFSR_S3 = 0x00; +u32 LFSR_S4 = 0x00; +u32 LFSR_S5 = 0x00; +u32 LFSR_S6 = 0x00; +u32 LFSR_S7 = 0x00; +u32 LFSR_S8 = 0x00; +u32 LFSR_S9 = 0x00; +u32 LFSR_S10 = 0x00; +u32 LFSR_S11 = 0x00; +u32 LFSR_S12 = 0x00; +u32 LFSR_S13 = 0x00; +u32 LFSR_S14 = 0x00; +u32 LFSR_S15 = 0x00; + +/* FSM */ + +u32 FSM_R1 = 0x00; +u32 FSM_R2 = 0x00; +u32 FSM_R3 = 0x00; + +/* Rijndael S-box SR */ + +u8 SR[256] = { +0x63,0x7C,0x77,0x7B,0xF2,0x6B,0x6F,0xC5,0x30,0x01,0x67,0x2B,0xFE,0xD7,0xAB,0x76, +0xCA,0x82,0xC9,0x7D,0xFA,0x59,0x47,0xF0,0xAD,0xD4,0xA2,0xAF,0x9C,0xA4,0x72,0xC0, +0xB7,0xFD,0x93,0x26,0x36,0x3F,0xF7,0xCC,0x34,0xA5,0xE5,0xF1,0x71,0xD8,0x31,0x15, +0x04,0xC7,0x23,0xC3,0x18,0x96,0x05,0x9A,0x07,0x12,0x80,0xE2,0xEB,0x27,0xB2,0x75, +0x09,0x83,0x2C,0x1A,0x1B,0x6E,0x5A,0xA0,0x52,0x3B,0xD6,0xB3,0x29,0xE3,0x2F,0x84, +0x53,0xD1,0x00,0xED,0x20,0xFC,0xB1,0x5B,0x6A,0xCB,0xBE,0x39,0x4A,0x4C,0x58,0xCF, +0xD0,0xEF,0xAA,0xFB,0x43,0x4D,0x33,0x85,0x45,0xF9,0x02,0x7F,0x50,0x3C,0x9F,0xA8, +0x51,0xA3,0x40,0x8F,0x92,0x9D,0x38,0xF5,0xBC,0xB6,0xDA,0x21,0x10,0xFF,0xF3,0xD2, +0xCD,0x0C,0x13,0xEC,0x5F,0x97,0x44,0x17,0xC4,0xA7,0x7E,0x3D,0x64,0x5D,0x19,0x73, +0x60,0x81,0x4F,0xDC,0x22,0x2A,0x90,0x88,0x46,0xEE,0xB8,0x14,0xDE,0x5E,0x0B,0xDB, +0xE0,0x32,0x3A,0x0A,0x49,0x06,0x24,0x5C,0xC2,0xD3,0xAC,0x62,0x91,0x95,0xE4,0x79, +0xE7,0xC8,0x37,0x6D,0x8D,0xD5,0x4E,0xA9,0x6C,0x56,0xF4,0xEA,0x65,0x7A,0xAE,0x08, +0xBA,0x78,0x25,0x2E,0x1C,0xA6,0xB4,0xC6,0xE8,0xDD,0x74,0x1F,0x4B,0xBD,0x8B,0x8A, +0x70,0x3E,0xB5,0x66,0x48,0x03,0xF6,0x0E,0x61,0x35,0x57,0xB9,0x86,0xC1,0x1D,0x9E, +0xE1,0xF8,0x98,0x11,0x69,0xD9,0x8E,0x94,0x9B,0x1E,0x87,0xE9,0xCE,0x55,0x28,0xDF, +0x8C,0xA1,0x89,0x0D,0xBF,0xE6,0x42,0x68,0x41,0x99,0x2D,0x0F,0xB0,0x54,0xBB,0x16 +}; + +/* S-box SQ */ + +u8 SQ[256] = { +0x25,0x24,0x73,0x67,0xD7,0xAE,0x5C,0x30,0xA4,0xEE,0x6E,0xCB,0x7D,0xB5,0x82,0xDB, +0xE4,0x8E,0x48,0x49,0x4F,0x5D,0x6A,0x78,0x70,0x88,0xE8,0x5F,0x5E,0x84,0x65,0xE2, +0xD8,0xE9,0xCC,0xED,0x40,0x2F,0x11,0x28,0x57,0xD2,0xAC,0xE3,0x4A,0x15,0x1B,0xB9, +0xB2,0x80,0x85,0xA6,0x2E,0x02,0x47,0x29,0x07,0x4B,0x0E,0xC1,0x51,0xAA,0x89,0xD4, +0xCA,0x01,0x46,0xB3,0xEF,0xDD,0x44,0x7B,0xC2,0x7F,0xBE,0xC3,0x9F,0x20,0x4C,0x64, +0x83,0xA2,0x68,0x42,0x13,0xB4,0x41,0xCD,0xBA,0xC6,0xBB,0x6D,0x4D,0x71,0x21,0xF4, +0x8D,0xB0,0xE5,0x93,0xFE,0x8F,0xE6,0xCF,0x43,0x45,0x31,0x22,0x37,0x36,0x96,0xFA, +0xBC,0x0F,0x08,0x52,0x1D,0x55,0x1A,0xC5,0x4E,0x23,0x69,0x7A,0x92,0xFF,0x5B,0x5A, +0xEB,0x9A,0x1C,0xA9,0xD1,0x7E,0x0D,0xFC,0x50,0x8A,0xB6,0x62,0xF5,0x0A,0xF8,0xDC, +0x03,0x3C,0x0C,0x39,0xF1,0xB8,0xF3,0x3D,0xF2,0xD5,0x97,0x66,0x81,0x32,0xA0,0x00, +0x06,0xCE,0xF6,0xEA,0xB7,0x17,0xF7,0x8C,0x79,0xD6,0xA7,0xBF,0x8B,0x3F,0x1F,0x53, +0x63,0x75,0x35,0x2C,0x60,0xFD,0x27,0xD3,0x94,0xA5,0x7C,0xA1,0x05,0x58,0x2D,0xBD, +0xD9,0xC7,0xAF,0x6B,0x54,0x0B,0xE0,0x38,0x04,0xC8,0x9D,0xE7,0x14,0xB1,0x87,0x9C, +0xDF,0x6F,0xF9,0xDA,0x2A,0xC4,0x59,0x16,0x74,0x91,0xAB,0x26,0x61,0x76,0x34,0x2B, +0xAD,0x99,0xFB,0x72,0xEC,0x33,0x12,0xDE,0x98,0x3B,0xC0,0x9B,0x3E,0x18,0x10,0x3A, +0x56,0xE1,0x77,0xC9,0x1E,0x9E,0x95,0xA3,0x90,0x19,0xA8,0x6C,0x09,0xD0,0xF0,0x86 +}; + +/* MULx. +* Input V: an 8-bit input. +* Input c: an 8-bit input. +* Output : an 8-bit output. +* See section 3.1.1 for details. +*/ + +u8 MULx(u8 V, u8 c) +{ + if ( V & 0x80 ) + return ( (V << 1) ^ c); + else + return ( V << 1); +} + +/* MULxPOW. +* Input V: an 8-bit input. +* Input i: a positive integer. +* Input c: an 8-bit input. +* Output : an 8-bit output. +* See section 3.1.2 for details. +*/ + +u8 MULxPOW(u8 V, u8 i, u8 c) +{ + if ( i == 0) + return V; + else + return MULx( MULxPOW( V, i-1, c ), c); +} + +/* The function MUL alpha. +* Input c: 8-bit input. +* Output : 32-bit output. +* See section 3.4.2 for details. +*/ + +u32 MULalpha(u8 c) +{ + return ( ( ((u32)MULxPOW(c, 23, 0xa9)) << 24 ) | + ( ((u32)MULxPOW(c, 245, 0xa9)) << 16 ) | + ( ((u32)MULxPOW(c, 48, 0xa9)) << 8 ) | + ( ((u32)MULxPOW(c, 239, 0xa9)) ) ) ; +} + +/* The function DIV alpha. +* Input c: 8-bit input. +* Output : 32-bit output. +* See section 3.4.3 for details. +*/ + +u32 DIValpha(u8 c) +{ + return ( ( ((u32)MULxPOW(c, 16, 0xa9)) << 24 ) | + ( ((u32)MULxPOW(c, 39, 0xa9)) << 16 ) | + ( ((u32)MULxPOW(c, 6, 0xa9)) << 8 ) | + ( ((u32)MULxPOW(c, 64, 0xa9)) ) ) ; +} + +/* The 32x32-bit S-Box S1 +* Input: a 32-bit input. +* Output: a 32-bit output of S1 box. +* See section 3.3.1. +*/ + +u32 S1(u32 w) +{ + u8 r0=0, r1=0, r2=0, r3=0; + u8 srw0 = SR[ (u8)((w >> 24) & 0xff) ]; + u8 srw1 = SR[ (u8)((w >> 16) & 0xff) ]; + u8 srw2 = SR[ (u8)((w >> 8) & 0xff) ]; + u8 srw3 = SR[ (u8)((w) & 0xff) ]; + r0 = ( ( MULx( srw0 , 0x1b) ) ^ + ( srw1 ) ^ + ( srw2 ) ^ + ( (MULx( srw3, 0x1b)) ^ srw3 ) + ); + r1 = ( ( ( MULx( srw0 , 0x1b) ) ^ srw0 ) ^ + ( MULx(srw1, 0x1b) ) ^ + ( srw2 ) ^ + ( srw3 ) + ); + r2 = ( ( srw0 ) ^ + ( ( MULx( srw1 , 0x1b) ) ^ srw1 ) ^ + ( MULx(srw2, 0x1b) ) ^ + ( srw3 ) + ); + r3 = ( ( srw0 ) ^ + ( srw1 ) ^ + ( ( MULx( srw2 , 0x1b) ) ^ srw2 ) ^ + ( MULx( srw3, 0x1b) ) + ); + + return ( ( ((u32)r0) << 24 ) | ( ((u32)r1) << 16 ) | ( ((u32)r2) << 8 ) | + ( ((u32)r3) ) ); +} + +/* The 32x32-bit S-Box S2 +* Input: a 32-bit input. +* Output: a 32-bit output of S2 box. +* See section 3.3.2. +*/ + +u32 S2(u32 w) +{ + u8 r0=0, r1=0, r2=0, r3=0; + u8 sqw0 = SQ[ (u8)((w >> 24) & 0xff) ]; + u8 sqw1 = SQ[ (u8)((w >> 16) & 0xff) ]; + u8 sqw2 = SQ[ (u8)((w >> 8) & 0xff) ]; + u8 sqw3 = SQ[ (u8)((w) & 0xff) ]; + r0 = ( ( MULx( sqw0 , 0x69) ) ^ + ( sqw1 ) ^ + ( sqw2 ) ^ + ( (MULx( sqw3, 0x69)) ^ sqw3 ) + ); + r1 = ( ( ( MULx( sqw0 , 0x69) ) ^ sqw0 ) ^ + ( MULx(sqw1, 0x69) ) ^ + ( sqw2 ) ^ + ( sqw3 ) + ); + r2 = ( ( sqw0 ) ^ + ( ( MULx( sqw1 , 0x69) ) ^ sqw1 ) ^ + ( MULx(sqw2, 0x69) ) ^ + ( sqw3 ) + ); + r3 = ( ( sqw0 ) ^ + ( sqw1 ) ^ + ( ( MULx( sqw2 , 0x69) ) ^ sqw2 ) ^ + ( MULx( sqw3, 0x69) ) + ); + return ( ( ((u32)r0) << 24 ) | ( ((u32)r1) << 16 ) | ( ((u32)r2) << 8 ) | + ( ((u32)r3) ) ); +} + +/* Clocking LFSR in initialization mode. +* LFSR Registers S0 to S15 are updated as the LFSR receives a single clock. +* Input F: a 32-bit word comes from output of FSM. +* See section 3.4.4. +*/ + +void ClockLFSRInitializationMode(u32 F) +{ + u32 v = ( ( (LFSR_S0 << 8) & 0xffffff00 ) ^ + ( MULalpha( (u8)((LFSR_S0>>24) & 0xff) ) ) ^ + ( LFSR_S2 ) ^ + ( (LFSR_S11 >> 8) & 0x00ffffff ) ^ + ( DIValpha( (u8)( ( LFSR_S11) & 0xff ) ) ) ^ + ( F ) + ); + LFSR_S0 = LFSR_S1; + LFSR_S1 = LFSR_S2; + LFSR_S2 = LFSR_S3; + LFSR_S3 = LFSR_S4; + LFSR_S4 = LFSR_S5; + LFSR_S5 = LFSR_S6; + LFSR_S6 = LFSR_S7; + LFSR_S7 = LFSR_S8; + LFSR_S8 = LFSR_S9; + LFSR_S9 = LFSR_S10; + LFSR_S10 = LFSR_S11; + LFSR_S11 = LFSR_S12; + LFSR_S12 = LFSR_S13; + LFSR_S13 = LFSR_S14; + LFSR_S14 = LFSR_S15; + LFSR_S15 = v; +} + +/* Clocking LFSR in keystream mode. +* LFSR Registers S0 to S15 are updated as the LFSR receives a single clock. +* See section 3.4.5. +*/ + +void ClockLFSRKeyStreamMode() +{ + u32 v = ( ( (LFSR_S0 << 8) & 0xffffff00 ) ^ + ( MULalpha( (u8)((LFSR_S0>>24) & 0xff) ) ) ^ + ( LFSR_S2 ) ^ + ( (LFSR_S11 >> 8) & 0x00ffffff ) ^ + ( DIValpha( (u8)( ( LFSR_S11) & 0xff ) ) ) + ); + LFSR_S0 = LFSR_S1; + LFSR_S1 = LFSR_S2; + LFSR_S2 = LFSR_S3; + LFSR_S3 = LFSR_S4; + LFSR_S4 = LFSR_S5; + LFSR_S5 = LFSR_S6; + LFSR_S6 = LFSR_S7; + LFSR_S7 = LFSR_S8; + LFSR_S8 = LFSR_S9; + LFSR_S9 = LFSR_S10; + LFSR_S10 = LFSR_S11; + LFSR_S11 = LFSR_S12; + LFSR_S12 = LFSR_S13; + LFSR_S13 = LFSR_S14; + LFSR_S14 = LFSR_S15; + LFSR_S15 = v; +} + +/* Clocking FSM. +* Produces a 32-bit word F. +* Updates FSM registers R1, R2, R3. +* See Section 3.4.6. +*/ + +u32 ClockFSM() +{ + u32 F = ( ( LFSR_S15 + FSM_R1 ) & 0xffffffff ) ^ FSM_R2 ; + u32 r = ( FSM_R2 + ( FSM_R3 ^ LFSR_S5 ) ) & 0xffffffff ; + FSM_R3 = S2(FSM_R2); + FSM_R2 = S1(FSM_R1); + FSM_R1 = r; + return F; +} + +/* Initialization. +* Input k[4]: Four 32-bit words making up 128-bit key. +* Input IV[4]: Four 32-bit words making 128-bit initialization variable. +* Output: All the LFSRs and FSM are initialized for key generation. +* See Section 4.1. +*/ + +void snow3g_initialize(u32 k[4], u32 IV[4]) +{ + u8 i=0; + u32 F = 0x0; + LFSR_S15 = k[3] ^ IV[0]; + LFSR_S14 = k[2]; + LFSR_S13 = k[1]; + LFSR_S12 = k[0] ^ IV[1]; + LFSR_S11 = k[3] ^ 0xffffffff; + LFSR_S10 = k[2] ^ 0xffffffff ^ IV[2]; + LFSR_S9 = k[1] ^ 0xffffffff ^ IV[3]; + LFSR_S8 = k[0] ^ 0xffffffff; + LFSR_S7 = k[3]; + LFSR_S6 = k[2]; + LFSR_S5 = k[1]; + LFSR_S4 = k[0]; + LFSR_S3 = k[3] ^ 0xffffffff; + LFSR_S2 = k[2] ^ 0xffffffff; + LFSR_S1 = k[1] ^ 0xffffffff; + LFSR_S0 = k[0] ^ 0xffffffff; + FSM_R1 = 0x0; + FSM_R2 = 0x0; + FSM_R3 = 0x0; + for(i=0;i<32;i++) + { + F = ClockFSM(); + ClockLFSRInitializationMode(F); + } +} + +/* Generation of Keystream. +* input n: number of 32-bit words of keystream. +* input z: space for the generated keystream, assumes +* memory is allocated already. +* output: generated keystream which is filled in z +* See section 4.2. +*/ + +void snow3g_generate_keystream(u32 n, u32 *ks) +{ + u32 t = 0; + u32 F = 0x0; + ClockFSM(); /* Clock FSM once. Discard the output. */ + ClockLFSRKeyStreamMode(); /* Clock LFSR in keystream mode once. */ + for ( t=0; t> 24) & 0xff; + data[4*i+1] ^= (u8) (KS[i] >> 16) & 0xff; + data[4*i+2] ^= (u8) (KS[i] >> 8) & 0xff; + data[4*i+3] ^= (u8) (KS[i] ) & 0xff; + } + + free(KS); + + /* zero last bits of data in case its length is not byte-aligned + this is an addition to the C reference code, which did not handle it */ + if (lastbits) + data[length/8] &= 256 - (1<>i ) & 0x1 ) + result ^= MUL64xPOW(V,i,c); + } + return result; +} + +/* mask8bit. + * Input n: an integer in 1-7. + * Output : an 8 bit mask. + * Prepares an 8 bit mask with required number of 1 bits on the MSB side. + */ +u8 mask8bit(int n) +{ + return 0xFF ^ ((1<<(8-n)) - 1); +} + +/* f9. + * Input key: 128 bit Integrity Key. + * Input count:32-bit Count, Frame dependent input. + * Input fresh: 32-bit Random number. + * Input dir:1 bit, direction of transmission (in the LSB). + * Input data: length number of bits, input bit stream. + * Input length: 64 bit Length, i.e., the number of bits to be MAC'd. + * Output : 32 bit block used as MAC + * Generates 32-bit MAC using UIA2 algorithm as defined in Section 4. + */ +u8* snow3g_f9( u8* key, u32 count, u32 fresh, u32 dir, u8 *data, u64 length) +{ + u32 K[4],IV[4], z[5]; + u32 i=0, D; + static u8 MAC_I[4] = {0,0,0,0}; /* static memory for the result */ + u64 EVAL; + u64 V; + u64 P; + u64 Q; + u64 c; + + u64 M_D_2; + int rem_bits = 0; + + /* Load the Integrity Key for SNOW3G initialization as in section 4.4. */ + for (i=0; i<4; i++) + K[3-i] = (key[4*i] << 24) ^ (key[4*i+1] << 16) ^ + (key[4*i+2] << 8) ^ (key[4*i+3]); + + /* Prepare the Initialization Vector (IV) for SNOW3G initialization as + in section 4.4. */ + IV[3] = count; + IV[2] = fresh; + IV[1] = count ^ ( dir << 31 ) ; + IV[0] = fresh ^ (dir << 15); + + z[0] = z[1] = z[2] = z[3] = z[4] = 0; + + /* Run SNOW 3G to produce 5 keystream words z_1, z_2, z_3, z_4 and z_5. */ + snow3g_initialize(K, IV); + snow3g_generate_keystream(5, z); + + P = (u64)z[0] << 32 | (u64)z[1]; + Q = (u64)z[2] << 32 | (u64)z[3]; + + /* Calculation */ + if ((length % 64) == 0) + D = (length>>6) + 1; + else + D = (length>>6) + 2; + EVAL = 0; + c = 0x1b; + + /* for 0 <= i <= D-3 */ + for (i=0; i 7) + { + M_D_2 |= (u64)data[8*(D-2)+i] << (8*(7-i)); + rem_bits -= 8; + i++; + } + if (rem_bits > 0) + M_D_2 |= (u64)(data[8*(D-2)+i] & mask8bit(rem_bits)) << (8*(7-i)); + + V = EVAL ^ M_D_2; + EVAL = MUL64(V,P,c); + + /* for D-1 */ + EVAL ^= length; + + /* Multiply by Q */ + EVAL = MUL64(EVAL,Q,c); + + /* XOR with z_5: this is a modification to the reference C code, + which forgot to XOR z[5] */ + for (i=0; i<4; i++) + /* + MAC_I[i] = (mac32 >> (8*(3-i))) & 0xff; + */ + MAC_I[i] = ((EVAL >> (56-(i*8))) ^ (z[4] >> (24-(i*8)))) & 0xff; + + return MAC_I; +} diff --git a/srslte/lib/common/task_dispatcher.cc b/srslte/lib/common/task_dispatcher.cc new file mode 100644 index 000000000..394bce5de --- /dev/null +++ b/srslte/lib/common/task_dispatcher.cc @@ -0,0 +1,75 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + + +#include "common/task_dispatcher.h" +#include + +namespace srslte { + +task_dispatcher::task_dispatcher(uint32_t max_pending_tasks) +{ + pthread_cond_init(&cvar, NULL); + pthread_mutex_init(&mutex, NULL); +} + +task_dispatcher::~task_dispatcher() +{ + running = false; + pthread_cond_signal(&cvar); + wait_thread_finish(); + pthread_cond_destroy(&cvar); + pthread_mutex_destroy(&mutex); +} + +void task_dispatcher::push_task(uint32_t task_code) +{ + pthread_mutex_lock(&mutex); + pending_tasks.push(task_code); + pthread_cond_signal(&cvar); + pthread_mutex_unlock(&mutex); +} + +void task_dispatcher::run_thread() +{ + running = true; + while(running) { + uint32_t task = 0; + pthread_mutex_lock(&mutex); + while(pending_tasks.empty()) { + pthread_cond_wait(&cvar, &mutex); + } + task = (uint32_t) pending_tasks.front(); + pending_tasks.pop(); + pthread_mutex_unlock(&mutex); + if (running) { + run_task(task); + } + } +} + + +} \ No newline at end of file diff --git a/srslte/lib/common/thread_pool.cc b/srslte/lib/common/thread_pool.cc new file mode 100644 index 000000000..330a38043 --- /dev/null +++ b/srslte/lib/common/thread_pool.cc @@ -0,0 +1,289 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + + +#include +#include +#include "common/thread_pool.h" + +#define DEBUG 0 +#define debug_thread(fmt, ...) do { if(DEBUG) printf(fmt, __VA_ARGS__); } while(0) + +#define USE_QUEUE + +namespace srslte { + + +void thread_pool::worker::setup(uint32_t id, thread_pool *parent, uint32_t prio, uint32_t mask) +{ + my_id = id; + my_parent = parent; + if(mask == 255) + { + start(prio); + } + else + { + start_cpu_mask(prio,mask); + } + +} + +void thread_pool::worker::run_thread() +{ + running = true; + while(running) { + wait_to_start(); + if (running) { + work_imp(); + finished(); + } + } +} + +uint32_t thread_pool::worker::get_id() +{ + return my_id; +} + +void thread_pool::worker::stop() +{ + running = false; + pthread_cond_signal(&my_parent->cvar[my_id]); + wait_thread_finish(); +} + +thread_pool::thread_pool(uint32_t max_workers_) : + workers(max_workers_), + status(max_workers_), + cvar(max_workers_), + mutex(max_workers_) + +{ + max_workers = max_workers_; + for (int i=0;i= nof_workers) { + nof_workers = id+1; + } + pthread_mutex_lock(&mutex_queue); + workers[id] = obj; + available_workers.push(obj); + obj->setup(id, this, prio, mask); + pthread_cond_signal(&cvar_queue); + pthread_mutex_unlock(&mutex_queue); + } +} + +void thread_pool::stop() +{ + /* Stop any thread waiting for available worker */ + running = false; + + /* Now stop all workers */ + for (uint32_t i=0;istop(); + // Need to call start to wake it up + start_worker(i); + workers[i]->wait_thread_finish(); + } + pthread_cond_destroy(&cvar[i]); + pthread_mutex_destroy(&mutex[i]); + } + pthread_cond_destroy(&cvar_queue); + pthread_mutex_destroy(&mutex_queue); +} + + +void thread_pool::worker::release() +{ + finished(); +} + +void thread_pool::worker::wait_to_start() +{ + + debug_thread("wait_to_start() id=%d, status=%d, enter\n", my_id, my_parent->status[my_id]); + + pthread_mutex_lock(&my_parent->mutex[my_id]); + while(my_parent->status[my_id] != START_WORK && running) { + pthread_cond_wait(&my_parent->cvar[my_id], &my_parent->mutex[my_id]); + } + my_parent->status[my_id] = WORKING; + pthread_mutex_unlock(&my_parent->mutex[my_id]); + + debug_thread("wait_to_start() id=%d, status=%d, exit\n", my_id, my_parent->status[my_id]); +} + +void thread_pool::worker::finished() +{ +#ifdef USE_QUEUE + pthread_mutex_lock(&my_parent->mutex[my_id]); + my_parent->status[my_id] = IDLE; + pthread_mutex_unlock(&my_parent->mutex[my_id]); + + pthread_mutex_lock(&my_parent->mutex_queue); + pthread_cond_signal(&my_parent->cvar_queue); + pthread_mutex_unlock(&my_parent->mutex_queue); +#else + pthread_mutex_lock(&my_parent->mutex[my_id]); + my_parent->status[my_id] = IDLE; + pthread_cond_signal(&my_parent->cvar[my_id]); + pthread_mutex_unlock(&my_parent->mutex[my_id]); +#endif +} + + +thread_pool::worker* thread_pool::wait_worker() +{ + return wait_worker(0); +} + +bool thread_pool::find_finished_worker(uint32_t tti, uint32_t *id) { + for(int i=0;i +#include +#include +#include +#include +#include + +#include "common/threads.h" + +bool threads_new_rt(pthread_t *thread, void *(*start_routine) (void*), void *arg) { + return threads_new_rt_prio(thread, start_routine, arg, -1); +} + +bool threads_new_rt_prio(pthread_t *thread, void *(*start_routine) (void*), void *arg, int prio_offset) { + return threads_new_rt_cpu(thread, start_routine, arg, -1, prio_offset); +} + +bool threads_new_rt_mask(pthread_t *thread, void *(*start_routine) (void*), void *arg,int mask, int prio_offset){ +return threads_new_rt_cpu(thread, start_routine, arg, mask*100, prio_offset);// we multiply mask by 100 to distinguish it from a single cpu core id +} + +bool threads_new_rt_cpu(pthread_t *thread, void *(*start_routine) (void*), void *arg, int cpu, int prio_offset) { + bool ret = false; + + pthread_attr_t attr; + struct sched_param param; + cpu_set_t cpuset; + if (prio_offset >= 0) { + param.sched_priority = sched_get_priority_max(SCHED_FIFO) - prio_offset; + pthread_attr_init(&attr); + if (pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED)) { + perror("pthread_attr_setinheritsched"); + } + if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO)) { + perror("pthread_attr_setschedpolicy"); + } + if (pthread_attr_setschedparam(&attr, ¶m)) { + perror("pthread_attr_setschedparam"); + fprintf(stderr, "Error not enough privileges to set Scheduling priority\n"); + } + } + if(cpu != -1) { + if(cpu > 50) { + int mask; + mask = cpu/100; + + CPU_ZERO(&cpuset); + for(int i = 0; i < 8;i++){ + if(((mask >> i) & 0x01) == 1){ + printf("Setting this worker with affinity to core %d\n", i); + CPU_SET((size_t) i , &cpuset); + } + } + } else { + CPU_ZERO(&cpuset); + CPU_SET((size_t) cpu, &cpuset); + printf("Setting CPU affinity to cpu_id=%d\n", cpu); + } + + if(pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset)) { + perror("pthread_attr_setaffinity_np"); + } + } + + int err = pthread_create(thread, prio_offset >= 0 ? &attr : NULL, start_routine, arg); + if (err) { + if (EPERM == err) { + perror("Warning: Failed to create thread with real-time priority. Creating it with normal priority"); + err = pthread_create(thread, NULL, start_routine, arg); + if (err) { + perror("pthread_create"); + } else { + ret = true; + } + } else { + perror("pthread_create"); + } + } else { + ret = true; + } + if (prio_offset >= 0) { + pthread_attr_destroy(&attr); + } + return ret; +} + +void threads_print_self() { + pthread_t thread; + cpu_set_t cpuset; + struct sched_param param; + int policy; + const char *p; + int s,j; + + thread = pthread_self(); + + s = pthread_getaffinity_np(thread, sizeof(cpu_set_t), &cpuset); + if (s != 0) { + printf("error pthread_getaffinity_np: %s\n",strerror(s)); + } + + printf("Set returned by pthread_getaffinity_np() contained:\n"); + for (j = 0; j < CPU_SETSIZE; j++) { + if (CPU_ISSET(j, &cpuset)) { + printf(" CPU %d\n", j); + } + } + + s = pthread_getschedparam(thread, &policy, ¶m); + if (s != 0) { + printf("error pthread_getaffinity_np: %s\n", strerror(s)); + } + + switch(policy) { + case SCHED_FIFO: + p = "SCHED_FIFO"; + break; + case SCHED_RR: + p = "SCHED_RR"; + break; + default: + p = "Other"; + break; + } + + printf("Sched policy is %s. Priority is %d\n",p,param.sched_priority); +} diff --git a/srslte/lib/common/tti_sync_cv.cc b/srslte/lib/common/tti_sync_cv.cc new file mode 100644 index 000000000..f68eb71fa --- /dev/null +++ b/srslte/lib/common/tti_sync_cv.cc @@ -0,0 +1,78 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include + +#include "common/tti_sync_cv.h" + + +namespace srslte { + + tti_sync_cv::tti_sync_cv(uint32_t modulus): tti_sync(modulus) + { + pthread_mutex_init(&mutex, NULL); + pthread_cond_init(&cond, NULL); + } + + tti_sync_cv::~tti_sync_cv() + { + pthread_cond_destroy(&cond); + pthread_mutex_destroy(&mutex); + } + + uint32_t tti_sync_cv::wait() + { + pthread_mutex_lock(&mutex); + while(wait_condition()) { + pthread_cond_wait(&cond, &mutex); + } + uint32_t x = consumer_cntr; + increase_consumer(); + pthread_mutex_unlock(&mutex); + return x; + } + + void tti_sync_cv::resync() + { + consumer_cntr = producer_cntr; + } + + void tti_sync_cv::set_producer_cntr(uint32_t producer_cntr) + { + pthread_mutex_lock(&mutex); + init_counters(producer_cntr); + pthread_cond_signal(&cond); + pthread_mutex_unlock(&mutex); + } + + void tti_sync_cv::increase() + { + pthread_mutex_lock(&mutex); + increase_producer(); + pthread_cond_signal(&cond); + pthread_mutex_unlock(&mutex); + } +} diff --git a/srslte/test/common/CMakeLists.txt b/srslte/test/common/CMakeLists.txt new file mode 100644 index 000000000..5eb73db56 --- /dev/null +++ b/srslte/test/common/CMakeLists.txt @@ -0,0 +1,37 @@ +# Copyright 2015 Software Radio Systems Limited +# +# This file is part of srsUE +# +# srsUE is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# srsUE 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 Affero General Public License for more details. +# +# A copy of the GNU Affero General Public License can be found in +# the LICENSE file in the top-level directory of this distribution +# and at http://www.gnu.org/licenses/. +# + +####################################################################### +# LOGGER TEST +####################################################################### +add_executable(logger_test logger_test.cc) +target_link_libraries(logger_test srslte_phy srslte_common srslte_phy lte ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +add_test(logger_test logger_test) + +add_executable(msg_queue_test msg_queue_test.cc) +target_link_libraries(msg_queue_test srslte_phy srslte_common ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +add_test(msg_queue_test msg_queue_test) + +add_executable(log_filter_test log_filter_test.cc) +target_link_libraries(log_filter_test srslte_phy srslte_common srslte_phy lte ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) + +add_executable(timeout_test timeout_test.cc) +target_link_libraries(timeout_test srslte_phy ${CMAKE_THREAD_LIBS_INIT}) + +add_executable(bcd_helpers_test bcd_helpers_test.cc) diff --git a/srslte/test/common/bcd_helpers_test.cc b/srslte/test/common/bcd_helpers_test.cc new file mode 100644 index 000000000..d581280db --- /dev/null +++ b/srslte/test/common/bcd_helpers_test.cc @@ -0,0 +1,67 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include "common/bcd_helpers.h" + +using namespace srslte; + +int main(int argc, char **argv) +{ + std::string mcc_str = "001"; + std::string mnc_str = "001"; + uint16_t mcc; + uint16_t mnc; + + // String to code + + assert(string_to_mcc(mcc_str, &mcc)); + assert(mcc == 0xF001); + + assert(string_to_mnc(mnc_str, &mnc)); + assert(mnc == 0xF001); + + mnc_str = "01"; + assert(string_to_mnc(mnc_str, &mnc)); + assert(mnc == 0xFF01); + + // Code to string + + mcc_str = ""; + mnc_str = ""; + mcc = 0xF001; + mnc = 0xF001; + + assert(mcc_to_string(mcc, &mcc_str)); + assert(mcc_str.compare("001") == 0); + + assert(mnc_to_string(mnc, &mnc_str)); + assert(mnc_str.compare("001") == 0); + + mnc = 0xFF01; + assert(mnc_to_string(mnc, &mnc_str)); + assert(mnc_str.compare("01") == 0); +} diff --git a/srslte/test/common/log_filter_test.cc b/srslte/test/common/log_filter_test.cc new file mode 100644 index 000000000..dd1f34fff --- /dev/null +++ b/srslte/test/common/log_filter_test.cc @@ -0,0 +1,133 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#define NTHREADS 100 +#define NMSGS 100 + +#include +#include "common/log_filter.h" + +using namespace srslte; + +typedef struct { + logger *l; + int thread_id; +}args_t; + +void* thread_loop(void *a) { + args_t *args = (args_t*)a; + char buf[100]; + + sprintf(buf, "LAYER%d", args->thread_id); + log_filter filter(buf, args->l); + filter.set_level(LOG_LEVEL_INFO); + + for(int i=0;ithread_id, i); + filter.warning("Thread %d: %d", args->thread_id, i); + filter.info("Thread %d: %d", args->thread_id, i); + filter.debug("Thread %d: %d", args->thread_id, i); + } +} + +void* thread_loop_hex(void *a) { + args_t *args = (args_t*)a; + char buf[100]; + uint8_t hex[100]; + + for(int i=0;i<100;i++) + hex[i] = i & 0xFF; + sprintf(buf, "LAYER%d", args->thread_id); + log_filter filter(buf, args->l); + filter.set_level(LOG_LEVEL_DEBUG); + filter.set_hex_limit(32); + + for(int i=0;ithread_id, i); + filter.warning_hex(hex, 100, "Thread %d: %d", args->thread_id, i); + filter.info_hex(hex, 100, "Thread %d: %d", args->thread_id, i); + filter.debug_hex(hex, 100, "Thread %d: %d", args->thread_id, i); + } + return NULL; +} + +void write(std::string filename) { + logger l; + l.init(filename); + pthread_t threads[NTHREADS]; + args_t args[NTHREADS]; + for(int i=0;i +#include +#include "common/logger.h" + +using namespace srslte; + +typedef struct { + logger *l; + int thread_id; +}args_t; + +void* thread_loop(void *a) { + args_t *args = (args_t*)a; + char buf[100]; + for(int i=0;ithread_id, i); + args->l->log(buf); + } + return NULL; +} + +void write(std::string filename) { + logger l; + l.init(filename); + pthread_t threads[NTHREADS]; + args_t args[NTHREADS]; + for(int i=0;i +#include "common/msg_queue.h" + +using namespace srslte; + +typedef struct { + msg_queue *q; +}args_t; + +void* write_thread(void *a) { + args_t *args = (args_t*)a; + for(uint32_t i=0;imsg, &i, 4); + b->N_bytes = 4; + args->q->write(b); + } + return NULL; +} + +int main(int argc, char **argv) { + bool result; + msg_queue q; + byte_buffer_t *b; + pthread_t thread; + args_t args; + u_int32_t r; + + result = true; + args.q = &q; + + pthread_create(&thread, NULL, &write_thread, &args); + + for(uint32_t i=0;imsg, 4); + delete b; + if(r != i) + result = false; + } + + pthread_join(thread, NULL); + + if(result) { + printf("Passed\n"); + exit(0); + }else{ + printf("Failed\n;"); + exit(1); + } +} diff --git a/srslte/test/common/timeout_test.cc b/srslte/test/common/timeout_test.cc new file mode 100644 index 000000000..57566c615 --- /dev/null +++ b/srslte/test/common/timeout_test.cc @@ -0,0 +1,92 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + + +#include +#include +#include "common/timeout.h" + +using namespace srslte; + +class callback + : public timeout_callback +{ +public: + callback() { + finished = false; + pthread_mutex_init(&mutex, NULL); + pthread_cond_init(&cvar, NULL); + } + + void timeout_expired(uint32_t timeout_id) + { + pthread_mutex_lock(&mutex); + finished = true; + pthread_cond_signal(&cvar); + pthread_mutex_unlock(&mutex); + } + void wait() + { + pthread_mutex_lock(&mutex); + while(!finished) { + pthread_cond_wait(&cvar, &mutex); + } + pthread_mutex_unlock(&mutex); + } + struct timeval start_time[3]; +private: + bool finished; + pthread_cond_t cvar; + pthread_mutex_t mutex; +}; + +int main(int argc, char **argv) { + bool result; + uint32_t id = 0; + uint32_t duration_msec = 5; + + callback c; + timeout t; + + gettimeofday(&c.start_time[1], NULL); + t.start(duration_msec, 0, &c); + c.wait(); + gettimeofday(&c.start_time[2], NULL); + get_time_interval(c.start_time); + uint32_t diff_ms = c.start_time[0].tv_usec*1e-3; + printf("Target duration: %dms, started: %ld:%ld, ended: %ld:%ld, actual duration %dms\n", + duration_msec, c.start_time[1].tv_sec, c.start_time[1].tv_usec, c.start_time[2].tv_sec, c.start_time[2].tv_usec, diff_ms); + + result = (diff_ms == duration_msec); + + if(result) { + printf("Passed\n"); + exit(0); + }else{ + printf("Failed\n;"); + exit(1); + } +}