11#include "rte/utils/buffer/rte_buffer.h"
12#include "rte/utils/cast/rte_cast.h"
13#include "rte/utils/lifecycle/rte_lifecycle.h"
14#include "rte/oal/log/rte_log.h"
15#include "rte/oal/memory/rte_mem_util.h"
16#include "rte/utils/notify/rte_notify.h"
41 rte_status_t lifecycle_status;
45 return RTE_STATUS_INVALID_PARAM;
47 lifecycle_status = rte_lifecycle_check_setup_allowed();
48 if (lifecycle_status != RTE_STATUS_OK)
50 return lifecycle_status;
54 return RTE_STATUS_RESOURCE_EXHAUSTED;
84 s = &sessions[train_id - 1U];
85 t = &db->
trains[train_id - 1U];
106 for (i = 0U; i < count; i++)
128 rte_mem_set(&ctx, 0,
sizeof(ctx));
170#define TRAIN_WIRE_HEADER_SIZE 12U
171#define TRAIN_WIRE_CONTENT_SIZE_BASE 24U
172#define TRAIN_WIRE_CONTENT_SIZE_M146 (TRAIN_WIRE_CONTENT_SIZE_BASE + 4U)
173#define TRAIN_WIRE_CONTENT_SIZE_M136 (TRAIN_WIRE_CONTENT_SIZE_BASE + 4U + 40U)
238 out[0] = (uint8_t)env->
kind;
242 (void)rte_buffer_set_length(&buf, 4U);
243 (void)rte_buffer_write_u16_le(&buf, l_message);
244 (void)rte_buffer_write_u16_le(&buf, 0U);
245 (void)rte_buffer_write_u32_le(&buf, env->
t_train);
246 (void)rte_buffer_write_u32_le(&buf, env->
cycle);
247 (void)rte_buffer_write_u32_le(&buf, env->
d_lrbg);
248 (void)rte_buffer_write_u32_le(&buf, env->
msg_type);
249 (void)rte_buffer_write_u32_le(&buf, env->
route_len);
251 (void)rte_buffer_write_u32_le(&buf, env->
ma_seq);
252 (void)rte_buffer_write_u32_le(&buf, env->
ma_length);
253 (void)rte_buffer_write_u32_le(&buf, env->
t_train_ack);
254 (void)rte_buffer_write_u32_le(&buf, env->
nid_lrbg);
255 (void)rte_buffer_write_u32_le(&buf, env->
q_dirlrbg);
256 (void)rte_buffer_write_u32_le(&buf, env->
q_dlrbg);
257 (void)rte_buffer_write_u32_le(&buf, env->
l_doubtover);
259 (void)rte_buffer_write_u32_le(&buf, env->
q_length);
260 (void)rte_buffer_write_u32_le(&buf, env->
v_train);
261 (void)rte_buffer_write_u32_le(&buf, env->
q_dirtrain);
262 (void)rte_buffer_write_u32_le(&buf, env->
m_mode);
263 (void)rte_buffer_write_u32_le(&buf, env->
m_level);
282 uint16_t expected_l_message;
284 rte_mem_set(&decoded, 0,
sizeof(decoded));
293 if (rte_buffer_read_u16_le(&buf, 4U, &l_message) != RTE_STATUS_OK)
298 if (l_message != expected_l_message)
306 if ((rte_buffer_read_u32_le(&buf, 8U, &decoded.
t_train) != RTE_STATUS_OK)
307 || (rte_buffer_read_u32_le(&buf, 12U, &decoded.
cycle) != RTE_STATUS_OK)
308 || (rte_buffer_read_u32_le(&buf, 16U, &decoded.
d_lrbg) != RTE_STATUS_OK)
309 || (rte_buffer_read_u32_le(&buf, 20U, &decoded.
msg_type) != RTE_STATUS_OK)
310 || (rte_buffer_read_u32_le(&buf, 24U, &decoded.
route_len) != RTE_STATUS_OK)
311 || (rte_buffer_read_u32_le(&buf, 28U, &decoded.
ma_seq) != RTE_STATUS_OK)
312 || (rte_buffer_read_u32_le(&buf, 32U, &decoded.
ma_length) != RTE_STATUS_OK))
316 if ((rte_buffer_read_u32_le(&buf, 36U, &decoded.
t_train_ack) != RTE_STATUS_OK)
317 || (rte_buffer_read_u32_le(&buf, 40U, &decoded.
nid_lrbg) != RTE_STATUS_OK)
318 || (rte_buffer_read_u32_le(&buf, 44U, &decoded.
q_dirlrbg) != RTE_STATUS_OK)
319 || (rte_buffer_read_u32_le(&buf, 48U, &decoded.
q_dlrbg) != RTE_STATUS_OK)
320 || (rte_buffer_read_u32_le(&buf, 52U, &decoded.
l_doubtover) != RTE_STATUS_OK)
321 || (rte_buffer_read_u32_le(&buf, 56U, &decoded.
l_doubtunder) != RTE_STATUS_OK)
322 || (rte_buffer_read_u32_le(&buf, 60U, &decoded.
q_length) != RTE_STATUS_OK)
323 || (rte_buffer_read_u32_le(&buf, 64U, &decoded.
v_train) != RTE_STATUS_OK)
324 || (rte_buffer_read_u32_le(&buf, 68U, &decoded.
q_dirtrain) != RTE_STATUS_OK)
325 || (rte_buffer_read_u32_le(&buf, 72U, &decoded.
m_mode) != RTE_STATUS_OK)
326 || (rte_buffer_read_u32_le(&buf, 76U, &decoded.
m_level) != RTE_STATUS_OK))
364 uint8_t this_train_id = (uint8_t)(i + 1U);
382 slot = &db->
trains[train_id - 1U];
392 rte_mem_set(slot, 0,
sizeof(*slot));
414 slot = &db->
trains[train_id - 1U];
424 rte_mem_set(slot, 0,
sizeof(*slot));
438 return &db->
trains[train_id - 1U];
449 if (out_train_id != NULL)
451 *out_train_id = (uint8_t)(i + 1U);
561 uint32_t d_lrbg, uint32_t msg_type)
565 rte_mem_set(&env, 0,
sizeof(env));
579 rte_mem_set(&env, 0,
sizeof(env));
590 const char *role_tag)
594 rte_mem_set(session, 0,
sizeof(*session));
601 RTE_EXAMPLE_LOG(
"[%s] cycle %u: [ONLINE] train %u connected (P0)\n", role_tag, cycle,
603 rte_log_write_event(RTE_LOG_LEVEL_INFO,
site_config_name(site), cycle,
"Train", role_tag,
"P0",
616 rte_log_write_event(RTE_LOG_LEVEL_DEBUG,
site_config_name(site), cycle,
"Train", role_tag,
"P0",
617 "redundant P0 for already-connected train - no-op, session untouched", NULL);
627 const char *role_tag, uint8_t idx, uint32_t cyc_msg_type_due[],
628 bool cyc_position_reply_due[])
630 uint32_t local_msg_type;
637 rte_mem_set(session, 0,
sizeof(*session));
670 cyc_msg_type_due[idx] = local_msg_type;
671 cyc_position_reply_due[idx] =
true;
675 const ab_site_balise_t *bal = ab_site_get_balise(env->
nid_lrbg);
676 const char *bal_name = (bal != NULL) ? bal->name :
"UNKNOWN_BG";
678 RTE_EXAMPLE_LOG(
"[%s] cycle %u: [ONLINE] train %u M136 NID_LRBG=%u (%s) D_LRBG=%u (its cycle %u) -> M%u\n", role_tag,
684 (void)snprintf(extra,
sizeof(extra),
"train_id=%u nid_lrbg=%u (%s) d_lrbg=%u", (
unsigned int)env->
train_id,
686 (void)snprintf(type_buf,
sizeof(type_buf),
"M%u", local_msg_type);
687 rte_log_write_event(RTE_LOG_LEVEL_INFO,
site_config_name(site), cycle,
"Train", role_tag, type_buf,
701 rte_log_write_event(RTE_LOG_LEVEL_INFO,
site_config_name(site), cycle,
"Train", role_tag,
"M146",
714 uint8_t held_count = 0U;
724 for (r = 0U; r < held_count; r++)
726 if (held_routes[r] != 0U)
734 if (ertms_ctx != NULL)
739 rte_mem_set(session, 0,
sizeof(*session));
742 "[%s] cycle %u: [ONLINE] train %u disconnected (released %u route(s))\n", role_tag, cycle,
743 (
unsigned int)env->
train_id, (
unsigned int)held_count);
744 rte_log_write_event(RTE_LOG_LEVEL_INFO,
site_config_name(site), cycle,
"Train", role_tag,
745 "DISCONNECT",
"removed", NULL);
752 bool cyc_position_reply_due[])
756 bool have_channel_data =
false;
768 RTE_EXAMPLE_LOG(
"[%s] cycle %u: malformed envelope from C (Train relay)\n", role_tag, cycle);
769 rte_log_write_event(RTE_LOG_LEVEL_ERROR,
site_config_name(site), cycle,
"C", role_tag,
"ENVELOPE",
775 RTE_EXAMPLE_LOG(
"[%s] cycle %u: Train relay envelope kind %d has out-of-range train_id=%u - dropping\n",
776 role_tag, cycle, (
int)env->
kind, (
unsigned int)env->
train_id);
782 idx = (uint8_t)(env->
train_id - 1U);
783 session = &sessions[idx];
791 have_channel_data =
handle_envelope_m136(session, sessions, db, env, cycle, site, role_tag, idx,
792 cyc_msg_type_due, cyc_position_reply_due);
802 "[%s] cycle %u: unexpected envelope kind %d on the Train relay channel - dropping\n", role_tag,
803 cycle, (
int)env->
kind);
806 return have_channel_data;
810 const bool cyc_position_reply_due[],
819 uint8_t train_id = (uint8_t)(i + 1U);
824 if (reply_type == 0U)
828 (void)snprintf(out[count].tag,
sizeof(out[count].tag),
"M%u", (
unsigned int)(reply_type & 0xFFU));
829 out[count].index = i;
836 rte_mem_copy(out[count].tag,
"M3", 3U);
837 out[count].index = i;
876 sessions[train_id - 1U].
ma_seq++;
898 sessions[train_id - 1U].
ma_acked = acked;
964 slot[0] = session->
in_use ? 1U : 0U;
965 slot[1] = session->train_id;
966 (void)rte_buffer_set_length(&buf, 2U);
967 (void)rte_buffer_write_u32_le(&buf, session->cycle);
968 (void)rte_buffer_write_u32_le(&buf, session->d_lrbg);
969 (void)rte_buffer_write_u32_le(&buf, session->granted_length);
970 (void)rte_buffer_write_u32_le(&buf, session->ma_seq);
971 slot[18] = session->ma_acked ? 1U : 0U;
995 uint32_t d_lrbg = 0U;
996 uint32_t granted_length = 0U;
997 uint32_t ma_seq = 0U;
999 rte_mem_set(out_session, 0,
sizeof(*out_session));
1005 if ((rte_buffer_read_u32_le(&buf, 2U, &cycle) != RTE_STATUS_OK)
1006 || (rte_buffer_read_u32_le(&buf, 6U, &d_lrbg) != RTE_STATUS_OK)
1007 || (rte_buffer_read_u32_le(&buf, 10U, &granted_length) != RTE_STATUS_OK)
1008 || (rte_buffer_read_u32_le(&buf, 14U, &ma_seq) != RTE_STATUS_OK))
1012 out_session->in_use = (slot[0] != 0U);
1013 out_session->train_id = slot[1];
1014 out_session->cycle = cycle;
1015 out_session->d_lrbg = d_lrbg;
1016 out_session->granted_length = granted_length;
1017 out_session->ma_seq = ma_seq;
1018 out_session->ma_acked = (slot[18] != 0U);
1019 out_session->ma_pending_send =
false;
rte_status_t ab_gp_channel_payload_register_collector(uint32_t wire_size, ab_gp_channel_payload_encode_fn encode_fn, ab_gp_channel_payload_decode_fn decode_fn, void *context, ab_gp_channel_payload_collector_id_t *out_id)
Registers a collector: a module's own fixed-size contribution to the combined A<->B payload - a fan-o...
Generic, data-blind wire framing for the A<->B peer link's AB_SAMPLE frame (CRC-64-protected,...
uint32_t ab_gp_channel_payload_collector_id_t
Opaque handle to a registered collector - returned by ab_gp_channel_payload_register_collector() belo...
bool ab_gp_db_route_disconnect_train(ab_gp_db_t *db, uint16_t route_id)
Reverses ab_gp_db_route_connect_train(): clears the route's own used_in_ma/train_id and removes it fr...
bool ab_gp_db_train_get_routes(const ab_gp_db_t *db, uint8_t train_id, uint16_t out_routes[RTE_EXAMPLE_MAX_ROUTES_PER_TRAIN], uint8_t *out_count)
Retrieves routes currently allocated to a train.
RTE_DECLARE_CALLBACK_LIST(ab_gp_db_route_context_list_t, ab_gp_route_context_notify_fn, AB_GP_DB_MAX_ROUTE_CONTEXT_SUBSCRIBERS)
ab_gp_ertms_train_context_t * ab_gp_ertms_engine_get_train_context(uint8_t train_id)
Retrieves the ERTMS procedure context for a given train slot.
Unified ERTMS Subset-026 Chapter 5 Operational Procedure Orchestrator.
bool ab_gp_proc_session_handle_termination(ab_gp_ertms_train_context_t *ctx, ab_gp_db_t *db)
Handles session termination (Msg 156 / Msg 41).
ERTMS Subset-026 ยง5.3 Communication Session Management Procedure.
static bool build_train_context(const ab_gp_train_session_t sessions[], const ab_gp_db_t *db, uint8_t train_id, ab_gp_train_context_t *out_ctx)
static bool train_wire_decode(const uint8_t in[RBC_ENVELOPE_WIRE_SIZE], rbc_envelope_t *out_env)
bool ab_gp_train_handle_connect(ab_gp_db_t *db, uint8_t train_id)
Handles an inbound P0 (connect handshake) - wraps ab_gp_train_add() with the same env->train_id-as-ni...
#define TRAIN_WIRE_HEADER_SIZE
#define TRAIN_WIRE_CONTENT_SIZE_M146
static ab_gp_train_context_list_t g_train_context_subscribers
#define TRAIN_WIRE_CONTENT_SIZE_BASE
bool ab_gp_train_add(ab_gp_db_t *db, uint8_t train_id, uint8_t nid_engine)
Adds a train on connect: fills db->trains[train_id-1] with nid_engine, connected=true,...
bool ab_gp_train_remove(ab_gp_db_t *db, uint8_t train_id)
Removes a train on disconnect: resets db->trains[train_id-1] back to its all-zero/disconnected state.
bool ab_gp_train_set_last_position(ab_gp_db_t *db, uint8_t train_id, uint32_t nid_lrbg)
Records this train's own most recently reported NID_LRBG - the write side of the field logic/'s own c...
static uint8_t train_wire_nid_message_for_kind(rbc_msg_kind_t kind)
static void train_wire_encode(uint8_t out[RBC_ENVELOPE_WIRE_SIZE], const rbc_envelope_t *env)
static bool nid_engine_connected_elsewhere(const ab_gp_db_t *db, uint8_t nid_engine, uint8_t exclude_train_id)
bool ab_gp_train_apply_envelope(ab_gp_train_session_t sessions[], ab_gp_db_t *db, const uint8_t env_bytes[RBC_ENVELOPE_WIRE_SIZE], uint32_t cycle, bool is_role_a, rte_example_site_t site, const char *role_tag, uint32_t cyc_msg_type_due[], bool cyc_position_reply_due[])
THE single entry point com/'s ab_gp_channel.c calls for every raw envelope popped off its dedicated T...
uint8_t ab_gp_train_build_outputs(const ab_gp_train_session_t sessions[], const uint32_t cyc_msg_type_due[], const bool cyc_position_reply_due[], ab_gp_train_pending_output_t out[AB_GP_TRAIN_MAX_PENDING_OUTPUTS])
Decides which trains need a Train-directed envelope THIS cycle and builds all of them - see this file...
static void train_sessions_collector_encode(void *context, const void *items, uint8_t *out)
static void handle_envelope_p0(ab_gp_train_session_t *session, ab_gp_train_session_t sessions[], ab_gp_db_t *db, const rbc_envelope_t *env, uint32_t cycle, rte_example_site_t site, const char *role_tag)
RBC_MSG_P0 handler: connect a new session, or no-op (logged at DEBUG) if already in use.
bool ab_gp_train_set_nid_engine(ab_gp_db_t *db, uint8_t train_id, uint8_t nid_engine)
void ab_gp_train_build_movement_authority(uint8_t out[RBC_ENVELOPE_WIRE_SIZE], uint8_t train_id, uint32_t ma_seq, uint32_t ma_length)
Builds and wire-encodes the outbound M3 (Movement Authority) envelope for train_id (kind=RBC_MSG_M3) ...
ab_gp_db_train_t * ab_gp_train_find(ab_gp_db_t *db, uint8_t train_id)
Finds a connected train's own slot for direct field access.
bool ab_gp_train_find_by_nid_engine(const ab_gp_db_t *db, uint8_t nid_engine, uint8_t *out_train_id)
Reverse lookup: which train_id (if any) is nid_engine currently connected as.
static bool handle_envelope_m136(ab_gp_train_session_t *session, ab_gp_train_session_t sessions[], ab_gp_db_t *db, const rbc_envelope_t *env, uint32_t cycle, rte_example_site_t site, const char *role_tag, uint8_t idx, uint32_t cyc_msg_type_due[], bool cyc_position_reply_due[])
RBC_MSG_M136 handler: record position, ack with M24. Sets have_channel_data.
bool ab_gp_train_is_connected(const ab_gp_db_t *db, uint8_t train_id)
void ab_gp_train_build_position_answer(uint8_t out[RBC_ENVELOPE_WIRE_SIZE], uint8_t train_id, uint32_t cycle, uint32_t d_lrbg, uint32_t msg_type)
Builds and wire-encodes the outbound M24/M15 Position Report answer for train_id (kind=RBC_MSG_M24_M1...
static uint16_t train_wire_content_size_for_kind(rbc_msg_kind_t kind)
#define TRAIN_WIRE_CONTENT_SIZE_M136
static void train_sessions_collector_decode(void *context, const uint8_t *in, void *out_items)
static void handle_envelope_disconnect(ab_gp_train_session_t *session, ab_gp_train_session_t sessions[], ab_gp_db_t *db, const rbc_envelope_t *env, uint32_t cycle, rte_example_site_t site, const char *role_tag)
RBC_MSG_TRAIN_DISCONNECT handler: release every held route, then remove the train.
bool ab_gp_train_handle_position_report(ab_gp_db_t *db, uint8_t train_id, uint32_t nid_lrbg)
Handles an inbound M136 (Position Report) - adds the train first (ab_gp_train_handle_connect()) if th...
static bool train_id_in_range(uint8_t train_id)
bool ab_gp_train_get_nid_engine(const ab_gp_db_t *db, uint8_t train_id, uint8_t *out_nid_engine)
bool ab_gp_train_get_route_count(const ab_gp_db_t *db, uint8_t train_id, uint8_t *out_route_count)
static ab_gp_channel_payload_collector_id_t g_train_payload_collector_id
static void notify_train_context(const ab_gp_train_session_t sessions[], const ab_gp_db_t *db, uint8_t train_id, ab_gp_train_update_type_t update_type)
rte_status_t ab_gp_train_init(void)
Registers this module's own ab_gp_train_session_t codec as a payload collector with com/ (AB/GP/com/a...
static void handle_envelope_m146(ab_gp_train_session_t *session, const rbc_envelope_t *env, uint32_t cycle, rte_example_site_t site, const char *role_tag)
RBC_MSG_M146 handler: ack the MA if the sequence number matches.
uint32_t ab_gp_train_payload_collector_id(void)
A/B's own train lifecycle handling against db/'s runtime table.
#define RTE_EXAMPLE_TRAIN_SESSION_WIRE_SIZE
#define AB_GP_TRAIN_MAX_PENDING_OUTPUTS
#define AB_GP_TRAIN_MAX_CONTEXT_SUBSCRIBERS
#define RTE_EXAMPLE_LOG(...)
#define RTE_EXAMPLE_MAX_ROUTES_PER_TRAIN
#define RTE_EXAMPLE_MSG_M24
#define RBC_ENVELOPE_WIRE_SIZE
#define RTE_EXAMPLE_MAX_TRAINS
rte_status_t ab_gp_register_train_context_notify(ab_gp_train_context_notify_fn fn, const void *context)
bool ab_gp_train_session_set_ctc_ma_granted_sent(ab_gp_train_session_t *sessions, uint8_t train_id, bool sent)
bool ab_gp_train_session_set_ctc_connected_sent(ab_gp_train_session_t *sessions, uint8_t train_id, bool sent)
bool ab_gp_train_session_set_ma_pending_send(ab_gp_train_session_t *sessions, uint8_t train_id, bool pending)
void ab_gp_train_notify_context_changed(const ab_gp_train_session_t *sessions, const ab_gp_db_t *db, uint8_t train_id, ab_gp_train_update_type_t update_type)
void(*) ab_gp_train_context_notify_fn(const void *context, const ab_gp_train_context_t *ctx, ab_gp_train_update_type_t update_type)
bool ab_gp_train_get_last_position(const ab_gp_db_t *db, uint8_t train_id, uint32_t *out_nid_lrbg)
bool ab_gp_train_session_set_ma_acked(ab_gp_train_session_t *sessions, uint8_t train_id, bool acked)
bool ab_gp_train_set_has_ma(ab_gp_db_t *db, uint8_t train_id, bool has_ma)
bool ab_gp_train_session_increment_ma_seq(ab_gp_train_session_t *sessions, uint8_t train_id)
bool ab_gp_train_session_add_granted_length(ab_gp_train_session_t *sessions, uint8_t train_id, uint32_t delta)
bool ab_gp_train_session_set_ctc_ma_notify_pending(ab_gp_train_session_t *sessions, uint8_t train_id, bool pending)
bool ab_gp_train_session_set_granted_length(ab_gp_train_session_t *sessions, uint8_t train_id, uint32_t granted_length)
ab_gp_train_update_type_t
bool ab_gp_get_train_context(const ab_gp_train_session_t *sessions, const ab_gp_db_t *db, uint8_t train_id, ab_gp_train_context_t *out_ctx)
rbc_msg_kind_t
Which of this envelope's fields are meaningful, and which direction it travels - see this file's own ...
@ RBC_MSG_TRAIN_DISCONNECT
const char * site_config_name(rte_example_site_t site)
ab_gp_db_train_t trains[RTE_EXAMPLE_MAX_TRAINS]
One train A/B's simplified database knows about.
uint16_t route_ids[RTE_EXAMPLE_MAX_ROUTES_PER_TRAIN]
Complete ERTMS state and procedure context for one train slot.
bool ctc_ma_notify_pending
uint16_t route_ids[RTE_EXAMPLE_MAX_ROUTES_PER_TRAIN]
bool position_reply_pending
uint32_t position_reply_msg_type
bool ctc_ma_notify_pending
One decoded envelope - see this file's own module doc for where the wire<->struct conversion now live...