diff options
author | Sylvain Munaut <tnt@246tNt.com> | 2014-06-09 20:02:23 +0200 |
---|---|---|
committer | Sylvain Munaut <tnt@246tNt.com> | 2014-06-15 19:31:12 +0200 |
commit | 31d3354b01e184e697df29d52da3066acd35d6b2 (patch) | |
tree | 9806819fc893e3b13c2b2ab1c98f22c3b54b00fb /src | |
parent | 9ec3f72277f4f3c96ac365de3022f4d181ba8c9f (diff) |
first hack that does something usefulsylvain/ms-sdr
Diffstat (limited to 'src')
-rw-r--r-- | src/host/layer23/configure.ac | 6 | ||||
-rw-r--r-- | src/host/layer23/src/Makefile.am | 4 | ||||
-rw-r--r-- | src/host/layer23/src/transceiver/l1ctl.c | 12 | ||||
-rw-r--r-- | src/host/layer23/src/transceiver/l1ctl_link.c | 136 | ||||
-rw-r--r-- | src/host/layer23/src/transceiver/l1ctl_link.h | 22 | ||||
-rw-r--r-- | src/host/layer23/src/transceiver/trx.c | 5 | ||||
-rw-r--r-- | src/host/layer23/src/transceiver_ms/Makefile.am | 6 | ||||
-rw-r--r-- | src/host/layer23/src/transceiver_ms/app.h | 50 | ||||
-rw-r--r-- | src/host/layer23/src/transceiver_ms/l1ctl.c | 294 | ||||
-rw-r--r-- | src/host/layer23/src/transceiver_ms/l1ctl.h | 31 | ||||
l--------- | src/host/layer23/src/transceiver_ms/l1ctl_link.c | 1 | ||||
l--------- | src/host/layer23/src/transceiver_ms/l1ctl_link.h | 1 | ||||
-rw-r--r-- | src/host/layer23/src/transceiver_ms/main.c | 76 | ||||
-rw-r--r-- | src/host/layer23/src/transceiver_ms/trx.c | 298 | ||||
-rw-r--r-- | src/host/layer23/src/transceiver_ms/trx.h | 45 |
15 files changed, 951 insertions, 36 deletions
diff --git a/src/host/layer23/configure.ac b/src/host/layer23/configure.ac index 1ff1bb70..8a34d9d4 100644 --- a/src/host/layer23/configure.ac +++ b/src/host/layer23/configure.ac @@ -29,6 +29,11 @@ if test "$osmo_ac_build_transceiver" = "yes" ; then fi AM_CONDITIONAL(BUILD_TRANSCEIVER, test "x$osmo_ac_build_transceiver" = "xyes") +dnl Optional transceiver_ms +AC_ARG_ENABLE([transceiver-ms], [AS_HELP_STRING([--enable-transceiver-ms], [Build the MS transceiver application])], + [osmo_ac_build_transceiver_ms="$enableval"]) +AM_CONDITIONAL(BUILD_TRANSCEIVER_MS, test "x$osmo_ac_build_transceiver_ms" = "xyes") + dnl checks for header files AC_HEADER_STDC @@ -40,6 +45,7 @@ AC_OUTPUT( src/misc/Makefile src/mobile/Makefile src/transceiver/Makefile + src/transceiver_ms/Makefile include/Makefile include/osmocom/Makefile include/osmocom/bb/Makefile diff --git a/src/host/layer23/src/Makefile.am b/src/host/layer23/src/Makefile.am index c46548c3..50b333f5 100644 --- a/src/host/layer23/src/Makefile.am +++ b/src/host/layer23/src/Makefile.am @@ -3,3 +3,7 @@ SUBDIRS = common misc mobile if BUILD_TRANSCEIVER SUBDIRS += transceiver endif + +if BUILD_TRANSCEIVER_MS +SUBDIRS += transceiver_ms +endif diff --git a/src/host/layer23/src/transceiver/l1ctl.c b/src/host/layer23/src/transceiver/l1ctl.c index e4cda24d..00308bff 100644 --- a/src/host/layer23/src/transceiver/l1ctl.c +++ b/src/host/layer23/src/transceiver/l1ctl.c @@ -175,7 +175,7 @@ _l1ctl_rx_bts_burst_nb_ind(struct app_state *as, struct msgb *msg) if (msgb_l1len(msg) < sizeof(*bi)) { LOGP(DL1C, LOGL_ERROR, "MSG too short Burst NB Ind: %u\n", - msgb_l2len(msg)); + msgb_l1len(msg)); rc = -EINVAL; goto exit; } @@ -214,7 +214,7 @@ _l1ctl_rx_bts_burst_ab_ind(struct app_state *as, struct msgb *msg) if (msgb_l1len(msg) < sizeof(*bi)) { LOGP(DL1C, LOGL_ERROR, "MSG too short Burst AB Ind: %u\n", - msgb_l2len(msg)); + msgb_l1len(msg)); rc = -EINVAL; goto exit; } @@ -245,14 +245,14 @@ _l1ctl_rx_data_ind(struct app_state *as, struct msgb *msg) if (msgb_l1len(msg) < sizeof(*dl)) { LOGP(DL1C, LOGL_ERROR, "Short Layer2 message: %u\n", - msgb_l2len(msg)); + msgb_l1len(msg)); rc = -EINVAL; goto exit; } if (msgb_l2len(msg) < sizeof(*di)) { LOGP(DL1C, LOGL_ERROR, "MSG too short Data Ind: %u\n", - msgb_l3len(msg)); + msgb_l2len(msg)); rc = -EINVAL; goto exit; } @@ -289,14 +289,14 @@ _l1ctl_rx_fbsb_conf(struct app_state *as, struct msgb *msg) if (msgb_l1len(msg) < sizeof(*dl)) { LOGP(DL1C, LOGL_ERROR, "Short Layer2 message: %u\n", - msgb_l2len(msg)); + msgb_l1len(msg)); rc = -EINVAL; goto exit; } if (msgb_l2len(msg) < sizeof(*sc)) { LOGP(DL1C, LOGL_ERROR, "MSG too short FBSB Conf: %u\n", - msgb_l3len(msg)); + msgb_l2len(msg)); rc = -EINVAL; goto exit; } diff --git a/src/host/layer23/src/transceiver/l1ctl_link.c b/src/host/layer23/src/transceiver/l1ctl_link.c index 5ec83e42..6060c821 100644 --- a/src/host/layer23/src/transceiver/l1ctl_link.c +++ b/src/host/layer23/src/transceiver/l1ctl_link.c @@ -29,6 +29,8 @@ #include <sys/un.h> #include <arpa/inet.h> +#include <osmocom/core/socket.h> +#include <osmocom/core/talloc.h> #include <osmocom/core/write_queue.h> #include <osmocom/bb/common/logging.h> @@ -103,44 +105,29 @@ _l1l_write(struct osmo_fd *fd, struct msgb *msg) int l1l_open(struct l1ctl_link *l1l, - const char *path, l1ctl_cb_t cb, void *cb_data) + const char *path, l1ctl_cb_t cb, void *cb_data) { - int rc, fd; - struct sockaddr_un local; + int rc; + + memset(l1l, 0x00, sizeof(struct l1ctl_link)); l1l->cb = cb; l1l->cb_data = cb_data; - fd = socket(AF_UNIX, SOCK_STREAM, 0); - if (fd < 0) { - LOGP(DL1C, LOGL_ERROR, "Failed to create unix domain socket.\n"); - return fd; - } - - l1l->wq.bfd.fd = fd; - - local.sun_family = AF_UNIX; - strncpy(local.sun_path, path, sizeof(local.sun_path)); - local.sun_path[sizeof(local.sun_path) - 1] = '\0'; - - rc = connect(fd, (struct sockaddr *) &local, sizeof(local)); - if (rc < 0) { - LOGP(DL1C, LOGL_ERROR, "Failed to connect to '%s': %s\n", - local.sun_path, strerror(errno)); - close(fd); - return rc; - } - osmo_wqueue_init(&l1l->wq, 100); l1l->wq.bfd.data = l1l; - l1l->wq.bfd.when = BSC_FD_READ; l1l->wq.read_cb = _l1l_read; l1l->wq.write_cb = _l1l_write; - rc = osmo_fd_register(&l1l->wq.bfd); - if (rc != 0) { - LOGP(DL1C, LOGL_ERROR, "Failed to register fd.\n"); - close(fd); + rc = osmo_sock_unix_init_ofd( + &l1l->wq.bfd, + SOCK_STREAM, 0, + path, + OSMO_SOCK_F_CONNECT + ); + + if (rc < 0) { + LOGP(DL1C, LOGL_ERROR, "Failed to create and init unix domain socket.\n"); return rc; } @@ -160,6 +147,9 @@ l1l_close(struct l1ctl_link *l1l) osmo_wqueue_clear(&l1l->wq); + if (l1l->to_free) + talloc_free(l1l); + return 0; } @@ -185,3 +175,93 @@ l1l_send(struct l1ctl_link *l1l, struct msgb *msg) return 0; } + + +static int +_l1l_accept(struct osmo_fd *fd, unsigned int flags) +{ + struct l1ctl_server *l1s = fd->data; + struct l1ctl_link *l1l; + struct sockaddr_un un_addr; + socklen_t len; + int cfd, rc; + + len = sizeof(un_addr); + cfd = accept(fd->fd, (struct sockaddr *) &un_addr, &len); + if (cfd < 0) { + LOGP(DL1C, LOGL_ERROR, "Failed to accept a new L1CTL connection.\n"); + return cfd; + } + + l1l = talloc_zero(NULL, struct l1ctl_link); + if (!l1l) { + LOGP(DL1C, LOGL_ERROR, "Failed to allocate a new L1CTL connection.\n"); + return -ENOMEM; + } + + l1l->to_free = 1; + + osmo_wqueue_init(&l1l->wq, 100); + l1l->wq.bfd.fd = cfd; + l1l->wq.bfd.data = l1l; + l1l->wq.bfd.when = BSC_FD_READ; + l1l->wq.read_cb = _l1l_read; + l1l->wq.write_cb = _l1l_write; + + INIT_LLIST_HEAD(&l1l->wq.bfd.list); + + rc = l1s->cb(l1s->cb_data, l1l); + if (rc) + goto error; + + if (!l1l->cb || !l1l->cb_data) { + LOGP(DL1C, LOGL_NOTICE, "New L1CTL callback didn't set message callback !\n"); + } + + rc = osmo_fd_register(&l1l->wq.bfd); + if (rc) { + LOGP(DL1C, LOGL_ERROR, "Failed to register fd of new L1CTL connection.\n"); + goto error; + } + + return 0; + +error: + if (l1l) + l1l_close(l1l); + + return rc; +} + +int +l1l_start_server(struct l1ctl_server *l1s, const char *path, + l1ctl_server_cb_t cb, void *cb_data) +{ + int rc; + + memset(l1s, 0x00, sizeof(struct l1ctl_server)); + + l1s->cb = cb; + l1s->cb_data = cb_data; + + l1s->bfd.cb = _l1l_accept; + l1s->bfd.data = l1s; + + rc = osmo_sock_unix_init_ofd( + &l1s->bfd, + SOCK_STREAM, 0, + path, + OSMO_SOCK_F_BIND + ); + if (rc < 0) + return rc; + + return 0; +} + +void +l1l_stop_server(struct l1ctl_server *l1s) +{ + /* FIXME */ + +} diff --git a/src/host/layer23/src/transceiver/l1ctl_link.h b/src/host/layer23/src/transceiver/l1ctl_link.h index e53bd829..8f96a0bc 100644 --- a/src/host/layer23/src/transceiver/l1ctl_link.h +++ b/src/host/layer23/src/transceiver/l1ctl_link.h @@ -25,9 +25,12 @@ #define __TRX_L1CTL_LINK_H__ +#include <osmocom/core/socket.h> #include <osmocom/core/write_queue.h> +/* Link */ + typedef int (*l1ctl_cb_t)(void *data, struct msgb *msgb); struct l1ctl_link @@ -36,6 +39,8 @@ struct l1ctl_link l1ctl_cb_t cb; void *cb_data; + + int to_free; }; @@ -47,4 +52,21 @@ int l1l_close(struct l1ctl_link *l1l); int l1l_send(struct l1ctl_link *l1l, struct msgb *msg); +/* Server */ + +typedef int (*l1ctl_server_cb_t)(void *data, struct l1ctl_link *l1l); + +struct l1ctl_server +{ + struct osmo_fd bfd; + + l1ctl_server_cb_t cb; + void *cb_data; +}; + +int l1l_start_server(struct l1ctl_server *l1s, const char *path, + l1ctl_server_cb_t cb, void *cb_data); +void l1l_stop_server (struct l1ctl_server *l1s); + + #endif /* __TRX_L1CTL_LINK_H__ */ diff --git a/src/host/layer23/src/transceiver/trx.c b/src/host/layer23/src/transceiver/trx.c index 9149b7ca..7d982b3b 100644 --- a/src/host/layer23/src/transceiver/trx.c +++ b/src/host/layer23/src/transceiver/trx.c @@ -56,10 +56,10 @@ static int _trx_data_read_cb(struct osmo_fd *ofd, unsigned int what); /* ------------------------------------------------------------------------ */ -/* Init */ +/* Init / Cleanup */ /* ------------------------------------------------------------------------ */ -int +static int _trx_udp_init(struct trx *trx, struct osmo_fd *ofd, const char *addr, uint16_t port, int (*cb)(struct osmo_fd *fd, unsigned int what)) @@ -150,6 +150,7 @@ trx_alloc(const char *addr, uint16_t base_port, struct l1ctl_link *l1l) return trx; err: + /* FIXME */ return NULL; } diff --git a/src/host/layer23/src/transceiver_ms/Makefile.am b/src/host/layer23/src/transceiver_ms/Makefile.am new file mode 100644 index 00000000..88d7a7b4 --- /dev/null +++ b/src/host/layer23/src/transceiver_ms/Makefile.am @@ -0,0 +1,6 @@ +AM_CFLAGS = -Wall $(all_includes) -I$(top_srcdir)/include $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBSOSMODSP_CFLAGS) +LDADD = ../common/liblayer23.a $(LIBOSMOCORE_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOCODEC_LIBS) $(LIBOSMODSP_LIBS) + +bin_PROGRAMS = transceiver-ms + +transceiver_ms_SOURCES = main.c l1ctl.c l1ctl_link.c trx.c ../common/logging.c diff --git a/src/host/layer23/src/transceiver_ms/app.h b/src/host/layer23/src/transceiver_ms/app.h new file mode 100644 index 00000000..0fca124a --- /dev/null +++ b/src/host/layer23/src/transceiver_ms/app.h @@ -0,0 +1,50 @@ +/* + * app.h + * + * Application state / defines + * + * Copyright (C) 2014 Sylvain Munaut <tnt@246tNt.com> + * + * All Rights Reserved + * + * This program 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __TRXMS_APP_H__ +#define __TRXMS_APP_H__ + + +#include <stdint.h> + +#include "l1ctl_link.h" + + +struct log_target; +struct trx; + +struct app_state +{ + /* Logging */ + struct log_target *stderr_target; + + /* L1CTL server & active link */ + struct l1ctl_server l1s; + struct l1ctl_link *l1l; + + /* TRX link to Transceiver */ + struct trx *trx; +}; + + +#endif /* __TRXMS_APP_H__ */ diff --git a/src/host/layer23/src/transceiver_ms/l1ctl.c b/src/host/layer23/src/transceiver_ms/l1ctl.c new file mode 100644 index 00000000..08f30eff --- /dev/null +++ b/src/host/layer23/src/transceiver_ms/l1ctl.c @@ -0,0 +1,294 @@ +/* + * l1ctl.c + * + * L1CTL interface + * + * Copyright (C) 2014 Sylvain Munaut <tnt@246tNt.com> + * + * + * All Rights Reserved + * + * This program 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <errno.h> +#include <arpa/inet.h> + +#include <osmocom/core/select.h> +#include <osmocom/core/talloc.h> +#include <osmocom/gsm/gsm_utils.h> + +#include <osmocom/bb/common/logging.h> +#include <l1ctl_proto.h> + +#include "app.h" +#include "l1ctl.h" +#include "l1ctl_link.h" +#include "trx.h" + + +/* ------------------------------------------------------------------------ */ +/* L1CTL exported API */ +/* ------------------------------------------------------------------------ */ + +static struct msgb * +_l1ctl_alloc(uint8_t msg_type) +{ + struct l1ctl_hdr *l1h; + struct msgb *msg = msgb_alloc_headroom(256, 4, "osmo_l1"); + + if (!msg) { + LOGP(DL1C, LOGL_ERROR, "Failed to allocate memory.\n"); + return NULL; + } + + msg->l1h = msgb_put(msg, sizeof(*l1h)); + l1h = (struct l1ctl_hdr *) msg->l1h; + l1h->msg_type = msg_type; + + return msg; +} + +int +l1ctl_tx_pm_conf(struct l1ctl_link *l1l, uint16_t band_arfcn, int dbm, int last) +{ + struct msgb *msg; + struct l1ctl_pm_conf *pmc; + + msg = _l1ctl_alloc(L1CTL_PM_CONF); + if (!msg) + return -ENOMEM; + + LOGP(DL1C, LOGL_DEBUG, "Tx PM Conf (%s %d = %d dBm)\n", + gsm_band_name(gsm_arfcn2band(band_arfcn)), + band_arfcn &~ ARFCN_FLAG_MASK, + dbm + ); + + pmc = (struct l1ctl_pm_conf *) msgb_put(msg, sizeof(*pmc)); + pmc->band_arfcn = htons(band_arfcn); + pmc->pm[0] = dbm2rxlev(dbm); + pmc->pm[1] = 0; + + if (last) { + struct l1ctl_hdr *l1h = ( struct l1ctl_hdr *)msg->l1h; + l1h->flags |= L1CTL_F_DONE; + } + + return l1l_send(l1l, msg); +} + +int +l1ctl_tx_reset_ind(struct l1ctl_link *l1l, uint8_t type) +{ + struct msgb *msg; + struct l1ctl_reset *res; + + msg = _l1ctl_alloc(L1CTL_RESET_IND); + if (!msg) + return -ENOMEM; + + LOGP(DL1C, LOGL_DEBUG, "Tx Reset Ind (%u)\n", type); + + res = (struct l1ctl_reset *) msgb_put(msg, sizeof(*res)); + res->type = type; + + return l1l_send(l1l, msg); +} + +int +l1ctl_tx_reset_conf(struct l1ctl_link *l1l, uint8_t type) +{ + struct msgb *msg; + struct l1ctl_reset *res; + + msg = _l1ctl_alloc(L1CTL_RESET_CONF); + if (!msg) + return -ENOMEM; + + LOGP(DL1C, LOGL_DEBUG, "Tx Reset Conf (%u)\n", type); + res = (struct l1ctl_reset *) msgb_put(msg, sizeof(*res)); + res->type = type; + + return l1l_send(l1l, msg); +} + + +/* ------------------------------------------------------------------------ */ +/* L1CTL Receive handling */ +/* ------------------------------------------------------------------------ */ + +static int +_l1ctl_rx_fbsb_req(struct app_state *as, struct msgb *msg) +{ + struct l1ctl_fbsb_req *fbsb; + uint16_t band_arfcn; + int rc = 0; + + /* Grab message */ + fbsb = (struct l1ctl_fbsb_req *) msg->l1h; + + if (msgb_l1len(msg) < sizeof(*fbsb)) { + LOGP(DL1C, LOGL_ERROR, "MSG too short FBSB Req: %u\n", + msgb_l1len(msg)); + rc = -EINVAL; + goto exit; + } + + band_arfcn = ntohs(fbsb->band_arfcn); + + LOGP(DL1C, LOGL_DEBUG, "Rx FBSB Req (%s %d)\n", + gsm_band_name(gsm_arfcn2band(band_arfcn)), + band_arfcn &~ ARFCN_FLAG_MASK + ); + + /* Send request to TRX */ + trx_ctrl_send_cmd(as->trx, "TXTUNE", "%d", + (int)gsm_arfcn2freq10(band_arfcn, 1) * 100); + trx_ctrl_send_cmd(as->trx, "RXTUNE", "%d", + (int)gsm_arfcn2freq10(band_arfcn, 0) * 100); + trx_ctrl_send_cmd(as->trx, "POWERON", NULL); + trx_ctrl_send_cmd(as->trx, "SYNC", NULL); + +exit: + msgb_free(msg); + + return rc; +} + +static int +_l1ctl_rx_pm_req(struct app_state *as, struct msgb *msg) +{ + struct l1ctl_pm_req *pmr; + uint16_t arfcn_start, arfcn_stop, arfcn; + int rc = 0; + + /* Grab message */ + pmr = (struct l1ctl_pm_req *) msg->l1h; + + if (msgb_l1len(msg) < sizeof(*pmr)) { + LOGP(DL1C, LOGL_ERROR, "MSG too short PM Req: %u\n", + msgb_l1len(msg)); + rc = -EINVAL; + goto exit; + } + + arfcn_start = ntohs(pmr->range.band_arfcn_from); + arfcn_stop = ntohs(pmr->range.band_arfcn_to); + + LOGP(DL1C, LOGL_DEBUG, "Rx PM Req (%s: %d -> %d)\n", + gsm_band_name(gsm_arfcn2band(arfcn_start)), + arfcn_start &~ ARFCN_FLAG_MASK, + arfcn_stop &~ ARFCN_FLAG_MASK + ); + + /* Send fake responses */ + for (arfcn=arfcn_start; arfcn<=arfcn_stop; arfcn++) + { + l1ctl_tx_pm_conf(as->l1l, arfcn, arfcn == 36 ? -60 : -120, arfcn == arfcn_stop); + } + +exit: + msgb_free(msg); + + return rc; +} + +static int +_l1ctl_rx_reset_req(struct app_state *as, struct msgb *msg) +{ + struct l1ctl_reset *res; + int rc = 0; + + /* Grab message */ + res = (struct l1ctl_reset *) msg->l1h; + + if (msgb_l1len(msg) < sizeof(*res)) { + LOGP(DL1C, LOGL_ERROR, "MSG too short Reset Req: %u\n", + msgb_l1len(msg)); + rc = -EINVAL; + goto exit; + } + + LOGP(DL1C, LOGL_DEBUG, "Rx Reset Req (%u)\n", res->type); + + /* Request power off */ + trx_ctrl_send_cmd(as->trx, "POWEROFF", NULL); + + /* Simply confirm */ + rc = l1ctl_tx_reset_conf(as->l1l, res->type); + +exit: + msgb_free(msg); + + return rc; +} + + +static int +_l1ctl_recv(void *data, struct msgb *msg) +{ + struct app_state *as = data; + struct l1ctl_hdr *l1h; + int rc = 0; + + /* move the l1 header pointer to point _BEHIND_ l1ctl_hdr, + as the l1ctl header is of no interest to subsequent code */ + l1h = (struct l1ctl_hdr *) msg->l1h; + msg->l1h = l1h->data; + + /* Act */ + switch (l1h->msg_type) { + case L1CTL_FBSB_REQ: + rc = _l1ctl_rx_fbsb_req(as, msg); + break; + case L1CTL_PM_REQ: + rc = _l1ctl_rx_pm_req(as, msg); + break; + case L1CTL_RESET_REQ: + rc = _l1ctl_rx_reset_req(as, msg); + break; + default: + LOGP(DL1C, LOGL_ERROR, "Unknown MSG: %u\n", l1h->msg_type); + msgb_free(msg); + } + + return rc; +} + +int +l1ctl_new_cb(void *data, struct l1ctl_link *l1l) +{ + struct app_state *as = data; + + LOGP(DL1C, LOGL_INFO, "New L1CTL connection\n"); + + /* Close previous link */ + if (as->l1l) { + LOGP(DL1C, LOGL_INFO, "Closing old L1CTL connection\n"); + l1l_close(as->l1l); + } + + /* Setup new one */ + as->l1l = l1l; + + l1l->cb = _l1ctl_recv; + l1l->cb_data = data; + + /* Send reset ind */ + l1ctl_tx_reset_ind(l1l, L1CTL_RES_T_BOOT); + + /* Done */ + return 0; +} diff --git a/src/host/layer23/src/transceiver_ms/l1ctl.h b/src/host/layer23/src/transceiver_ms/l1ctl.h new file mode 100644 index 00000000..e5dd931a --- /dev/null +++ b/src/host/layer23/src/transceiver_ms/l1ctl.h @@ -0,0 +1,31 @@ +/* + * l1ctl.h + * + * L1CTL interface + * + * Copyright (C) 2014 Sylvain Munaut <tnt@246tNt.com> + * + * All Rights Reserved + * + * This program 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __TRXMS_L1CTL_H__ +#define __TRXMS_L1CTL_H__ + +struct l1ctl_link; + +int l1ctl_new_cb(void *data, struct l1ctl_link *l1l); + +#endif /* __TRXMS_L1CTL_H__ */ diff --git a/src/host/layer23/src/transceiver_ms/l1ctl_link.c b/src/host/layer23/src/transceiver_ms/l1ctl_link.c new file mode 120000 index 00000000..b2a489bc --- /dev/null +++ b/src/host/layer23/src/transceiver_ms/l1ctl_link.c @@ -0,0 +1 @@ +../transceiver/l1ctl_link.c
\ No newline at end of file diff --git a/src/host/layer23/src/transceiver_ms/l1ctl_link.h b/src/host/layer23/src/transceiver_ms/l1ctl_link.h new file mode 120000 index 00000000..12cdab9e --- /dev/null +++ b/src/host/layer23/src/transceiver_ms/l1ctl_link.h @@ -0,0 +1 @@ +../transceiver/l1ctl_link.h
\ No newline at end of file diff --git a/src/host/layer23/src/transceiver_ms/main.c b/src/host/layer23/src/transceiver_ms/main.c new file mode 100644 index 00000000..1598ab22 --- /dev/null +++ b/src/host/layer23/src/transceiver_ms/main.c @@ -0,0 +1,76 @@ +/* + * main.c + * + * MS-side Transceiver main program + * + * Copyright (C) 2014 Sylvain Munaut <tnt@246tNt.com> + * + * All Rights Reserved + * + * This program 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdio.h> +#include <string.h> + +#include <osmocom/core/talloc.h> + +#include <osmocom/bb/common/logging.h> + +#include "app.h" +#include "l1ctl.h" +#include "l1ctl_link.h" +#include "trx.h" + + +void *l23_ctx = NULL; + + +int main(int argc, char *argv[]) +{ + struct app_state _as, *as = &_as; + int rv; + + /* Options */ + + /* App state init */ + memset(as, 0x00, sizeof(struct app_state)); + + /* Init talloc */ + l23_ctx = talloc_named_const(NULL, 1, "l23 app context"); + + /* Init logging */ + log_init(&log_info, l23_ctx); + + as->stderr_target = log_target_create_stderr(); + + log_add_target(as->stderr_target); + log_set_all_filter(as->stderr_target, 1); + log_set_log_level(as->stderr_target, LOGL_DEBUG); + + /* Init TRX interface */ + as->trx = trx_alloc("127.0.0.1", 5700); + if (!as->trx) + exit(-1); + + /* Start L1CTL server */ + l1l_start_server(&as->l1s, "/tmp/osmocom_l2", l1ctl_new_cb, as); + + /* Main loop */ + while (1) { + osmo_select_main(0); + } + + return 0; +} diff --git a/src/host/layer23/src/transceiver_ms/trx.c b/src/host/layer23/src/transceiver_ms/trx.c new file mode 100644 index 00000000..d20dd541 --- /dev/null +++ b/src/host/layer23/src/transceiver_ms/trx.c @@ -0,0 +1,298 @@ +/* + * trx.c + * + * OpenBTS TRX interface handling + * + * Copyright (C) 2014 Sylvain Munaut <tnt@246tNt.com> + * + * All Rights Reserved + * + * This program 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <errno.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include <sys/types.h> +#include <sys/socket.h> + +#include <netinet/in.h> + +#include <osmocom/core/select.h> +#include <osmocom/core/socket.h> +#include <osmocom/core/talloc.h> + +#include <osmocom/bb/common/logging.h> + +#include "trx.h" + + +static int _trx_clk_read_cb(struct osmo_fd *ofd, unsigned int what); +static int _trx_ctrl_read_cb(struct osmo_fd *ofd, unsigned int what); +static int _trx_data_read_cb(struct osmo_fd *ofd, unsigned int what); + + +/* ------------------------------------------------------------------------ */ +/* Init / Cleanup */ +/* ------------------------------------------------------------------------ */ + +static int +_trx_udp_init(struct trx *trx, + struct osmo_fd *ofd, const char *addr, uint16_t port, + int (*cb)(struct osmo_fd *fd, unsigned int what)) +{ + struct sockaddr_storage _sas; + struct sockaddr *sa = (struct sockaddr *)&_sas; + socklen_t sa_len; + int rv; + + /* Init */ + ofd->fd = -1; + ofd->cb = cb; + ofd->data = trx; + + /* Listen / Binds */ + rv = osmo_sock_init_ofd( + ofd, + AF_UNSPEC, SOCK_DGRAM, 0, addr, port + 100, + OSMO_SOCK_F_BIND); + if (rv < 0) + goto err; + + /* Connect */ + sa_len = sizeof(struct sockaddr_storage); + rv = getsockname(ofd->fd, sa, &sa_len); + if (rv) + goto err; + + if (sa->sa_family == AF_INET) { + struct sockaddr_in *sin = (struct sockaddr_in *)sa; + sin->sin_port = htons(ntohs(sin->sin_port)-100); + } else if (sa->sa_family == AF_INET6) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; + sin6->sin6_port = htons(ntohs(sin6->sin6_port)-100); + } else { + rv = -EINVAL; + goto err; + } + + rv = connect(ofd->fd, sa, sa_len); + if (rv) + goto err; + + return 0; + +err: + if (ofd->fd >= 0) { + osmo_fd_unregister(ofd); + close(ofd->fd); + } + + return rv; +} + + +struct trx * +trx_alloc(const char *addr, uint16_t base_port) +{ + struct trx *trx; + int rv; + + /* Alloc */ + trx = talloc_zero(NULL, struct trx); + if (!trx) + return NULL; + + /* Clock */ + rv = _trx_udp_init(trx, &trx->ofd_clk, addr, base_port, _trx_clk_read_cb); + if (rv) + goto err; + + /* Control */ + rv = _trx_udp_init(trx, &trx->ofd_ctrl, addr, base_port+1, _trx_ctrl_read_cb); + if (rv) + goto err; + + /* Data */ + rv = _trx_udp_init(trx, &trx->ofd_data, addr, base_port+2, _trx_data_read_cb); + if (rv) + goto err; + + /* Done */ + return trx; + + /* Error path */ +err: + trx_free(trx); + + return NULL; +} + +void +trx_free(struct trx *trx) +{ + if (trx->ofd_data.fd >= 0) { + osmo_fd_unregister(&trx->ofd_data); + close(trx->ofd_data.fd); + } + + if (trx->ofd_ctrl.fd >= 0) { + osmo_fd_unregister(&trx->ofd_ctrl); + close(trx->ofd_ctrl.fd); + } + + if (trx->ofd_clk.fd >= 0) { + osmo_fd_unregister(&trx->ofd_clk); + close(trx->ofd_clk.fd); + } + + talloc_free(trx); +} + + +/* ------------------------------------------------------------------------ */ +/* Clock interface */ +/* ------------------------------------------------------------------------ */ + +#define CLK_BUF_LEN 128 + +static int +_trx_clk_read_cb(struct osmo_fd *ofd, unsigned int what) +{ + char buf[CLK_BUF_LEN]; + uint32_t fn; + int l; + + l = recv(ofd->fd, buf, sizeof(buf), MSG_TRUNC); + if (l <= 0) + return -EIO; + if (l >= sizeof(buf)) { + LOGP(DTRX, LOGL_ERROR, + "Received large message on CLK interface (%d)\n", l); + return -EINVAL; + } + + if (memcmp("IND CLOCK ", buf, 10) || buf[l-1]) { + LOGP(DTRX, LOGL_ERROR, + "Received invalid message on CLK interface\n"); + return -EINVAL; + } + + fn = atoi(&buf[11]); + + LOGP(DTRX, LOGL_DEBUG, "Clock IND: fn=%d\n", (int)fn); + + /* FIXME call the clk ind callback */ + + return 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Control interface */ +/* ------------------------------------------------------------------------ */ + +#define CMD_BUF_LEN 128 + +static int +_trx_ctrl_read_cb(struct osmo_fd *ofd, unsigned int what) +{ + char buf[CMD_BUF_LEN]; + int l; + + l = recv(ofd->fd, buf, sizeof(buf), MSG_TRUNC); + if (l <= 0) + return -EIO; + + /* FIXME should not happen ... */ + + printf("Here %s\n", buf); + + return 0; +} + +#include <fcntl.h> + +int +trx_ctrl_send_cmd(struct trx *trx, const char *cmd, const char *fmt, ...) +{ + va_list ap; + char buf[CMD_BUF_LEN], cmd_match[32]; + int l; + + /* Send the commands */ + l = snprintf(buf, sizeof(buf)-1, "CMD %s%s", cmd, fmt ? " " : ""); + + if (fmt) { + va_start(ap, fmt); + l += vsnprintf(buf+l, sizeof(buf)-l-1, fmt, ap); + va_end(ap); + } + + buf[l] = '\0'; + + LOGP(DTRX, LOGL_DEBUG, "TRX Control send: |%s|\n", buf); + + send(trx->ofd_ctrl.fd, buf, strlen(buf)+1, 0); + + /* Wait for response */ + { + int fd = trx->ofd_ctrl.fd; + int flags; + + /* make FD nonblocking */ + flags = fcntl(fd, F_GETFL); + if (flags < 0) + return flags; + flags &= ~O_NONBLOCK; + flags = fcntl(fd, F_SETFL, flags); + if (flags < 0) + return flags; + } + + /* Get a response */ + l = recv(trx->ofd_ctrl.fd, buf, sizeof(buf), MSG_TRUNC); + if (l <= 0) + return -EIO; + + if (memcmp(buf, "RSP ", 4) || buf[l-1] != '\0') { + LOGP(DTRX, LOGL_ERROR, "Invalid response on TRX Control socket\n"); + return -EIO; + } + + LOGP(DTRX, LOGL_DEBUG, "TRX Control read: |%s|\n", buf); + + return 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Data interface */ +/* ------------------------------------------------------------------------ */ + +static int +_trx_data_read_cb(struct osmo_fd *ofd, unsigned int what) +{ + char buf[128]; + int l; + + l = recv(ofd->fd, buf, sizeof(buf), MSG_TRUNC); + if (l <= 0) + return -EIO; + + return 0; +} diff --git a/src/host/layer23/src/transceiver_ms/trx.h b/src/host/layer23/src/transceiver_ms/trx.h new file mode 100644 index 00000000..8485cd80 --- /dev/null +++ b/src/host/layer23/src/transceiver_ms/trx.h @@ -0,0 +1,45 @@ +/* + * trx.h + * + * OpenBTS TRX interface handling + * + * Copyright (C) 2014 Sylvain Munaut <tnt@246tNt.com> + * + * All Rights Reserved + * + * This program 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __TRXMS_TRX_H__ +#define __TRXMS_TRX_H__ + + +#include <stdint.h> + + +struct trx { + /* UDP sockets */ + struct osmo_fd ofd_clk; + struct osmo_fd ofd_ctrl; + struct osmo_fd ofd_data; + + /* */ +}; + +struct trx *trx_alloc(const char *addr, uint16_t base_port); +void trx_free(struct trx *trx); + +int trx_ctrl_send_cmd(struct trx *trx, const char *cmd, const char *fmt, ...); + +#endif /* __TRXMS_TRX_H__ */ |