Completed implementation of v5x_l1_fsm.c

This commit is contained in:
Andreas Eversberg 2022-12-23 21:50:47 +01:00
parent 4ea1488df2
commit 4916de8b50
4 changed files with 711 additions and 6 deletions

View File

@ -9,6 +9,12 @@ static const struct log_info_cat log_categories[] = {
.color = "\033[0;31m",
.enabled = 1, .loglevel = LOGL_INFO,
},
[DV5L1] = {
.name = "DV5L1",
.description = "V5 L1 link FSM",
.color = "\033[0;36m",
.enabled = 1, .loglevel = LOGL_INFO,
},
[DV5CTRL] = {
.name = "DV5CTRL",
.description = "V5 control protocol",

View File

@ -4,6 +4,7 @@
enum {
DV5,
DV5L1,
DV5CTRL,
DV5PORT,
DV5PSTN,

View File

@ -1,6 +1,6 @@
/* ITU-T G.964 Section 14.3.3 V5.1-intterface Layer 1 FSM - AN and LE */
/* (C) 2021 by Harald Welte <laforge@gnumonks.org>
/* (C) 2022 by Andreas Eversberg <jolly@eversberg.eu>
*
* All Rights Reserved
*
@ -22,14 +22,705 @@
*
*/
/***********************************************************************/
/* internal data structures */
/***********************************************************************/
#include <errno.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/gsm/tlv.h>
#include "v5x_internal.h"
#include "v5x_protocol.h"
#include "v52_le_lcp_fsm.h"
#include "layer1.h"
#include "v5x_l1_fsm.h"
#include "logging.h"
#define S(x) (1 << (x))
#define TIMEOUT 1
/***********************************************************************/
/* state names, event names, primitives, ... */
/***********************************************************************/
enum v5x_l1_fsm_state {
V5X_L1FSM_S_LE1_NORMAL,
V5X_L1FSM_S_LE2_LOCALLY_DET_FAIL,
V5X_L1FSM_S_LE3_REMOTELY_DET_FAIL,
V5X_L1FSM_S_LE4_INTERNAL_FAIL,
V5X_L1FSM_S_ANLE1_NORMAL,
V5X_L1FSM_S_ANLE2_LOCALLY_DET_FAIL,
V5X_L1FSM_S_ANLE3_REMOTELY_DET_FAIL,
V5X_L1FSM_S_ANLE4_INTERNAL_FAIL,
V5X_L1FSM_S_ANLE51_LINK_ID_SENDING,
V5X_L1FSM_S_ANLE52_LINK_ID_RECEIVED,
};
/* TODO */
enum v5x_l1_fsm_event {
/* V5.x events */
V5X_L1FSM_E_MPH_stop, /* Request to stop with error report */
V5X_L1FSM_E_MPH_proceed,/* Request to proceed with error report */
V5X_L1FSM_E_NORMAL, /* Normal frames, Sa7 == 1 */
V5X_L1FSM_E_LOS, /* Loss of signal/frame */
V5X_L1FSM_E_RAI, /* Remote alarm indication */
V5X_L1FSM_E_AIS, /* Alarm indication signal */
V5X_L1FSM_E_INTERNAL_F, /* Internal failure */
V5X_L1FSM_E_INTERNAL_D, /* Internal failure disappears */
V5X_L1FSM_E_TIMEOUT, /* Persistence check timer fired */
/* V5.2 events */
V5X_L1FSM_E_MPH_ID, /* Send link identification signal */
V5X_L1FSM_E_MPH_NOR, /* Remove link identification signal */
V5X_L1FSM_E_MPH_IDR, /* Link identification request */
V5X_L1FSM_E_NORMAL_Sa7, /* Normal frames, Sa7 == 0 */
};
static const struct value_string v5x_l1_fsm_event_names[] = {
{ V5X_L1FSM_E_MPH_stop, "Request to stop with error report" },
{ V5X_L1FSM_E_MPH_proceed, "Request to proceed with error report" },
{ V5X_L1FSM_E_NORMAL, "Normal frames, Sa7 = ONE" },
{ V5X_L1FSM_E_LOS, "Loss of signal/frame" },
{ V5X_L1FSM_E_RAI, "Remote alarm indication" },
{ V5X_L1FSM_E_AIS, "Alarm indication signal" },
{ V5X_L1FSM_E_INTERNAL_F, "Internal failure" },
{ V5X_L1FSM_E_INTERNAL_D, "Internal failure disappears" },
{ V5X_L1FSM_E_TIMEOUT, "Expiry of persistence check timer" },
{ V5X_L1FSM_E_MPH_ID, "Send link identification signal" },
{ V5X_L1FSM_E_MPH_NOR, "Remove link identification signal" },
{ V5X_L1FSM_E_MPH_IDR, "Link identification request" },
{ V5X_L1FSM_E_NORMAL_Sa7, "Normal frames, Sa7 = ZERO" },
{ 0, NULL }
};
/***********************************************************************/
/* Messages to other layers */
/***********************************************************************/
/* send message to upper (LCP) layer */
static void mph_rcv(struct osmo_fsm_inst *fi, enum v5x_mph_prim prim)
{
struct v5x_l1_proto *l1 = fi->priv;
struct v5x_link *v5l = l1->v5l;
if (v5l->fi)
v52_le_lcp_mph_rcv(v5l, prim);
// FIXME: send to other protocols too
}
static void signal_snd(struct osmo_fsm_inst *fi, enum l1_signal_prim prim)
{
struct v5x_l1_proto *l1 = fi->priv;
struct v5x_link *v5l = l1->v5l;
v5x_l1_signal_snd(v5l, prim);
}
/***********************************************************************/
/* L1 state FSM */
/***********************************************************************/
static int v5x_l1_fsm_timer_cb(struct osmo_fsm_inst *fi)
{
osmo_fsm_inst_dispatch(fi, V5X_L1FSM_E_TIMEOUT, NULL);
return 0;
}
static void l1_fsm_le1_normal(struct osmo_fsm_inst *fi, uint32_t event, void __attribute__((unused)) *data)
{
switch (event) {
case V5X_L1FSM_E_NORMAL:
/* ignore */
break;
case V5X_L1FSM_E_LOS:
/* Start timer */
osmo_fsm_inst_state_chg(fi, V5X_L1FSM_S_ANLE2_LOCALLY_DET_FAIL, TIMEOUT, 0);
/* send MPH-EIa */
mph_rcv(fi, MPH_EIa);
break;
case V5X_L1FSM_E_RAI:
/* Start timer */
osmo_fsm_inst_state_chg(fi, V5X_L1FSM_S_ANLE3_REMOTELY_DET_FAIL, TIMEOUT, 0);
/* send MPH-EIb */
mph_rcv(fi, MPH_EIb);
break;
case V5X_L1FSM_E_AIS:
/* Start timer */
osmo_fsm_inst_state_chg(fi, V5X_L1FSM_S_ANLE2_LOCALLY_DET_FAIL, TIMEOUT, 0);
/* send MPH-EIc */
mph_rcv(fi, MPH_EIc);
break;
case V5X_L1FSM_E_INTERNAL_F:
osmo_fsm_inst_state_chg(fi, V5X_L1FSM_S_ANLE4_INTERNAL_FAIL, 0, 0);
/* send MPH-DI */
mph_rcv(fi, MPH_DI);
/* send MPH-EId */
mph_rcv(fi, MPH_EId);
break;
case V5X_L1FSM_E_TIMEOUT:
/* send MPH-AI */
mph_rcv(fi, MPH_AI);
break;
case V5X_L1FSM_E_MPH_ID:
osmo_fsm_inst_state_chg(fi, V5X_L1FSM_S_ANLE51_LINK_ID_SENDING, 0, 0);
/* send Sa7 = ZERO */
signal_snd(fi, L1_SIGNAL_SA7_0);
break;
case V5X_L1FSM_E_MPH_NOR:
/* ignore */
break;
case V5X_L1FSM_E_NORMAL_Sa7:
osmo_fsm_inst_state_chg(fi, V5X_L1FSM_S_ANLE52_LINK_ID_RECEIVED, 0, 0);
break;
case V5X_L1FSM_E_MPH_IDR:
/* send MPH-EIg */
mph_rcv(fi, MPH_EIg);
break;
default:
OSMO_ASSERT(0);
}
}
static void l1_fsm_le2_locally_det_fail(struct osmo_fsm_inst *fi, uint32_t event, void __attribute__((unused)) *data)
{
switch (event) {
case V5X_L1FSM_E_NORMAL:
/* Start timer */
osmo_fsm_inst_state_chg(fi, V5X_L1FSM_S_ANLE1_NORMAL, TIMEOUT, 0);
break;
case V5X_L1FSM_E_LOS:
/* send MPH-EIa */
mph_rcv(fi, MPH_EIa);
break;
case V5X_L1FSM_E_RAI:
osmo_fsm_inst_state_chg(fi, V5X_L1FSM_S_ANLE3_REMOTELY_DET_FAIL, 0, 0);
/* send MPH-EIdr */
mph_rcv(fi, MPH_EIdr);
/* send MPH-EIb */
mph_rcv(fi, MPH_EIb);
break;
case V5X_L1FSM_E_AIS:
/* send MPH-EIc */
mph_rcv(fi, MPH_EIc);
break;
case V5X_L1FSM_E_INTERNAL_F:
osmo_fsm_inst_state_chg(fi, V5X_L1FSM_S_ANLE4_INTERNAL_FAIL, 0, 0);
/* send MPH-DI */
mph_rcv(fi, MPH_DI);
/* send MPH-EId */
mph_rcv(fi, MPH_EId);
break;
case V5X_L1FSM_E_TIMEOUT:
/* send MPH-DI */
mph_rcv(fi, MPH_DI);
break;
case V5X_L1FSM_E_MPH_ID:
/* send MPH-DI */
mph_rcv(fi, MPH_DI);
break;
case V5X_L1FSM_E_MPH_NOR:
/* send MPH-DI */
mph_rcv(fi, MPH_DI);
break;
case V5X_L1FSM_E_NORMAL_Sa7:
/* Start timer */
osmo_fsm_inst_state_chg(fi, V5X_L1FSM_S_ANLE52_LINK_ID_RECEIVED, TIMEOUT, 0);
break;
case V5X_L1FSM_E_MPH_IDR:
/* send MPH-DI */
mph_rcv(fi, MPH_DI);
break;
default:
OSMO_ASSERT(0);
}
}
static void l1_fsm_le3_remotely_det_fail(struct osmo_fsm_inst *fi, uint32_t event, void __attribute__((unused)) *data)
{
switch (event) {
case V5X_L1FSM_E_NORMAL:
/* Start timer */
osmo_fsm_inst_state_chg(fi, V5X_L1FSM_S_ANLE1_NORMAL, TIMEOUT, 0);
break;
case V5X_L1FSM_E_LOS:
osmo_fsm_inst_state_chg(fi, V5X_L1FSM_S_ANLE2_LOCALLY_DET_FAIL, 0, 0);
/* send MPH-EIa */
mph_rcv(fi, MPH_EIa);
/* send MPH-EIbr */
mph_rcv(fi, MPH_EIbr);
break;
case V5X_L1FSM_E_RAI:
/* ignore */
break;
case V5X_L1FSM_E_AIS:
osmo_fsm_inst_state_chg(fi, V5X_L1FSM_S_ANLE2_LOCALLY_DET_FAIL, 0, 0);
/* send MPH-EIc */
mph_rcv(fi, MPH_EIc);
/* send MPH-EIbr */
mph_rcv(fi, MPH_EIbr);
break;
case V5X_L1FSM_E_INTERNAL_F:
osmo_fsm_inst_state_chg(fi, V5X_L1FSM_S_ANLE4_INTERNAL_FAIL, 0, 0);
/* send MPH-DI */
mph_rcv(fi, MPH_DI);
/* send MPH-EId */
mph_rcv(fi, MPH_EId);
break;
case V5X_L1FSM_E_TIMEOUT:
/* send MPH-DI */
mph_rcv(fi, MPH_DI);
break;
case V5X_L1FSM_E_MPH_ID:
/* send MPH-DI */
mph_rcv(fi, MPH_DI);
break;
case V5X_L1FSM_E_MPH_NOR:
/* send MPH-DI */
mph_rcv(fi, MPH_DI);
break;
case V5X_L1FSM_E_NORMAL_Sa7:
/* Start timer */
osmo_fsm_inst_state_chg(fi, V5X_L1FSM_S_ANLE52_LINK_ID_RECEIVED, TIMEOUT, 0);
break;
case V5X_L1FSM_E_MPH_IDR:
/* send MPH-DI */
mph_rcv(fi, MPH_DI);
break;
default:
OSMO_ASSERT(0);
}
}
static void l1_fsm_le4_internal_fail(struct osmo_fsm_inst *fi, uint32_t event, void __attribute__((unused)) *data)
{
struct v5x_link *v5l = fi->priv;
struct v5x_l1_proto *l1 = v5l->l1;
switch (event) {
case V5X_L1FSM_E_NORMAL:
/* ignore */
break;
case V5X_L1FSM_E_LOS:
/* send MPH-EIa */
mph_rcv(fi, MPH_EIa);
break;
case V5X_L1FSM_E_RAI:
/* ignore */
break;
case V5X_L1FSM_E_AIS:
/* send MPH-EIc */
mph_rcv(fi, MPH_EIc);
break;
case V5X_L1FSM_E_INTERNAL_F:
/* ignore */
break;
case V5X_L1FSM_E_INTERNAL_D:
osmo_fsm_inst_state_chg(fi, V5X_L1FSM_S_ANLE3_REMOTELY_DET_FAIL, 0, 0);
/* send MPH-EIbr */
mph_rcv(fi, MPH_EIbr);
/* Go on to normal state, when no alarm persists.
* We must do this, because there is no frame reception to trigger this.
*/
if (!l1->los && !l1->rai && !l1->ais) {
if (l1->sa7_zero)
osmo_fsm_inst_dispatch(fi, V5X_L1FSM_E_NORMAL_Sa7, NULL);
else
osmo_fsm_inst_dispatch(fi, V5X_L1FSM_E_NORMAL, NULL);
}
break;
case V5X_L1FSM_E_TIMEOUT:
/* ignore */
break;
case V5X_L1FSM_E_MPH_ID:
/* send MPH-DI */
mph_rcv(fi, MPH_DI);
break;
case V5X_L1FSM_E_MPH_NOR:
/* send MPH-DI */
mph_rcv(fi, MPH_DI);
break;
case V5X_L1FSM_E_NORMAL_Sa7:
/* ignore */
break;
case V5X_L1FSM_E_MPH_IDR:
/* send MPH-DI */
mph_rcv(fi, MPH_DI);
break;
default:
OSMO_ASSERT(0);
}
}
static void l1_fsm_le51_link_id_sending(struct osmo_fsm_inst *fi, uint32_t event, void __attribute__((unused)) *data)
{
switch (event) {
case V5X_L1FSM_E_NORMAL:
/* ignore */
break;
case V5X_L1FSM_E_LOS:
/* Start timer */
osmo_fsm_inst_state_chg(fi, V5X_L1FSM_S_ANLE2_LOCALLY_DET_FAIL, TIMEOUT, 0);
/* send Sa7 = ONE */
signal_snd(fi, L1_SIGNAL_SA7_1);
/* send MPH-EIa */
mph_rcv(fi, MPH_EIa);
break;
case V5X_L1FSM_E_RAI:
/* Start timer */
osmo_fsm_inst_state_chg(fi, V5X_L1FSM_S_ANLE3_REMOTELY_DET_FAIL, TIMEOUT, 0);
/* send Sa7 = ONE */
signal_snd(fi, L1_SIGNAL_SA7_1);
/* send MPH-EIb */
mph_rcv(fi, MPH_EIb);
break;
case V5X_L1FSM_E_AIS:
/* Start timer */
osmo_fsm_inst_state_chg(fi, V5X_L1FSM_S_ANLE2_LOCALLY_DET_FAIL, TIMEOUT, 0);
/* send Sa7 = ONE */
signal_snd(fi, L1_SIGNAL_SA7_1);
/* send MPH-EIc */
mph_rcv(fi, MPH_EIc);
break;
case V5X_L1FSM_E_INTERNAL_F:
osmo_fsm_inst_state_chg(fi, V5X_L1FSM_S_ANLE4_INTERNAL_FAIL, 0, 0);
/* send Sa7 = ONE */
signal_snd(fi, L1_SIGNAL_SA7_1);
/* send MPH-DI */
mph_rcv(fi, MPH_DI);
/* send MPH-EId */
mph_rcv(fi, MPH_EId);
break;
case V5X_L1FSM_E_MPH_ID:
/* ignore */
break;
case V5X_L1FSM_E_MPH_NOR:
osmo_fsm_inst_state_chg(fi, V5X_L1FSM_S_ANLE1_NORMAL, 0, 0);
/* send Sa7 = ONE */
signal_snd(fi, L1_SIGNAL_SA7_1);
break;
case V5X_L1FSM_E_NORMAL_Sa7:
/* ignore */
break;
default:
OSMO_ASSERT(0);
}
}
static void l1_fsm_le52_link_id_received(struct osmo_fsm_inst *fi, uint32_t event, void __attribute__((unused)) *data)
{
switch (event) {
case V5X_L1FSM_E_NORMAL:
break;
case V5X_L1FSM_E_LOS:
/* Start timer */
osmo_fsm_inst_state_chg(fi, V5X_L1FSM_S_ANLE2_LOCALLY_DET_FAIL, TIMEOUT, 0);
/* send MPH-EIa */
mph_rcv(fi, MPH_EIa);
break;
case V5X_L1FSM_E_RAI:
/* Start timer */
osmo_fsm_inst_state_chg(fi, V5X_L1FSM_S_ANLE3_REMOTELY_DET_FAIL, TIMEOUT, 0);
/* send MPH-EIb */
mph_rcv(fi, MPH_EIb);
break;
case V5X_L1FSM_E_AIS:
/* Start timer */
osmo_fsm_inst_state_chg(fi, V5X_L1FSM_S_ANLE2_LOCALLY_DET_FAIL, TIMEOUT, 0);
/* send MPH-EIc */
mph_rcv(fi, MPH_EIc);
break;
case V5X_L1FSM_E_INTERNAL_F:
osmo_fsm_inst_state_chg(fi, V5X_L1FSM_S_ANLE4_INTERNAL_FAIL, 0, 0);
/* send MPH-DI */
mph_rcv(fi, MPH_DI);
/* send MPH-EId */
mph_rcv(fi, MPH_EId);
break;
case V5X_L1FSM_E_TIMEOUT:
/* send MPH-DI */
mph_rcv(fi, MPH_AI);
break;
case V5X_L1FSM_E_MPH_ID:
osmo_fsm_inst_state_chg(fi, V5X_L1FSM_S_ANLE51_LINK_ID_SENDING, 0, 0);
/* send Sa7 = ZERO */
signal_snd(fi, L1_SIGNAL_SA7_0);
break;
case V5X_L1FSM_E_NORMAL_Sa7:
/* ignore */
break;
case V5X_L1FSM_E_MPH_IDR:
/* send MPH-IDI */
mph_rcv(fi, MPH_IDI);
break;
default:
OSMO_ASSERT(0);
}
}
/* Table 12/G.965 */
static const struct osmo_fsm_state v5x_l1_fsm_states[] = {
[V5X_L1FSM_S_ANLE1_NORMAL] = {
.name = "AN/LE1 Normal",
.in_event_mask = S(V5X_L1FSM_E_NORMAL) |
S(V5X_L1FSM_E_LOS) |
S(V5X_L1FSM_E_RAI) |
S(V5X_L1FSM_E_AIS) |
S(V5X_L1FSM_E_INTERNAL_F) |
S(V5X_L1FSM_E_TIMEOUT) |
S(V5X_L1FSM_E_MPH_ID) |
S(V5X_L1FSM_E_MPH_NOR) |
S(V5X_L1FSM_E_NORMAL_Sa7) |
S(V5X_L1FSM_E_MPH_IDR),
.out_state_mask = S(V5X_L1FSM_S_ANLE2_LOCALLY_DET_FAIL) |
S(V5X_L1FSM_S_ANLE3_REMOTELY_DET_FAIL) |
S(V5X_L1FSM_S_ANLE4_INTERNAL_FAIL) |
S(V5X_L1FSM_S_ANLE51_LINK_ID_SENDING) |
S(V5X_L1FSM_S_ANLE52_LINK_ID_RECEIVED),
.action = l1_fsm_le1_normal,
},
[V5X_L1FSM_S_ANLE2_LOCALLY_DET_FAIL] = {
.name = "AN/LE2 Locally detected failure",
.in_event_mask = S(V5X_L1FSM_E_NORMAL) |
S(V5X_L1FSM_E_LOS) |
S(V5X_L1FSM_E_RAI) |
S(V5X_L1FSM_E_AIS) |
S(V5X_L1FSM_E_INTERNAL_F) |
S(V5X_L1FSM_E_TIMEOUT) |
S(V5X_L1FSM_E_MPH_ID) |
S(V5X_L1FSM_E_MPH_NOR) |
S(V5X_L1FSM_E_NORMAL_Sa7) |
S(V5X_L1FSM_E_MPH_IDR),
.out_state_mask = S(V5X_L1FSM_S_ANLE1_NORMAL) |
S(V5X_L1FSM_S_ANLE3_REMOTELY_DET_FAIL) |
S(V5X_L1FSM_S_ANLE4_INTERNAL_FAIL) |
S(V5X_L1FSM_S_ANLE52_LINK_ID_RECEIVED),
.action = l1_fsm_le2_locally_det_fail,
},
[V5X_L1FSM_S_ANLE3_REMOTELY_DET_FAIL] = {
.name = "AN/LE3 Remotely detected failure",
.in_event_mask = S(V5X_L1FSM_E_NORMAL) |
S(V5X_L1FSM_E_LOS) |
S(V5X_L1FSM_E_RAI) |
S(V5X_L1FSM_E_AIS) |
S(V5X_L1FSM_E_INTERNAL_F) |
S(V5X_L1FSM_E_TIMEOUT) |
S(V5X_L1FSM_E_MPH_ID) |
S(V5X_L1FSM_E_MPH_NOR) |
S(V5X_L1FSM_E_NORMAL_Sa7) |
S(V5X_L1FSM_E_MPH_IDR),
.out_state_mask = S(V5X_L1FSM_S_ANLE1_NORMAL) |
S(V5X_L1FSM_S_ANLE2_LOCALLY_DET_FAIL) |
S(V5X_L1FSM_S_ANLE4_INTERNAL_FAIL) |
S(V5X_L1FSM_S_ANLE52_LINK_ID_RECEIVED),
.action = l1_fsm_le3_remotely_det_fail,
},
[V5X_L1FSM_S_ANLE4_INTERNAL_FAIL] = {
.name = "AN/LE4 Internal failure",
.in_event_mask = S(V5X_L1FSM_E_NORMAL) |
S(V5X_L1FSM_E_LOS) |
S(V5X_L1FSM_E_RAI) |
S(V5X_L1FSM_E_AIS) |
S(V5X_L1FSM_E_INTERNAL_F) |
S(V5X_L1FSM_E_INTERNAL_D) |
S(V5X_L1FSM_E_TIMEOUT) |
S(V5X_L1FSM_E_MPH_ID) |
S(V5X_L1FSM_E_MPH_NOR) |
S(V5X_L1FSM_E_NORMAL_Sa7) |
S(V5X_L1FSM_E_MPH_IDR),
.out_state_mask = S(V5X_L1FSM_S_ANLE3_REMOTELY_DET_FAIL),
.action = l1_fsm_le4_internal_fail,
},
[V5X_L1FSM_S_ANLE51_LINK_ID_SENDING] = {
.name = "AN/LE5.1 Link ID sending",
.in_event_mask = S(V5X_L1FSM_E_NORMAL) |
S(V5X_L1FSM_E_LOS) |
S(V5X_L1FSM_E_RAI) |
S(V5X_L1FSM_E_AIS) |
S(V5X_L1FSM_E_INTERNAL_F) |
S(V5X_L1FSM_E_MPH_ID) |
S(V5X_L1FSM_E_MPH_NOR) |
S(V5X_L1FSM_E_NORMAL_Sa7),
.out_state_mask = S(V5X_L1FSM_S_ANLE1_NORMAL) |
S(V5X_L1FSM_S_ANLE2_LOCALLY_DET_FAIL) |
S(V5X_L1FSM_S_ANLE3_REMOTELY_DET_FAIL) |
S(V5X_L1FSM_S_ANLE4_INTERNAL_FAIL),
.action = l1_fsm_le51_link_id_sending,
},
[V5X_L1FSM_S_ANLE52_LINK_ID_RECEIVED] = {
.name = "AN/LE5.2 Link ID received",
.in_event_mask = S(V5X_L1FSM_E_NORMAL) |
S(V5X_L1FSM_E_LOS) |
S(V5X_L1FSM_E_RAI) |
S(V5X_L1FSM_E_AIS) |
S(V5X_L1FSM_E_INTERNAL_F) |
S(V5X_L1FSM_E_TIMEOUT) |
S(V5X_L1FSM_E_MPH_ID) |
S(V5X_L1FSM_E_NORMAL_Sa7) |
S(V5X_L1FSM_E_MPH_IDR),
.out_state_mask = S(V5X_L1FSM_S_ANLE1_NORMAL) |
S(V5X_L1FSM_S_ANLE2_LOCALLY_DET_FAIL) |
S(V5X_L1FSM_S_ANLE3_REMOTELY_DET_FAIL) |
S(V5X_L1FSM_S_ANLE4_INTERNAL_FAIL) |
S(V5X_L1FSM_S_ANLE51_LINK_ID_SENDING),
.action = l1_fsm_le52_link_id_received,
},
};
struct osmo_fsm v5x_l1_fsm = {
.name = "V5X_L1",
.states = v5x_l1_fsm_states,
.num_states = ARRAY_SIZE(v5x_l1_fsm_states),
.timer_cb = v5x_l1_fsm_timer_cb,
.log_subsys = DV5L1,
.event_names = v5x_l1_fsm_event_names,
};
struct v5x_l1_proto *v5x_l1_fsm_create(void *ctx, struct v5x_link *v5l, uint8_t id)
{
struct v5x_l1_proto *l1;
OSMO_ASSERT(v5l);
l1 = talloc_zero(ctx, struct v5x_l1_proto);
if (!l1)
return NULL;
l1->v5l = v5l;
l1->fi = osmo_fsm_inst_alloc(&v5x_l1_fsm, l1, l1, LOGL_DEBUG, NULL);
if (!l1->fi)
return NULL;
osmo_fsm_inst_update_id_f(l1->fi, "%d", id);
return l1;
}
void v5x_l1_fsm_destroy(struct v5x_l1_proto *l1)
{
if (l1->fi) {
osmo_fsm_inst_free(l1->fi);
}
talloc_free(l1);
}
const char *v5x_l1_fsm_state_name(struct v5x_l1_proto *l1)
{
return v5x_l1_fsm_states[l1->fi->state].name;
}
void v5x_l1_init(void)
{
int rc;
rc = osmo_fsm_register(&v5x_l1_fsm);
OSMO_ASSERT(!rc);
LOGP(DV5PSTN, LOGL_NOTICE, "Using V5x L1 protocol\n");
}
/***********************************************************************
* Messages from other layers
***********************************************************************/
/* receive primitive from physical E1 layer */
int v5x_l1_signal_rcv(struct v5x_link *v5l, enum l1_signal_prim prim)
{
struct v5x_l1_proto *l1 = v5l->l1;
struct osmo_fsm_inst *fi = l1->fi;
int state_changed = 0;
switch (prim) {
case L1_SIGNAL_LOS:
if (!l1->los) {
l1->los = 1;
osmo_fsm_inst_dispatch(fi, V5X_L1FSM_E_LOS, NULL);
}
break;
case L1_SIGNAL_NO_LOS:
if (l1->los) {
l1->los = 0;
state_changed = 1;
}
break;
case L1_SIGNAL_RAI:
if (!l1->rai) {
l1->rai = 1;
osmo_fsm_inst_dispatch(fi, V5X_L1FSM_E_RAI, NULL);
}
break;
case L1_SIGNAL_NO_RAI:
if (l1->rai) {
l1->rai = 0;
state_changed = 1;
}
break;
case L1_SIGNAL_AIS:
if (!l1->ais) {
l1->ais = 1;
osmo_fsm_inst_dispatch(fi, V5X_L1FSM_E_AIS, NULL);
}
break;
case L1_SIGNAL_NO_AIS:
if (l1->ais) {
l1->ais = 0;
state_changed = 1;
}
break;
case L1_SIGNAL_SA7_0:
if (!l1->sa7_zero) {
l1->sa7_zero = 1;
state_changed = 1;
}
break;
case L1_SIGNAL_SA7_1:
if (l1->sa7_zero) {
l1->sa7_zero = 0;
state_changed = 1;
}
break;
default:
LOGP(DV5PSTN, LOGL_NOTICE, "Invalid L1 primitive %d receied from physical layer.\n", prim);
return -EINVAL;
}
/* Go on to normal state, when no alarm persists.
* We must do this, because there is no frame reception to trigger this.
*/
if (state_changed && !l1->los && !l1->rai && !l1->ais) {
if (l1->sa7_zero)
osmo_fsm_inst_dispatch(fi, V5X_L1FSM_E_NORMAL_Sa7, NULL);
else
osmo_fsm_inst_dispatch(fi, V5X_L1FSM_E_NORMAL, NULL);
}
return 0;
}
/* receive message from upper (LCP) layer */
void v5x_l1_mph_snd(struct v5x_link *v5l, enum v5x_mph_prim prim)
{
struct v5x_l1_proto *l1 = v5l->l1;
enum v5x_l1_fsm_event event;
switch (prim) {
case MPH_ID:
event = V5X_L1FSM_E_MPH_ID;
break;
case MPH_NOR:
event = V5X_L1FSM_E_MPH_NOR;
break;
case MPH_IDR:
event = V5X_L1FSM_E_MPH_IDR;
break;
case MPH_stop:
// FIXME: do we need this?
break;
case MPH_proceed:
// FIXME: do we need this?
break;
default:
LOGP(DV5PORT, LOGL_NOTICE, "Got invalid prim %d at this protocol\n", prim);
return;
}
/* send event to FSM */
osmo_fsm_inst_dispatch(l1->fi, event, NULL);
}

7
src/v5x_l1_fsm.h Normal file
View File

@ -0,0 +1,7 @@
void v5x_l1_mph_snd(struct v5x_link *v5i, enum v5x_mph_prim prim);
struct v5x_l1_proto *v5x_l1_fsm_create(void *ctx, struct v5x_link *v5l, uint8_t id);
void v5x_l1_fsm_destroy(struct v5x_l1_proto *l1);
void v5x_l1_init(void);
int v5x_l1_signal_rcv(struct v5x_link *v5i, enum l1_signal_prim prim);
int v5x_l1_signal_snd(struct v5x_link *v5i, enum l1_signal_prim prim);