trx: Initial attempt to implement a single TRX commands queue.
This commit is contained in:
parent
4e3bfe1412
commit
917d214872
|
@ -142,12 +142,9 @@ struct trx_config {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct trx_l1h {
|
struct trx_l1h {
|
||||||
struct llist_head trx_ctrl_list;
|
|
||||||
|
|
||||||
struct gsm_bts_trx *trx;
|
struct gsm_bts_trx *trx;
|
||||||
|
|
||||||
struct osmo_fd trx_ofd_ctrl;
|
struct osmo_fd trx_ofd_ctrl;
|
||||||
struct osmo_timer_list trx_ctrl_timer;
|
|
||||||
struct osmo_fd trx_ofd_data;
|
struct osmo_fd trx_ofd_data;
|
||||||
|
|
||||||
/* transceiver config */
|
/* transceiver config */
|
||||||
|
|
|
@ -49,6 +49,10 @@ const char *transceiver_ip = "127.0.0.1";
|
||||||
int settsc_enabled = 0;
|
int settsc_enabled = 0;
|
||||||
int setbsic_enabled = 0;
|
int setbsic_enabled = 0;
|
||||||
|
|
||||||
|
/* control socket queue */
|
||||||
|
struct llist_head trx_ctrl_list;
|
||||||
|
struct osmo_timer_list trx_ctrl_timer;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* socket
|
* socket
|
||||||
*/
|
*/
|
||||||
|
@ -158,35 +162,39 @@ static int trx_clk_read_cb(struct osmo_fd *ofd, unsigned int what)
|
||||||
static void trx_ctrl_timer_cb(void *data);
|
static void trx_ctrl_timer_cb(void *data);
|
||||||
|
|
||||||
/* send first ctrl message and start timer */
|
/* send first ctrl message and start timer */
|
||||||
static void trx_ctrl_send(struct trx_l1h *l1h)
|
static void trx_ctrl_send(struct gsm_bts *bts)
|
||||||
{
|
{
|
||||||
struct trx_ctrl_msg *tcm;
|
struct trx_ctrl_msg *tcm;
|
||||||
|
struct gsm_bts_trx *trx;
|
||||||
|
struct trx_l1h *l1h;
|
||||||
|
|
||||||
/* get first command */
|
/* get first command */
|
||||||
if (llist_empty(&l1h->trx_ctrl_list))
|
if (llist_empty(&trx_ctrl_list))
|
||||||
return;
|
return;
|
||||||
tcm = llist_entry(l1h->trx_ctrl_list.next, struct trx_ctrl_msg, list);
|
tcm = llist_entry(trx_ctrl_list.next, struct trx_ctrl_msg, list);
|
||||||
|
|
||||||
LOGP(DTRX, LOGL_DEBUG, "Sending control '%s' to trx=%u\n", tcm->cmd,
|
LOGP(DTRX, LOGL_DEBUG, "Sending control '%s' to trx=%u\n", tcm->cmd,
|
||||||
l1h->trx->nr);
|
tcm->trx_num);
|
||||||
/* send command */
|
/* send command */
|
||||||
|
trx = gsm_bts_trx_num(bts, tcm->trx_num);
|
||||||
|
l1h = trx_l1h_hdl(trx);
|
||||||
send(l1h->trx_ofd_ctrl.fd, tcm->cmd, strlen(tcm->cmd)+1, 0);
|
send(l1h->trx_ofd_ctrl.fd, tcm->cmd, strlen(tcm->cmd)+1, 0);
|
||||||
|
|
||||||
/* start timer */
|
/* start timer */
|
||||||
l1h->trx_ctrl_timer.cb = trx_ctrl_timer_cb;
|
trx_ctrl_timer.cb = trx_ctrl_timer_cb;
|
||||||
l1h->trx_ctrl_timer.data = l1h;
|
trx_ctrl_timer.data = trx;
|
||||||
osmo_timer_schedule(&l1h->trx_ctrl_timer, 2, 0);
|
osmo_timer_schedule(&trx_ctrl_timer, 2, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* send first ctrl message and start timer */
|
/* send first ctrl message and start timer */
|
||||||
static void trx_ctrl_timer_cb(void *data)
|
static void trx_ctrl_timer_cb(void *data)
|
||||||
{
|
{
|
||||||
struct trx_l1h *l1h = data;
|
struct gsm_bts_trx *trx = data;
|
||||||
|
|
||||||
LOGP(DTRX, LOGL_NOTICE, "No response from transceiver for trx=%d\n",
|
LOGP(DTRX, LOGL_NOTICE, "No response from transceiver for trx=%d\n",
|
||||||
l1h->trx->nr);
|
trx->nr);
|
||||||
|
|
||||||
trx_ctrl_send(l1h);
|
trx_ctrl_send(trx->bts);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add a new ctrl command */
|
/* add a new ctrl command */
|
||||||
|
@ -203,11 +211,12 @@ static int trx_ctrl_cmd(struct trx_l1h *l1h, int critical, const char *cmd,
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!llist_empty(&l1h->trx_ctrl_list))
|
if (!llist_empty(&trx_ctrl_list))
|
||||||
pending = 1;
|
pending = 1;
|
||||||
|
|
||||||
/* create message */
|
/* create message */
|
||||||
tcm = talloc_zero(tall_bts_ctx, struct trx_ctrl_msg);
|
tcm = talloc_zero(tall_bts_ctx, struct trx_ctrl_msg);
|
||||||
|
tcm->trx_num = l1h->trx->nr;
|
||||||
if (!tcm)
|
if (!tcm)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
if (fmt && fmt[0]) {
|
if (fmt && fmt[0]) {
|
||||||
|
@ -219,12 +228,12 @@ static int trx_ctrl_cmd(struct trx_l1h *l1h, int critical, const char *cmd,
|
||||||
snprintf(tcm->cmd, sizeof(tcm->cmd)-1, "CMD %s", cmd);
|
snprintf(tcm->cmd, sizeof(tcm->cmd)-1, "CMD %s", cmd);
|
||||||
tcm->cmd_len = strlen(cmd);
|
tcm->cmd_len = strlen(cmd);
|
||||||
tcm->critical = critical;
|
tcm->critical = critical;
|
||||||
llist_add_tail(&tcm->list, &l1h->trx_ctrl_list);
|
llist_add_tail(&tcm->list, &trx_ctrl_list);
|
||||||
LOGP(DTRX, LOGL_INFO, "Adding new control '%s'\n", tcm->cmd);
|
LOGP(DTRX, LOGL_INFO, "Adding new control '%s'\n", tcm->cmd);
|
||||||
|
|
||||||
/* send message, if no pending message */
|
/* send this message, if there are no other pending messages */
|
||||||
if (!pending)
|
if (!pending)
|
||||||
trx_ctrl_send(l1h);
|
trx_ctrl_send(l1h->trx->bts);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -319,12 +328,46 @@ int trx_if_cmd_nohandover(struct trx_l1h *l1h, uint8_t tn, uint8_t ss)
|
||||||
return trx_ctrl_cmd(l1h, 1, "NOHANDOVER", "%d %d", tn, ss);
|
return trx_ctrl_cmd(l1h, 1, "NOHANDOVER", "%d %d", tn, ss);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int check_resp(char *buf, struct trx_ctrl_msg *tcm, struct trx_l1h *l1h)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
int rsp_len = 0;
|
||||||
|
int resp;
|
||||||
|
|
||||||
|
/* calculate the length of response item */
|
||||||
|
p = strchr(buf + 4, ' ');
|
||||||
|
if (p)
|
||||||
|
rsp_len = p - buf - 4;
|
||||||
|
else
|
||||||
|
rsp_len = strlen(buf) - 4;
|
||||||
|
|
||||||
|
/* check if respose matches command */
|
||||||
|
if (rsp_len != tcm->cmd_len
|
||||||
|
|| !!strncmp(buf + 4, tcm->cmd + 4, rsp_len)) {
|
||||||
|
LOGP(DTRX, (tcm->critical) ? LOGL_FATAL : LOGL_NOTICE,
|
||||||
|
"Response message '%s' does not match command "
|
||||||
|
"message '%s'\n", buf, tcm->cmd);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check for response code */
|
||||||
|
sscanf(p + 1, "%d", &resp);
|
||||||
|
if (resp) {
|
||||||
|
LOGP(DTRX, (tcm->critical) ? LOGL_FATAL : LOGL_NOTICE,
|
||||||
|
"transceiver (trx=%d) rejected TRX command "
|
||||||
|
"with response: '%s'\n", l1h->trx->nr, buf);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* get response from ctrl socket */
|
/* get response from ctrl socket */
|
||||||
static int trx_ctrl_read_cb(struct osmo_fd *ofd, unsigned int what)
|
static int trx_ctrl_read_cb(struct osmo_fd *ofd, unsigned int what)
|
||||||
{
|
{
|
||||||
struct trx_l1h *l1h = ofd->data;
|
struct trx_l1h *l1h = ofd->data;
|
||||||
char buf[1500];
|
char buf[1500];
|
||||||
int len, resp;
|
int len;
|
||||||
|
|
||||||
len = recv(ofd->fd, buf, sizeof(buf) - 1, 0);
|
len = recv(ofd->fd, buf, sizeof(buf) - 1, 0);
|
||||||
if (len <= 0)
|
if (len <= 0)
|
||||||
|
@ -333,49 +376,23 @@ static int trx_ctrl_read_cb(struct osmo_fd *ofd, unsigned int what)
|
||||||
|
|
||||||
if (!strncmp(buf, "RSP ", 4)) {
|
if (!strncmp(buf, "RSP ", 4)) {
|
||||||
struct trx_ctrl_msg *tcm;
|
struct trx_ctrl_msg *tcm;
|
||||||
char *p;
|
|
||||||
int rsp_len = 0;
|
|
||||||
|
|
||||||
/* calculate the length of response item */
|
|
||||||
p = strchr(buf + 4, ' ');
|
|
||||||
if (p)
|
|
||||||
rsp_len = p - buf - 4;
|
|
||||||
else
|
|
||||||
rsp_len = strlen(buf) - 4;
|
|
||||||
|
|
||||||
LOGP(DTRX, LOGL_INFO, "Response message: '%s'\n", buf);
|
LOGP(DTRX, LOGL_INFO, "Response message: '%s'\n", buf);
|
||||||
|
|
||||||
/* abort timer and send next message, if any */
|
/* abort timer */
|
||||||
if (osmo_timer_pending(&l1h->trx_ctrl_timer))
|
if (osmo_timer_pending(&trx_ctrl_timer))
|
||||||
osmo_timer_del(&l1h->trx_ctrl_timer);
|
osmo_timer_del(&trx_ctrl_timer);
|
||||||
|
|
||||||
/* get command for response message */
|
/* get command for response message */
|
||||||
if (llist_empty(&l1h->trx_ctrl_list)) {
|
if (llist_empty(&trx_ctrl_list)) {
|
||||||
LOGP(DTRX, LOGL_NOTICE, "Response message without "
|
LOGP(DTRX, LOGL_NOTICE, "Response message without "
|
||||||
"command\n");
|
"command\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
tcm = llist_entry(l1h->trx_ctrl_list.next, struct trx_ctrl_msg,
|
tcm = llist_entry(trx_ctrl_list.next, struct trx_ctrl_msg, list);
|
||||||
list);
|
|
||||||
|
|
||||||
/* check if respose matches command */
|
/* check if respose matches command and it's a success response */
|
||||||
if (rsp_len != tcm->cmd_len) {
|
if (check_resp(buf, tcm, l1h) < 0) {
|
||||||
notmatch:
|
|
||||||
LOGP(DTRX, (tcm->critical) ? LOGL_FATAL : LOGL_NOTICE,
|
|
||||||
"Response message '%s' does not match command "
|
|
||||||
"message '%s'\n", buf, tcm->cmd);
|
|
||||||
goto rsp_error;
|
|
||||||
}
|
|
||||||
if (!!strncmp(buf + 4, tcm->cmd + 4, rsp_len))
|
|
||||||
goto notmatch;
|
|
||||||
|
|
||||||
/* check for response code */
|
|
||||||
sscanf(p + 1, "%d", &resp);
|
|
||||||
if (resp) {
|
|
||||||
LOGP(DTRX, (tcm->critical) ? LOGL_FATAL : LOGL_NOTICE,
|
|
||||||
"transceiver (trx=%d) rejected TRX command "
|
|
||||||
"with response: '%s'\n", l1h->trx->nr, buf);
|
|
||||||
rsp_error:
|
|
||||||
if (tcm->critical) {
|
if (tcm->critical) {
|
||||||
bts_shutdown(l1h->trx->bts, "SIGINT");
|
bts_shutdown(l1h->trx->bts, "SIGINT");
|
||||||
/* keep tcm list, so process is stopped */
|
/* keep tcm list, so process is stopped */
|
||||||
|
@ -387,7 +404,8 @@ rsp_error:
|
||||||
llist_del(&tcm->list);
|
llist_del(&tcm->list);
|
||||||
talloc_free(tcm);
|
talloc_free(tcm);
|
||||||
|
|
||||||
trx_ctrl_send(l1h);
|
/* send next command */
|
||||||
|
trx_ctrl_send(l1h->trx->bts);
|
||||||
} else
|
} else
|
||||||
LOGP(DTRX, LOGL_NOTICE, "Unknown message on ctrl port: %s\n",
|
LOGP(DTRX, LOGL_NOTICE, "Unknown message on ctrl port: %s\n",
|
||||||
buf);
|
buf);
|
||||||
|
@ -478,7 +496,7 @@ int trx_if_data(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, uint8_t pwr,
|
||||||
|
|
||||||
/* we must be sure that we have clock, and we have sent all control
|
/* we must be sure that we have clock, and we have sent all control
|
||||||
* data */
|
* data */
|
||||||
if (transceiver_available && llist_empty(&l1h->trx_ctrl_list)) {
|
if (transceiver_available && llist_empty(&trx_ctrl_list)) {
|
||||||
send(l1h->trx_ofd_data.fd, buf, 154, 0);
|
send(l1h->trx_ofd_data.fd, buf, 154, 0);
|
||||||
} else
|
} else
|
||||||
LOGP(DTRX, LOGL_DEBUG, "Ignoring TX data, transceiver "
|
LOGP(DTRX, LOGL_DEBUG, "Ignoring TX data, transceiver "
|
||||||
|
@ -499,7 +517,8 @@ int trx_if_open(struct trx_l1h *l1h)
|
||||||
LOGP(DTRX, LOGL_NOTICE, "Open transceiver for trx=%u\n", l1h->trx->nr);
|
LOGP(DTRX, LOGL_NOTICE, "Open transceiver for trx=%u\n", l1h->trx->nr);
|
||||||
|
|
||||||
/* initialize ctrl queue */
|
/* initialize ctrl queue */
|
||||||
INIT_LLIST_HEAD(&l1h->trx_ctrl_list);
|
if (l1h->trx->nr == 0)
|
||||||
|
INIT_LLIST_HEAD(&trx_ctrl_list);
|
||||||
|
|
||||||
/* open sockets */
|
/* open sockets */
|
||||||
if (l1h->trx->nr == 0) {
|
if (l1h->trx->nr == 0) {
|
||||||
|
@ -537,8 +556,8 @@ void trx_if_flush(struct trx_l1h *l1h)
|
||||||
struct trx_ctrl_msg *tcm;
|
struct trx_ctrl_msg *tcm;
|
||||||
|
|
||||||
/* free ctrl message list */
|
/* free ctrl message list */
|
||||||
while (!llist_empty(&l1h->trx_ctrl_list)) {
|
while (!llist_empty(&trx_ctrl_list)) {
|
||||||
tcm = llist_entry(l1h->trx_ctrl_list.next, struct trx_ctrl_msg,
|
tcm = llist_entry(trx_ctrl_list.next, struct trx_ctrl_msg,
|
||||||
list);
|
list);
|
||||||
llist_del(&tcm->list);
|
llist_del(&tcm->list);
|
||||||
talloc_free(tcm);
|
talloc_free(tcm);
|
||||||
|
|
|
@ -9,6 +9,7 @@ extern int setbsic_enabled;
|
||||||
|
|
||||||
struct trx_ctrl_msg {
|
struct trx_ctrl_msg {
|
||||||
struct llist_head list;
|
struct llist_head list;
|
||||||
|
int trx_num;
|
||||||
char cmd[128];
|
char cmd[128];
|
||||||
int cmd_len;
|
int cmd_len;
|
||||||
int critical;
|
int critical;
|
||||||
|
|
Loading…
Reference in New Issue