first hack that does something useful
This commit is contained in:
parent
9ec3f72277
commit
31d3354b01
|
@ -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
|
||||
|
|
|
@ -3,3 +3,7 @@ SUBDIRS = common misc mobile
|
|||
if BUILD_TRANSCEIVER
|
||||
SUBDIRS += transceiver
|
||||
endif
|
||||
|
||||
if BUILD_TRANSCEIVER_MS
|
||||
SUBDIRS += transceiver_ms
|
||||
endif
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
||||
}
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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__ */
|
|
@ -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;
|
||||
}
|
|
@ -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__ */
|
|
@ -0,0 +1 @@
|
|||
../transceiver/l1ctl_link.c
|
|
@ -0,0 +1 @@
|
|||
../transceiver/l1ctl_link.h
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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__ */
|
Loading…
Reference in New Issue