update
This commit is contained in:
@@ -122,23 +122,28 @@ static void process_command(const char *cmd, char *response, size_t resp_size)
|
||||
}
|
||||
}
|
||||
else if (strcmp(p, "STATUS") == 0) {
|
||||
bool in_recovery = nr_is_in_recovery_mode(g_ctrl.ant_state);
|
||||
snprintf(response, resp_size,
|
||||
"=== Antenna Status ===\n"
|
||||
"TX Array: %s\n"
|
||||
" Antennas: %d configured, %d active\n"
|
||||
" Bitmask: 0x%02X\n"
|
||||
" Antenna 0 protected: %s\n"
|
||||
"RX Array: %s\n"
|
||||
" Antennas: %d configured, %d active\n"
|
||||
" Bitmask: 0x%02X\n"
|
||||
"Recovery Mode: %s\n"
|
||||
"Backend: %s\n",
|
||||
g_ctrl.ant_state->tx_array_name,
|
||||
g_ctrl.ant_state->num_tx_antennas,
|
||||
nr_get_active_tx_antenna_count(g_ctrl.ant_state),
|
||||
nr_get_tx_antenna_bitmask(g_ctrl.ant_state),
|
||||
g_ctrl.ant_state->config.protect_antenna0 ? "YES" : "NO",
|
||||
g_ctrl.ant_state->rx_array_name,
|
||||
g_ctrl.ant_state->num_rx_antennas,
|
||||
nr_get_active_rx_antenna_count(g_ctrl.ant_state),
|
||||
nr_get_rx_antenna_bitmask(g_ctrl.ant_state),
|
||||
in_recovery ? "ACTIVE (use identity matrix)" : "OFF",
|
||||
g_ctrl.backend == ANTENNA_CTRL_BACKEND_MPLANE ? "O-RAN M-Plane NETCONF" :
|
||||
g_ctrl.backend == ANTENNA_CTRL_BACKEND_TEST_SOCKET ? "Test Socket (NOT O-RAN)" :
|
||||
"None");
|
||||
@@ -158,17 +163,24 @@ static void process_command(const char *cmd, char *response, size_t resp_size)
|
||||
snprintf(response, resp_size, "OK: Statistics reset\n");
|
||||
}
|
||||
else if (strcmp(p, "RESET") == 0 || strcmp(p, "UNMUTE ALL") == 0) {
|
||||
// Reset all antennas to active state
|
||||
uint8_t all_tx = (1 << g_ctrl.ant_state->num_tx_antennas) - 1;
|
||||
uint8_t all_rx = (1 << g_ctrl.ant_state->num_rx_antennas) - 1;
|
||||
nr_set_tx_antenna_bitmask(g_ctrl.ant_state, all_tx);
|
||||
nr_set_rx_antenna_bitmask(g_ctrl.ant_state, all_rx);
|
||||
// Reset all antennas to active state with recovery mode
|
||||
nr_unmute_all_tx_antennas(g_ctrl.ant_state);
|
||||
nr_unmute_all_rx_antennas(g_ctrl.ant_state);
|
||||
snprintf(response, resp_size,
|
||||
"OK: All antennas unmuted\n"
|
||||
"OK: All antennas unmuted (recovery mode: %u ms)\n"
|
||||
" TX mask: 0x%02X (%d antennas)\n"
|
||||
" RX mask: 0x%02X (%d antennas)\n",
|
||||
all_tx, g_ctrl.ant_state->num_tx_antennas,
|
||||
all_rx, g_ctrl.ant_state->num_rx_antennas);
|
||||
g_ctrl.ant_state->recovery.recovery_duration_ms,
|
||||
nr_get_tx_antenna_bitmask(g_ctrl.ant_state), g_ctrl.ant_state->num_tx_antennas,
|
||||
nr_get_rx_antenna_bitmask(g_ctrl.ant_state), g_ctrl.ant_state->num_rx_antennas);
|
||||
}
|
||||
else if (strcmp(p, "PROTECT ANT0 ON") == 0) {
|
||||
nr_set_antenna0_protection(g_ctrl.ant_state, true);
|
||||
snprintf(response, resp_size, "OK: Antenna 0 protection enabled (SSB)\n");
|
||||
}
|
||||
else if (strcmp(p, "PROTECT ANT0 OFF") == 0) {
|
||||
nr_set_antenna0_protection(g_ctrl.ant_state, false);
|
||||
snprintf(response, resp_size, "OK: Antenna 0 protection disabled (WARNING: may cause UE sync loss)\n");
|
||||
}
|
||||
else if (strcmp(p, "SYNC") == 0) {
|
||||
// Synchronize to RU (only works with M-Plane backend)
|
||||
@@ -180,26 +192,15 @@ static void process_command(const char *cmd, char *response, size_t resp_size)
|
||||
}
|
||||
else if (strcmp(p, "HELP") == 0) {
|
||||
snprintf(response, resp_size,
|
||||
"=== O-RAN Antenna Control Interface ===\n"
|
||||
"Commands:\n"
|
||||
" MUTE TX <ant_id> - Mute TX antenna (0-based)\n"
|
||||
" UNMUTE TX <ant_id> - Unmute TX antenna\n"
|
||||
" MUTE RX <ant_id> - Mute RX antenna\n"
|
||||
" UNMUTE RX <ant_id> - Unmute RX antenna\n"
|
||||
" SET TX MASK <hex> - Set TX bitmask (O-RAN compliant)\n"
|
||||
" SET RX MASK <hex> - Set RX bitmask (O-RAN compliant)\n"
|
||||
" STATUS - Show current antenna state\n"
|
||||
" STATS - Show energy saving statistics\n"
|
||||
" RESET STATS - Reset statistics\n"
|
||||
" RESET / UNMUTE ALL - Unmute all antennas (restore default)\n"
|
||||
" SYNC - Sync state to RU (M-Plane only)\n"
|
||||
" HELP - Show this help\n"
|
||||
" QUIT - Close connection\n"
|
||||
"\n"
|
||||
"Example: SET TX MASK 03 (enables antennas 0,1; mutes 2,3)\n"
|
||||
"\n"
|
||||
"NOTE: This test socket interface is NOT O-RAN compliant.\n"
|
||||
" For production, use NETCONF via radio/fhi_72/mplane/\n");
|
||||
"=== Antenna Control ===\n"
|
||||
"MUTE TX/RX <id> - Mute antenna\n"
|
||||
"UNMUTE TX/RX <id> - Unmute antenna\n"
|
||||
"SET TX/RX MASK <hex> - Set bitmask\n"
|
||||
"STATUS - Show state\n"
|
||||
"STATS - Show statistics\n"
|
||||
"RESET - Unmute all\n"
|
||||
"PROTECT ANT0 ON/OFF\n"
|
||||
"HELP/QUIT\n");
|
||||
}
|
||||
else if (strcmp(p, "QUIT") == 0 || strcmp(p, "EXIT") == 0) {
|
||||
snprintf(response, resp_size, "BYE\n");
|
||||
|
||||
@@ -84,10 +84,19 @@ void nr_init_antenna_state(nr_antenna_state_t *state,
|
||||
|
||||
state->stats.last_update_timestamp = get_timestamp_us();
|
||||
|
||||
// Initialize recovery mode
|
||||
state->recovery.in_recovery = false;
|
||||
state->recovery.recovery_start_ts = 0;
|
||||
state->recovery.recovery_duration_ms = 500; // 500ms default recovery time
|
||||
|
||||
// Protect antenna 0 by default (needed for SSB/PSS/SSS)
|
||||
state->config.protect_antenna0 = true;
|
||||
|
||||
LOG_I(PHY, "[ANTENNA_STATE] Initialized: TX antennas=%d (mask=0x%02X, array=%s), "
|
||||
"RX antennas=%d (mask=0x%02X, array=%s)\n",
|
||||
"RX antennas=%d (mask=0x%02X, array=%s), antenna0_protected=%d\n",
|
||||
state->num_tx_antennas, state->tx_antenna_bitmask, state->tx_array_name,
|
||||
state->num_rx_antennas, state->rx_antenna_bitmask, state->rx_array_name);
|
||||
state->num_rx_antennas, state->rx_antenna_bitmask, state->rx_array_name,
|
||||
state->config.protect_antenna0);
|
||||
}
|
||||
|
||||
void nr_free_antenna_state(nr_antenna_state_t *state)
|
||||
@@ -153,13 +162,19 @@ uint8_t nr_set_rx_antenna_bitmask(nr_antenna_state_t *state, uint8_t bitmask)
|
||||
uint8_t nr_get_tx_antenna_bitmask(const nr_antenna_state_t *state)
|
||||
{
|
||||
if (state == NULL) return 0xFF;
|
||||
return state->tx_antenna_bitmask;
|
||||
pthread_mutex_lock((pthread_mutex_t*)&state->lock);
|
||||
uint8_t m = state->tx_antenna_bitmask;
|
||||
pthread_mutex_unlock((pthread_mutex_t*)&state->lock);
|
||||
return m;
|
||||
}
|
||||
|
||||
uint8_t nr_get_rx_antenna_bitmask(const nr_antenna_state_t *state)
|
||||
{
|
||||
if (state == NULL) return 0xFF;
|
||||
return state->rx_antenna_bitmask;
|
||||
pthread_mutex_lock((pthread_mutex_t*)&state->lock);
|
||||
uint8_t m = state->rx_antenna_bitmask;
|
||||
pthread_mutex_unlock((pthread_mutex_t*)&state->lock);
|
||||
return m;
|
||||
}
|
||||
|
||||
bool nr_is_tx_antenna_active(const nr_antenna_state_t *state, uint8_t ant_id)
|
||||
@@ -190,6 +205,13 @@ void nr_mute_tx_antenna(nr_antenna_state_t *state, uint8_t ant_id)
|
||||
{
|
||||
if (state == NULL || ant_id >= state->num_tx_antennas) return;
|
||||
|
||||
// Protect antenna 0 if configured (needed for SSB/PSS/SSS transmission)
|
||||
if (ant_id == 0 && state->config.protect_antenna0) {
|
||||
LOG_W(PHY, "[ANTENNA_STATE] Cannot mute TX antenna 0: protected for SSB transmission\n");
|
||||
LOG_W(PHY, "[ANTENNA_STATE] Use 'SET TX MASK' to override protection if needed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t new_mask = state->tx_antenna_bitmask & ~(1 << ant_id);
|
||||
nr_set_tx_antenna_bitmask(state, new_mask);
|
||||
}
|
||||
@@ -294,3 +316,81 @@ void nr_reset_antenna_stats(nr_antenna_state_t *state)
|
||||
pthread_mutex_unlock(&state->lock);
|
||||
}
|
||||
|
||||
void nr_unmute_all_tx_antennas(nr_antenna_state_t *state)
|
||||
{
|
||||
if (state == NULL) return;
|
||||
|
||||
pthread_mutex_lock(&state->lock);
|
||||
|
||||
uint8_t old_mask = state->tx_antenna_bitmask;
|
||||
uint8_t all_on = (1 << state->num_tx_antennas) - 1;
|
||||
state->tx_antenna_bitmask = all_on;
|
||||
|
||||
// Enter recovery mode if we were muted
|
||||
if (old_mask != all_on) {
|
||||
state->recovery.in_recovery = true;
|
||||
state->recovery.recovery_start_ts = get_timestamp_us();
|
||||
LOG_I(PHY, "[ANTENNA_STATE] Entering recovery mode for %u ms after unmuting TX antennas\n",
|
||||
state->recovery.recovery_duration_ms);
|
||||
}
|
||||
|
||||
state->stats.tx_mute_events++;
|
||||
state->stats.last_update_timestamp = get_timestamp_us();
|
||||
|
||||
LOG_I(PHY, "[ANTENNA_STATE] All TX antennas unmuted: 0x%02X -> 0x%02X (array=%s)\n",
|
||||
old_mask, all_on, state->tx_array_name);
|
||||
|
||||
pthread_mutex_unlock(&state->lock);
|
||||
}
|
||||
|
||||
void nr_unmute_all_rx_antennas(nr_antenna_state_t *state)
|
||||
{
|
||||
if (state == NULL) return;
|
||||
|
||||
pthread_mutex_lock(&state->lock);
|
||||
|
||||
uint8_t old_mask = state->rx_antenna_bitmask;
|
||||
uint8_t all_on = (1 << state->num_rx_antennas) - 1;
|
||||
state->rx_antenna_bitmask = all_on;
|
||||
|
||||
state->stats.rx_mute_events++;
|
||||
state->stats.last_update_timestamp = get_timestamp_us();
|
||||
|
||||
LOG_I(PHY, "[ANTENNA_STATE] All RX antennas unmuted: 0x%02X -> 0x%02X (array=%s)\n",
|
||||
old_mask, all_on, state->rx_array_name);
|
||||
|
||||
pthread_mutex_unlock(&state->lock);
|
||||
}
|
||||
|
||||
bool nr_is_in_recovery_mode(const nr_antenna_state_t *state)
|
||||
{
|
||||
if (state == NULL) return false;
|
||||
|
||||
if (!state->recovery.in_recovery) return false;
|
||||
|
||||
// Check if recovery period has elapsed
|
||||
uint64_t now = get_timestamp_us();
|
||||
uint64_t elapsed_us = now - state->recovery.recovery_start_ts;
|
||||
uint64_t duration_us = (uint64_t)state->recovery.recovery_duration_ms * 1000ULL;
|
||||
|
||||
if (elapsed_us >= duration_us) {
|
||||
// Recovery complete - cast away const for state update
|
||||
nr_antenna_state_t *s = (nr_antenna_state_t *)state;
|
||||
s->recovery.in_recovery = false;
|
||||
LOG_I(PHY, "[ANTENNA_STATE] Recovery mode complete after %lu ms\n", elapsed_us / 1000);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void nr_set_antenna0_protection(nr_antenna_state_t *state, bool protect)
|
||||
{
|
||||
if (state == NULL) return;
|
||||
|
||||
pthread_mutex_lock(&state->lock);
|
||||
state->config.protect_antenna0 = protect;
|
||||
LOG_I(PHY, "[ANTENNA_STATE] Antenna 0 protection %s\n", protect ? "enabled" : "disabled");
|
||||
pthread_mutex_unlock(&state->lock);
|
||||
}
|
||||
|
||||
|
||||
@@ -72,6 +72,18 @@ typedef struct {
|
||||
char tx_array_name[64];
|
||||
char rx_array_name[64];
|
||||
|
||||
/// Recovery mode: after unmuting, allow CSI to update before using full capacity
|
||||
struct {
|
||||
bool in_recovery; ///< Currently in recovery mode
|
||||
uint64_t recovery_start_ts; ///< Timestamp when recovery started (us)
|
||||
uint32_t recovery_duration_ms; ///< Recovery duration in milliseconds (default 500ms)
|
||||
} recovery;
|
||||
|
||||
/// Configuration flags
|
||||
struct {
|
||||
bool protect_antenna0; ///< Never mute antenna 0 (needed for SSB)
|
||||
} config;
|
||||
|
||||
} nr_antenna_state_t;
|
||||
|
||||
/**
|
||||
@@ -222,6 +234,35 @@ void nr_get_antenna_stats(const nr_antenna_state_t *state,
|
||||
*/
|
||||
void nr_reset_antenna_stats(nr_antenna_state_t *state);
|
||||
|
||||
/**
|
||||
* @brief Unmute all TX antennas and enter recovery mode
|
||||
* @param state Pointer to antenna state structure
|
||||
*
|
||||
* This initiates a recovery period during which the scheduler
|
||||
* uses conservative settings to allow UE CSI reports to update.
|
||||
*/
|
||||
void nr_unmute_all_tx_antennas(nr_antenna_state_t *state);
|
||||
|
||||
/**
|
||||
* @brief Unmute all RX antennas
|
||||
* @param state Pointer to antenna state structure
|
||||
*/
|
||||
void nr_unmute_all_rx_antennas(nr_antenna_state_t *state);
|
||||
|
||||
/**
|
||||
* @brief Check if system is in recovery mode after unmuting
|
||||
* @param state Pointer to antenna state structure
|
||||
* @return true if in recovery mode
|
||||
*/
|
||||
bool nr_is_in_recovery_mode(const nr_antenna_state_t *state);
|
||||
|
||||
/**
|
||||
* @brief Set antenna 0 protection (SSB antenna)
|
||||
* @param state Pointer to antenna state structure
|
||||
* @param protect true to prevent muting antenna 0
|
||||
*/
|
||||
void nr_set_antenna0_protection(nr_antenna_state_t *state, bool protect);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user