diff options
Diffstat (limited to 'src/pcu_l1_if.cpp')
-rw-r--r-- | src/pcu_l1_if.cpp | 204 |
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; +} + |