diff options
Diffstat (limited to 'src/host/trxcon')
-rw-r--r-- | src/host/trxcon/l1ctl_link.c | 35 | ||||
-rw-r--r-- | src/host/trxcon/l1ctl_link.h | 7 | ||||
-rw-r--r-- | src/host/trxcon/trx_if.c | 123 | ||||
-rw-r--r-- | src/host/trxcon/trx_if.h | 12 | ||||
-rw-r--r-- | src/host/trxcon/trxcon.c | 66 | ||||
-rw-r--r-- | src/host/trxcon/trxcon.h | 19 |
6 files changed, 238 insertions, 24 deletions
diff --git a/src/host/trxcon/l1ctl_link.c b/src/host/trxcon/l1ctl_link.c index 62e8943f..34aa4aaf 100644 --- a/src/host/trxcon/l1ctl_link.c +++ b/src/host/trxcon/l1ctl_link.c @@ -34,15 +34,36 @@ #include <arpa/inet.h> #include <sys/socket.h> +#include <osmocom/core/fsm.h> #include <osmocom/core/talloc.h> #include <osmocom/core/select.h> #include <osmocom/core/socket.h> #include <osmocom/core/write_queue.h> +#include "trxcon.h" #include "logging.h" #include "l1ctl_link.h" extern void *tall_trx_ctx; +extern struct osmo_fsm_inst *trxcon_fsm; + +static struct osmo_fsm_state l1ctl_fsm_states[] = { + [L1CTL_STATE_IDLE] = { + .out_state_mask = GEN_MASK(L1CTL_STATE_CONNECTED), + .name = "IDLE", + }, + [L1CTL_STATE_CONNECTED] = { + .out_state_mask = GEN_MASK(L1CTL_STATE_IDLE), + .name = "CONNECTED", + }, +}; + +static struct osmo_fsm l1ctl_fsm = { + .name = "l1ctl_link_fsm", + .states = l1ctl_fsm_states, + .num_states = ARRAY_SIZE(l1ctl_fsm_states), + .log_subsys = DL1C, +}; static int l1ctl_link_read_cb(struct osmo_fd *bfd) { @@ -154,7 +175,9 @@ static int l1ctl_link_accept(struct osmo_fd *bfd, unsigned int flags) return -1; } - /* TODO: switch the bridge to CONNECTED state */ + osmo_fsm_inst_dispatch(trxcon_fsm, L1CTL_EVENT_CONNECT, l1l); + osmo_fsm_inst_state_chg(l1l->fsm, L1CTL_STATE_CONNECTED, 0, 0); + LOGP(DL1C, LOGL_NOTICE, "L1CTL has a new connection\n"); return 0; @@ -199,7 +222,9 @@ int l1ctl_link_close_conn(struct l1ctl_link *l1l) /* Clear pending messages */ osmo_wqueue_clear(&l1l->wq); - /* TODO: switch the bridge to IDLE state */ + osmo_fsm_inst_dispatch(trxcon_fsm, L1CTL_EVENT_DISCONNECT, l1l); + osmo_fsm_inst_state_chg(l1l->fsm, L1CTL_STATE_IDLE, 0, 0); + return 0; } @@ -238,6 +263,11 @@ int l1ctl_link_init(struct l1ctl_link **l1l, const char *sock_path) */ l1l_new->wq.bfd.fd = -1; + /* Allocate a new dedicated state machine */ + osmo_fsm_register(&l1ctl_fsm); + l1l_new->fsm = osmo_fsm_inst_alloc(&l1ctl_fsm, l1l_new, + NULL, LOGL_DEBUG, sock_path); + *l1l = l1l_new; return 0; @@ -266,5 +296,6 @@ void l1ctl_link_shutdown(struct l1ctl_link *l1l) listen_bfd->fd = -1; } + osmo_fsm_inst_free(l1l->fsm); talloc_free(l1l); } diff --git a/src/host/trxcon/l1ctl_link.h b/src/host/trxcon/l1ctl_link.h index 417dc757..620dde50 100644 --- a/src/host/trxcon/l1ctl_link.h +++ b/src/host/trxcon/l1ctl_link.h @@ -3,11 +3,18 @@ #include <osmocom/core/write_queue.h> #include <osmocom/core/select.h> #include <osmocom/core/msgb.h> +#include <osmocom/core/fsm.h> #define L1CTL_LENGTH 256 #define L1CTL_HEADROOM 32 +enum l1ctl_fsm_states { + L1CTL_STATE_IDLE = 0, + L1CTL_STATE_CONNECTED, +}; + struct l1ctl_link { + struct osmo_fsm_inst *fsm; struct osmo_fd listen_bfd; struct osmo_wqueue wq; }; diff --git a/src/host/trxcon/trx_if.c b/src/host/trxcon/trx_if.c index 5b0b7b1c..8f93b0a6 100644 --- a/src/host/trxcon/trx_if.c +++ b/src/host/trxcon/trx_if.c @@ -35,13 +35,49 @@ #include <osmocom/core/socket.h> #include <osmocom/core/talloc.h> #include <osmocom/core/bits.h> +#include <osmocom/core/fsm.h> #include <osmocom/gsm/gsm_utils.h> +#include "trxcon.h" #include "trx_if.h" #include "logging.h" extern void *tall_trx_ctx; +extern struct osmo_fsm_inst *trxcon_fsm; + +static struct osmo_fsm_state trx_fsm_states[] = { + [TRX_STATE_OFFLINE] = { + .out_state_mask = ( + GEN_MASK(TRX_STATE_IDLE) | + GEN_MASK(TRX_STATE_RSP_WAIT)), + .name = "OFFLINE", + }, + [TRX_STATE_IDLE] = { + .out_state_mask = UINT32_MAX, + .name = "IDLE", + }, + [TRX_STATE_ACTIVE] = { + .out_state_mask = ( + GEN_MASK(TRX_STATE_IDLE) | + GEN_MASK(TRX_STATE_RSP_WAIT)), + .name = "ACTIVE", + }, + [TRX_STATE_RSP_WAIT] = { + .out_state_mask = ( + GEN_MASK(TRX_STATE_IDLE) | + GEN_MASK(TRX_STATE_ACTIVE) | + GEN_MASK(TRX_STATE_OFFLINE)), + .name = "RSP_WAIT", + }, +}; + +static struct osmo_fsm trx_fsm = { + .name = "trx_interface_fsm", + .states = trx_fsm_states, + .num_states = ARRAY_SIZE(trx_fsm_states), + .log_subsys = DTRX, +}; static int trx_udp_open(void *priv, struct osmo_fd *ofd, const char *host, uint16_t port_local, uint16_t port_remote, @@ -178,6 +214,12 @@ static void trx_ctrl_send(struct trx_instance *trx) LOGP(DTRX, LOGL_DEBUG, "Sending control '%s'\n", tcm->cmd); send(trx->trx_ofd_ctrl.fd, tcm->cmd, strlen(tcm->cmd) + 1, 0); + /* Trigger state machine */ + if (trx->fsm->state != TRX_STATE_RSP_WAIT) { + trx->prev_state = trx->fsm->state; + osmo_fsm_inst_state_chg(trx->fsm, TRX_STATE_RSP_WAIT, 0, 0); + } + /* Start expire timer */ trx->trx_ctrl_timer.data = trx; trx->trx_ctrl_timer.cb = trx_ctrl_timer_cb; @@ -186,10 +228,25 @@ static void trx_ctrl_send(struct trx_instance *trx) static void trx_ctrl_timer_cb(void *data) { + struct trx_instance *trx = (struct trx_instance *) data; + struct trx_ctrl_msg *tcm; + + /* Queue may be cleaned at this moment */ + if (llist_empty(&trx->trx_ctrl_list)) + return; + LOGP(DTRX, LOGL_NOTICE, "No response from transceiver...\n"); + tcm = llist_entry(trx->trx_ctrl_list.next, struct trx_ctrl_msg, list); + if (++tcm->retry_cnt > 3) { + LOGP(DTRX, LOGL_NOTICE, "Transceiver offline\n"); + osmo_fsm_inst_state_chg(trx->fsm, TRX_STATE_OFFLINE, 0, 0); + osmo_fsm_inst_dispatch(trxcon_fsm, TRX_EVENT_OFFLINE, trx); + return; + } + /* Attempt to send a command again */ - trx_ctrl_send((struct trx_instance *) data); + trx_ctrl_send(trx); } /* Add a new CTRL command to the trx_ctrl_list */ @@ -200,11 +257,7 @@ static int trx_ctrl_cmd(struct trx_instance *trx, int critical, int len, pending = 0; va_list ap; - /*if (!transceiver_available && !!strcmp(cmd, "POWEROFF")) { - LOGP(DTRX, LOGL_ERROR, "CTRL ignored: No clock from " - "transceiver, please fix!\n"); - return -EIO; - }*/ + /* TODO: make sure that transceiver online */ if (!llist_empty(&trx->trx_ctrl_list)) pending = 1; @@ -419,6 +472,18 @@ static int trx_ctrl_read_cb(struct osmo_fd *ofd, unsigned int what) goto rsp_error; } + /* Trigger state machine */ + if (!strncmp(tcm->cmd + 4, "POWERON", 7)) + osmo_fsm_inst_state_chg(trx->fsm, TRX_STATE_ACTIVE, 0, 0); + else if (!strncmp(tcm->cmd + 4, "POWEROFF", 8)) + osmo_fsm_inst_state_chg(trx->fsm, TRX_STATE_IDLE, 0, 0); + else if (!strncmp(tcm->cmd + 4, "ECHO", 4)) { + osmo_fsm_inst_state_chg(trx->fsm, TRX_STATE_IDLE, 0, 0); + osmo_fsm_inst_dispatch(trxcon_fsm, + TRX_EVENT_RESET_IND, trx); + } else + osmo_fsm_inst_state_chg(trx->fsm, trx->prev_state, 0, 0); + /* Remove command from list */ llist_del(&tcm->list); talloc_free(tcm); @@ -429,10 +494,8 @@ static int trx_ctrl_read_cb(struct osmo_fd *ofd, unsigned int what) return 0; rsp_error: - /** - * TODO: stop/freeze trxcon process - * or notify higher layers about the problem with L1 - */ + /* Notify higher layers about the problem */ + osmo_fsm_inst_dispatch(trxcon_fsm, TRX_EVENT_RSP_ERROR, trx); return -EIO; } @@ -512,6 +575,18 @@ int trx_if_data(struct trx_instance *trx, uint8_t tn, uint32_t fn, { uint8_t buf[256]; + /** + * We must be sure that we have clock, + * and we have sent all control data + * + * TODO: should we wait in TRX_STATE_RSP_WAIT state? + */ + if (trx->fsm->state != TRX_STATE_ACTIVE) { + LOGP(DTRX, LOGL_DEBUG, "Ignoring TX data, " + "transceiver isn't ready\n"); + return -EAGAIN; + } + LOGP(DTRX, LOGL_DEBUG, "TX burst tn=%u fn=%u pwr=%u\n", tn, fn, pwr); buf[0] = tn; @@ -524,17 +599,8 @@ int trx_if_data(struct trx_instance *trx, uint8_t tn, uint32_t fn, /* Copy ubits {0,1} */ memcpy(buf + 6, bits, 148); - /** - * TODO: is transceiver available??? - * - * We must be sure that we have clock, - * and we have sent all control data - * - * if (transceiver_available && llist_empty(&l1h->trx_ctrl_list)) - * send(l1h->trx_ofd_data.fd, buf, 154, 0); - * else - * LOGP(DTRX, LOGL_DEBUG, "Ignoring TX data, transceiver offline.\n"); - */ + /* Send data to transceiver */ + send(trx->trx_ofd_data.fd, buf, 154, 0); return 0; } @@ -546,6 +612,7 @@ int trx_if_data(struct trx_instance *trx, uint8_t tn, uint32_t fn, int trx_if_open(struct trx_instance **trx, const char *host, uint16_t port) { struct trx_instance *trx_new; + char *inst_name; int rc; LOGP(DTRX, LOGL_NOTICE, "Init transceiver interface\n"); @@ -576,6 +643,13 @@ int trx_if_open(struct trx_instance **trx, const char *host, uint16_t port) if (rc < 0) goto error; + /* Allocate a new dedicated state machine */ + osmo_fsm_register(&trx_fsm); + inst_name = talloc_asprintf(trx_new, "%s:%u", host, port); + trx_new->fsm = osmo_fsm_inst_alloc(&trx_fsm, trx_new, + NULL, LOGL_DEBUG, inst_name); + talloc_free(inst_name); + *trx = trx_new; return 0; @@ -587,10 +661,14 @@ error: } /* Flush pending control messages */ -static void trx_if_flush_ctrl(struct trx_instance *trx) +void trx_if_flush_ctrl(struct trx_instance *trx) { struct trx_ctrl_msg *tcm; + /* Reset state machine */ + osmo_fsm_inst_state_chg(trx->fsm, TRX_STATE_IDLE, 0, 0); + + /* Clear command queue */ while (!llist_empty(&trx->trx_ctrl_list)) { tcm = llist_entry(trx->trx_ctrl_list.next, struct trx_ctrl_msg, list); @@ -616,5 +694,6 @@ void trx_if_close(struct trx_instance *trx) trx_udp_close(&trx->trx_ofd_data); /* Free memory */ + osmo_fsm_inst_free(trx->fsm); talloc_free(trx); } diff --git a/src/host/trxcon/trx_if.h b/src/host/trxcon/trx_if.h index 6f54b3e6..a81da37e 100644 --- a/src/host/trxcon/trx_if.h +++ b/src/host/trxcon/trx_if.h @@ -3,6 +3,14 @@ #include <osmocom/core/linuxlist.h> #include <osmocom/core/select.h> #include <osmocom/core/timer.h> +#include <osmocom/core/fsm.h> + +enum trx_fsm_states { + TRX_STATE_OFFLINE = 0, + TRX_STATE_IDLE, + TRX_STATE_ACTIVE, + TRX_STATE_RSP_WAIT, +}; struct trx_instance { struct osmo_fd trx_ofd_clck; @@ -11,16 +19,20 @@ struct trx_instance { struct osmo_timer_list trx_ctrl_timer; struct llist_head trx_ctrl_list; + struct osmo_fsm_inst *fsm; + uint32_t prev_state; }; struct trx_ctrl_msg { struct llist_head list; char cmd[128]; + int retry_cnt; int critical; int cmd_len; }; int trx_if_open(struct trx_instance **trx, const char *host, uint16_t port); +void trx_if_flush_ctrl(struct trx_instance *trx); void trx_if_close(struct trx_instance *trx); int trx_if_cmd_poweron(struct trx_instance *trx); diff --git a/src/host/trxcon/trxcon.c b/src/host/trxcon/trxcon.c index 781942a6..5874560d 100644 --- a/src/host/trxcon/trxcon.c +++ b/src/host/trxcon/trxcon.c @@ -29,12 +29,14 @@ #include <unistd.h> #include <signal.h> +#include <osmocom/core/fsm.h> #include <osmocom/core/msgb.h> #include <osmocom/core/talloc.h> #include <osmocom/core/signal.h> #include <osmocom/core/select.h> #include <osmocom/core/application.h> +#include "trxcon.h" #include "trx_if.h" #include "logging.h" #include "l1ctl_link.h" @@ -62,6 +64,62 @@ static struct { } app_data; void *tall_trx_ctx = NULL; +struct osmo_fsm_inst *trxcon_fsm; + +static void trxcon_fsm_idle_action(struct osmo_fsm_inst *fi, + uint32_t event, void *data) +{ + if (event == L1CTL_EVENT_CONNECT) + osmo_fsm_inst_state_chg(trxcon_fsm, TRXCON_STATE_MANAGED, 0, 0); +} + +static void trxcon_fsm_managed_action(struct osmo_fsm_inst *fi, + uint32_t event, void *data) +{ + switch (event) { + case L1CTL_EVENT_DISCONNECT: + osmo_fsm_inst_state_chg(trxcon_fsm, TRXCON_STATE_IDLE, 0, 0); + + if (app_data.trx->fsm->state != TRX_STATE_OFFLINE) { + trx_if_flush_ctrl(app_data.trx); + trx_if_cmd_poweroff(app_data.trx); + } + break; + case TRX_EVENT_RESET_IND: + case TRX_EVENT_RSP_ERROR: + case TRX_EVENT_OFFLINE: + /* TODO: notify L2 & L3 about that */ + break; + default: + LOGPFSML(fi, LOGL_ERROR, "Unhandled event %u\n", event); + } +} + +static struct osmo_fsm_state trxcon_fsm_states[] = { + [TRXCON_STATE_IDLE] = { + .in_event_mask = GEN_MASK(L1CTL_EVENT_CONNECT), + .out_state_mask = GEN_MASK(TRXCON_STATE_MANAGED), + .name = "IDLE", + .action = trxcon_fsm_idle_action, + }, + [TRXCON_STATE_MANAGED] = { + .in_event_mask = ( + GEN_MASK(L1CTL_EVENT_DISCONNECT) | + GEN_MASK(TRX_EVENT_RESET_IND) | + GEN_MASK(TRX_EVENT_RSP_ERROR) | + GEN_MASK(TRX_EVENT_OFFLINE)), + .out_state_mask = GEN_MASK(TRXCON_STATE_IDLE), + .name = "MANAGED", + .action = trxcon_fsm_managed_action, + }, +}; + +static struct osmo_fsm trxcon_fsm_def = { + .name = "trxcon_app_fsm", + .states = trxcon_fsm_states, + .num_states = ARRAY_SIZE(trxcon_fsm_states), + .log_subsys = DAPP, +}; static void print_usage(const char *app) { @@ -175,6 +233,11 @@ int main(int argc, char **argv) /* Init logging system */ trx_log_init(app_data.debug_mask); + /* Allocate the application state machine */ + osmo_fsm_register(&trxcon_fsm_def); + trxcon_fsm = osmo_fsm_inst_alloc(&trxcon_fsm_def, tall_trx_ctx, + NULL, LOGL_DEBUG, "main"); + /* Init L1CTL server */ rc = l1ctl_link_init(&app_data.l1l, app_data.bind_socket); if (rc) @@ -203,6 +266,9 @@ exit: l1ctl_link_shutdown(app_data.l1l); trx_if_close(app_data.trx); + /* Shutdown main state machine */ + osmo_fsm_inst_free(trxcon_fsm); + /* Make Valgrind happy */ log_fini(); talloc_free(tall_trx_ctx); diff --git a/src/host/trxcon/trxcon.h b/src/host/trxcon/trxcon.h new file mode 100644 index 00000000..a7a3a65f --- /dev/null +++ b/src/host/trxcon/trxcon.h @@ -0,0 +1,19 @@ +#pragma once + +#define GEN_MASK(state) (0x01 << state) + +enum trxcon_fsm_states { + TRXCON_STATE_IDLE = 0, + TRXCON_STATE_MANAGED, +}; + +enum trxcon_fsm_events { + /* L1CTL specific events */ + L1CTL_EVENT_CONNECT, + L1CTL_EVENT_DISCONNECT, + + /* TRX specific events */ + TRX_EVENT_RESET_IND, + TRX_EVENT_RSP_ERROR, + TRX_EVENT_OFFLINE, +}; |