aboutsummaryrefslogtreecommitdiffstats
path: root/src/pcu_l1_if.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/pcu_l1_if.cpp')
-rw-r--r--src/pcu_l1_if.cpp204
1 files changed, 175 insertions, 29 deletions
diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp
index fe933b93..4836e940 100644
--- a/src/pcu_l1_if.cpp
+++ b/src/pcu_l1_if.cpp
@@ -17,12 +17,64 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#include <errno.h>
+#include <string.h>
#include <gprs_rlcmac.h>
#include <pcu_l1_if.h>
#include <gprs_debug.h>
+#include <bitvector.h>
+#include <gsmL1prim.h>
+#include <sys/socket.h>
+#include <linux/in.h>
+extern "C" {
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/write_queue.h>
+#include <osmocom/core/socket.h>
+#include <osmocom/core/timer.h>
+#include <osmocom/gsm/gsm_utils.h>
+}
#define MAX_UDP_LENGTH 1500
+#define msgb_l1prim(msg) ((GsmL1_Prim_t *)(msg)->l1h)
+
+struct femtol1_hdl {
+ struct gsm_time gsm_time;
+ uint32_t hLayer1; /* handle to the L1 instance in the DSP */
+ uint32_t dsp_trace_f;
+ uint16_t clk_cal;
+ struct llist_head wlc_list;
+
+ void *priv; /* user reference */
+
+ struct osmo_timer_list alive_timer;
+ unsigned int alive_prim_cnt;
+
+ struct osmo_fd read_ofd; /* osmo file descriptors */
+ struct osmo_wqueue write_q;
+
+ struct {
+ uint16_t arfcn;
+ uint8_t tn;
+ uint8_t tsc;
+ uint16_t ta;
+ } channel_info;
+
+};
+
+struct l1fwd_hdl {
+ struct sockaddr_storage remote_sa;
+ socklen_t remote_sa_len;
+
+ struct osmo_wqueue udp_wq;
+
+ struct femtol1_hdl *fl1h;
+};
+
+struct l1fwd_hdl *l1fh = talloc_zero(NULL, struct l1fwd_hdl);
+
+struct pcu_l1if_bts pcu_l1if_bts;
+
// Variable for storage current FN.
int frame_number;
@@ -46,34 +98,31 @@ struct msgb *l1p_msgb_alloc(void)
return msg;
}
-struct msgb *gen_dummy_msg(void)
+// Send RLC/MAC block to OpenBTS.
+void pcu_l1if_tx_pdtch(msgb *msg, uint8_t trx, uint8_t ts, uint16_t arfcn,
+ uint32_t fn, uint8_t block_nr)
{
- struct msgb *msg = l1p_msgb_alloc();
- GsmL1_Prim_t *prim = msgb_l1prim(msg);
- // RLC/MAC filler with USF=1
- bitvec *filler = bitvec_alloc(23);
- bitvec_unhex(filler, "41942b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
+ struct msgb *nmsg = l1p_msgb_alloc();
+ GsmL1_Prim_t *prim = msgb_l1prim(nmsg);
+
prim->id = GsmL1_PrimId_PhDataReq;
- prim->u.phDataReq.sapi = GsmL1_Sapi_Pacch;
- bitvec_pack(filler, prim->u.phDataReq.msgUnitParam.u8Buffer);
- prim->u.phDataReq.msgUnitParam.u8Size = filler->data_len;
- bitvec_free(filler);
- return msg;
+ prim->u.phDataReq.sapi = GsmL1_Sapi_Pdtch;
+ memcpy(prim->u.phDataReq.msgUnitParam.u8Buffer, msg->data, msg->len);
+ prim->u.phDataReq.msgUnitParam.u8Size = msg->len;
+ osmo_wqueue_enqueue(&l1fh->udp_wq, nmsg);
+ msgb_free(msg);
}
-// Send RLC/MAC block to OpenBTS.
-void pcu_l1if_tx(bitvec * block, GsmL1_Sapi_t sapi, int len)
+void pcu_l1if_tx_agch(bitvec * block, int len)
{
struct msgb *msg = l1p_msgb_alloc();
- struct osmo_wqueue * queue;
- queue = &((l1fh->fl1h)->write_q);
GsmL1_Prim_t *prim = msgb_l1prim(msg);
prim->id = GsmL1_PrimId_PhDataReq;
- prim->u.phDataReq.sapi = sapi;
+ prim->u.phDataReq.sapi = GsmL1_Sapi_Agch;
bitvec_pack(block, prim->u.phDataReq.msgUnitParam.u8Buffer);
prim->u.phDataReq.msgUnitParam.u8Size = len;
- osmo_wqueue_enqueue(queue, msg);
+ osmo_wqueue_enqueue(&l1fh->udp_wq, msg);
}
int pcu_l1if_rx_pdch(GsmL1_PhDataInd_t *data_ind)
@@ -82,31 +131,27 @@ int pcu_l1if_rx_pdch(GsmL1_PhDataInd_t *data_ind)
bitvec_unpack(block, data_ind->msgUnitParam.u8Buffer);
gprs_rlcmac_rcv_block(block);
bitvec_free(block);
+
+ return 0;
}
static int handle_ph_connect_ind(struct femtol1_hdl *fl1, GsmL1_PhConnectInd_t *connect_ind)
{
+ pcu_l1if_bts.trx[0].arfcn = connect_ind->u16Arfcn;
+ pcu_l1if_bts.trx[0].ts[connect_ind->u8Tn].enable = 1;
+ pcu_l1if_bts.trx[0].ts[connect_ind->u8Tn].tsc = connect_ind->u8Tsc;
(l1fh->fl1h)->channel_info.arfcn = connect_ind->u16Arfcn;
(l1fh->fl1h)->channel_info.tn = connect_ind->u8Tn;
(l1fh->fl1h)->channel_info.tsc = connect_ind->u8Tsc;
LOGP(DL1IF, LOGL_NOTICE, "RX: [ PCU <- BTS ] PhConnectInd: ARFCN: %u TN: %u TSC: %u \n",
connect_ind->u16Arfcn, (unsigned)connect_ind->u8Tn, (unsigned)connect_ind->u8Tsc);
+
+ return 0;
}
static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1, GsmL1_PhReadyToSendInd_t *readytosend_ind)
{
- struct msgb *resp_msg;
- struct osmo_wqueue * queue;
- queue = &((l1fh->fl1h)->write_q);
-
- set_current_fn(readytosend_ind->u32Fn);
- resp_msg = msgb_dequeue(&queue->msg_queue);
- if (!resp_msg) {
- resp_msg = gen_dummy_msg();
- if (!resp_msg)
- return 0;
- }
- osmo_wqueue_enqueue(&l1fh->udp_wq, resp_msg);
+ gprs_rlcmac_rcv_rts_block(0,0, (l1fh->fl1h)->channel_info.arfcn, readytosend_ind->u32Fn, 0);
return 1;
}
@@ -172,3 +217,104 @@ int pcu_l1if_handle_l1prim(struct femtol1_hdl *fl1, struct msgb *msg)
return rc;
}
+
+/* OpenBTS socket functions */
+
+// TODO: We should move this parameters to config file.
+#define PCU_L1_IF_PORT 5944
+
+/* data has arrived on the udp socket */
+static int udp_read_cb(struct osmo_fd *ofd)
+{
+ struct msgb *msg = msgb_alloc_headroom(2048, 128, "udp_rx");
+ struct l1fwd_hdl *l1fh = (l1fwd_hdl *)ofd->data;
+ struct femtol1_hdl *fl1h = l1fh->fl1h;
+ int rc;
+
+ if (!msg)
+ return -ENOMEM;
+
+ msg->l1h = msg->data;
+
+ l1fh->remote_sa_len = sizeof(l1fh->remote_sa);
+ rc = recvfrom(ofd->fd, msg->l1h, msgb_tailroom(msg), 0,
+ (struct sockaddr *) &l1fh->remote_sa, &l1fh->remote_sa_len);
+ if (rc < 0) {
+ perror("read from udp");
+ msgb_free(msg);
+ return rc;
+ } else if (rc == 0) {
+ perror("len=0 read from udp");
+ msgb_free(msg);
+ return rc;
+ }
+ msgb_put(msg, rc);
+
+ rc = pcu_l1if_handle_l1prim(fl1h, msg);
+ return rc;
+}
+
+/* callback when we can write to the UDP socket */
+static int udp_write_cb(struct osmo_fd *ofd, struct msgb *msg)
+{
+ int rc;
+ struct l1fwd_hdl *l1fh = (l1fwd_hdl *)ofd->data;
+
+ //DEBUGP(DGPRS, "UDP: Writing %u bytes for MQ_L1_WRITE queue\n", msgb_l1len(msg));
+
+ rc = sendto(ofd->fd, msg->l1h, msgb_l1len(msg), 0,
+ (const struct sockaddr *)&l1fh->remote_sa, l1fh->remote_sa_len);
+ if (rc < 0) {
+ LOGP(DPCU, LOGL_ERROR, "error writing to L1 msg_queue: %s\n",
+ strerror(errno));
+ return rc;
+ } else if (rc < (int)msgb_l1len(msg)) {
+ LOGP(DPCU, LOGL_ERROR, "short write to L1 msg_queue: "
+ "%u < %u\n", rc, msgb_l1len(msg));
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int pcu_l1if_open()
+{
+ //struct l1fwd_hdl *l1fh;
+ struct femtol1_hdl *fl1h;
+ int rc;
+
+ memset(&pcu_l1if_bts, 0, sizeof(pcu_l1if_bts));
+
+ /* allocate new femtol1_handle */
+ fl1h = talloc_zero(NULL, struct femtol1_hdl);
+ INIT_LLIST_HEAD(&fl1h->wlc_list);
+
+ l1fh->fl1h = fl1h;
+ fl1h->priv = l1fh;
+
+ struct osmo_wqueue * queue = &((l1fh->fl1h)->write_q);
+ osmo_wqueue_init(queue, 10);
+ queue->bfd.when |= BSC_FD_READ;
+ queue->bfd.data = l1fh;
+ queue->bfd.priv_nr = 0;
+
+ /* Open UDP */
+ struct osmo_wqueue *wq = &l1fh->udp_wq;
+
+ osmo_wqueue_init(wq, 10);
+ wq->write_cb = udp_write_cb;
+ wq->read_cb = udp_read_cb;
+ wq->bfd.when |= BSC_FD_READ;
+ wq->bfd.data = l1fh;
+ wq->bfd.priv_nr = 0;
+ rc = osmo_sock_init_ofd(&wq->bfd, AF_UNSPEC, SOCK_DGRAM,
+ IPPROTO_UDP, NULL, PCU_L1_IF_PORT,
+ OSMO_SOCK_F_BIND);
+ if (rc < 0) {
+ perror("sock_init");
+ exit(1);
+ }
+
+ return 0;
+}
+