Files
kunlun/plc/halmac/zc/zc_1/mac_zc.c
2024-09-28 14:24:04 +08:00

3334 lines
115 KiB
C

/****************************************************************************
Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED.
This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT
be copied by any method or incorporated into another program without
the express written consent of Aerospace C.Power. This Information or any portion
thereof remains the property of Aerospace C.Power. The Information contained herein
is believed to be accurate and Aerospace C.Power assumes no responsibility or
liability for its use in any way and conveys no license or title under
any patent or copyright and makes no representation or warranty that this
Information is free from patent or copyright infringement.
****************************************************************************/
#include "os_types.h"
#include "os_mem.h"
#include "os_utils.h"
#include "os_timer.h"
#include "iot_errno_api.h"
#include "iot_io_api.h"
#include "iot_system.h"
#include "iot_oem.h"
#include "plc_protocol.h"
#include "mac_pdev.h"
#include "mac_vdev.h"
#include "mac_msg.h"
#include "mac.h"
#include "mac_sched_hw.h"
#include "mac_isr.h"
#include "mac_tx_power.h"
#include "mac_cfg.h"
#include "mac_status.h"
#include "mac_cmn_hw.h"
#include "hw_zc_cmn.h"
#include "mac_zc_hw.h"
#include "mac_zc.h"
#include "iot_bitops_api.h"
#include "iot_board_api.h"
#include "gpio_mtx.h"
/* mac zc system debug log level, 0 - disable, others: enable */
#define MAC_ZC_DBG_LOG_LEVEL 0
/* mac zc feature start { */
/* 1 - check whether the phase difference of the collected values among
* different phase lines meets the rules.
* 0 - only check current collect phase's period meets the rules.
* Note: default set to 0.
*/
#define MAC_ZC_PHASE_DIFF_CHECK_ENA 0
/* TODO: will disable this debug macro*/
/* only for mac zc debug issue */
#define MAC_ZC_COLLECT_DEBUG_ENA 0
/* mac zc system daemon, when the system abnormal, reset zc system */
#define MAC_ZC_SYS_DAEMON_RESET_ENA 0
/* only for mac zc check update info debug */
#define MAC_ZC_CHECK_INFO_DBG_ENA 1
/* update all delayed info when zc update function excute */
#define MAC_ZC_UPDATE_DLY_INFO_ENA 0
/* mac zc feature end } */
/* TODO: 150cnt * 20ms = 3000ms. when bbai move to share task, revert */
/* error accumulation cnt max for collect, when collect stage, the err counter
* exceeds this value, then this phase has powerdown.
*/
#define MAC_ZC_COLLECT_LOSS_CNT 150
/* all phase loss check cnt. */
/* when any phase error cnt > MAC_ZC_COLLECT_LOSS_CNT,
* then check all phase error cnt.
* if the phase error cnt > (MAC_ZC_COLLECT_LOSS_CNT -
* MAC_ZC_COLLECT_LOSS_MARGIN_CNT),
* means this phase is also a collect loss(power down).
*/
#define MAC_ZC_COLLECT_LOSS_MARGIN_CNT 6
/* when inactive stage, the err counter exceeds this value, then this phase
* has power on.
*/
#define MAC_ZC_COLLECT_RESTORE_CNT 32
/* all phase restore check cnt */
/* when any phase error cnt > MAC_ZC_COLLECT_RESTORE_CNT,
* then check all phase error cnt.
* if the phase error cnt > (MAC_ZC_COLLECT_RESTORE_CNT -
* MAC_ZC_COLLECT_LOSS_MARGIN_CNT),
* means this phase is also a collect restore(power on).
*/
#define MAC_ZC_COLLECT_RESTORE_MARGIN_CNT 6
/* the max gap between two period allowed, unit ntb */
#define MAC_ZC_PERIOD_JITTER_GAP_NTB 12500
/* all phase goldon gap ntb = 20ms */
#define MAC_ZC_ALL_PHASE_GOLDON_GAP_NTB 500000
/* when the train fail, the delay time to retrain, unit: ms */
#define MAC_ZC_TRAIN_RESTART_DELAY_MS 30000
/* TODO: check protocol need support max count */
/* sg protocol ntb copy count equal 1 Byte 255 */
#define MAC_ZC_RPT_NTB_CNT_MAX 255
/**
* The part below is zc check_bitmap assert trace code
*/
/* check bitmap trace data buffer size */
#define MAC_ZC_BITMAP_TRACE_BUF_SIZE 6
/* assign mac_zc_sm_train_bound_intr_wait_exec() call id 1 */
#define MAC_ZC_CALL_BOUND 1
/* assign mac_zc_systic_trig() call id 2 */
#define MAC_ZC_CALL_SYSTIC 2
/* assign mac_zc_cal_collect_phase_bitmap call id 3 */
#define MAC_ZC_CALL_CAL 3
/* macro define function */
/**
* @brief get mac zc ctxt ptr by pdev_id(mac_zc_id)
* @param id: mac pdev id or mac zc id
* @retval: mac zc ctxt ptr
*/
#define mac_zc_ctxt_get(id) (((id) >= MAC_ZC_NUM_MAX) ? NULL : \
&g_mac_zc_ctxt[id])
/**
* @brief get mac ctxt collecting status
* @param id: mac zc ctxt ptr
* @retval: 1 - collecting, 0 - not collecting
*/
#define mac_zc_is_collecting(zc_ctxt) \
(((mac_zc_ctxt_t *)(zc_ctxt))->sm_info.cur_sm == MAC_ZC_SM_COLLECT)
/**
* @brief get mac ctxt is stoped status
* @param id: mac zc ctxt ptr
* @retval: 1 - stoped, 0 - running
*/
#define mac_zc_is_stoped(zc_ctxt) \
(((mac_zc_ctxt_t *)(zc_ctxt))->sm_info.cur_sm == MAC_ZC_SM_IDLE)
/**
* @brief get current reference phase d
* @param id: mac zc ctxt ptr
* @retval: MAC_ZC_PHASE_XXX
*/
#define mac_zc_get_ref_phase_id(zc_ctxt) \
(((mac_zc_ctxt_t *)(zc_ctxt))->ref_phase_id)
/**
* @brief get mac zc ctxt phase collect status is active
* @param phase_info: mac zc phase info ctxt ptr
* @retval: 0 - inactive, 1 - active.
*/
#define mac_zc_phase_is_active(phase_info) \
(((mac_zc_phase_info_t *)(phase_info))->collect_sts)
#define mac_zc_phase_is_repeat(phase_info, phase_id) \
((((mac_zc_phase_info_t *)(phase_info))->repeat_phase) != (phase_id))
/**
* @brief get mac zc phase is support to collect
* @param phase_info: mac zc phase info ctxt ptr
* @param phase_info: mac zc phase id
* @retval: 0 - nonsupport, 1 - support.
*/
#define mac_zc_phase_is_support(zc_ctxt, phase_id) \
(!!(((mac_zc_ctxt_t *)(zc_ctxt))->nv_info.support_phase_bitmap \
& (1 << (phase_id))))
/**
* @brief get ring buffer last valid data index
* @param phase_info: mac zc phase info ctxt ptr
* @retval: last valid data index
*/
#define mac_zc_ring_get_last_idx(phase_info) \
((uint32_t)(((mac_zc_phase_info_t *)(phase_info))->write_idx ? \
(((mac_zc_phase_info_t *)(phase_info))->write_idx - 1) : \
(((mac_zc_phase_info_t *)(phase_info))->ntb_ring_size - 1)))
/**
* @brief get ring buffer first valid data index
* @param phase_info: mac zc phase info ctxt ptr
* @retval: first valid data index
*/
#define mac_zc_ring_get_first_idx(phase_info) \
(((mac_zc_phase_info_t *)(phase_info))->is_ring_full ? \
((mac_zc_phase_info_t *)(phase_info))->write_idx : 0)
/**
* @brief calibration input ring index value
* @param phase_info: mac zc phase info ctxt ptr
* @param idx: input ring index
* @retval: legal ring index
*/
#define mac_zc_ring_get_legal_idx(phase_info, idx) \
(((idx) < ((mac_zc_phase_info_t *)(phase_info))->ntb_ring_size) ? \
(idx) : ((idx) - ((mac_zc_phase_info_t *)(phase_info))->ntb_ring_size))
/**
* @brief get real index from mapped index
* @param mapped_idx: mapped index
* @param start_idx : start index
* @param data_sz : mapped ring data size
*/
#define mac_zc_ring_get_real_idx(mapped_idx, start_idx, data_sz) \
((mapped_idx) + (start_idx) < (data_sz)) ? ((mapped_idx) + (start_idx)) \
: ((mapped_idx) + (start_idx) - (data_sz))
/**
* @brief get ring buffer valid data size
* @param phase_info: mac zc phase info ctxt ptr
* @retval: valid data size
*/
#define mac_zc_ring_get_valid_size(phase_info) \
((((mac_zc_phase_info_t *)(phase_info))->is_ring_full) ? \
(((mac_zc_phase_info_t *)(phase_info))->ntb_ring_size) : \
(((mac_zc_phase_info_t *)(phase_info))->write_idx))
/**
* @brief get cap id base on mac zc phase id
* @param zc_ctxt: mac zc ctxt ptr
* @param phase_id: mac zc phase id, see MAC_ZC_PHASE_A/B/C
* @retval: cap id
*/
#define mac_zc_map_info_phase2cap(zc_ctxt, phase_id) \
(((mac_zc_ctxt_t *)(zc_ctxt))->nv_info.phase_map[phase_id].cap_id)
/**
* @brief get signal id base on mac zc phase id
* @param zc_ctxt: mac zc ctxt ptr
* @param phase_id: mac zc phase id, see MAC_ZC_PHASE_A/B/C
* @retval: signal id
*/
#define mac_zc_map_info_phase2sig(zc_ctxt, phase_id) \
(((mac_zc_ctxt_t *)(zc_ctxt))->nv_info.phase_map[phase_id].signal)
/**
* @brief stop train timer
* @param zc_ctxt: mac zc ctxt ptr
* @retval: none
*/
#define mac_zc_train_timer_stop(zc_ctxt) \
os_stop_timer(((mac_zc_ctxt_t *)(zc_ctxt))->timer_train)
/**
* @brief start train timer and update train timeout ctxt
* @param zc_ctxt: mac zc ctxt ptr
* @param timeout_ms: timer timeout, unit:ms
* @retval: none
*/
#define mac_zc_train_timer_start(zc_ctxt, timeout_ms) \
do {\
os_start_timer(((mac_zc_ctxt_t *)(zc_ctxt))->timer_train, \
(timeout_ms)); \
((mac_zc_ctxt_t *)(zc_ctxt))->train_elapsed_time += (timeout_ms); \
} while(0)
/**
* @brief clear all phase info ctxt abnormal_cnt
* @param zc_ctxt: mac zc ctxt ptr
* @retval: none
*/
#define mac_zc_all_phase_abnormal_cnt_clr(zc_ctxt) \
do {\
uint8_t __id; \
for (__id = MAC_ZC_PHASE_A; __id < MAC_ZC_PHASE_CNT; __id++) { \
((mac_zc_ctxt_t *)(zc_ctxt))->phase_info[__id].abnormal_cnt = 0; \
} \
} while(0)
#define mac_zc_all_phase_init_active_sts(zc_ctxt) \
do {\
uint8_t __id; \
for (__id = MAC_ZC_PHASE_A; __id < MAC_ZC_PHASE_CNT; __id++) { \
((mac_zc_ctxt_t *)(zc_ctxt))->phase_info[__id].collect_sts = \
mac_zc_phase_is_support(zc_ctxt, __id); \
} \
} while(0)
#define mac_zc_all_phase_set_collet_default_sts(zc_ctxt) \
do {\
uint8_t __id; \
for (__id = MAC_ZC_PHASE_A; __id < MAC_ZC_PHASE_CNT; __id++) { \
((mac_zc_ctxt_t *)(zc_ctxt))->phase_info[__id].collect_sts = 0; \
} \
} while(0)
/**
* @brief load default hw phase map info to zc ctxt
* @param zc_ctxt: mac zc ctxt ptr
* @retval: none
*/
#define mac_zc_def_phase_map_load(zc_ctxt) \
do { \
uint8_t __id; \
for (__id = MAC_ZC_PHASE_A; __id < MAC_ZC_PHASE_CNT; __id++) { \
mac_zc_hw_load_phase_map_def(\
&((mac_zc_ctxt_t *)(zc_ctxt))->nv_info.phase_map[__id], \
__id);\
} \
} while(0)
/* one period ntb equal 500000, min jitter = 10000, 500000/10000 = 50
* in extreme bad condition 50 jitters equal one period.
* So cvg copy 250 ntb data , we must support worst case 250/50 + 1 = 6
* Then set the search window to 12, so two sides can avoid the worst case
*/
/**
* @brief get search window half count
* @param period: search ring buffer period ntb
* @retval: window half count
*/
#define mac_zc_get_ntb_search_window_half(period) \
(MAC_ZC_RPT_NTB_CNT_MAX * MAC_ZC_PERIOD_JITTER_GAP_NTB / (period) + 1)
/**
* @brief set mac_zc bitmap and record the caller and timestamp
* @param bitmap_trace: bitmap_trace context
* @param bitmap : set bitmap value
* @param pos_call: caller position
* @retval: none
*/
#define mac_zc_set_phase_bitmap(bitmap_trace,bitmap,pos_call) \
{ \
uint32_t idx; \
bitmap_trace_ctxt_t *bm_trace = (bitmap_trace_ctxt_t *)(bitmap_trace); \
idx = bm_trace->wr_idx; \
bm_trace->trace_buf[idx].func_traced_ra = (pos_call); \
bm_trace->trace_buf[idx].set_bitmap_ts = mac_sched_get_ntb(NULL); \
bm_trace->trace_buf[idx++].set_bitmap_val = (bitmap); \
if (idx >= MAC_ZC_BITMAP_TRACE_BUF_SIZE) { \
idx = 0; \
} \
bm_trace->wr_idx = idx; \
} \
/**
* @brief get the postion edge type
* @pos the offset refer to ring start
* @retval edge type
*/
#define mac_zc_get_ring_position_edge(pos) \
(((pos) & 0x01) ? (MAC_ZC_PLC_EDGE_FALL) : \
(MAC_ZC_PLC_EDGE_RISE))
/**
* @brief get zc is in half collect state
* @zc_ctxt zc context
* @phase which phase you want get
* @retval is half collect state
* @TODO: retval base on active and is_switch_gpio
*/
#define mac_zc_is_half_clct_state(zc_ctxt, phs) \
((uint8_t)((((phs) < MAC_ZC_PHASE_ALL) && mac_zc_phase_is_active( \
&((mac_zc_ctxt_t *)(zc_ctxt))->phase_info[phs])) \
? (((mac_zc_ctxt_t *)(zc_ctxt))->nv_info.is_switch_gpio_clct) : 0))
/**
*@brief is this phase buffer is empty
*@phase_info the phase to query
*retval buffer is empty return true else return false
*/
#define mac_zc_is_ring_empty(phase_info) \
((((mac_zc_phase_info_t *)(phase_info))->write_idx == 0) && \
(((mac_zc_phase_info_t *)(phase_info))->is_ring_full == 0))
/* indicate mac zc train status */
typedef enum _mac_zc_train_status {
MAC_ZC_TRAIN_ONGOING = 0,
MAC_ZC_TRAIN_SUCCESS,
MAC_ZC_TRAIN_FAIL,
MAC_ZC_TRAIN_MAX,
} mac_zc_train_status_t;
typedef enum _mac_zc_phase_degree_id {
MAC_ZC_PHASE_DEGREE_INVALID = 0,
MAC_ZC_PHASE_DEGREE_0,
MAC_ZC_PHASE_DEGREE_30,
MAC_ZC_PHASE_DEGREE_60,
MAC_ZC_PHASE_DEGREE_120,
MAC_ZC_PHASE_DEGREE_240,
MAC_ZC_PHASE_DEGREE_300,
MAC_ZC_PHASE_DEGREE_330,
MAC_ZC_PHASE_DEGREE_OTHERS,
} mac_zc_phase_degree_id_t;
/* indicate power line status */
typedef enum _mac_zc_collect_status {
/* phase inactive. this phase is cold line, or phase loss(power down) */
MAC_ZC_COLLECT_INACTIVE = 0,
/* phase active. this phase is trained success or power restore */
MAC_ZC_COLLECT_ACTIVE,
} mac_zc_collect_status_t;
/* mac zc system state machine running tirger event id */
typedef enum _mac_zc_triger_id {
/* triger id for start zc system request */
MAC_ZC_TRIG_SYS_START_REQ = 0,
/* triger id for stop zc system request */
MAC_ZC_TRIG_SYS_STOP_REQ, //1
/* triger id for hw zc cap0/1/2 interrupt */
/* Note: not used */
MAC_ZC_TRIG_HW_CAP_INT, //2
/* triger id for hw zc bound low interrupt */
/* Note: not used */
MAC_ZC_TRIG_HW_LOWER_BOUND_INT, //3
/* triger id for hw zc bound upper interrupt */
MAC_ZC_TRIG_HW_UPPER_BOUND_INT, //4
/* triger id for zc system train timer timeout callback */
MAC_ZC_TRIG_TRAIN_TIMER, //5
/* triger id for os systic timer callback */
MAC_ZC_TRIG_SYSTIC_TIMER, //6
/* triger id max */
MAC_ZC_TRIG_MAX,
} mac_zc_triger_id_t;
/* mac zc train state id */
typedef enum _mac_zc_train_state_id {
/* state for wait hw zc gen to be ready */
MAC_ZC_TRAIN_STATE_GEN_WAIT = 0,
/* state for config hw zc gen capture, generate low/upper bound interrupt */
MAC_ZC_TRAIN_STATE_BOUND_INTR_WAIT,
/* state for train and colloct by system kick timer */
MAC_ZC_TRAIN_STATE_SYSTICK_WAIT,
} mac_zc_train_state_id_t;
/* mac zc system state machine id */
typedef enum _mac_zc_sm_id {
/* state for system idle state */
MAC_ZC_SM_IDLE = 0,
/* state for zc system ininted and stoped */
MAC_ZC_SM_INITED, //1
/* state for wait hw zc gen to be ready */
MAC_ZC_SM_TRAIN_INIT, //2
/* state for config hw zc gen capture, generate low/upper bound interrupt */
MAC_ZC_SM_TRAIN_BOUND_INTR_WAIT, //3
/* state for train and colloct by system kick timer */
MAC_ZC_SM_TRAIN_SYSTICK_WAIT, //4
/* state for collecting */
MAC_ZC_SM_COLLECT, //5
/* state id max */
MAC_ZC_SM_MAX,
} mac_zc_sm_id_t;
/* save info for not clear when reset */
typedef struct _mac_zc_nv_info {
/* save mac zc hw capture edge */
uint32_t cap_edge : 1,
/* save mac zc hw collect period: full or half period */
is_half_collect : 1,
/* indicate support phase bitmap.
* bit0: MAC_ZC_PHASE_A, bit1: MAC_ZC_PHASE_B, bit2: MAC_ZC_PHASE_C...
*/
support_phase_bitmap : 3,
/* is new board using switch gpio collect zc ntb */
is_switch_gpio_clct : 1,
rsvd0 : 26;
/* save mac zc system run on os task handle */
os_task_h *hdl;
/* save mac zc dsr table address */
void *dsr_tbl;
/* save dsr set entry function address */
mac_zc_dsr_set_entry_fn_t dsr_set_entry;
/* save dsr event clear function address */
mac_zc_dsr_clr_fn_t dsr_clr;
/* HW phase map info */
mac_zc_hw_map_info_t phase_map[MAC_ZC_PHASE_CNT];
/* save zc calibration info */
/* TODO: will add */
int32_t phase_cali[MAC_ZC_PHASE_CNT];
} mac_zc_nv_info_t;
/* mac zc state machine info */
typedef struct _mac_zc_sm_info {
/* mac zc prev state id, see mac_zc_sm_id_t */
uint32_t prev_sm : 8,
/* mac zc current state id */
cur_sm : 8,
/* last exec sm */
exec_sm : 8,
rsvd : 8;
} mac_zc_sm_info_t;
typedef struct _mac_zc_phase_info {
/* indicate the phase collect status */
uint32_t collect_sts : 1,
/* indicate the ntb ring buffer full wrap */
is_ring_full : 1,
/* reuse for this phase abnormal count */
abnormal_cnt : 8,
/* reuse for this phase collect count */
collect_cnt : 6,
/* repeat phase id, refer MAC_ZC_PHASE_XXX */
repeat_phase : 2,
/* reserved */
resv : 14;
/* save this phase last collected zc timestamp */
/* TODO: maybe save the mac local timer ntb */
uint32_t last_ts;
/* last switch gpio local ts */
uint32_t last_switch_lts;
/* record start ntb */
uint32_t start_ntb;
/* power line real period */
uint32_t period;
/* ntb ring write index, max support 65535 */
uint32_t write_idx : 16,
/* indicate ntb ring DW size, max support 65535 */
ntb_ring_size : 16;
/* ntb ring buffer header address */
uint32_t *ntb_ring;
} mac_zc_phase_info_t;
typedef struct _bitmap_trace_bug {
/* record the function who set bitmap */
uint32_t func_traced_ra;
/* record the bitmap set val */
uint32_t set_bitmap_val;
/* record when set bitmap */
uint32_t set_bitmap_ts;
} bitmap_trace_bug_t;
typedef struct _bitmap_trace_ctxt {
bitmap_trace_bug_t trace_buf[MAC_ZC_BITMAP_TRACE_BUF_SIZE];
uint32_t wr_idx;
} bitmap_trace_ctxt_t;
typedef struct _mac_zc_ctxt {
/* indicate os systic triger valid */
uint32_t systic_trig_en : 1,
/* indicate need collecet phase bitmap.
* bit0 - zc phase A, bit1 - zc phase B, bit2 - zc phase C ...
*/
check_phase_bitmap : 3,
/* indicate check phase collect zc valid reference phase id */
ref_phase_id : 2,
/* indicate pdev id */
ref_pdev_id : 2,
/* indicate reset system */
is_need_reset : 1,
/* reserved */
rsvd0 : 3,
/* train elapsed time, unit:ms. */
train_elapsed_time : 20;
/* current ctxt state info */
mac_zc_sm_info_t sm_info;
/* save the alloc ntb ring header address */
uint32_t *ring;
/* ring buffer size, unit: 4byte */
uint32_t ring_sz : 16,
/* reserved */
rsvd1 : 16;
/* timer for trainning, each sm_state multi use */
timer_id_t timer_train;
/* current mac zc all phase info */
mac_zc_phase_info_t phase_info[MAC_ZC_PHASE_CNT];
/* do not clean this info when reset system */
mac_zc_nv_info_t nv_info;
#if MAC_ZC_COLLECT_DEBUG_ENA
bitmap_trace_ctxt_t bitmap_trace;
#endif
} mac_zc_ctxt_t;
#if MAC_ZC_ENABLE
mac_zc_ctxt_t g_mac_zc_ctxt[MAC_ZC_NUM_MAX] = {0};
static void mac_dsr_zc_upper_bound(void);
/* base on map info, convert MAC_ZC_HW_CAPx to MAC_ZC_PHASE_XXX */
static uint8_t mac_zc_map_info_cap2phase(mac_zc_ctxt_t *zc_ctxt,
uint8_t cap_id)
{
uint8_t i;
IOT_ASSERT(zc_ctxt);
for (i = MAC_ZC_PHASE_A; i < MAC_ZC_PHASE_CNT; i++) {
if (zc_ctxt->nv_info.phase_map[i].cap_id == cap_id) {
return i;
}
}
return MAC_ZC_PHASE_CNT;
}
/* base on map info, convert MAC_ZC_HW_CAPx to chip signal id */
static uint8_t mac_zc_map_info_cap2sig(mac_zc_ctxt_t *zc_ctxt,
uint8_t cap_id)
{
uint8_t i;
IOT_ASSERT(zc_ctxt);
for (i = MAC_ZC_PHASE_A; i < MAC_ZC_PHASE_CNT; i++) {
if (zc_ctxt->nv_info.phase_map[i].cap_id == cap_id) {
return zc_ctxt->nv_info.phase_map[i].signal;
}
}
return 0;
}
/**
* @brief get mac zc ctxt active phase count
* @retval: total active count
*/
static uint8_t IRAM_ATTR mac_zc_get_active_phase_cnt(mac_zc_ctxt_t *zc_ctxt)
{
uint8_t count = 0, phase_id;
if (zc_ctxt) {
for (phase_id = MAC_ZC_PHASE_A; phase_id < MAC_ZC_PHASE_CNT;
phase_id++) {
if (mac_zc_phase_is_support(zc_ctxt, phase_id)) {
count += (uint8_t)mac_zc_phase_is_active(
&zc_ctxt->phase_info[phase_id]);
}
}
}
return count;
}
/**
* @brief : compare one phase ntb with other phase ntb
* @param ntb : to compare phase ntb
* @param ref_ntb : refered phase ntb
* @retval : ntb larger than ref_ntb return 1, else return 0
*/
static uint8_t mac_zc_ntb_is_larger_ref(uint32_t ntb, uint32_t ref_ntb)
{
uint32_t delta_ntb;
uint8_t res;
if (ntb > ref_ntb) {
delta_ntb = ntb - ref_ntb;
res = 1;
} else {
delta_ntb = ref_ntb - ntb;
res = 0;
}
/* ntb wrapped invert result */
if (delta_ntb > 0x7fffffff) {
res = !res;
}
return res;
}
/**
* @brief update current reference phase id
* @param zc_ctxt: mac zc ctxt ptr
* @param phase_id: indicate set the reference phase id.
* when phase_id != MAC_ZC_PHASE_ALL, means set
* ref_phase_id = phase_id.
* others, set ref_phase id to the max last_ts phase.
* @retval: current reference phase id
*/
static uint8_t mac_zc_update_ref_phase_id(mac_zc_ctxt_t *zc_ctxt,
uint8_t phase_id)
{
uint8_t ref_phase_id = MAC_ZC_PHASE_ALL;
mac_zc_phase_info_t *phs_info;
uint8_t active_cnt = mac_zc_get_active_phase_cnt(zc_ctxt);
IOT_ASSERT(zc_ctxt);
if (MAC_ZC_PHASE_ALL != phase_id) {
ref_phase_id = phase_id;
} else {
/* find the active phase which has max start ntb */
for (uint8_t i = (active_cnt > 1) ? MAC_ZC_PHASE_B : MAC_ZC_PHASE_A;
i < MAC_ZC_PHASE_CNT; i++) {
phs_info = &zc_ctxt->phase_info[i];
if (mac_zc_phase_is_active(phs_info)) {
#if MAC_ZC_DBG_LOG_LEVEL >= 2
iot_printf("[zc]unsorted: phase=%d, ntb=%u\n", i,
phs_info->start_ntb);
#endif
if (ref_phase_id == MAC_ZC_PHASE_ALL) {
ref_phase_id = i;
continue;
}
if (mac_zc_ntb_is_larger_ref(phs_info->start_ntb,
zc_ctxt->phase_info[ref_phase_id].start_ntb)) {
ref_phase_id = i;
}
}
}
}
if (MAC_ZC_PHASE_ALL != ref_phase_id) {
zc_ctxt->ref_phase_id = ref_phase_id;
iot_printf("zc:ref_phase=%d\n", ref_phase_id);
}
ref_phase_id = (uint8_t)(zc_ctxt->ref_phase_id);
return ref_phase_id;
}
/**
* @brief clear all phase info ctxt collect_cnt
* @param zc_ctxt: mac zc ctxt ptr
* @param phase_bitmap: clear phase bitmap.
* bit0 - MAC_ZC_PHASE_A
* bit0 - MAC_ZC_PHASE_B
* bit0 - MAC_ZC_PHASE_C...
* @retval: none
*/
static void mac_zc_phase_collect_cnt_clr(mac_zc_ctxt_t *zc_ctxt,
uint8_t phase_bitmap)
{
uint8_t phase_id;
phase_bitmap &= (uint8_t)((1 << MAC_ZC_PHASE_CNT) - 1);
if (zc_ctxt) {
while (phase_bitmap) {
phase_id = iot_bitops_ffs(phase_bitmap) - 1;
zc_ctxt->phase_info[phase_id].collect_cnt = 0;
phase_bitmap &= ~(1 << phase_id);
}
}
}
static uint32_t mac_zc_get_phase_collect_cnt(mac_zc_ctxt_t *zc_ctxt,
uint8_t phase_bitmap)
{
uint8_t phase_id;
uint32_t count = 0;
phase_bitmap &= (uint8_t)((1 << MAC_ZC_PHASE_CNT) - 1);
if (zc_ctxt) {
while (phase_bitmap) {
phase_id = iot_bitops_ffs(phase_bitmap) - 1;
if (mac_zc_phase_is_support(zc_ctxt, phase_id)) {
count += zc_ctxt->phase_info[phase_id].collect_cnt;
}
phase_bitmap &= ~(1 << phase_id);
}
}
return count;
}
static inline uint8_t mac_zc_get_average_weight_power(uint32_t rule)
{
uint8_t shift_cnt = 0;
if (rule >= 1 && rule <= 2) {
shift_cnt = 1;
} else if (rule > 2 && rule <= 4) {
shift_cnt = 2;
} else if (rule > 4 && rule <= 8) {
shift_cnt = 3;
} else if (rule > 8 && rule <= 16) {
shift_cnt = 4;
} else if (rule > 16 && rule <= 32) {
shift_cnt = 5;
} else {
shift_cnt = 6;
}
#if (MAC_ZC_DBG_LOG_LEVEL >= 3)
iot_printf("[zc]get_weight_power:rule=%d, shift=%d\n", rule, shift_cnt);
#endif
return shift_cnt;
}
/* weight_power means 2 ^ weight_power. */
static inline int64_t mac_zc_updata_average_accum(int64_t src,
int64_t update, uint8_t weight_power)
{
return (uint32_t)((src - (src >> weight_power)) + (update >> weight_power));
}
/* enable/disable mac zc upper bound interrupt */
static void mac_zc_upper_bound_intr_ena(mac_zc_ctxt_t *zc_ctxt, uint8_t enable)
{
#if (HW_PLATFORM >= HW_PLATFORM_FPGA)
if (zc_ctxt && zc_ctxt->nv_info.dsr_set_entry && \
zc_ctxt->nv_info.dsr_tbl) {
if (enable) {
/* enable upper bound interrupt */
mac_isr_enable(MAC_ISR_ZC_UPPER_BOUND_ID);
zc_ctxt->nv_info.dsr_set_entry(zc_ctxt->nv_info.dsr_tbl, \
(uint8_t)MAC_DSR_ZC_UPPER_BOUND_ID, mac_dsr_zc_upper_bound);
} else {
/* disable upper bound interrupt */
mac_isr_disable(MAC_ISR_ZC_UPPER_BOUND_ID);
zc_ctxt->nv_info.dsr_set_entry(zc_ctxt->nv_info.dsr_tbl, \
(uint8_t)MAC_DSR_ZC_UPPER_BOUND_ID, NULL);
}
}
#else //HW_PLATFORM >= HW_PLATFORM_FPGA
(void)zc_ctxt;
(void)enable;
#endif
}
/* get last valid zc timestamp */ //TODO: move to hw.c
static uint32_t mac_zc_get_cur_zc(mac_zc_ctxt_t *zc_ctxt, uint8_t cap_id)
{
uint32_t cur_zc = mac_zc_hw_get_last_zc_ts(cap_id);
/* for WAR, trigger capx reset */
mac_zc_hw_capx_reset_trig(mac_zc_map_info_cap2sig(zc_ctxt, cap_id), \
(uint8_t)zc_ctxt->nv_info.cap_edge);
/* WAR for trigger capture hw */
mac_zc_hw_capx_trig(1 << cap_id);
#if ((HW_PLATFORM >= HW_PLATFORM_FPGA) && (MAC_ZC_DBG_LOG_LEVEL >= 2))
uint8_t sig = mac_zc_map_info_cap2sig(zc_ctxt, cap_id);
iot_printf("[zc]phase=%d, hw_period=%u, sig=%d <==> gpio=%d\n",
mac_zc_map_info_cap2phase(zc_ctxt, cap_id),
mac_zc_hw_get_zc_period(cap_id), sig, gpio_mtx_sig_in_get_gpio(sig));
#endif
return cur_zc;
}
/* print current systme collect status */
static void mac_zc_system_status_print(mac_zc_ctxt_t *zc_ctxt)
{
#define STATUS_PRINT_STR_LEN 40
char str_buf[STATUS_PRINT_STR_LEN] = {0};
uint8_t idx = 0, phase_id;
idx += (uint8_t)iot_snprintf(str_buf, sizeof(str_buf), "zc:chk-%d-", \
(char)zc_ctxt->sm_info.cur_sm);
for (phase_id = MAC_ZC_PHASE_A; phase_id < MAC_ZC_PHASE_CNT; phase_id++) {
idx += (uint8_t)iot_snprintf(str_buf + idx, sizeof(str_buf),
"[%d:%d-%d]",
(char)mac_zc_phase_is_support(zc_ctxt,phase_id),
(char)mac_zc_phase_is_active(&zc_ctxt->phase_info[phase_id]),
#if (HW_PLATFORM >= HW_PLATFORM_FPGA)
(char)gpio_mtx_sig_in_get_gpio(
zc_ctxt->nv_info.phase_map[phase_id].signal)
#else
(char)0
#endif
);
}
idx += (uint8_t)iot_snprintf(str_buf + idx, sizeof(str_buf), "-%d",
(char)mac_zc_is_power_collapsed((uint8_t)zc_ctxt->ref_pdev_id));
IOT_ASSERT(idx <= STATUS_PRINT_STR_LEN);
iot_printf("%s\n", str_buf);
}
static void mac_zc_set_event(mac_zc_ctxt_t *zc_ctxt, uint32_t event)
{
uint8_t phase_id;
uint32_t phase_status;
mac_vdev_t *vdev;
iot_printf("zc:event-0x%x\n", event);
IOT_ASSERT(zc_ctxt && event);
vdev = get_vdev_ptr(zc_ctxt->ref_pdev_id, PLC_DEFAULT_VDEV);
if (vdev && vdev->start_cfg.mac_zc_status_rpt_func) {
for (phase_id = MAC_ZC_PHASE_A, phase_status = 0; \
phase_id < MAC_ZC_PHASE_CNT; phase_id++) {
phase_status |= mac_zc_phase_is_active(\
&zc_ctxt->phase_info[phase_id]) << phase_id;
}
vdev->start_cfg.mac_zc_status_rpt_func(
vdev->start_cfg.mac_callback_arg, phase_status);
}
mac_status_add_zc_event_cnt();
}
static void mac_zc_hw_map_def_gpio(mac_zc_ctxt_t *zc_ctxt)
{
IOT_ASSERT(zc_ctxt);
mac_zc_nv_info_t *nv_info = &zc_ctxt->nv_info;
for (uint8_t phase = MAC_ZC_PHASE_A; phase < MAC_ZC_PHASE_CNT; phase++) {
if (mac_zc_phase_is_support(zc_ctxt, phase)) {
mac_zc_hw_fix_map_gpio2sig(nv_info->phase_map[phase].gpio,
nv_info->phase_map[phase].signal);
}
}
}
static void mac_zc_load_oem_info(mac_zc_ctxt_t *zc_ctxt)
{
uint8_t phase_id;
if (!zc_ctxt) {
IOT_ASSERT(0);
return;
}
/* update phase map info */
mac_zc_def_phase_map_load(zc_ctxt);
for (phase_id = MAC_ZC_PHASE_A; phase_id < MAC_ZC_PHASE_CNT; phase_id++) {
if (zc_ctxt->nv_info.phase_map[phase_id].gpio != GPIO_NO_VALID) {
zc_ctxt->nv_info.support_phase_bitmap |= 1 << phase_id;
}
}
/* NOTE: for kl1, if set to half period, chip cap edge must be rise. */
/* early version board hw only support to collect the rise edge input to
* the hw board. and the hw board design reverses input the zero crossing
* signal of board into the chip. then for early version hw board:
* i. for PLC rise edge, input the chip signal is fall
* ii. for PLC fall edge, input the chip signal is rise.
*/
if (GPIO_NO_VALID != zc_ctxt->nv_info.phase_map[MAC_ZC_PHASE_A].gpio_ext) {
/* board hw support double edge collect for one phase */
zc_ctxt->nv_info.cap_edge = MAC_ZC_HW_CAP_EDGE_RISE;
zc_ctxt->nv_info.is_switch_gpio_clct = 1;
} else {
zc_ctxt->nv_info.cap_edge = iot_board_support_zc_pulse()
? MAC_ZC_HW_CAP_EDGE_RISE : MAC_ZC_HW_CAP_EDGE_FALL;
zc_ctxt->nv_info.is_switch_gpio_clct = 0;
}
/* init mac zc hw full period collect */
zc_ctxt->nv_info.is_half_collect = 0;
//TODO: will add load zc calibration info
/* update oem info to flash */
mac_status_zc_nv_para_update(
(uint8_t)zc_ctxt->nv_info.is_half_collect,
(uint8_t)zc_ctxt->nv_info.cap_edge,
(uint8_t)zc_ctxt->nv_info.support_phase_bitmap,
(uint8_t)zc_ctxt->nv_info.is_switch_gpio_clct);
iot_printf("zc:support_phase_bitmap=0x%x, edge:%d, is_half=%d, "
"is_swt_gpio=%d\n",
zc_ctxt->nv_info.support_phase_bitmap,
zc_ctxt->nv_info.cap_edge,
zc_ctxt->nv_info.is_half_collect,
zc_ctxt->nv_info.is_switch_gpio_clct);
}
static void mac_zc_phase_ring_reset(mac_zc_ctxt_t *zc_ctxt)
{
uint8_t id;
mac_zc_phase_info_t *phase_info;
IOT_ASSERT(zc_ctxt);
for (id = MAC_ZC_PHASE_A; id < MAC_ZC_PHASE_CNT; id++) {
phase_info = &zc_ctxt->phase_info[id];
phase_info->is_ring_full = 0;
phase_info->abnormal_cnt = 0;
phase_info->write_idx = 0;
}
}
/* init all phase ring buffer base ctxt->ring. */
static void mac_zc_phase_info_init(mac_zc_ctxt_t *zc_ctxt)
{
uint8_t phase_cnt, id;
mac_zc_phase_info_t *phase_info;
IOT_ASSERT(zc_ctxt && zc_ctxt->ring);
//TODO: load module type from iot_oem_get_module_type(), then set bitmap.
phase_cnt = iot_bitops_cbs(\
(uint8_t)zc_ctxt->nv_info.support_phase_bitmap);
/* Note:
* 1. for support 1 phase, then only MAC_ZC_PHASE_A is valid.
* zc_ctxt->ring is all mounted to the MAC_ZC_PHASE_A's ntb_ring.
* 2. for support 2 phase, then MAC_ZC_PHASE_A & B is valid.
* zc_ctxt->ring is evenly divided mounted to the 2phase's ntb_ring.
* 2. for support 3 phase, then MAC_ZC_PHASE_A & B & C is valid.
* zc_ctxt->ring is evenly divided mounted to the 3phase's ntb_ring.
*/
mac_zc_phase_ring_reset(zc_ctxt);
for (id = MAC_ZC_PHASE_A; id < MAC_ZC_PHASE_CNT; id++) {
phase_info = &zc_ctxt->phase_info[id];
if (mac_zc_phase_is_support(zc_ctxt, id)) {
/* init this phase ring buffer size */
phase_info->ntb_ring_size = zc_ctxt->ring_sz / phase_cnt;
/* init this phase ring buffer ptr */
phase_info->ntb_ring = (uint32_t *)(zc_ctxt->ring \
+ (phase_info->ntb_ring_size * id));
} else {
/* clear phase info ctxt */
os_mem_set(phase_info, 0, sizeof(*phase_info));
}
#if (MAC_ZC_DBG_LOG_LEVEL >= 1)
iot_printf("[zc]%s:%d,support=%d,ring=0x%x,"
"phase_ring=0x%x,size=%d\n",
__FUNCTION__, id, zc_ctxt->nv_info.support_phase_bitmap,
(uint32_t)zc_ctxt->ring, (uint32_t)phase_info->ntb_ring,
phase_info->ntb_ring_size);
#endif
}
}
/* normal full period collect */
static uint32_t mac_zc_system_start(mac_zc_ctxt_t *zc_ctxt)
{
iot_printf("zc:sys_start-0x%x\n", (uint32_t)zc_ctxt);
IOT_ASSERT(zc_ctxt);
/* check ctxt valid */
if (NULL == zc_ctxt->ring) {
IOT_ASSERT_DUMP(0, (uint32_t *)zc_ctxt, \
sizeof(*zc_ctxt)/sizeof(uint32_t));
return ERR_NOMEM;
}
/* clear dsr event */
if (zc_ctxt->nv_info.dsr_clr) {
zc_ctxt->nv_info.dsr_clr(MAC_DSR_ZC_SYSTIC_TRIG_CB_ID);
zc_ctxt->nv_info.dsr_clr(MAC_DSR_ZC_UPPER_BOUND_ID);
}
/* clean zc ctxt for training */
zc_ctxt->systic_trig_en = 0;
/* map default gpio to signal, maybe sig and cap have been swaped.
* so mac_zc_hw_load_phase_map_def() isn't fit here.
*/
if (zc_ctxt->nv_info.is_switch_gpio_clct) {
mac_zc_hw_map_def_gpio(zc_ctxt);
}
/* re-config zc hw */
mac_zc_hw_init((uint8_t)zc_ctxt->nv_info.is_half_collect, \
(uint8_t)zc_ctxt->nv_info.cap_edge);
/* enable mac zc hw */
mac_zc_hw_capx_enable(((uint8_t)(1 << MAC_ZC_HW_CAP0) \
| (1 << MAC_ZC_HW_CAP1) | (1 << MAC_ZC_HW_CAP2)), 1);
/* disable gen bound isr/dsr */
mac_zc_upper_bound_intr_ena(zc_ctxt, 0);
mac_zc_hw_set_vibrate_protect_dur(MAC_ZC_HW_DEBOUNCE_NTB);
/* trigger ac track hw run */
mac_zc_hw_ac_track_trig();
return ERR_OK;
}
/* stop mac zc system */
static uint32_t mac_zc_system_stop(mac_zc_ctxt_t *zc_ctxt)
{
iot_printf("zc:sys_stop-0x%x\n", (uint32_t)zc_ctxt);
IOT_ASSERT(zc_ctxt);
/* stop training timer */
if (zc_ctxt->timer_train) {
mac_zc_train_timer_stop(zc_ctxt);
}
/* disable zc hw */
mac_zc_hw_capx_enable(((uint8_t)(1 << MAC_ZC_HW_CAP0) \
| (1 << MAC_ZC_HW_CAP1) | (1 << MAC_ZC_HW_CAP2)), 0);
/* disable systic trig en */
zc_ctxt->systic_trig_en = 0;
/* disable gen bound isr/dsr */
mac_zc_upper_bound_intr_ena(zc_ctxt, 0);
/* clear dsr event */
if (zc_ctxt->nv_info.dsr_clr) {
zc_ctxt->nv_info.dsr_clr(MAC_DSR_ZC_SYSTIC_TRIG_CB_ID);
zc_ctxt->nv_info.dsr_clr(MAC_DSR_ZC_UPPER_BOUND_ID);
}
return ERR_OK;
}
static uint32_t mac_zc_system_status_check(mac_zc_ctxt_t *zc_ctxt)
{
uint8_t id;
if (NULL == zc_ctxt) {
IOT_ASSERT(0);
return ERR_INVAL;
}
if (!mac_zc_is_collecting(zc_ctxt)) {
return ERR_OK;
}
for (id = MAC_ZC_PHASE_A; id < MAC_ZC_PHASE_CNT; id++) {
if (mac_zc_phase_is_support(zc_ctxt, id)
^ mac_zc_phase_is_active(&zc_ctxt->phase_info[id])) {
/* if the phase support collect, but it is not active */
mac_zc_system_status_print(zc_ctxt);
iot_printf("zc:[WARN].ntb=%u,lts=%u\n",
mac_sched_get_ntb(NULL), mac_sched_get_lts());
mem_dump((uint32_t *)zc_ctxt, sizeof(*zc_ctxt)/sizeof(uint32_t));
return ERR_FAIL;
}
}
return ERR_OK;
}
static mac_zc_phase_degree_id_t mac_zc_get_phase_degree(uint32_t base,
uint32_t target, uint32_t period)
{
int32_t diff_check;
mac_zc_phase_degree_id_t deg_id;
diff_check = IOT_ABS((int32_t)(target - base));
#if MAC_ZC_PHASE_DIFF_CHECK_ENA
int32_t std_min, std_max;
for (deg_id = MAC_ZC_PHASE_DEGREE_0;
deg_id < MAC_ZC_PHASE_DEGREE_OTHERS; deg_id++) {
switch (deg_id) {
case MAC_ZC_PHASE_DEGREE_0:
std_min = (int32_t)(-MAC_ZC_PERIOD_JITTER_GAP_NTB);
std_max = (int32_t)MAC_ZC_PERIOD_JITTER_GAP_NTB;
break;
case MAC_ZC_PHASE_DEGREE_30: // 30/360 = 1/12
std_min = (int32_t)(period / 12) - MAC_ZC_PERIOD_JITTER_GAP_NTB;
std_max = (int32_t)(period / 12) + MAC_ZC_PERIOD_JITTER_GAP_NTB;
break;
case MAC_ZC_PHASE_DEGREE_60: // 60/360 = 1/6
std_min = (int32_t)(period / 6) - MAC_ZC_PERIOD_JITTER_GAP_NTB;
std_max = (int32_t)(period / 6) + MAC_ZC_PERIOD_JITTER_GAP_NTB;
break;
case MAC_ZC_PHASE_DEGREE_120: // 120/360 = 1/3
std_min = (int32_t)(period / 3) - MAC_ZC_PERIOD_JITTER_GAP_NTB;
std_max = (int32_t)(period / 3) + MAC_ZC_PERIOD_JITTER_GAP_NTB;
break;
case MAC_ZC_PHASE_DEGREE_240: // 240/360 = 2/3
std_min = (int32_t)((period << 1) / 3) \
- MAC_ZC_PERIOD_JITTER_GAP_NTB;
std_max = (int32_t)((period << 1) / 3) \
+ MAC_ZC_PERIOD_JITTER_GAP_NTB;
break;
case MAC_ZC_PHASE_DEGREE_300: // 300/360 = 5/6
std_min = (int32_t)(period - (period / 6)) \
- MAC_ZC_PERIOD_JITTER_GAP_NTB;
std_max = (int32_t)(period - (period / 6)) \
+ MAC_ZC_PERIOD_JITTER_GAP_NTB;
break;
case MAC_ZC_PHASE_DEGREE_330: // 330/360 = 11/12
std_min = (int32_t)(period - (period / 12)) \
- MAC_ZC_PERIOD_JITTER_GAP_NTB;
std_max = (int32_t)(period - (period / 12)) \
+ MAC_ZC_PERIOD_JITTER_GAP_NTB;
break;
default:
return MAC_ZC_PHASE_DEGREE_INVALID;
}
if ((diff_check >= std_min) && (diff_check <= std_max)) {
break;
}
}
#else //MAC_ZC_PHASE_DIFF_CHECK_ENA
/* for not check phase diff. if the diff between target and the base value
* is within one period, it is considered a valid data.
*/
if (diff_check < (int32_t)MAC_ZC_PERIOD_JITTER_GAP_NTB) {
deg_id = MAC_ZC_PHASE_DEGREE_0;
} else if (diff_check < (int32_t)(period - MAC_ZC_PERIOD_JITTER_GAP_NTB)) {
deg_id = MAC_ZC_PHASE_DEGREE_OTHERS;
} else {
deg_id = MAC_ZC_PHASE_DEGREE_INVALID;
}
#endif
#if (MAC_ZC_DBG_LOG_LEVEL >= 2)
iot_printf("[zc]degree:%d,base:%u,target:%u,period:%u,diff=%u\n", \
deg_id, base, target, period, diff_check);
#endif
return deg_id;
}
#if MAC_ZC_CHECK_INFO_DBG_ENA
static void mac_zc_update_info_check(mac_zc_ctxt_t *zc_ctxt)
{
mac_zc_phase_info_t *phase_info;
uint32_t err_code = 0;
uint32_t ref_wr_idx ;
uint32_t ntb[MAC_ZC_PHASE_CNT] = {0};
uint32_t idx[MAC_ZC_PHASE_CNT] = {0};
uint32_t phase_ring_size;
uint8_t cnt;
uint8_t phase;
IOT_ASSERT(zc_ctxt);
/* find refer phase id and refer phase write index */
phase = (uint8_t)mac_zc_get_ref_phase_id(zc_ctxt);
if (phase >= MAC_ZC_PHASE_ALL) {
err_code = __LINE__;
goto out;
}
phase_info = &zc_ctxt->phase_info[phase];
if (mac_zc_phase_is_active(phase_info) &&
!mac_zc_is_ring_empty(phase_info)) {
ref_wr_idx = mac_zc_ring_get_last_idx(phase_info);
} else {
goto out;
}
/* 1, record ring buffer ntb in same write index, to check delta ntb
* 2, record phase's latest write index, to check delta write index
* 3, check every active phase ring size
*/
cnt = iot_bitops_cbs((uint8_t)zc_ctxt->nv_info.support_phase_bitmap);
if ((cnt != 1) && (cnt != 3)) {
err_code = __LINE__;
goto out;
}
phase_ring_size = (uint32_t)(zc_ctxt->ring_sz / cnt);
for (phase = MAC_ZC_PHASE_A, cnt = 0; phase < MAC_ZC_PHASE_CNT; phase++) {
phase_info = &zc_ctxt->phase_info[phase];
if (mac_zc_phase_is_support(zc_ctxt, phase) &&
(phase_info->ntb_ring_size != phase_ring_size)) {
err_code = __LINE__;
goto out;
}
if (mac_zc_phase_is_active(phase_info) &&
!mac_zc_is_ring_empty(phase_info)) {
ntb[cnt] = phase_info->ntb_ring[ref_wr_idx];
idx[cnt++] = mac_zc_ring_get_last_idx(phase_info);
} else if (phase_info->write_idx) {
err_code = __LINE__;
goto out;
}
}
/* active phases less than 2, no need to check */
if (cnt < 2) {
goto out;
}
/* check delta ntb and delta write index between every active phase */
for (uint8_t i = 0; i < (cnt - 1); i++) {
for (uint8_t j = i + 1; j < cnt; j++) {
uint32_t abs_diff_ntb = IOT_ABS((int32_t)(ntb[i] - ntb[j]));
if (abs_diff_ntb >= MAC_ZC_ALL_PHASE_GOLDON_GAP_NTB) {
err_code = __LINE__;
goto out;
}
uint32_t abs_diff_idx = IOT_ABS((int32_t)(idx[i] - idx[j]));
if (abs_diff_idx > (phase_ring_size >> 1)) {
abs_diff_idx = phase_ring_size - abs_diff_idx;
}
if (abs_diff_idx > MAC_ZC_PHASE_CNT) {
err_code = __LINE__;
goto out;
}
}
}
out:
if (err_code) {
iot_printf("zc:chk_info errno=%u, cur_ntb=%u, cur_lts=%u\n",
err_code, mac_sched_get_ntb(NULL), mac_sched_get_lts());
mem_dump((uint32_t *)zc_ctxt, sizeof(*zc_ctxt) / sizeof(uint32_t));
mac_zc_set_func_cmd((uint8_t)zc_ctxt->ref_pdev_id,
MAC_ZC_FUNC_CMD_DELAY_RESET_HW, NULL);
}
}
#else
#define mac_zc_update_info_check(zc_ctxt) ((void)zc_ctxt)
#endif
static void mac_zc_phase_ring_write(mac_zc_ctxt_t *zc_ctxt, uint8_t phase_id,
uint32_t wdata)
{
uint32_t widx;
mac_zc_phase_info_t *phase;
phase = &zc_ctxt->phase_info[phase_id];
widx = phase->write_idx;
/* update current zc ntb to phase ring buffer */
phase->ntb_ring[widx] = wdata;
#if (MAC_ZC_DBG_LOG_LEVEL >= 1)
iot_printf("[zc]phase-%d,update_ring[%u]=%u\n",
phase_id, widx, phase->ntb_ring[widx]);
#endif
widx++;
if (widx >= phase->ntb_ring_size) {
IOT_ASSERT(widx == phase->ntb_ring_size);
/* update the ntb ring buffer full wrap */
phase->is_ring_full = 1;
widx = 0;
}
phase->write_idx = widx;
}
static uint8_t mac_zc_phase_id_zc2plc(uint8_t zc_phase_id)
{
if (zc_phase_id >= MAC_ZC_PHASE_A && zc_phase_id < MAC_ZC_PHASE_ALL) {
return zc_phase_id - MAC_ZC_PHASE_A + PLC_PHASE_A;
} else {
IOT_ASSERT(0);
return 0;
}
}
static void mac_zc_repeat_phase_init(mac_zc_ctxt_t *zc_ctxt)
{
IOT_ASSERT(zc_ctxt);
for (uint8_t phase = MAC_ZC_PHASE_A; phase < MAC_ZC_PHASE_CNT; phase++) {
zc_ctxt->phase_info[phase].repeat_phase = phase;
}
}
static void mac_zc_repeat_connect_check(mac_zc_ctxt_t *zc_ctxt)
{
uint8_t chk_pid, base_pid;
IOT_ASSERT(zc_ctxt);
#if MAC_ZC_DBG_LOG_LEVEL >= 1
iot_printf("zc:repeat0.%d:%d:%d-%d:%d:%d\n",
zc_ctxt->phase_info[MAC_ZC_PHASE_A].collect_sts,
zc_ctxt->phase_info[MAC_ZC_PHASE_B].collect_sts,
zc_ctxt->phase_info[MAC_ZC_PHASE_C].collect_sts,
zc_ctxt->phase_info[MAC_ZC_PHASE_A].repeat_phase,
zc_ctxt->phase_info[MAC_ZC_PHASE_B].repeat_phase,
zc_ctxt->phase_info[MAC_ZC_PHASE_C].repeat_phase);
#endif
mac_zc_repeat_phase_init(zc_ctxt);
for (chk_pid = (MAC_ZC_PHASE_CNT - 1); chk_pid > MAC_ZC_PHASE_A; chk_pid--)
{
if ((0 == mac_zc_phase_is_support(zc_ctxt, chk_pid)) ||
(0 == zc_ctxt->phase_info[chk_pid].last_ts)) {
continue;
}
for (base_pid = MAC_ZC_PHASE_A; base_pid < chk_pid; base_pid++) {
if ((0 == mac_zc_phase_is_support(zc_ctxt, base_pid)) ||
(0 == zc_ctxt->phase_info[base_pid].last_ts)) {
continue;
}
if (MAC_ZC_PHASE_DEGREE_0 == mac_zc_get_phase_degree(
zc_ctxt->phase_info[base_pid].last_ts,
zc_ctxt->phase_info[chk_pid].last_ts,
zc_ctxt->phase_info[base_pid].period)) {
if (!mac_zc_phase_is_repeat(&zc_ctxt->phase_info[chk_pid],
chk_pid)) {
zc_ctxt->phase_info[chk_pid].repeat_phase = base_pid;
}
/* set this phase inactive */
zc_ctxt->phase_info[chk_pid].collect_sts = 0;
iot_printf("zc:repeat.%d-%d\n", chk_pid, base_pid);
}
}
}
iot_printf("zc:repeat1.%d:%d:%d-%d:%d:%d\n",
zc_ctxt->phase_info[MAC_ZC_PHASE_A].collect_sts,
zc_ctxt->phase_info[MAC_ZC_PHASE_B].collect_sts,
zc_ctxt->phase_info[MAC_ZC_PHASE_C].collect_sts,
zc_ctxt->phase_info[MAC_ZC_PHASE_A].repeat_phase,
zc_ctxt->phase_info[MAC_ZC_PHASE_B].repeat_phase,
zc_ctxt->phase_info[MAC_ZC_PHASE_C].repeat_phase);
}
static uint8_t mac_zc_is_repeat_connect(mac_zc_ctxt_t *zc_ctxt)
{
uint8_t is_repeat = 0;
uint8_t pid;
if (zc_ctxt) {
for (pid = MAC_ZC_PHASE_A; pid < MAC_ZC_PHASE_CNT; pid++) {
if (mac_zc_phase_is_support(zc_ctxt, pid)
&& mac_zc_phase_is_repeat(&zc_ctxt->phase_info[pid], pid)) {
is_repeat = 1;
break;
}
}
}
return is_repeat;
}
/*
* @brief update collect data to phase_id's phase_info.
* @param zc_id: which pdev to reset
* @param reason reset reason, see MAC_ZC_RST_REASON_ID
* @retval: indicate this phase collect status.
* 1 - this phase is abnormal.
* 0 - this phase is ok.
*/
static uint8_t mac_zc_update_collect_info(mac_zc_ctxt_t *zc_ctxt,
uint8_t phase_id, uint8_t is_update_ring, uint32_t zc_ntb,
uint8_t is_half_clct)
{
uint8_t is_abnormal, ref_phase_id;
int32_t delta = 0;
uint32_t save_zc, cur_ntb;
mac_zc_phase_info_t *phase_info;
mac_zc_phase_degree_id_t phase_degree = MAC_ZC_PHASE_DEGREE_INVALID;
cur_ntb = mac_sched_get_ntb(NULL);
is_half_clct = !!is_half_clct;
phase_info = &zc_ctxt->phase_info[phase_id];
ref_phase_id = (uint8_t)mac_zc_get_ref_phase_id(zc_ctxt);
/* this parameter save the data is expected flag.
* 0 - is ok, it is expected. 1 - abnormal.
*/
is_abnormal = 0;
save_zc = zc_ntb;
/* this phae last_zc and period both valid, base on this info to check
* current collect valid, and then update: last_zc, period, phase_diff_ntb
*/
if (phase_info->last_ts && phase_info->period) {
/* check valid base on current phase ctxt */
phase_degree = mac_zc_get_phase_degree((uint32_t)(phase_info->last_ts
+ (phase_info->period >> is_half_clct)), zc_ntb,
phase_info->period);
if (MAC_ZC_PHASE_DEGREE_0 != phase_degree) {
is_abnormal = 1; //phase diff must be 0 degree
}
/* for non-reference phase, check phase diff base on reference phase */
if (!is_abnormal && (phase_id != ref_phase_id)
&& (ref_phase_id != MAC_ZC_PHASE_ALL)) {
phase_degree = mac_zc_get_phase_degree(
zc_ctxt->phase_info[ref_phase_id].last_ts,
zc_ntb, phase_info->period);
if ((MAC_ZC_PHASE_DEGREE_INVALID == phase_degree)
#if MAC_ZC_PHASE_DIFF_CHECK_ENA
|| (MAC_ZC_PHASE_DEGREE_OTHERS == phase_degree)
#endif
)
{
is_abnormal = 1;
}
}
/* check repeat phase */
if (!is_abnormal && mac_zc_phase_is_repeat(phase_info, phase_id) &&
MAC_ZC_PHASE_DEGREE_0 == mac_zc_get_phase_degree(zc_ntb,
zc_ctxt->phase_info[phase_info->repeat_phase].last_ts,
phase_info->period)) {
is_abnormal = 1;
}
if (is_abnormal) {
if (mac_zc_phase_is_active(phase_info) || !zc_ntb) {
/* make sure save_zc is a valid data. */
save_zc = phase_info->last_ts +
(phase_info->period >> is_half_clct);
if (mac_zc_ntb_is_larger_ref(save_zc, cur_ntb)) {
iot_printf("zc:calc_err-%d.last:%u,sw:%u,hw:%u,cur:%u\n",
phase_id, phase_info->last_ts, save_zc, zc_ntb,
cur_ntb);
save_zc = phase_info->last_ts;
is_update_ring = 0;
if (zc_ctxt->sm_info.cur_sm
>= MAC_ZC_SM_TRAIN_SYSTICK_WAIT) {
zc_ctxt->is_need_reset = 1;
}
}
}
} else {
/* update this phase period */
delta = (zc_ntb - phase_info->last_ts) << is_half_clct;
phase_info->period = (uint32_t)mac_zc_updata_average_accum(\
(int64_t)phase_info->period, (int64_t)delta, \
mac_zc_get_average_weight_power(phase_info->collect_cnt));
}
/* note: if a normal last_ts equal to 0, we will make it 1 in order to
* avoid next time update zc information go into 'else' branch.
*/
if (save_zc == 0) {
save_zc++;
}
phase_info->last_ts = save_zc;
} else {
/* for history last_zc or peiod invalid, but current collect is valid,
* then update last_zc and period ctxt
*/
phase_info->period = zc_ctxt->phase_info[ref_phase_id].period;
if (zc_ntb) {
phase_info->last_ts = zc_ntb;
}
is_abnormal = 1;
}
/* update this phase abnormal counter */
if (mac_zc_phase_is_active(phase_info) == is_abnormal) {
/* if not corresponding to the phase's collect status */
if (phase_info->abnormal_cnt < 255) {
phase_info->abnormal_cnt++;
}
} else {
if (phase_info->abnormal_cnt) {
phase_info->abnormal_cnt--;
}
}
/* update collect counter */
if (!is_abnormal && (phase_info->collect_cnt < 63)) {
phase_info->collect_cnt++;
}
#if (MAC_ZC_DBG_LOG_LEVEL >= 1)
iot_printf("[zc]phase-%d,active:%d,degree:%d,zc=[%u][%u],last=%u,diff=%d,"
"is_abnor=%d,abnor_cnt=%d,sw_period=%u,collect_cnt=%d, is_half=%d, "
"is_power_collapse=%d, cur_ntb=%u\n",
phase_id, mac_zc_phase_is_active(phase_info), phase_degree, \
zc_ntb, save_zc, phase_info->last_ts, delta, \
is_abnormal, phase_info->abnormal_cnt,\
phase_info->period, phase_info->collect_cnt, is_half_clct,
mac_zc_is_power_collapsed((uint8_t)zc_ctxt->ref_pdev_id),
mac_sched_get_ntb(NULL));
#endif
/* update phase ring buffer */
if (is_update_ring && mac_zc_phase_is_support(zc_ctxt, phase_id) \
&& mac_zc_phase_is_active(phase_info)) {
IOT_ASSERT_DUMP(phase_info->ntb_ring, (uint32_t *)phase_info, \
sizeof(*phase_info)/sizeof(uint32_t));
mac_zc_phase_ring_write(zc_ctxt, phase_id, save_zc);
}
/* Notifies the caller that the phase data needs to be checked */
return !(is_abnormal ^ mac_zc_phase_is_active(phase_info));
}
/* swap two phase_map infomation */
static void mac_zc_exec_swap_phase_map(mac_zc_hw_map_info_t *swap0,
mac_zc_hw_map_info_t *swap1)
{
mac_zc_hw_map_info_t tmp_map_info;
if (!swap0 || !swap1 || (swap0->gpio == GPIO_NO_VALID) ||
(swap1->gpio == GPIO_NO_VALID)) {
return;
}
#if (MAC_ZC_DBG_LOG_LEVEL >= 1)
iot_printf("[zc]swap_befor:[%d:%d:%d:%d]-[%d:%d:%d:%d]\n", \
swap0->phase_id, swap0->gpio, swap0->signal, swap0->cap_id, \
swap1->phase_id, swap1->gpio, swap1->signal, swap1->cap_id);
#endif
/* save map0 info to tmp */
os_mem_cpy(&tmp_map_info, swap0, sizeof(tmp_map_info));
/* copy map1's cap&signal to map0. but not exchange gpio, gpio&zc_phase_id
* must be match.
*/
swap0->cap_id = swap1->cap_id;
swap0->signal = swap1->signal;
/* copy map0's cap&signal to map1 */
swap1->cap_id = tmp_map_info.cap_id;
swap1->signal = tmp_map_info.signal;
/* updata hw gpio->signal setting */
mac_zc_hw_fix_map_gpio2sig(swap0->gpio, swap0->signal);
mac_zc_hw_fix_map_gpio2sig(swap1->gpio, swap1->signal);
iot_printf("zc:swap_phase:[%d:%d:%d:%d]-[%d:%d:%d:%d]\n", \
swap0->phase_id, swap0->gpio, swap0->signal, swap0->cap_id, \
swap1->phase_id, swap1->gpio, swap1->signal, swap1->cap_id);
}
/* make sure if cap0's zc is max, phaseA not map to cap0.
* return: low_4bit and high_4bit represent the need swap phase_id
* if not need swap, then return 0
*/
static uint8_t mac_zc_get_swap_phase_id(mac_zc_ctxt_t *zc_ctxt)
{
uint8_t phase_id, max_phase, support_bitmap;
IOT_ASSERT(zc_ctxt);
support_bitmap = (uint8_t)zc_ctxt->nv_info.support_phase_bitmap;
max_phase = MAC_ZC_PHASE_CNT;
for (phase_id = MAC_ZC_PHASE_A; phase_id < MAC_ZC_PHASE_CNT;
phase_id++) {
if (0 == zc_ctxt->phase_info[phase_id].last_ts) {
continue;
}
if ((MAC_ZC_PHASE_CNT == max_phase) \
|| (zc_ctxt->phase_info[phase_id].last_ts \
> zc_ctxt->phase_info[max_phase].last_ts)) {
/* get first valid phase id */
max_phase = phase_id;
}
#if (MAC_ZC_DBG_LOG_LEVEL >= 1)
iot_printf("[zc]max_phase=%d\n", max_phase);
#endif
}
phase_id = mac_zc_map_info_cap2phase(zc_ctxt, MAC_ZC_HW_CAP0);
if (MAC_ZC_PHASE_CNT == max_phase) {
/* all phase is inactive, force max_phase = cap0's phase for search */
max_phase = phase_id;
} else if (mac_zc_phase_is_active(&zc_ctxt->phase_info[phase_id]) \
&& (1 == mac_zc_get_active_phase_cnt(zc_ctxt))) {
/* only cap0's phase active, no need swap */
return 0;
} else {
/* if cap0 connect to first support phase(e.g. PhaseA), and the last_ts
* of this phase is the max(max_phase), then need swap this phase to
* other cap. otherwise not need swap phase map info with return 0.
*/
phase_id = iot_bitops_ffs(support_bitmap) - 1;
if ((mac_zc_map_info_cap2phase(zc_ctxt, MAC_ZC_HW_CAP0) != phase_id) \
|| (max_phase != phase_id)) {
return 0;
}
}
uint8_t cnt;
phase_id = max_phase;
for (cnt = 0; cnt < MAC_ZC_PHASE_CNT; cnt++) {
phase_id = (phase_id + MAC_ZC_PHASE_CNT - 1) % MAC_ZC_PHASE_CNT;
if ((1 << phase_id) & support_bitmap) {
return (max_phase & 0x0F) | ((phase_id << 4) & 0xF0);
}
}
return 0;
}
static mac_zc_train_status_t mac_zc_train_gen_bound_intr_process(
mac_zc_ctxt_t *zc_ctxt)
{
uint8_t cap_id, phase_id, is_abnormal;
uint8_t is_need_chk = 0;
uint32_t cur_zc;
mac_zc_phase_info_t *phase_info;
IOT_ASSERT(zc_ctxt);
/* update train collect value */
for (cap_id = MAC_ZC_HW_CAP0; cap_id < MAC_ZC_HW_CAP_CNT; cap_id++) {
phase_id = mac_zc_map_info_cap2phase(zc_ctxt, cap_id);
phase_info = &zc_ctxt->phase_info[phase_id];
if (!mac_zc_phase_is_support(zc_ctxt, phase_id)) {
continue;
}
cur_zc = mac_zc_get_cur_zc(zc_ctxt, cap_id);
if (0 == mac_zc_get_phase_collect_cnt(zc_ctxt, \
(uint8_t)((1 << MAC_ZC_PHASE_CNT) - 1))) {
phase_info->last_ts = cur_zc;
phase_info->period = mac_zc_hw_get_zc_period(cap_id);
if (phase_info->period) {
phase_info->collect_cnt = 1;
} else {
phase_info->collect_cnt = 0;
}
#if (MAC_ZC_DBG_LOG_LEVEL >= 2)
iot_printf("[zc]train_bound:init-phase:%d,cap:%d,cur=%u,"
"period:%u\n", \
phase_id, cap_id, cur_zc, phase_info->period);
#endif
continue;
}
/* in state train_bound_wait always full period collect,
* so set function parameter is_half_clct = 0
*/
is_abnormal = mac_zc_update_collect_info(zc_ctxt, phase_id, 0,
cur_zc, 0);
/* update phase train cnt. reuse abnormal_cnt to save the phase
* train collect cnt
*/
if (is_abnormal) {
/* if this phase collect error, re-training */
mac_zc_phase_collect_cnt_clr(zc_ctxt, (uint8_t)(1 << phase_id));
} else if (mac_zc_get_phase_collect_cnt(zc_ctxt, \
(uint8_t)(1 << phase_id)) > MAC_ZC_TRAIN_BOUND_CONS_CNT) {
is_need_chk = 1;
}
#if (MAC_ZC_DBG_LOG_LEVEL >= 2)
iot_printf("[zc]train_bound:cap:%d,phase_chk=%d,is_aborn=%d,"
"zc=%u,avg=%u,collect_cnt=%d\n",
cap_id, phase_id, is_abnormal, cur_zc,
phase_info->period,
phase_info->collect_cnt);
#endif
}
if (is_need_chk) {
/* update phase status */
for (phase_id = MAC_ZC_PHASE_A; phase_id < MAC_ZC_PHASE_CNT;
phase_id++) {
phase_info = &zc_ctxt->phase_info[phase_id];
phase_info->collect_sts = (phase_info->collect_cnt > \
(MAC_ZC_TRAIN_BOUND_CONS_CNT - MAC_ZC_TRAIN_BOUND_MARGIN_CNT))\
? MAC_ZC_COLLECT_ACTIVE : MAC_ZC_COLLECT_INACTIVE;
/* clean inactive phase's last_zc and period for not trigger
* by system tick timer
*/
if (MAC_ZC_COLLECT_INACTIVE == phase_info->collect_sts) {
phase_info->last_ts = 0;
phase_info->period = 0;
} else {
phase_info->start_ntb = phase_info->last_ts;
iot_printf("zc:phase:%d, start_ts=%u\n",
phase_id, phase_info->start_ntb);
}
mac_status_zc_status_para_update(
(uint8_t)mac_zc_phase_is_active(phase_info), phase_id);
}
mac_zc_repeat_connect_check(zc_ctxt);
mac_zc_update_ref_phase_id(zc_ctxt, MAC_ZC_PHASE_ALL);
mac_zc_system_status_print(zc_ctxt);
return MAC_ZC_TRAIN_SUCCESS;
}
return MAC_ZC_TRAIN_ONGOING;
}
static uint8_t mac_zc_cal_collect_phase_bitmap(mac_zc_ctxt_t *zc_ctxt)
{
uint8_t phase_id, phase_bitmap;
mac_zc_phase_info_t *phase_info;
//support_phase_bitmap same as phase_info->enable
phase_bitmap = (uint8_t)(zc_ctxt->check_phase_bitmap \
& zc_ctxt->nv_info.support_phase_bitmap);
#if MAC_ZC_COLLECT_DEBUG_ENA
mac_zc_set_phase_bitmap(&zc_ctxt->bitmap_trace ,
(zc_ctxt->check_phase_bitmap & (~phase_bitmap)), MAC_ZC_CALL_CAL);
#endif
if (!phase_bitmap) {
#if MAC_ZC_COLLECT_DEBUG_ENA
IOT_ASSERT_DUMP(0, (uint32_t *)zc_ctxt,
sizeof(*zc_ctxt)/sizeof(uint32_t));
#endif
return 0;
}
zc_ctxt->check_phase_bitmap &= ~phase_bitmap;
#if (MAC_ZC_DBG_LOG_LEVEL >= 1)
iot_printf("[zc]systick_collect_phase_bitmap=0x%x\n", phase_bitmap);
#endif
for (phase_id = MAC_ZC_PHASE_A; phase_id < MAC_ZC_PHASE_CNT; phase_id++) {
phase_info = &zc_ctxt->phase_info[phase_id];
if (!mac_zc_phase_is_support(zc_ctxt, phase_id)
|| mac_zc_phase_is_repeat(phase_info, phase_id)
|| mac_zc_phase_is_active(phase_info)) {
continue;
}
/* for some phase not collect, maybe this phase restore,
* force trigger collect the phase.
*/
if (!phase_info->last_ts
|| ((uint32_t)IOT_ABS((int32_t)(mac_sched_get_ntb(NULL)
- phase_info->last_ts)) > phase_info->period)) {
phase_bitmap |= 1 << phase_id;
}
}
return phase_bitmap;
}
#if MAC_ZC_UPDATE_DLY_INFO_ENA
/* calculate the delayed periods since last update phase info */
static uint32_t mac_zc_calc_dly_periods(mac_zc_ctxt_t *zc_ctxt, uint8_t phase)
{
mac_zc_phase_info_t *phase_info;
uint32_t abs_diff_ntb, period;
uint32_t dly_periods = 0;
IOT_ASSERT(zc_ctxt && (phase < MAC_ZC_PHASE_CNT));
if (!mac_zc_is_collecting(zc_ctxt)) {
return dly_periods;
}
phase_info = &zc_ctxt->phase_info[phase];
abs_diff_ntb = IOT_ABS((int32_t)(mac_sched_get_ntb(NULL) -
phase_info->last_ts));
period = phase_info->period >> (zc_ctxt->nv_info.is_switch_gpio_clct);
/* calc active phase real delayed periods, inactive phase return 0 */
if (mac_zc_phase_is_active(phase_info) && period &&
(abs_diff_ntb > (period + MAC_ZC_HW_CAP_INT_PROTECT_NTB))) {
dly_periods = (abs_diff_ntb - MAC_ZC_HW_CAP_INT_PROTECT_NTB) / period;
iot_printf("zc:dly_chk. phase=%d, cur_ntb=%u, last_ts=%u, widx=%d"
"dly_periods=%u\n", phase, mac_sched_get_ntb(NULL),
phase_info->last_ts, phase_info->write_idx, dly_periods);
}
return dly_periods;
}
/* update zc delayed info when task is delayed */
static void mac_zc_update_dly_info(mac_zc_ctxt_t *zc_ctxt)
{
uint32_t dly_periods, wr_idx;
uint8_t phase_id, is_half_clct;
mac_zc_phase_info_t *phase_info;
IOT_ASSERT(zc_ctxt);
if (!mac_zc_is_collecting(zc_ctxt)) {
return;
}
for (phase_id = MAC_ZC_PHASE_A; phase_id < MAC_ZC_PHASE_CNT; phase_id++) {
phase_info = &zc_ctxt->phase_info[phase_id];
if ((!mac_zc_phase_is_support(zc_ctxt, phase_id)) ||
(!mac_zc_phase_is_active(phase_info))) {
continue;
}
dly_periods = mac_zc_calc_dly_periods(zc_ctxt, phase_id);
/* only when dly_periods >= 2 update dly_info, to avoid three phase
* LN reverse, reversed phase always be updated by this function.
* for long time running, deviation will be larger than one period.
*/
if (dly_periods < 2) {
continue;
}
is_half_clct = mac_zc_is_half_clct_state(zc_ctxt, phase_id);
wr_idx = phase_info->write_idx;
/* update zc phase info */
for (uint32_t i = 0; i < dly_periods; i++) {
phase_info->last_ts += (phase_info->period >> is_half_clct);
phase_info->ntb_ring[wr_idx] = phase_info->last_ts;
if (++wr_idx >= phase_info->ntb_ring_size) {
IOT_ASSERT(wr_idx == phase_info->ntb_ring_size);
/* update the ntb ring buffer full wrap */
phase_info->is_ring_full = 1;
wr_idx = 0;
}
}
phase_info->write_idx = wr_idx;
iot_printf("zc:dly_update. phase-%d,ring[%u]=%u\n", phase_id,
mac_zc_ring_get_last_idx(phase_info), phase_info->last_ts);
}
}
#else
#define mac_zc_update_dly_info(zc_ctxt) ((void)(zc_ctxt))
#endif
/* update collected ntb of corresponding phase and return abnormal phase bitmap */
static uint8_t mac_zc_phase_collect(mac_zc_ctxt_t *zc_ctxt,
uint8_t is_update_ring, uint8_t collect_phase_bitmap)
{
uint8_t phase_id, is_abnormal, abnormal_phase_bitmap = 0;
uint8_t is_half_clct;
#if (MAC_ZC_DBG_LOG_LEVEL >= 1)
iot_printf("[zc]%s:0x%x\n", __FUNCTION__, collect_phase_bitmap);
#endif
while (collect_phase_bitmap) {
phase_id = iot_bitops_ffs(collect_phase_bitmap) - 1;
IOT_ASSERT(phase_id < MAC_ZC_PHASE_CNT);
collect_phase_bitmap &= ~(1 << phase_id);
is_half_clct = mac_zc_is_half_clct_state(zc_ctxt, phase_id);
is_abnormal = mac_zc_update_collect_info(zc_ctxt, phase_id, \
is_update_ring, mac_zc_get_cur_zc(zc_ctxt, \
mac_zc_map_info_phase2cap(zc_ctxt, phase_id)), is_half_clct);
abnormal_phase_bitmap |= is_abnormal << phase_id;
}
mac_zc_update_info_check(zc_ctxt);
return abnormal_phase_bitmap;
}
static void mac_zc_phase_collect_start_ts_update(mac_zc_ctxt_t *zc_ctxt)
{
uint8_t phase_id;
uint32_t last_idx;
mac_zc_phase_info_t *phase_info;
for (phase_id = MAC_ZC_PHASE_A; phase_id < MAC_ZC_PHASE_CNT; phase_id++) {
phase_info = &zc_ctxt->phase_info[phase_id];
if (!phase_info->collect_sts) {
continue;
}
if (mac_zc_is_ring_empty(phase_info)) {
phase_info->start_ntb = phase_info->last_ts;
} else {
last_idx = mac_zc_ring_get_last_idx(phase_info);
if (zc_ctxt->nv_info.is_switch_gpio_clct) {
last_idx &= ~((uint32_t)1);
}
phase_info->start_ntb = phase_info->ntb_ring[last_idx];
}
iot_printf("zc:%d collect start_ts=%u\n",
phase_id, phase_info->start_ntb);
}
}
static void mac_zc_phase_collect_start(mac_zc_ctxt_t *zc_ctxt)
{
uint8_t phase_id, max_ts_id, is_first_phase;
mac_zc_phase_info_t *phase_info;
uint32_t w_ntb;
mac_zc_phase_ring_reset(zc_ctxt);
max_ts_id = MAC_ZC_PHASE_CNT;
for (phase_id = MAC_ZC_PHASE_A; phase_id < MAC_ZC_PHASE_CNT; phase_id++) {
phase_info = &zc_ctxt->phase_info[phase_id];
if (!phase_info->collect_sts
|| !mac_zc_phase_is_support(zc_ctxt, phase_id)) {
continue;
}
if (MAC_ZC_PHASE_CNT == max_ts_id) {
max_ts_id = phase_id;
continue;
}
if (mac_zc_ntb_is_larger_ref(phase_info->start_ntb,
zc_ctxt->phase_info[max_ts_id].start_ntb)) {
max_ts_id = phase_id;
}
}
#if (MAC_ZC_DBG_LOG_LEVEL >= 1)
iot_printf("[zc]collect_start. max ts id %d\n", max_ts_id);
#endif
is_first_phase = 1;
for (phase_id = MAC_ZC_PHASE_A; phase_id < MAC_ZC_PHASE_CNT; phase_id++) {
phase_info = &zc_ctxt->phase_info[phase_id];
if (!phase_info->collect_sts
|| !mac_zc_phase_is_support(zc_ctxt, phase_id)) {
continue;
}
if (is_first_phase && (phase_id == max_ts_id)) {
phase_info->start_ntb -= phase_info->period;
}
w_ntb = phase_info->start_ntb;
is_first_phase = 0;
do {
mac_zc_phase_ring_write(zc_ctxt, phase_id, w_ntb);
w_ntb += phase_info->period >> zc_ctxt->nv_info.is_switch_gpio_clct;
int32_t delta = (int32_t)(phase_info->last_ts - w_ntb);
if ((IOT_ABS(delta) > MAC_ZC_PERIOD_JITTER_GAP_NTB)
&& mac_zc_ntb_is_larger_ref(w_ntb, phase_info->last_ts)) {
break;
}
} while (1);
}
mac_zc_update_ref_phase_id(zc_ctxt, MAC_ZC_PHASE_ALL);
}
/* mac_zc collect zc ntb in train state in systick dsr */
static mac_zc_train_status_t mac_zc_train_systick_intr(mac_zc_ctxt_t *zc_ctxt)
{
uint8_t phase_id, phase_bitmap, is_need_chk = 0, is_abnormal;
mac_zc_phase_info_t *phase_info;
phase_bitmap = mac_zc_cal_collect_phase_bitmap(zc_ctxt);
mac_zc_phase_collect(zc_ctxt, 1, phase_bitmap);
while (phase_bitmap) {
phase_id = iot_bitops_ffs(phase_bitmap) - 1;
phase_info = &zc_ctxt->phase_info[phase_id];
if (mac_zc_phase_is_support(zc_ctxt, phase_id) \
&& mac_zc_phase_is_active(phase_info) \
&& (mac_zc_get_phase_collect_cnt(zc_ctxt, \
(uint8_t)(1 << phase_id)) > MAC_ZC_TRAIN_SYSTIC_CNT)) {
is_need_chk = 1;
break;
}
phase_bitmap &= ~(1 << phase_id);
}
if (zc_ctxt->is_need_reset) {
zc_ctxt->is_need_reset = 0;
mac_zc_set_func_cmd((uint8_t)zc_ctxt->ref_pdev_id,
MAC_ZC_FUNC_CMD_DELAY_RESET_HW, NULL);
return MAC_ZC_TRAIN_FAIL;
}
if (is_need_chk) {
for (phase_id = MAC_ZC_PHASE_A; phase_id < MAC_ZC_PHASE_CNT;
phase_id++) {
phase_info = &zc_ctxt->phase_info[phase_id];
if (mac_zc_phase_is_support(zc_ctxt, phase_id) \
&& phase_info->abnormal_cnt > (MAC_ZC_TRAIN_SYSTIC_CNT \
- MAC_ZC_TRAIN_SYSTIC_MARGIN_CNT) \
) {
is_abnormal = !mac_zc_phase_is_active(phase_info);
phase_info->collect_sts = is_abnormal;
if (!phase_info->collect_sts) {
mac_zc_hw_fix_map_gpio2sig(
zc_ctxt->nv_info.phase_map[phase_id].gpio,
zc_ctxt->nv_info.phase_map[phase_id].signal);
}
}
mac_status_zc_status_para_update(
(uint8_t)mac_zc_phase_is_active(phase_info), phase_id);
}
mac_zc_phase_collect_start_ts_update(zc_ctxt);
mac_zc_system_status_print(zc_ctxt);
return MAC_ZC_TRAIN_SUCCESS;
} else {
return MAC_ZC_TRAIN_ONGOING;
}
}
/* mac_zc collect zc ntb and update power status in systick dsr */
static uint32_t mac_zc_systick_collect(mac_zc_ctxt_t *zc_ctxt)
{
uint8_t phase_id, phase_bitmap, is_abnormal;
uint8_t ref_abnormal_cnt;
uint8_t is_power_change = 0;
mac_zc_phase_info_t *phase_info;
phase_id = mac_zc_cal_collect_phase_bitmap(zc_ctxt);
/* phase_bitmap save the phase is abnormal. 0 - normal, 1 - abnormal.
* bit0 - Phase A, bit1 - Phase B. bit2 - Phase C.
*/
phase_bitmap = mac_zc_phase_collect(zc_ctxt, 1, phase_id);
/* check power change status */
while (phase_bitmap) {
phase_id = iot_bitops_ffs(phase_bitmap) - 1;
ref_abnormal_cnt = mac_zc_phase_is_active(
&zc_ctxt->phase_info[phase_id])
? MAC_ZC_COLLECT_LOSS_CNT : MAC_ZC_COLLECT_RESTORE_CNT;
if (zc_ctxt->phase_info[phase_id].abnormal_cnt > ref_abnormal_cnt) {
is_power_change = 1;
break;
}
phase_bitmap &= ~(1 << phase_id);
}
#if (MAC_ZC_DBG_LOG_LEVEL >= 1 && MAC_ZC_COLLECT_DEBUG_ENA)
iot_printf("cur_wr_idx=%d\n", zc_ctxt->bitmap_trace.wr_idx);
for(uint16_t i = 0 ; i < MAC_ZC_BITMAP_TRACE_BUF_SIZE; i++) {
iot_printf("caller_id:%x, bitmap_val:%d, ts:%u, idx:%d\n",
zc_ctxt->bitmap_trace.trace_buf[i].func_traced_ra,
zc_ctxt->bitmap_trace.trace_buf[i].set_bitmap_val,
zc_ctxt->bitmap_trace.trace_buf[i].set_bitmap_ts, i);
}
#endif
if (zc_ctxt->is_need_reset) {
zc_ctxt->is_need_reset = 0;
mac_zc_set_func_cmd((uint8_t)zc_ctxt->ref_pdev_id,
MAC_ZC_FUNC_CMD_DELAY_RESET_HW, NULL);
return ERR_FAIL;
}
/* update phase status */
if (is_power_change) {
phase_bitmap = 0;
for (phase_id = MAC_ZC_PHASE_A; phase_id < MAC_ZC_PHASE_CNT;
phase_id++) {
phase_info = &zc_ctxt->phase_info[phase_id];
ref_abnormal_cnt = mac_zc_phase_is_active(phase_info)
? (MAC_ZC_COLLECT_LOSS_CNT - MAC_ZC_COLLECT_LOSS_MARGIN_CNT)
: (MAC_ZC_COLLECT_RESTORE_CNT
- MAC_ZC_COLLECT_RESTORE_MARGIN_CNT);
if (phase_info->abnormal_cnt > ref_abnormal_cnt) {
os_disable_irq();
/* reuse is_abnormal to save phase collect status */
is_abnormal = !(uint8_t)phase_info->collect_sts;
/* update phase status ctxt */
phase_info->collect_sts = is_abnormal;
os_enable_irq();
/* phase inactive map default gpio to signal */
if (!is_abnormal && mac_zc_phase_is_support(zc_ctxt, phase_id))
{
mac_zc_hw_fix_map_gpio2sig(
zc_ctxt->nv_info.phase_map[phase_id].gpio,
zc_ctxt->nv_info.phase_map[phase_id].signal);
}
/* reuse phase_bitmap save the phase event.
* bit1:0 - Phase A, bit3:2 - Phase B. bit5:4- Phase C.
*/
phase_bitmap |= (uint8_t)((is_abnormal ?
MAC_ZC_EVENT_PHASE_RESTORE : MAC_ZC_EVENT_PHASE_LOSS)
<< (iot_bitops_fls(MAC_ZC_EVENT_MAX) * phase_id));
/* do clean this phase ctxt */
/* clean this phase abnormal cnt */
phase_info->abnormal_cnt = 0;
mac_status_add_zc_phase_chg_cnt(phase_id);
mac_status_zc_status_para_update(
(uint8_t)mac_zc_phase_is_active(phase_info), phase_id);
}
}
mac_zc_phase_collect_start_ts_update(zc_ctxt);
mac_zc_repeat_connect_check(zc_ctxt);
mac_zc_set_event(zc_ctxt, (uint32_t)phase_bitmap);
/* for power collapsed, not update reference phase id */
if (!mac_zc_is_power_collapsed((uint8_t)zc_ctxt->ref_pdev_id)) {
mac_zc_update_ref_phase_id(zc_ctxt, MAC_ZC_PHASE_ALL);
}
mac_zc_system_status_print(zc_ctxt);
mac_zc_phase_collect_start(zc_ctxt);
}
return ERR_OK;
}
static mac_zc_sm_id_t mac_zc_sm_idle_exec(mac_zc_ctxt_t *zc_ctxt,
mac_zc_triger_id_t trigger_id)
{
mac_zc_sm_id_t next_sm = MAC_ZC_SM_IDLE;
IOT_ASSERT(zc_ctxt);
switch (trigger_id) {
case MAC_ZC_TRIG_SYS_START_REQ:
case MAC_ZC_TRIG_TRAIN_TIMER:
if (ERR_OK != mac_zc_system_start(zc_ctxt)) {
//TODO: replace assert with abnormal flash log
//next_sm = MAC_ZC_SM_IDLE;
IOT_ASSERT_DUMP(0, (uint32_t *)zc_ctxt, \
sizeof(*zc_ctxt) / sizeof(uint32_t));
break;
}
/* clean train elapsed time ctxt */
zc_ctxt->train_elapsed_time = 0;
/* WAR: delay for wait mac zc ac track hw ready
* if timeout, will entry this sm MAC_ZC_TRIG_TRAIN_TIMER
*/
mac_zc_train_timer_start(zc_ctxt, MAC_ZC_TRAIN_AC_TRACK_TIME_MS);
next_sm = MAC_ZC_SM_INITED;
break;
case MAC_ZC_TRIG_SYS_STOP_REQ:
mac_zc_system_stop(zc_ctxt);
next_sm = MAC_ZC_SM_IDLE;
break;
default:
break;
}
return next_sm;
}
static mac_zc_sm_id_t mac_zc_sm_inited_exec(mac_zc_ctxt_t *zc_ctxt,
mac_zc_triger_id_t trigger_id)
{
mac_zc_sm_id_t next_sm = MAC_ZC_SM_INITED;
IOT_ASSERT(zc_ctxt);
switch (trigger_id) {
case MAC_ZC_TRIG_TRAIN_TIMER:
/* zc hw ready. ac track running. then trigger gen hw */
/* re-cfg hw collect interval after collect edge is seleceted */
mac_zc_hw_set_vibrate_protect_dur(MAC_ZC_HW_VIBRATE_PROTECT_NTB);
/* disable square wave upper bound interrupt */
mac_zc_upper_bound_intr_ena(zc_ctxt, 0);
/* cfg sw produce square wave by zc sw */
mac_zc_hw_gen_set_gen_sel_mtx(MAC_ZC_HW_GEN_SELIN_INTERNAL);
/* delay 4s for hw traning, then cfg hw produce square wave*/
/* if timeout, will entry MAC_ZC_SM_TRAIN_GEN_READY's
* MAC_ZC_TRIG_TRAIN_TIMER
*/
/* map default gpio to signal */
if (zc_ctxt->nv_info.is_switch_gpio_clct) {
mac_zc_hw_map_def_gpio(zc_ctxt);
}
next_sm = MAC_ZC_SM_TRAIN_INIT;
mac_zc_train_timer_start(zc_ctxt, MAC_ZC_TRAIN_GEN_SW_MTX_TIME_MS);
break;
case MAC_ZC_TRIG_SYS_STOP_REQ:
mac_zc_system_stop(zc_ctxt);
next_sm = MAC_ZC_SM_IDLE;
break;
default:
break;
}
return next_sm;
}
/* mac_zc train hw init or do gpio and signal mapping swap */
static mac_zc_sm_id_t mac_zc_sm_train_init_exec(mac_zc_ctxt_t *zc_ctxt,
mac_zc_triger_id_t trigger_id)
{
uint8_t phase_id;
mac_zc_sm_id_t next_sm = MAC_ZC_SM_TRAIN_INIT;
IOT_ASSERT(zc_ctxt);
switch (trigger_id) {
/* training timer timeout */
case MAC_ZC_TRIG_TRAIN_TIMER:
/* this timeout case come from MAC_ZC_SM_INITED's
* MAC_ZC_TRAIN_GEN_SW_MTX_MS
*/
if (MAC_ZC_SM_INITED == zc_ctxt->sm_info.exec_sm) {
for (phase_id = MAC_ZC_PHASE_A; phase_id < MAC_ZC_PHASE_CNT;
phase_id++) {
zc_ctxt->phase_info[phase_id].last_ts = 0;
zc_ctxt->phase_info[phase_id].last_switch_lts = 0;
}
mac_zc_repeat_phase_init(zc_ctxt);
/* config produce square wave base zc hw cap */
mac_zc_hw_gen_set_gen_sel_mtx(MAC_ZC_HW_GEN_SELIN_CAP0);
/* enable square wave upper bound interrupt. start collect */
mac_zc_upper_bound_intr_ena(zc_ctxt, 1);
/* for switch zc gen select to hw input, wait upper/low bound
* interrupt, if timeout, means cap0 map phase not zc,
* then need swich phase map(the next else_if case).
*/
mac_zc_train_timer_start(zc_ctxt, MAC_ZC_TRAIN_BOUND_INT_WAIT_MS);
} else if (MAC_ZC_SM_TRAIN_INIT == zc_ctxt->sm_info.exec_sm) {
/* collect timeout, switch phase map info */
/* disable square wave upper bound interrupt */
mac_zc_upper_bound_intr_ena(zc_ctxt, 0);
phase_id = mac_zc_get_swap_phase_id(zc_ctxt);
if (phase_id) {
mac_zc_exec_swap_phase_map(\
&zc_ctxt->nv_info.phase_map[phase_id & 0x0F], \
&zc_ctxt->nv_info.phase_map[phase_id >> 4]);
}
/* re-train */
next_sm = MAC_ZC_SM_INITED;
mac_zc_train_timer_start(zc_ctxt, MAC_ZC_TRAIN_FORCE_TIME_MS);
mac_zc_hw_capx_trig(MAC_ZC_HW_BITMAP_CAP_ALL);
}
#if (MAC_ZC_DBG_LOG_LEVEL >= 1)
else {
IOT_ASSERT_DUMP(0, (uint32_t *)zc_ctxt,
sizeof(*zc_ctxt)/sizeof(uint32_t));
}
#endif
break;
case MAC_ZC_TRIG_HW_UPPER_BOUND_INT:
#if (MAC_ZC_DBG_LOG_LEVEL >= 1)
/* check cap edge config matched current real cap edge. */
if (mac_zc_hw_get_curr_cap_edge() != mac_zc_hw_cap_get_edge()) {
/* TODO: only support phaseA */
iot_printf("[zc]get_cap_edge_not_match:%d:%d\n",
mac_zc_hw_get_curr_cap_edge(), mac_zc_hw_cap_get_edge());
}
#endif
/* stop this sm training timer when cap0 captured data */
mac_zc_train_timer_stop(zc_ctxt);
/* for all phase train fail or not train, set the all enable's
* phase is active to start training.
*/
mac_zc_all_phase_init_active_sts(zc_ctxt);
/* clear all phase collect counter */
mac_zc_phase_collect_cnt_clr(zc_ctxt, \
(uint8_t)((1 << MAC_ZC_PHASE_CNT) - 1));
/* force ref phase id set to cap0's phase.
* at this state, all the zc data is collected based on cap0.
*/
mac_zc_update_ref_phase_id(zc_ctxt, \
mac_zc_map_info_cap2phase(zc_ctxt, MAC_ZC_HW_CAP0));
/* if timeout, will entry this sm MAC_ZC_TRIG_TRAIN_TIMER */
mac_zc_train_timer_start(zc_ctxt, MAC_ZC_TRAIN_GEN_INTR_TIME_MS);
/* set next state */
next_sm = MAC_ZC_SM_TRAIN_BOUND_INTR_WAIT;
mac_zc_hw_capx_trig(MAC_ZC_HW_BITMAP_CAP_ALL);
break;
case MAC_ZC_TRIG_SYS_STOP_REQ:
mac_zc_system_stop(zc_ctxt);
next_sm = MAC_ZC_SM_IDLE;
break;
default:
break;
}
return next_sm;
}
/* mac_zc train zc collect in upper bound interrupt dsr */
static mac_zc_sm_id_t mac_zc_sm_train_bound_intr_wait_exec(
mac_zc_ctxt_t *zc_ctxt, mac_zc_triger_id_t trigger_id)
{
mac_zc_sm_id_t next_sm = MAC_ZC_SM_TRAIN_BOUND_INTR_WAIT;
uint8_t phase_id;
IOT_ASSERT(zc_ctxt);
switch (trigger_id) {
case MAC_ZC_TRIG_HW_UPPER_BOUND_INT:
if (MAC_ZC_TRAIN_SUCCESS == \
mac_zc_train_gen_bound_intr_process(zc_ctxt)) {
mac_zc_train_timer_stop(zc_ctxt);
phase_id = mac_zc_get_swap_phase_id(zc_ctxt);
#if (MAC_ZC_DBG_LOG_LEVEL >= 1)
iot_printf("[zc]get_swap_phase:%d-%d\n", \
phase_id & 0x0F, phase_id >> 4);
#endif
if (phase_id) {
/* TODO: maybe not need set next sm to MAC_ZC_SM_INITED.
* 1. not disable mac_zc_upper_bound_int_ena()
* 2. set zc_ctxt->train_collect_cnt, prev/ave_period....
* 3. retrain use current sm.
*/
mac_zc_exec_swap_phase_map(\
&zc_ctxt->nv_info.phase_map[phase_id & 0x0F],
&zc_ctxt->nv_info.phase_map[(phase_id >> 4) & 0x0F]);
/* re-train */
next_sm = MAC_ZC_SM_INITED;
mac_zc_train_timer_start(zc_ctxt, \
MAC_ZC_TRAIN_FORCE_TIME_MS);
} else {
/* not phase exchange, then goto next state */
/* disable upper bound interrupt, use systick tigger collect */
mac_zc_upper_bound_intr_ena(zc_ctxt, 0);
zc_ctxt->check_phase_bitmap = 0;
#if MAC_ZC_COLLECT_DEBUG_ENA
mac_zc_set_phase_bitmap(&zc_ctxt->bitmap_trace,
zc_ctxt->check_phase_bitmap, MAC_ZC_CALL_BOUND);
#endif
/* verify that all supported/enable phase have successfully
* trained. if all the phase are trained successfully, then the
* state go to MAC_ZC_SM_COLLECT, otherwise the state go to
* MAC_ZC_SM_TRAIN_SYSTICK_WAIT.
*/
for (phase_id = MAC_ZC_PHASE_A; phase_id < MAC_ZC_PHASE_CNT;
phase_id++) {
if (!mac_zc_phase_is_active(&zc_ctxt->phase_info[phase_id])
&& mac_zc_phase_is_support(zc_ctxt, phase_id)) {
/* support this phase, but inactive */
break;
}
}
/* update next state mechine */
if (zc_ctxt->nv_info.is_switch_gpio_clct) {
/* start switch gpio mapping to signal */
next_sm = MAC_ZC_SM_TRAIN_SYSTICK_WAIT;
} else if (phase_id < MAC_ZC_PHASE_CNT) {
/* some support phase train failed. systick wait sm train */
next_sm = MAC_ZC_SM_TRAIN_SYSTICK_WAIT;
} else {
/* all support phase train success, also need systick wait
* sm train, to avoid sw_period result influenced by a bad
* hw_period in MAC_ZC_SM_COLLECT state
*/
next_sm = MAC_ZC_SM_TRAIN_SYSTICK_WAIT;
}
/* clear all phase collect counter */
mac_zc_phase_collect_cnt_clr(zc_ctxt, \
(uint8_t)((1 << MAC_ZC_PHASE_CNT) - 1));
mac_zc_phase_collect_start(zc_ctxt);
/* enable systic trigger */
zc_ctxt->systic_trig_en = 1;
}
}
break;
/* train upper bound int timeout */
case MAC_ZC_TRIG_TRAIN_TIMER:
/* disable upper bound interrupt */
mac_zc_upper_bound_intr_ena(zc_ctxt, 0);
/* disable systic trigger */
zc_ctxt->systic_trig_en = 0;
/* re-train */
next_sm = MAC_ZC_SM_INITED;
mac_zc_train_timer_start(zc_ctxt, MAC_ZC_TRAIN_FORCE_TIME_MS);
break;
case MAC_ZC_TRIG_SYS_STOP_REQ:
mac_zc_system_stop(zc_ctxt);
next_sm = MAC_ZC_SM_IDLE;
break;
default:
break;
}
return next_sm;
}
/* mac_zc train zc collect function in systick interrupt dsr */
static mac_zc_sm_id_t mac_zc_sm_train_systick_wait_exec(mac_zc_ctxt_t *zc_ctxt,
mac_zc_triger_id_t trigger_id)
{
mac_zc_sm_id_t next_sm = MAC_ZC_SM_TRAIN_SYSTICK_WAIT;
IOT_ASSERT(zc_ctxt);
switch (trigger_id) {
case MAC_ZC_TRIG_SYSTIC_TIMER:
switch (mac_zc_train_systick_intr(zc_ctxt)) {
case MAC_ZC_TRAIN_SUCCESS:
/* init ctxt */
mac_zc_all_phase_abnormal_cnt_clr(zc_ctxt);
mac_zc_repeat_connect_check(zc_ctxt);
mac_zc_update_ref_phase_id(zc_ctxt, MAC_ZC_PHASE_ALL);
mac_zc_phase_collect_start(zc_ctxt);
/* set next state */
next_sm = MAC_ZC_SM_COLLECT;
break;
case MAC_ZC_TRAIN_ONGOING:
case MAC_ZC_TRAIN_FAIL:
default:
break;
}
/* enable systic trigger */
zc_ctxt->systic_trig_en = 1;
break;
case MAC_ZC_TRIG_SYS_STOP_REQ:
mac_zc_system_stop(zc_ctxt);
next_sm = MAC_ZC_SM_IDLE;
break;
default:
break;
}
return next_sm;
}
/* mac_zc collect execute function in state machine */
static mac_zc_sm_id_t mac_zc_sm_collect_exec(mac_zc_ctxt_t *zc_ctxt,
mac_zc_triger_id_t trigger_id)
{
mac_zc_sm_id_t next_sm = MAC_ZC_SM_COLLECT;
switch (trigger_id) {
case MAC_ZC_TRIG_SYSTIC_TIMER:
mac_zc_systick_collect(zc_ctxt);
mac_zc_update_dly_info(zc_ctxt);
/* enable systic trigger */
zc_ctxt->systic_trig_en = 1;
break;
case MAC_ZC_TRIG_SYS_STOP_REQ:
mac_zc_system_stop(zc_ctxt);
next_sm = MAC_ZC_SM_IDLE;
break;
default:
break;
}
return next_sm;
}
/* mac_zc collect state machine */
static void mac_zc_state_machine(mac_zc_ctxt_t *zc_ctxt,
mac_zc_triger_id_t trigger_id)
{
mac_zc_sm_id_t cur_sm, next_sm;
IOT_ASSERT(zc_ctxt);
cur_sm = (mac_zc_sm_id_t)zc_ctxt->sm_info.cur_sm;
#if (MAC_ZC_DBG_LOG_LEVEL >= 1)
iot_printf("[zc]sm:%d,trig:%d\n", cur_sm, trigger_id);
#endif
switch (cur_sm) {
case MAC_ZC_SM_IDLE:
next_sm = mac_zc_sm_idle_exec(zc_ctxt, trigger_id);
break;
case MAC_ZC_SM_INITED:
next_sm = mac_zc_sm_inited_exec(zc_ctxt, trigger_id);
break;
case MAC_ZC_SM_TRAIN_INIT:
next_sm = mac_zc_sm_train_init_exec(zc_ctxt, trigger_id);
break;
case MAC_ZC_SM_TRAIN_BOUND_INTR_WAIT:
next_sm = mac_zc_sm_train_bound_intr_wait_exec(zc_ctxt, trigger_id);
break;
case MAC_ZC_SM_TRAIN_SYSTICK_WAIT:
next_sm = mac_zc_sm_train_systick_wait_exec(zc_ctxt, trigger_id);
break;
case MAC_ZC_SM_COLLECT:
next_sm = mac_zc_sm_collect_exec(zc_ctxt, trigger_id);
break;
default:
IOT_ASSERT_DUMP(0, (uint32_t *)zc_ctxt, sizeof(*zc_ctxt));
next_sm = MAC_ZC_SM_IDLE;
break;
}
if (next_sm != cur_sm)
{
iot_printf("zc:state %d to %d.trig:%d, is_power_collapsed=%d\n",
(uint8_t)cur_sm, (uint8_t)next_sm, trigger_id,
mac_zc_is_power_collapsed((uint8_t)zc_ctxt->ref_pdev_id));
zc_ctxt->sm_info.prev_sm = (uint32_t)cur_sm;
zc_ctxt->sm_info.cur_sm = (uint32_t)next_sm;
/* trigger start system daemon function */
if (MAC_ZC_SM_COLLECT == next_sm) {
mac_zc_train_timer_stop(zc_ctxt);
zc_ctxt->train_elapsed_time = 0;
mac_zc_train_timer_start(zc_ctxt, MAC_ZC_SYS_DAEMON_PERIOD_MS);
}
}
zc_ctxt->sm_info.exec_sm = cur_sm;
}
/* mac_zc find target ntb position in phase ring and return valid ntb count */
static uint32_t mac_zc_get_ring_positon_by_ntb(mac_zc_ctxt_t *zc_ctxt,
uint8_t phase_id, uint32_t tgt_ntb, uint32_t *find_pos,
uint8_t is_half_clct, uint8_t edge_tp)
{
mac_zc_phase_info_t *phase_info = &zc_ctxt->phase_info[phase_id];
uint32_t find_cnt = 0;
uint32_t start_pos;
uint32_t end_pos;
uint32_t data_sz;
uint32_t wnd_st;
uint32_t wnd_end;
uint32_t mapped_idx;
uint32_t real_idx;
int32_t tmp_delta;
uint32_t search_wnd_half;
uint32_t period;
uint64_t start_ntb;
uint64_t end_ntb;
uint64_t mapped_tgt_ntb;
/* sanity check */
if (!phase_info || !find_pos || !phase_info->ntb_ring ||
(phase_info->ntb_ring_size > (((uint32_t)-1) / phase_info->period))) {
iot_printf("zc:find_ntb_dump: %p, %p, %p, %d\n", phase_info,
find_pos, phase_info->ntb_ring, phase_info->ntb_ring_size);
IOT_ASSERT(0);
return find_cnt;
}
if (!mac_zc_phase_is_support(zc_ctxt, phase_id) ||
(!phase_info->is_ring_full && !phase_info->write_idx)) {
return find_cnt;
}
/* calc period according to hw zc collect method */
period = (is_half_clct) ? (phase_info->period >> 1) : (phase_info->period);
search_wnd_half = mac_zc_get_ntb_search_window_half(period);
/* calc start position end position and valid data size */
start_pos = mac_zc_ring_get_first_idx(phase_info);
end_pos = mac_zc_ring_get_last_idx(phase_info);
data_sz = mac_zc_ring_get_valid_size(phase_info);
/* check if ntb wrap out , if so conpensate it */
start_ntb = phase_info->ntb_ring[start_pos];
end_ntb = phase_info->ntb_ring[end_pos];
mapped_tgt_ntb = tgt_ntb;
if (start_ntb > end_ntb) {
if (!(end_ntb & (1 << 31))) {
end_ntb |= ((uint64_t)0x1 << 32);
}
if (!(mapped_tgt_ntb & (1 << 31))) {
mapped_tgt_ntb |= ((uint64_t)0x1 << 32);
}
}
if ((mapped_tgt_ntb < start_ntb) || (mapped_tgt_ntb > end_ntb)) {
return find_cnt;
}
/* calc target ntb mapped index */
mapped_idx = (uint32_t)iot_ceil(((mapped_tgt_ntb -
phase_info->ntb_ring[start_pos]) * (data_sz - 1)),
(end_ntb - phase_info->ntb_ring[start_pos]));
#if MAC_ZC_DBG_LOG_LEVEL >= PLC_MAC_LOG_LEVEL_1
iot_printf("[zc]ring[%d]=%u, is_ring_full=%d\n", start_pos,
phase_info->ntb_ring[start_pos], phase_info->is_ring_full);
#endif
/* calc the seach window start position */
wnd_st = max(((int32_t)(mapped_idx - search_wnd_half)), 0);
wnd_end = min((mapped_idx + search_wnd_half), (data_sz - 1));
/* TODO: the size of the dump buffer needs to calculated based
* on the period
*/
/* buffer size = mac_zc_get_ntb_search_window_half(period) * 2 + 1 */
uint32_t dump_buf[13] = {0};
/* find target ntb in the seach window */
for (mapped_idx = wnd_st; mapped_idx < wnd_end; mapped_idx++) {
real_idx = mac_zc_ring_get_real_idx(mapped_idx, start_pos, data_sz);
if (is_half_clct && (mac_zc_get_ring_position_edge(real_idx)
!= edge_tp)) {
continue;
}
tmp_delta = (int32_t)(tgt_ntb - phase_info->ntb_ring[real_idx]);
dump_buf[((mapped_idx - wnd_st) >> is_half_clct)] =
phase_info->ntb_ring[real_idx];
if ((uint32_t)IOT_ABS(tmp_delta) < phase_info->period) {
*find_pos = real_idx;
find_cnt = data_sz - mapped_idx;
break;
}
}
dump_buf[sizeof(dump_buf)/sizeof(dump_buf[0]) - 1] = tgt_ntb;
IOT_ASSERT_DUMP(find_cnt, dump_buf, sizeof(dump_buf)/sizeof(uint32_t));
return find_cnt;
}
/* mac_zc get position from latest zc_ntb ring foreward by count */
static uint32_t mac_zc_get_position_by_count(mac_zc_phase_info_t *phase_info,
uint32_t tar_cnt, uint32_t *find_pos, uint8_t is_half_clct, uint8_t edge_tp)
{
uint32_t valid_cnt;
uint32_t tmp_tar_cnt;
valid_cnt = phase_info->is_ring_full ? phase_info->ntb_ring_size \
: phase_info->write_idx;
tmp_tar_cnt = is_half_clct ? (tar_cnt + 1) : tar_cnt;
if (tmp_tar_cnt > valid_cnt) {
*find_pos = mac_zc_ring_get_first_idx(phase_info);
} else {
*find_pos = (phase_info->ntb_ring_size + phase_info->write_idx \
- tmp_tar_cnt) % phase_info->ntb_ring_size;
}
if (is_half_clct && (mac_zc_get_ring_position_edge(*find_pos)
!= edge_tp)) {
*find_pos = mac_zc_ring_get_legal_idx(phase_info, (*find_pos) + 1);
if (valid_cnt) {
valid_cnt--;
}
}
if (valid_cnt > tar_cnt) {
valid_cnt = tar_cnt;
}
return valid_cnt;
}
/* copy ntb from assigned start position of ring buffer to rpt buffer */
static uint32_t mac_zc_get_ntb_from_phase_ring(mac_zc_ctxt_t *zc_ctxt,
uint32_t *rpt_buf, uint8_t get_phase_id, uint8_t is_full_period,
uint32_t count, uint32_t start_pos, uint8_t edge_type)
{
uint8_t phase_id, ref_phase, is_half_clct;
uint32_t tmp;
uint8_t phase_cnt;
uint32_t rpt_pos, ring_pos, find_cnt;
mac_zc_phase_info_t *phase_info[MAC_ZC_PHASE_CNT] = {0};
IOT_ASSERT(zc_ctxt);
if (0 == count) {
return 0;
}
/* get target phase, and save phase_info ptr to phase_info[].
* phase_id range: MAC_ZC_PHASE_A ~ MAC_ZC_PHASE_C
*/
phase_id = (uint8_t)((get_phase_id == MAC_ZC_PHASE_ALL) ? \
MAC_ZC_PHASE_A : get_phase_id);
phase_cnt = 0;
do {
if (mac_zc_phase_is_active(&zc_ctxt->phase_info[phase_id])) {
phase_info[phase_cnt++] = &zc_ctxt->phase_info[phase_id];
}
} while (++phase_id < get_phase_id);
if (!phase_cnt) {
/* valid phase count = 0, then return find 0 count zc ntb */
return 0;
}
ring_pos = start_pos;
ref_phase = (uint8_t)mac_zc_get_ref_phase_id(zc_ctxt);
is_half_clct = mac_zc_is_half_clct_state(zc_ctxt, ref_phase);
/* check the same edge offset base on ref phase */
if (is_half_clct && (mac_zc_get_ring_position_edge(ring_pos)
!= edge_type)) {
IOT_ASSERT(0);
}
rpt_pos = 0;
find_cnt = 0;
do {
/* phase_id range: 0 ~ (phase_cnt - 1) */
for (phase_id = 0; (phase_id < phase_cnt) && (find_cnt < count); \
phase_id++) {
rpt_buf[rpt_pos] = phase_info[phase_id]->ntb_ring[ring_pos];
#if (MAC_ZC_DBG_LOG_LEVEL >= 2)
iot_printf("[zc]cp_ring:phase=%d,rpt_buf[%u]<-ring[%u]=%u\n", \
phase_id, rpt_pos, ring_pos, rpt_buf[rpt_pos]);
#endif
find_cnt++;
/* get half collect value */
if (!is_full_period && !is_half_clct) {
if (find_cnt >= count) {
break;
}
tmp = mac_zc_ring_get_legal_idx(phase_info[phase_id], \
ring_pos + 1);
if ((rpt_pos + phase_cnt) < count) {
rpt_buf[rpt_pos + phase_cnt] = mac_zc_get_ntb_mid(\
phase_info[phase_id]->ntb_ring[ring_pos], \
phase_info[phase_id]->ntb_ring[tmp]);
#if (MAC_ZC_DBG_LOG_LEVEL >= 2)
iot_printf("[zc]cp_ring-half:phase=%d,"
"rpt_buf[%u]<-ring[%u]-ring[%u]=%u\n", \
phase_id, rpt_pos + phase_cnt, tmp, ring_pos, \
rpt_buf[rpt_pos + phase_cnt]);
#endif
find_cnt++;
}
}
/* update rpt_pos in the collect period */
rpt_pos++;
}
if (find_cnt >= count) {
break;
}
/* update rpt_pos for next collect period */
if (!is_full_period && !is_half_clct) {
rpt_pos += phase_cnt;
}
/* update ntb ring buffer position */
if (is_full_period && is_half_clct) {
ring_pos = mac_zc_ring_get_legal_idx(phase_info[0], ring_pos + 2);
} else {
ring_pos = mac_zc_ring_get_legal_idx(phase_info[0], ring_pos + 1);
}
} while (1);
/* rpt data dump and check phase diff */
#if (MAC_ZC_DBG_LOG_LEVEL >= 2)
iot_printf("zc_rpt_dump:\n");
for (uint32_t i = 0; i < find_cnt; i++) {
if (i && !(i % 3)) {
iot_printf("%u %u %u\n",
IOT_ABS((int32_t)(rpt_buf[i-2] - rpt_buf[i-3])),
IOT_ABS((int32_t)(rpt_buf[i-1] - rpt_buf[i-2])),
IOT_ABS((int32_t)(rpt_buf[i-1] - rpt_buf[i-3])));
}
iot_printf("%u ", rpt_buf[i]);
}
iot_printf("\n");
#endif
return find_cnt;
}
/* mac_zc copy real time ntb or history ntb to upper layer rpt buffer */
uint32_t mac_zc_get_ntb(uint8_t id, mac_zc_ntb_rpt_t *rpt,
uint16_t count, uint8_t is_full_period, uint8_t is_history_ntb,
uint32_t nid, uint32_t ntb)
{
#if (HW_PLATFORM >= HW_PLATFORM_FPGA)
uint32_t ret = ERR_OK;
uint32_t err_code = 0;
uint32_t find_cnt, find_pos;
uint8_t ref_phase_id, is_half_clct;
uint8_t edge_type = MAC_ZC_PLC_EDGE_DFT;
mac_zc_ctxt_t *zc_ctxt = mac_zc_ctxt_get(id);
#if (MAC_ZC_DBG_LOG_LEVEL >= 1)
iot_printf("[zc]get_para-cnt:%d,is_full:%d,is_his:%d,tar_nid:0x%x,"
"tar_ntb:%u,cur_ntb:%u\n",
count, is_full_period, is_history_ntb, nid, ntb,
mac_sched_get_ntb(NULL));
#endif
IOT_ASSERT(zc_ctxt && rpt);
if (!mac_zc_is_collecting(zc_ctxt)) {
ret = ERR_NOT_READY;
err_code = __LINE__;
goto out;
}
if (PLC_NID_INVALID != nid) {
if (is_history_ntb) {
/* convert neighbor nid history ntb to current nid ntb.
* neighbor nid -> my nid ntb */
if (ERR_OK != mac_other_ntb_to_myntb(id, (nid_t)nid, &ntb, 1)) {
ret = ERR_NOT_EXIST;
err_code = __LINE__;
goto out;
}
#if (MAC_ZC_DBG_LOG_LEVEL >= 1)
iot_printf("[zc]near_nid convert rst:ntb=%u\n", ntb);
#endif
}
}
/* get first valid phase id */
ref_phase_id = mac_zc_get_ref_phase_id(zc_ctxt);
/* get ref phase is half collect state */
is_half_clct = mac_zc_is_half_clct_state(zc_ctxt, ref_phase_id);
if (count && (MAC_ZC_PHASE_ALL != ref_phase_id)) {
/* get find count and find position base MAC_ZC_PHASE_A */
if (is_history_ntb) {
find_cnt = mac_zc_get_ring_positon_by_ntb(zc_ctxt, ref_phase_id,
ntb, &find_pos, is_half_clct, edge_type);
} else {
/* calculate ref phase find count */
/* zc full period collect but upper layer fetch half period data */
uint32_t collect_cnt;
if (!is_full_period && !is_half_clct) {
collect_cnt = (count >> 1) + 1;
/* zc half period collect but upper layer fetch full period data */
} else if (is_full_period && is_half_clct) {
collect_cnt = (count << 1);
}else {
collect_cnt = count;
}
/* base phase rpt count */
collect_cnt = iot_ceil(collect_cnt,
mac_zc_get_active_phase_cnt(zc_ctxt));
find_cnt = mac_zc_get_position_by_count(\
&zc_ctxt->phase_info[ref_phase_id], collect_cnt, &find_pos,
is_half_clct, edge_type);
}
} else {
/* for only get zc phase info(count == 0), or all the support phase
* inactive(MAC_ZC_PHASE_ALL = ref_phase_id), not search
*/
find_cnt = 0;
}
#if (MAC_ZC_DBG_LOG_LEVEL >= 1)
if (find_cnt) {
/* find success */
iot_printf("[zc]get_ntb.ok-find_cnt:%d,ntb[%d]=%u\n", \
find_cnt, find_pos, \
zc_ctxt->phase_info[ref_phase_id].ntb_ring[find_pos]);
} else {
/* find fail */
iot_printf("[zc]get_ntb.fail-");
if (mac_zc_phase_is_active(&zc_ctxt->phase_info[ref_phase_id])) {
iot_printf("nid:0x%x,widx=%d,last_ntb:%u,cur_ntb:%u\n", \
nid, zc_ctxt->phase_info[ref_phase_id].write_idx, \
zc_ctxt->phase_info[ref_phase_id].ntb_ring[\
mac_zc_ring_get_last_idx(\
&zc_ctxt->phase_info[ref_phase_id])],
mac_sched_get_ntb(NULL));
} else {
iot_printf("ref_phase inactive\n");
}
}
#endif
/* fill rpt info */
if (find_cnt) {
/* find cnt save base phase(single phase) find cnt */
/* calculate max rpt ntb count, save to tmp */
uint32_t max_rpt_cnt = find_cnt * mac_zc_get_active_phase_cnt(zc_ctxt);
if (!is_full_period && !is_half_clct) {
max_rpt_cnt <<= 1;
} else if (is_full_period && is_half_clct) {
max_rpt_cnt >>= 1;
}
/* calculate actual rpt count */
if (max_rpt_cnt > count) {
max_rpt_cnt = count;
}
/* copy ntb from ring buffer to rpt */
find_cnt = mac_zc_get_ntb_from_phase_ring(zc_ctxt, rpt->ntb, \
MAC_ZC_PHASE_ALL, is_full_period, max_rpt_cnt, find_pos, edge_type);
if (PLC_NID_INVALID != nid) {
if (ERR_OK != mac_myntb_to_other_ntb(id, nid, rpt->ntb, find_cnt)) {
ret = ERR_NOT_EXIST;
err_code = __LINE__;
goto out;
}
}
}
rpt->phase_a_valid = mac_zc_phase_is_active(
&zc_ctxt->phase_info[MAC_ZC_PHASE_A]);
rpt->phase_b_valid = mac_zc_phase_is_active(
&zc_ctxt->phase_info[MAC_ZC_PHASE_B]);
rpt->phase_c_valid = mac_zc_phase_is_active(
&zc_ctxt->phase_info[MAC_ZC_PHASE_C]);
rpt->phase_cnt = mac_zc_get_active_phase_cnt(zc_ctxt);
rpt->is_full_period = !!is_full_period;
rpt->ntb_cnt = find_cnt;
rpt->is_repeat_phase = mac_zc_is_repeat_connect(zc_ctxt);
rpt->phase_a_repeat = mac_zc_phase_id_zc2plc(
zc_ctxt->phase_info[MAC_ZC_PHASE_A].repeat_phase);
rpt->phase_b_repeat = mac_zc_phase_id_zc2plc(
zc_ctxt->phase_info[MAC_ZC_PHASE_B].repeat_phase);
rpt->phase_c_repeat = mac_zc_phase_id_zc2plc(
zc_ctxt->phase_info[MAC_ZC_PHASE_C].repeat_phase);
for (uint8_t i = MAC_ZC_PHASE_A;
i < min(MAC_ZC_PHASE_CNT, sizeof(rpt->avg_period) /
sizeof(rpt->avg_period[0]));
i++) {
rpt->avg_period[i] = zc_ctxt->phase_info[i].period;
}
out:
iot_printf("zc:rpt-%d:%u.cnt-%d:%d,v-%d:%d:%d,full=%d,repeat:%d,cur:%u\n",
ret, err_code, rpt->phase_cnt, rpt->ntb_cnt,
rpt->phase_a_valid, rpt->phase_b_valid, rpt->phase_c_valid,
rpt->is_full_period, rpt->is_repeat_phase, mac_sched_get_ntb(NULL));
if (rpt->ntb_cnt) {
iot_printf("ntb=%u:%u\n",
rpt->ntb[0], rpt->ntb[rpt->ntb_cnt - 1]);
}
return ret;
#else //HW_PLATFORM >= HW_PLATFORM_FPGA
uint32_t size, ntb_cnt, phase_id;
(void)id;
(void)nid; //TODO: maybe need support in simulator
mac_zc_ctxt_t *zc_ctxt = mac_zc_ctxt_get(id);
if (NULL == rpt) {
return ERR_INVAL;
}
//for simulator, cvg alloc pkt must be phase aligment
if (count) {
ntb_cnt = count % (is_full_period ? 3 : 6);
if (ntb_cnt) {
ntb_cnt = count + ((is_full_period ? 3 : 6) - ntb_cnt);
} else {
ntb_cnt = count;
}
/* get start position zc ntb */
if (is_history_ntb) {
/* get history ntb */
rpt->ntb[0] = ntb;
} else {
/* get current ntb */
size = (is_full_period ? count : ((count - (count % 3)) >> 1)) / 3;
rpt->ntb[0] = (uint32_t)(mac_sched_get_ntb(NULL) \
- (MAC_ZC_ALL_PHASE_GOLDON_GAP_NTB * size));
}
if (is_full_period) {
for (size = 1; size < ntb_cnt; size++) {
rpt->ntb[size] = rpt->ntb[size - 1] + 166666;
}
} else {
if (ntb_cnt > 3) {
rpt->ntb[3] = rpt->ntb[0] + 83333;
}
for (size = 1; size < ntb_cnt;) {
rpt->ntb[size] = rpt->ntb[size - 1] + 166666;
if ((size + 3) < ntb_cnt) {
rpt->ntb[size + 3] = rpt->ntb[size] + 83333;
}
size++;
if (0 == (size % 3)) {
size += 3;
}
}
}
}
rpt->ntb_cnt = count;
rpt->phase_cnt = 3;
rpt->phase_a_valid = true;
rpt->phase_b_valid = true;
rpt->phase_c_valid = true;
rpt->is_full_period = !!is_full_period;
rpt->is_repeat_phase = mac_zc_is_repeat_connect(zc_ctxt);
for (phase_id = MAC_ZC_PHASE_A;
phase_id < min(MAC_ZC_PHASE_CNT, sizeof(rpt->avg_period) /
sizeof(rpt->avg_period[0]));
phase_id++) {
rpt->avg_period[phase_id] = zc_ctxt->phase_info[phase_id].period;
}
return ERR_OK;
#endif
}
static void IRAM_ATTR mac_zc_switch_map_gpio(mac_zc_phase_info_t *phs_info,
mac_zc_hw_map_info_t *hw_map)
{
uint32_t current_lts, current_ts;
uint32_t abs_lts, min_period, periods, ahead_ts;
IOT_ASSERT(phs_info && hw_map);
current_lts = mac_sched_get_lts();
current_ts = mac_sched_get_ntb(NULL);
min_period = phs_info->period >> 1;
/* phase inactive dont't switch gpio */
if (!mac_zc_phase_is_active(phs_info)) {
phs_info->last_switch_lts = 0;
return;
}
if (!phs_info->last_switch_lts) {
phs_info->last_switch_lts = phs_info->last_ts +
(current_lts - current_ts) - MAC_ZC_SW_GPIO_AHEAD_NTB;
}
abs_lts = (uint32_t)(current_lts - phs_info->last_switch_lts);
if (abs_lts >= min_period) {
periods = abs_lts / min_period;
ahead_ts = abs_lts % min_period;
if ((periods & 0x01) && (ahead_ts <= MAC_ZC_SW_GPIO_AHEAD_NTB)) {
if ((uint32_t)(current_ts - phs_info->last_ts) < min_period) {
phs_info->last_switch_lts = phs_info->last_ts +
(current_lts - current_ts) + min_period
- MAC_ZC_SW_GPIO_AHEAD_NTB;
} else {
phs_info->last_switch_lts += (periods * min_period);
}
#if HW_PLATFORM >= HW_PLATFORM_FPGA
/* switch gpio mapping to sig */
uint8_t current_gpio = gpio_mtx_sig_in_get_gpio(hw_map->signal);
if (current_gpio == hw_map->gpio) {
mac_zc_hw_fix_map_gpio2sig(hw_map->gpio_ext, hw_map->signal);
} else if (current_gpio == hw_map->gpio_ext) {
mac_zc_hw_fix_map_gpio2sig(hw_map->gpio, hw_map->signal);
} else {
IOT_ASSERT(0);
}
#endif
}
}
}
static void mac_dsr_zc_upper_bound(void)
{
uint8_t i;
mac_zc_ctxt_t *zc_ctxt;
for(i = 0; i < MAC_ZC_NUM_MAX; i++) {
zc_ctxt = mac_zc_ctxt_get(i);
if (zc_ctxt) {
mac_zc_state_machine(zc_ctxt, MAC_ZC_TRIG_HW_UPPER_BOUND_INT);
}
}
}
/* mac_zc update need check phase bitmap and set systick dsr */
void IRAM_ATTR mac_zc_systic_trig(void)
{
uint8_t i, phase_id, phase_bitmap, is_half_clct, is_power_collapse;
mac_zc_ctxt_t *zc_ctxt;
mac_zc_phase_info_t *phase_info;
for(i = 0; i < MAC_ZC_NUM_MAX; i++) {
zc_ctxt = mac_zc_ctxt_get(i);
if (!zc_ctxt) {
continue;
}
phase_bitmap = 0;
is_power_collapse = mac_zc_is_power_collapsed(i);
/* power collapsed status, only check reference phase */
for (phase_id = is_power_collapse ? \
(uint8_t)mac_zc_get_ref_phase_id(zc_ctxt) : MAC_ZC_PHASE_A;
phase_id < MAC_ZC_PHASE_CNT; \
phase_id++) {
phase_info = &zc_ctxt->phase_info[phase_id];
/* switch gpio mapping */
if (zc_ctxt->nv_info.is_switch_gpio_clct &&
zc_ctxt->sm_info.cur_sm >= MAC_ZC_SM_TRAIN_SYSTICK_WAIT &&
mac_zc_phase_is_support(zc_ctxt, phase_id)) {
mac_zc_switch_map_gpio(phase_info,
&zc_ctxt->nv_info.phase_map[phase_id]);
}
if ((!is_power_collapse) && (!mac_zc_phase_is_active(phase_info) \
|| (!mac_zc_phase_is_support(zc_ctxt, phase_id)))) {
continue;
}
is_half_clct = mac_zc_is_half_clct_state(zc_ctxt, phase_id);
if (zc_ctxt->systic_trig_en && phase_info->last_ts &&
phase_info->period && ((uint32_t)(mac_sched_get_ntb(NULL) -
phase_info->last_ts) > ((phase_info->period >> is_half_clct)
+ MAC_ZC_HW_CAP_INT_PROTECT_NTB))) {
phase_bitmap |= (uint8_t)(1 << phase_id);
}
if (is_power_collapse) {
break;
}
}
if (phase_bitmap && zc_ctxt->nv_info.hdl) {
zc_ctxt->systic_trig_en = 0;
zc_ctxt->check_phase_bitmap |= (uint32_t)phase_bitmap;
#if MAC_ZC_COLLECT_DEBUG_ENA
mac_zc_set_phase_bitmap(&zc_ctxt->bitmap_trace,
zc_ctxt->check_phase_bitmap, MAC_ZC_CALL_SYSTIC);
#endif
os_set_task_event_with_v_from_isr( \
zc_ctxt->nv_info.hdl, \
(uint32_t)(0x1 << MAC_DSR_ZC_SYSTIC_TRIG_CB_ID));
}
}
}
void mac_zc_train_hw_timeout_internal(uint32_t id, void *arg)
{
mac_zc_ctxt_t *zc_ctxt = (mac_zc_ctxt_t *)arg;
(void)id;
#if (MAC_ZC_DBG_LOG_LEVEL >= 1)
iot_printf("[zc]train_elapsed:%d\n", zc_ctxt->train_elapsed_time);
#endif
if (mac_zc_is_collecting(zc_ctxt)) {
/* system collecting, background check system running satus. */
if (ERR_OK == mac_zc_system_status_check(zc_ctxt)) {
zc_ctxt->train_elapsed_time = 0;
}
#if MAC_ZC_SYS_DAEMON_RESET_ENA
if (zc_ctxt->train_elapsed_time > MAC_ZC_SYS_DAEMON_TIMEOUT_MS) {
iot_printf("zc:daemon timeout.%d\n", zc_ctxt->train_elapsed_time);
zc_ctxt->train_elapsed_time = 0;
mac_zc_state_machine(zc_ctxt, MAC_ZC_TRIG_SYS_STOP_REQ);
mac_zc_train_timer_start(zc_ctxt, MAC_ZC_TRAIN_FORCE_TIME_MS);
} else
#endif
{
/* continue to trigger the timer */
mac_zc_train_timer_start(zc_ctxt, MAC_ZC_SYS_DAEMON_PERIOD_MS);
}
} else {
/* system training */
if (zc_ctxt->train_elapsed_time > MAC_ZC_TRAIN_TIMEOUT_MS) {
iot_printf("zc:train timeout.%d\n", zc_ctxt->train_elapsed_time);
mac_zc_state_machine(zc_ctxt, MAC_ZC_TRIG_SYS_STOP_REQ);
mac_zc_all_phase_set_collet_default_sts(zc_ctxt);
mac_zc_train_timer_start(zc_ctxt, MAC_ZC_TRAIN_RESTART_DELAY_MS);
/* Note: must be clear train_elapsed_time after start train timer.*/
zc_ctxt->train_elapsed_time = 0;
} else {
mac_zc_state_machine(zc_ctxt, MAC_ZC_TRIG_TRAIN_TIMER);
}
}
}
void mac_zc_train_hw_timeout(timer_id_t timer_id, void *arg)
{
(void)timer_id;
mac_msg_t *msg = mac_alloc_msg();
if (msg == NULL) {
IOT_ASSERT(0);
return;
}
msg->type = MAC_MSG_TYPE_TIMER;
msg->id = MAC_MSG_ID_ZC_TRAIN_HW_TIMER;
msg->data1 = (uint32_t)timer_id;
msg->data2 = arg;
mac_queue_msg(msg, MAC_MSG_QUEUE_HP);
}
void mac_zc_set_func_cmd_internal(uint8_t zc_id, uint8_t cmd, void *arg)
{
(void)arg;
mac_zc_ctxt_t *zc_ctxt;
zc_ctxt = mac_zc_ctxt_get(zc_id);
IOT_ASSERT(zc_ctxt);
switch((mac_zc_func_cmd_id_t)cmd) {
case MAC_ZC_FUNC_CMD_DELAY_RESET_HW:
/* stop mac zc system */
mac_zc_state_machine(zc_ctxt, MAC_ZC_TRIG_SYS_STOP_REQ);
/* start mac zc system */
mac_zc_state_machine(zc_ctxt, MAC_ZC_TRIG_SYS_START_REQ);
mac_status_add_zc_reset_hw_cnt();
break;
default:
break;
}
}
void mac_zc_set_func_cmd(uint8_t zc_id, mac_zc_func_cmd_id_t cmd, void *arg)
{
#if (HW_PLATFORM >= HW_PLATFORM_FPGA)
mac_zc_ctxt_t *zc_ctxt;
mac_msg_t *msg = NULL;
(void)arg;
zc_ctxt = mac_zc_ctxt_get(zc_id);
IOT_ASSERT(zc_ctxt);
iot_printf("zc:set_cmd-%u\n", cmd);
switch ((mac_zc_func_cmd_id_t)cmd) {
case MAC_ZC_FUNC_CMD_RESET_HW:
/* stop mac zc system */
mac_zc_state_machine(zc_ctxt, MAC_ZC_TRIG_SYS_STOP_REQ);
/* start mac zc system */
mac_zc_state_machine(zc_ctxt, MAC_ZC_TRIG_SYS_START_REQ);
mac_status_add_zc_reset_hw_cnt();
break;
case MAC_ZC_FUNC_CMD_COLLECT_STOP:
mac_zc_state_machine(zc_ctxt, MAC_ZC_TRIG_SYS_STOP_REQ);
break;
case MAC_ZC_FUNC_CMD_DELAY_RESET_HW:
msg = mac_alloc_msg();
if (msg) {
msg->type = MAC_MSG_TYPE_MAC;
msg->id = MAC_MSG_ID_MAC_ZC_SET_FUNC_CMD;
msg->data1 = zc_id | (cmd << 8);
msg->data2 = arg;
mac_queue_msg(msg, MAC_MSG_QUEUE_HP);
} else {
IOT_ASSERT(0);
}
break;
default:
break;
}
#else
(void)zc_id;
(void)cmd;
(void)arg;
#endif
}
uint8_t IRAM_ATTR mac_zc_is_power_collapsed(uint8_t pdev_id)
{
mac_zc_ctxt_t *zc_ctxt = mac_zc_ctxt_get(pdev_id);
if (zc_ctxt && mac_zc_is_collecting(zc_ctxt)) {
return (!mac_zc_get_active_phase_cnt(zc_ctxt));
}
return 0;
}
void mac_dsr_zc_systic_trig_cb(void)
{
uint8_t i;
mac_zc_ctxt_t *zc_ctxt;
for(i = 0; i < MAC_ZC_NUM_MAX; i++) {
zc_ctxt = mac_zc_ctxt_get(i);
if (zc_ctxt) {
mac_zc_state_machine(zc_ctxt, MAC_ZC_TRIG_SYSTIC_TIMER);
}
}
}
#endif //MAC_ZC_ENABLE
//TODO: will move into MAC_ZC_ENABLE
uint32_t mac_zc_system_init(uint8_t id, void *task_hdl, void *dsr_tbl,
void *dsr_set_fn, void *dsr_clr_fn)
{
#if MAC_ZC_ENABLE
uint32_t size;
mac_zc_ctxt_t *zc_ctxt;
iot_printf("zc:sys_init-%d.[%u]\n", id, mac_sched_get_ntb(NULL));
if (id >= MAC_ZC_NUM_MAX) {
return ERR_INVAL;
}
zc_ctxt = mac_zc_ctxt_get(id);
if (NULL == zc_ctxt) {
IOT_ASSERT(zc_ctxt);
return ERR_INVAL;
}
/* clean zc ctxt data */
os_mem_set(zc_ctxt, 0, sizeof(*zc_ctxt));
zc_ctxt->ref_pdev_id = id;
switch (iot_oem_get_module_type()) {
case MODULE_TYPE_CCO:
BUILD_BUG_ON(MAC_ZC_NTB_SUPPORT_CNT_CCO <= MAC_ZC_BUF_SIZE_MAX_CCO);
size = MAC_ZC_NTB_SUPPORT_CNT_CCO;
break;
case MODULE_TYPE_3_PHASE_STA:
BUILD_BUG_ON(MAC_ZC_NTB_SUPPORT_CNT_STA_3P
<= MAC_ZC_BUF_SIZE_MAX_STA_3P);
if (iot_board_get_tsfm_mode() == HW_REC_MODE_WQ) {
#if RUN_IN_PSRAM
size = MAC_ZC_NTB_SUPPORT_CNT_STA_3P;
#else
size = MAC_ZC_NTB_SUPPORT_CNT_STA;
#endif
} else {
size = MAC_ZC_NTB_SUPPORT_CNT_STA_3P;
}
break;
default:
BUILD_BUG_ON(MAC_ZC_NTB_SUPPORT_CNT_STA <= MAC_ZC_BUF_SIZE_MAX_STA);
size = MAC_ZC_NTB_SUPPORT_CNT_STA;
break;
}
/* alloc zc ring buffer */
if (NULL == zc_ctxt->ring) {
zc_ctxt->ring = os_mem_malloc(PLC_MAC_ZC_MID, size * sizeof(uint32_t));
if (NULL == zc_ctxt->ring) {
/* memory must be allocated successfully */
IOT_ASSERT(0);
return ERR_NOMEM;
}
} else {
IOT_ASSERT(0);
}
zc_ctxt->ring_sz = size;
/* init task & dsr ctxt config */
zc_ctxt->nv_info.hdl = task_hdl;
zc_ctxt->nv_info.dsr_tbl = dsr_tbl;
zc_ctxt->nv_info.dsr_set_entry = \
(mac_zc_dsr_set_entry_fn_t)dsr_set_fn;
zc_ctxt->nv_info.dsr_clr = (mac_zc_dsr_clr_fn_t)dsr_clr_fn;
/* register mac zc systick dsr */
if (dsr_tbl && dsr_set_fn) {
zc_ctxt->nv_info.dsr_set_entry(zc_ctxt->nv_info.dsr_tbl,
(uint8_t)MAC_DSR_ZC_SYSTIC_TRIG_CB_ID,
(void *)mac_dsr_zc_systic_trig_cb);
}
/* init timer */
//TODO: mm_mode use message, ftm_mode use timer callback
zc_ctxt->timer_train = os_create_timer(PLC_MAC_ZC_MID, 0,
(os_timer_func_t)mac_zc_train_hw_timeout, zc_ctxt);
if (!zc_ctxt->timer_train) {
IOT_ASSERT(0);
return ERR_NOMEM;
}
/* update default support phase bitmap */
mac_zc_load_oem_info(zc_ctxt);
/* stop zc system */
mac_zc_system_stop(zc_ctxt);
/* clean train elapsed time ctxt */
//TODO: maybe move to mac_zc_system_stop()???
zc_ctxt->train_elapsed_time = 0;
/* init ring */
mac_zc_phase_info_init(zc_ctxt);
zc_ctxt->sm_info.prev_sm = MAC_ZC_SM_IDLE;
zc_ctxt->sm_info.cur_sm = MAC_ZC_SM_IDLE;
return ERR_OK;
#else
(void)task_hdl;
(void)dsr_tbl;
(void)dsr_set_fn;
(void)dsr_clr_fn;
iot_printf("zc:sys_init-%d.[%u]\n", id, mac_sched_get_ntb(NULL));
return ERR_NOSUPP;
#endif
}