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

2887 lines
89 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_status.h"
#include "iot_bitops_api.h"
#include "iot_bitmap_api.h"
#include "iot_board_api.h"
#include "gpio_mtx.h"
#include "mac_zc_hw.h"
#include "mac_zc.h"
#include "iot_dbglog_parser.h"
#include "iot_dbglog_api.h"
#if HPLC_RF_DEV_SUPPORT
#include "mac_rf_common_hw.h"
#endif
/* mac zc system debug log level, 0 - disable, others: enable */
#define MAC_ZC_DBG_LOG_LEVEL 1
/* mac zc system self map signal and gpio */
#define MAC_ZC_SELF_MAP_GPIO_ENA 1
/* report repeat collect/phase ntb */
#define MAC_ZC_GET_RPT_REPEAT_ENA 0
/* each capture sw fifo buffer size, unit: 4byte */
#define MAC_ZC_CAP_SW_FIFO_SIZE 100
#define MAC_ZC_COLLECT_BUF_SIZE MAC_ZC_CAP_SW_FIFO_SIZE
/* the max gap between two period allowed, unit: ntb */
#define MAC_ZC_PERIOD_JITTER_GAP_NTB 12500
/* default period goldon gap ntb = 20ms */
#define MAC_ZC_PERIOD_DEF_GOLDON_GAP_NTB 500000
/* systick interval period count */
#define MAC_ZC_SYSTICK_PERIOD_CNT 1
/* success collect count */
#define MAC_ZC_COLLECT_SUCCESS_CNT 32
/* success collect margin count */
#define MAC_ZC_COLLECT_SUCCESS_MARGIN 8
/* loss collect margin count */
#define MAC_ZC_COLLECT_LOSS_MARGIN 4
/* get ntb search max count base on reference index */
#define MAC_ZC_SEARCH_MAX_CNT 7
/* in order to ensure that the first effective phase line is always used
* as the reference phase line, some adjustment may be required for the
* starting reporting position of the non reference phase line, so as
* to ensure that the first NTB sample is always after the first sample
* of the reference phase line.
* here, the maximum allowable adjustment distance of the starting position
* of the non reference phase line is defined
*/
#define MAC_ZC_NO_REF_PHASE_START_MAX_ADJ_CNT 2
/* update ntb and local ts convert info period (ring write count) */
#define MAC_ZC_NTB_LTS_RECORD_W_CNT_SHITF (7)
#define MAC_ZC_NTB_LTS_RECORD_W_CNT \
(1 << MAC_ZC_NTB_LTS_RECORD_W_CNT_SHITF)
/* convert local timestamp to ntb timestamp max ppm */
#define MAC_ZC_CONVERT_TS_PPM_MAX 50
/* lts to ntb write flashlog count max */
#define MAC_ZC_LTS_TO_NTB_LOG_CNT_MAX 3
/* mac zc system state machine running tirger event id */
typedef enum _mac_zc_trigger_id {
/* trigger id for start zc system request */
MAC_ZC_TRIG_SYS_START_REQ = 0,
/* trigger id for stop zc system request */
MAC_ZC_TRIG_SYS_STOP_REQ = 1,
/* trigger id for systick interrupt */
MAC_ZC_TRIG_SYSTICK_INT = 2,
/* trigger id max */
MAC_ZC_TRIG_MAX = 3,
} mac_zc_trigger_id_t;
/* mac zc system state machine id */
typedef enum _mac_zc_state_id {
/* state for system idle state */
MAC_ZC_STATE_IDLE = 0,
/* state for training and wait for system to stabilize */
MAC_ZC_STATE_TRAINING = 1,
/* state for train successful */
MAC_ZC_STATE_TRAINED = 2,
/* state for collecting */
MAC_ZC_STATE_COLLECT = 3,
/* state id max */
MAC_ZC_STATE_MAX = 4,
} mac_zc_state_id_t;
/* mac zc state machine info */
typedef struct _mac_zc_sm_info {
/* mac zc prev state id */
mac_zc_state_id_t prev_state;
/* mac zc current state id */
mac_zc_state_id_t cur_state;
} mac_zc_sm_info_t;
typedef struct _mac_zc_map_info {
/* capture id */
uint8_t cap_id;
/* plc phase id */
uint8_t phase_id;
/* hw gpio id */
uint8_t gpio;
/* is extern phase gpio */
uint8_t is_ext;
} mac_zc_map_info_t;
typedef struct _mac_zc_pre_update_info {
/* current period */
uint32_t period : 24,
/* int8_t */
collect_cnt : 8;
/* last collect ts before upate */
uint32_t last_ts;
/* current update write last ts */
uint32_t cur_last_ts;
/* current ring write index */
uint16_t ring_wr_idx;
/* indicate collect valid */
uint16_t is_collect : 1,
/* reserved */
rsvd : 15;
} mac_zc_pre_update_info_t;
typedef struct _mac_zc_daemon_info {
/* all of active collect last timestamp */
uint32_t last_collect_ts;
/* enter collect update timestamp */
uint32_t enter_collect_ts;
/* exit collect update timestamp */
uint32_t exit_collect_ts;
/* collect updata reload count */
uint8_t collect_reload_cnt;
/* lts to ntb write flash log count */
uint8_t lts_to_ntb_log_cnt;
/* reserved */
uint16_t rsvd;
/* daemon pre update collect information */
mac_zc_pre_update_info_t pre_info[MAC_ZC_HW_CAP_CNT];
} mac_zc_daemon_info_t;
typedef struct _mac_zc_hook_ctxt {
/* 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;
} mac_zc_hook_ctxt_t;
typedef struct _mac_zc_nv_info {
/* indicate support capture bitmap */
uint16_t ena_cap_bitmap : 6,
/* indicate input chip hw capture edge, the board hardware will convert all
* the signals input to the chip to the same edge.
*/
cap_edge : 1,
/* indicate use 2 hw capture collect 1 phase double edge */
is_double_collect : 1,
/* indicate collect base on ntb fifo or local fifo */
is_ntb_collect : 1,
/* reserved */
rsvd : 7;
/* collect buffer size, unit: 4byte */
uint16_t buf_sz;
/* save collect data */
uint32_t *buffer;
/* mac zc system mapping */
mac_zc_map_info_t map[MAC_ZC_HW_CAP_CNT];
} mac_zc_nv_info_t;
typedef struct _mac_zc_ring_ctxt {
/* ring buffer address */
uint32_t *buf;
/* ring buffer write index */
uint16_t wr_idx;
/* ring buffer size, unit: 4byte */
uint16_t size : 15,
/* indicate the ring buffer is full wrap */
is_full : 1;
/* wirte bitmap byte size */
uint16_t wr_bm_sz;
/* zc ring id */
uint16_t ring_id : 3,
/* reserved */
rsvd : 13;
/* write buffer valid data bitmap */
uint8_t *wr_bitmap;
} mac_zc_ring_ctxt_t;
typedef struct _mac_zc_sw_fifo_ctxt {
/* fifo buffer */
uint32_t *buf;
/* fifo size */
uint8_t size;
/* fifo write index */
uint8_t wr_idx;
/* fifo read index */
uint8_t rd_idx;
/* indicate write overflow */
uint8_t is_overflow : 1,
/* reserved */
rsvd : 7;
} mac_zc_sw_fifo_ctxt_t;
typedef struct _mac_zc_collect_info {
/* collect period, unit: 1ntb */
uint32_t period : 24,
/* indicate the phase collect status */
is_collect : 1,
/* reuse for collect count */
collect_cnt : 7;
/* indicate repeat cap id, if value is self cap id, indicate no repeat
* connect.
*/
uint32_t repeat_id : 3,
/* reserved */
rsvd : 29;
/* last collect timestamp */
uint32_t last_ts;
/* ring context */
mac_zc_ring_ctxt_t ring;
/* capture sw fifo */
mac_zc_sw_fifo_ctxt_t ntb_fifo;
} mac_zc_collect_info_t;
typedef struct _mac_zc_systick_info {
/* systick check period, unit: 1ntb */
uint32_t check_period : 24,
/* indicate systick check enable or disable */
is_ena : 1,
/* reserved */
rsvd : 7;
/* systick last entry ts, unit: 1ntb */
uint32_t ts;
/* systick isr collect temp buffer */
uint32_t isr_buf[MAC_ZC_HW_CAP_BUF_DEPTH];
} mac_zc_systick_info_t;
typedef struct _mac_zc_ntb_lts_record_info {
/* beacon rx local timestamp */
uint32_t bcn_rx_lts;
/* beacon remote tx ntb */
uint32_t bcn_tx_ntb;
/* ntb ppm, unit: 1/(1 << PLC_NTB_PPM_SHIFT) */
int16_t ntb_ppm;
/* current record plc ppm is valid or not */
uint16_t is_plc_valid : 1,
/* current record rf ppm is valid or not */
is_rf_valid : 1,
/* reserved */
rsvd : 14;
} mac_zc_ntb_lts_record_t;
typedef struct _mac_zc_ntb_lts_sync_info {
/* record info number */
uint16_t num : 15,
/* indicate ntb lts sync start or stop */
is_start : 1;
/* current record index */
uint16_t cur_idx;
/* ntb and local ts convert infomation */
mac_zc_ntb_lts_record_t *record;
} mac_zc_ntb_lts_sync_info_t;
typedef struct _mac_zc_ctxt {
/* indicate pdev id */
uint8_t ref_pdev_id : 2,
/* indicate mac zc power state */
is_power_collapsed : 1,
/* reserved */
rsvd0 : 5;
/* reserved */
uint8_t rsvd1;
/* reserved */
uint16_t rsvd2;
/* collect temp buffer */
uint32_t collect_buf[MAC_ZC_COLLECT_BUF_SIZE];
/* systick callback ctxt info */
mac_zc_systick_info_t systick;
/* mac zc system hook context */
mac_zc_hook_ctxt_t hook;
/* mac zc system nv info */
mac_zc_nv_info_t nv;
/* mac zc state information context */
mac_zc_sm_info_t sm;
/* mac zc system daemon context */
mac_zc_daemon_info_t daemon;
/* mac zc collect ntb and local ts sync information */
mac_zc_ntb_lts_sync_info_t ntb_lts_sync;
/* mac zc capture collect conetext */
mac_zc_collect_info_t collect[MAC_ZC_HW_CAP_CNT];
} mac_zc_ctxt_t;
/* 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 ctxt: mac zc ctxt ptr
* @retval: 1 - collecting, 0 - not collecting
*/
#define mac_zc_is_collecting(ctxt) \
(((mac_zc_ctxt_t *)(ctxt))->sm.cur_state == MAC_ZC_STATE_COLLECT)
/* get hw capture support bitmap */
#define mac_zc_cap_support_bm_get(ctxt) \
(((mac_zc_ctxt_t *)(ctxt))->nv.ena_cap_bitmap)
/* get cap_id is support */
#define mac_zc_cap_is_support(ctxt, cap_id) \
(0 != (mac_zc_cap_support_bm_get(ctxt) & (1 << (cap_id))))
/* update collect average period */
#define mac_zc_period_update(src, update) \
((src) - ((src) >> 3) + ((update) >> 3))
#define mac_zc_phase_cap_to_ext(cap_id) \
((cap_id) + MAC_ZC_PHASE_CNT)
#define mac_zc_phase_cap_is_ext(cap_id) \
(((cap_id) >= MAC_ZC_PHASE_CNT))
#define mac_zc_phase_ext_to_cap(cap_ext_id) \
((cap_ext_id) - MAC_ZC_PHASE_CNT)
#define mac_zc_cap_id_to_phase(ctxt, cap_id) \
(((mac_zc_ctxt_t *)(ctxt))->nv.map[cap_id].phase_id)
#define mac_zc_cap_is_repeat(ctxt, cap_id) \
((((mac_zc_ctxt_t *)(ctxt))->collect[cap_id].repeat_id) != (cap_id))
#define mac_zc_phase_id_zc_to_plc(id) \
((id) - MAC_ZC_PHASE_A + PLC_PHASE_A)
#if MAC_ZC_ENABLE
static mac_zc_ctxt_t g_mac_zc_ctxt[MAC_ZC_NUM_MAX] = {0};
static void mac_zc_state_machine(mac_zc_ctxt_t *ctxt,
mac_zc_trigger_id_t trig_id);
#if (MAC_ZC_DBG_LOG_LEVEL >= 2)
void mac_zc_dbg_collect_print(uint8_t cap_id, uint8_t num, uint32_t *buf)
{
uint8_t i;
if ((0 == num) || !buf) {
return;
}
iot_printf("[zc]cap-%d,num-%d,lts=%u,ntb=%u,buf: ",
cap_id, num, mac_sched_get_lts(), mac_sched_get_ntb(NULL));
for (i = 0; i < num; i++) {
iot_printf("%u, ", buf[i]);
if (i > 0) {
uint32_t delta = (uint32_t)(buf[i] - buf[i - 1]);
if (delta > (MAC_ZC_PERIOD_DEF_GOLDON_GAP_NTB
+ MAC_ZC_PERIOD_JITTER_GAP_NTB)) {
iot_printf("\n!!!!error, %u\n", delta);
}
}
}
iot_printf("\n");
}
#else
#define mac_zc_dbg_collect_print(cap_id, num, buf)
#endif
/* return ntb is larger than base_ntb.
* 1 - ntb > base_ntb, 0 - ntb <= base_ntb
*/
static uint8_t mac_zc_ntb_is_larger_base(uint32_t base_ntb, uint32_t ntb)
{
int32_t delta;
delta = (int32_t)(ntb - base_ntb);
return ((delta > 0) ^ (IOT_ABS(delta) > 0x7FFFFFFF));
}
static int32_t mac_zc_ntb_get_degree(int32_t ntb_d, uint32_t ntb_period)
{
int32_t degree;
degree = ntb_d * 360;
degree += (degree >= 0) ? (ntb_period >> 1) : -(ntb_period >> 1);
degree /= (int32_t)ntb_period;
return degree % 360;
}
static uint8_t IRAM_ATTR mac_zc_sw_fifo_elements(mac_zc_sw_fifo_ctxt_t *fifo)
{
uint8_t wr_idx = fifo->wr_idx;
uint8_t rd_idx = fifo->rd_idx;
return (uint8_t)((rd_idx > wr_idx) ? (fifo->size + wr_idx - rd_idx)
: (wr_idx - rd_idx));
}
uint8_t IRAM_ATTR mac_zc_sw_fifo_puts(mac_zc_sw_fifo_ctxt_t *fifo,
uint32_t *buf, uint8_t num)
{
uint8_t cnt, i;
cnt = (uint8_t)min(fifo->size - mac_zc_sw_fifo_elements(fifo) - 1, num);
for (i = 0; i < cnt; i++) {
fifo->buf[fifo->wr_idx++] = buf[i];
if (fifo->wr_idx >= fifo->size) {
fifo->wr_idx = 0;
}
}
return cnt;
}
uint8_t mac_zc_sw_fifo_gets(mac_zc_sw_fifo_ctxt_t *fifo, uint32_t *buf,
uint8_t num)
{
uint8_t cnt, i;
cnt = min(mac_zc_sw_fifo_elements(fifo), num);
for (i = 0; i < cnt; i++) {
buf[i] = fifo->buf[fifo->rd_idx++];
if (fifo->rd_idx >= fifo->size) {
fifo->rd_idx = 0;
}
}
return cnt;
}
void mac_zc_collect_sw_fifo_clr(mac_zc_ctxt_t *ctxt, uint8_t collect_bm)
{
uint8_t id;
while (collect_bm) {
id = iot_bitops_ffs(collect_bm) - 1;
collect_bm &= ~(1 << id);
mac_zc_sw_fifo_gets(&ctxt->collect[id].ntb_fifo,
ctxt->collect_buf, MAC_ZC_COLLECT_BUF_SIZE);
ctxt->collect[id].ntb_fifo.is_overflow = 0;
}
}
static uint8_t mac_zc_phase_id_to_cap(mac_zc_ctxt_t *ctxt, uint8_t phase_id,
uint8_t is_ext)
{
uint8_t cap_id;
mac_zc_map_info_t *map;
for (cap_id = MAC_ZC_HW_CAP0; cap_id < MAC_ZC_HW_CAP_CNT; cap_id++) {
map = &ctxt->nv.map[cap_id];
if ((map->phase_id == phase_id) && (map->is_ext == !!is_ext)) {
return cap_id;
}
}
IOT_ASSERT(0);
return MAC_ZC_HW_CAP_CNT;
}
static void mac_zc_collect_info_reset(mac_zc_ctxt_t *ctxt, uint8_t collect_bm)
{
uint8_t id;
while (collect_bm) {
id = iot_bitops_ffs(collect_bm) - 1;
collect_bm &= ~(1 << id);
ctxt->collect[id].period = 0;
ctxt->collect[id].is_collect = 0;
ctxt->collect[id].collect_cnt = 0;
ctxt->collect[id].last_ts = 0;
ctxt->collect[id].repeat_id = id;
}
}
static void mac_zc_collect_ring_reset(mac_zc_ctxt_t *ctxt, uint8_t collect_bm)
{
uint8_t id;
while (collect_bm) {
id = iot_bitops_ffs(collect_bm) - 1;
collect_bm &= ~(1 << id);
ctxt->collect[id].ring.wr_idx = 0;
ctxt->collect[id].ring.is_full = 0;
if (ctxt->collect[id].ring.wr_bitmap) {
os_mem_set(ctxt->collect[id].ring.wr_bitmap, 0,
ctxt->collect[id].ring.wr_bm_sz);
}
}
}
static uint32_t mac_zc_collect_ring_elements(mac_zc_ring_ctxt_t *ring)
{
return iot_bitmap_cbs(ring->wr_bitmap, ring->wr_bm_sz);
}
static uint32_t mac_zc_collect_ring_legal_idx_get(mac_zc_ring_ctxt_t *ring,
int32_t idx)
{
if (idx < 0) {
idx += ring->size;
IOT_ASSERT(idx >= 0);
}
if (idx < ring->size) {
return idx;
} else {
return (idx - ring->size);
}
}
static uint8_t mac_zc_collect_ring_idx_is_valid(mac_zc_ring_ctxt_t *ring,
uint32_t idx)
{
return iot_bitmap_is_set(ring->wr_bitmap, ring->wr_bm_sz, idx + 1);
}
static uint32_t mac_zc_collect_ring_last_idx_get(mac_zc_ring_ctxt_t *ring)
{
uint32_t last_idx;
if (ring->wr_idx) {
last_idx = ring->wr_idx - 1;
} else {
last_idx = ring->size - 1;
}
IOT_ASSERT(ring->wr_bitmap[last_idx >> 3] & (1 << (last_idx & 0x07)));
return last_idx;
}
static uint32_t mac_zc_collect_ring_idx2widx_interval(mac_zc_ring_ctxt_t *ring,
uint32_t idx)
{
if (idx <= ring->wr_idx) {
return ring->wr_idx - idx;
} else {
return ring->size + ring->wr_idx - idx;
}
}
static void mac_zc_collect_ring_write(mac_zc_ring_ctxt_t *ring, uint32_t wdata)
{
uint16_t widx;
widx = ring->wr_idx;
ring->buf[widx] = wdata;
ring->wr_bitmap[widx >> 3] |= 1 << (widx & 0x07);
#if (MAC_ZC_DBG_LOG_LEVEL >= 2)
iot_printf("[zc]cap_id:%lu.bm[%d]=0x%02x,wr[%d]=%u\n", ring->ring_id,
widx >> 3, ring->wr_bitmap[widx >> 3], widx, wdata);
#endif
widx++;
if (widx >= ring->size) {
ring->is_full = 1;
widx = 0;
}
ring->wr_idx = widx;
}
static uint32_t mac_zc_collect_ref_period_get(mac_zc_ctxt_t *ctxt)
{
uint8_t cap_bm, id;
cap_bm = (uint8_t)mac_zc_cap_support_bm_get(ctxt);
while (cap_bm) {
id = iot_bitops_ffs(cap_bm) - 1;
if (ctxt->collect[id].is_collect) {
return ctxt->collect[id].period;
}
cap_bm &= ~(1 << id);
}
/* at least one of collect is active when this function is called */
IOT_ASSERT_DUMP(0, (uint32_t *)ctxt, iot_ceil(sizeof(*ctxt), 4));
return 0;
}
static uint8_t mac_zc_collect_record_is_valid(mac_zc_ctxt_t *ctxt,
uint32_t ring_idx)
{
uint32_t record_idx;
mac_zc_ntb_lts_record_t *record;
if (NULL == ctxt->ntb_lts_sync.record) {
return 0;
}
record_idx = ring_idx >> MAC_ZC_NTB_LTS_RECORD_W_CNT_SHITF;
IOT_ASSERT(record_idx < ctxt->ntb_lts_sync.num);
record = &ctxt->ntb_lts_sync.record[record_idx];
return !!(record->is_plc_valid || record->is_rf_valid);
}
static void mac_zc_collect_ntb_lts_record(mac_zc_ctxt_t *ctxt,
uint32_t ring_idx)
{
uint8_t idx, is_rf_valid = 0, is_plc_valid = 0;
uint64_t cur_ntb64;
int64_t delta;
uint32_t chk_period;
mac_vdev_t *plc_vdev;
if (NULL == ctxt->ntb_lts_sync.record) {
return;
}
/* ring write index to record index */
idx = (uint8_t)(ring_idx >> MAC_ZC_NTB_LTS_RECORD_W_CNT_SHITF);
if (idx != ctxt->ntb_lts_sync.cur_idx) {
cur_ntb64 = mac_sched_get_ntb64(NULL);
plc_vdev = get_vdev_ptr(ctxt->ref_pdev_id, PLC_DEFAULT_VDEV);
chk_period = MAC_MS_TO_NTB(vdev_get_bc_period_ms(plc_vdev,
PHY_PROTO_TYPE_GET()) * 6);
if (plc_vdev->mac_ppm.ntb_record.last_saved_ntb) {
delta = cur_ntb64 - plc_vdev->mac_ppm.ntb_record.last_saved_ntb;
if ((delta > 0) && (delta < chk_period)) {
is_plc_valid = 1;
}
}
#if HPLC_RF_DEV_SUPPORT
mac_rf_vdev_t *rf_vdev;
rf_vdev = get_rf_vdev_ptr(ctxt->ref_pdev_id, RF_PDEV_ID,
plc_vdev->rf_vdev_id);
if (!is_plc_valid && rf_vdev->mac_rf_ppm.last_saved_ntb) {
delta = cur_ntb64 - rf_vdev->mac_rf_ppm.last_saved_ntb;
if ((delta > 0) && (delta < chk_period)) {
is_rf_valid = 1;
}
}
#endif
if (is_plc_valid) {
ctxt->ntb_lts_sync.record[idx].ntb_ppm =
-plc_vdev->mac_ppm.ntb_ppm;
ctxt->ntb_lts_sync.record[idx].bcn_rx_lts =
plc_vdev->mac_ppm.ntb_record.last_bcn_local_ts
- MAC_SCHED_GOLDEN_GAP;
ctxt->ntb_lts_sync.record[idx].bcn_tx_ntb =
plc_vdev->mac_ppm.ntb_record.last_bcn_remote_tx_ntb;
}
#if HPLC_RF_DEV_SUPPORT
else if (is_rf_valid) {
ctxt->ntb_lts_sync.record[idx].ntb_ppm = -rf_vdev->rf_ntb_ppm;
ctxt->ntb_lts_sync.record[idx].bcn_rx_lts =
rf_vdev->mac_rf_ppm.last_bcn_local_ts;
ctxt->ntb_lts_sync.record[idx].bcn_tx_ntb =
rf_vdev->mac_rf_ppm.last_bcn_remote_tx_ntb;
}
#endif
else {
ctxt->ntb_lts_sync.record[idx].ntb_ppm =
-phy_get_cal_ppm_in_pib() << PLC_NTB_PPM_SHIFT;
os_disable_irq();
ctxt->ntb_lts_sync.record[idx].bcn_rx_lts = mac_sched_get_lts();
ctxt->ntb_lts_sync.record[idx].bcn_tx_ntb =
mac_sched_get_ntb(NULL);
os_enable_irq();
}
ctxt->ntb_lts_sync.cur_idx = idx;
ctxt->ntb_lts_sync.record[idx].is_plc_valid = is_plc_valid;
ctxt->ntb_lts_sync.record[idx].is_rf_valid = is_rf_valid;
#if (MAC_ZC_DBG_LOG_LEVEL >= 1)
iot_printf("[zc]ntb_lts_sync. idx:%d,lts:%u,ntb:%u,ppm:%d,"
"vaild:%d-%d\n",
ctxt->ntb_lts_sync.cur_idx,
ctxt->ntb_lts_sync.record[idx].bcn_rx_lts,
ctxt->ntb_lts_sync.record[idx].bcn_tx_ntb,
ctxt->ntb_lts_sync.record[idx].ntb_ppm, is_plc_valid, is_rf_valid);
#endif
}
}
static void mac_zc_collect_lts_to_ntb(mac_zc_ctxt_t *ctxt, uint32_t ring_idx,
uint32_t *lts_buf, uint32_t len, uint32_t *ntb_buf)
{
uint32_t i, record_idx;
int64_t delta, ntb_ppm;
mac_zc_ntb_lts_record_t *record;
if ((0 == len) || !lts_buf || !ntb_buf) {
return;
}
record_idx = ring_idx >> MAC_ZC_NTB_LTS_RECORD_W_CNT_SHITF;
IOT_ASSERT(record_idx < ctxt->ntb_lts_sync.num);
record = &ctxt->ntb_lts_sync.record[record_idx];
#if (MAC_ZC_DBG_LOG_LEVEL >= 2)
iot_printf("[zc]lts_to_ntb. remote_ntb:%u, local_ts:%u, ppm:%d\n",
record->bcn_tx_ntb, record->bcn_rx_lts, record->ntb_ppm);
iot_printf("[zc]lts_to_ntb. lts: ");
for (i = 0; i < len; i++) {
iot_printf("%u, ", lts_buf[i]);
}
iot_printf("\n");
#endif
record_idx = lts_buf[0]; /* reuse record_idx save start lts */
ntb_ppm = record->ntb_ppm;
if (IOT_ABS(ntb_ppm) > (MAC_ZC_CONVERT_TS_PPM_MAX
<< PLC_NTB_PPM_SHIFT)) {
ntb_ppm = (ntb_ppm < 0) ? -(MAC_ZC_CONVERT_TS_PPM_MAX
<< PLC_NTB_PPM_SHIFT) : (MAC_ZC_CONVERT_TS_PPM_MAX
<< PLC_NTB_PPM_SHIFT);
}
/* ntb1 = (lts1 - lts0)/(ppm/2^20 + 1) + ntb0 */
if (ntb_ppm) {
ntb_ppm += (1 << (PPM_CALC_MILLION_SHIFT + PLC_NTB_PPM_SHIFT));
for (i = 0; i < len; i++) {
delta = (int64_t)(lts_buf[i] - record->bcn_rx_lts)
<< (PPM_CALC_MILLION_SHIFT + PLC_NTB_PPM_SHIFT);
ntb_buf[i] = delta / ntb_ppm + record->bcn_tx_ntb;
}
} else {
delta = record->bcn_tx_ntb - record->bcn_rx_lts;
for (i = 0; i < len; i++) {
ntb_buf[i] = lts_buf[i] + delta;
}
}
#if (MAC_ZC_DBG_LOG_LEVEL >= 2)
iot_printf("[zc]lts_to_ntb. ntb: ");
for (i = 0; i < len; i++) {
iot_printf("%u, ", ntb_buf[i]);
}
iot_printf("\n");
#endif
if (ctxt->daemon.lts_to_ntb_log_cnt < MAC_ZC_LTS_TO_NTB_LOG_CNT_MAX) {
ring_idx = (ring_idx & 0xFFFF) | ((uint32_t)record->is_plc_valid << 16)
| ((uint32_t)record->is_rf_valid << 17);
iot_dbglog_input(PLC_MAC_ZC_MID, DBGLOG_ERR, IOT_MAC_ZC_LTS_TO_NTB_ID,
6, ring_idx, record->bcn_rx_lts, record->bcn_tx_ntb,
record->ntb_ppm, record_idx, ntb_buf[0]);
ctxt->daemon.lts_to_ntb_log_cnt++;
}
}
static void mac_zc_collect_ntb_to_lts(mac_zc_ctxt_t *ctxt, uint32_t ring_idx,
uint32_t *ntb_buf, uint32_t len, uint32_t *lts_buf)
{
uint32_t i, record_idx;
int32_t delta, fix_delta;
int16_t ntb_ppm;
mac_zc_ntb_lts_record_t *record;
if ((0 == len) || !lts_buf || !ntb_buf) {
return;
}
record_idx = ring_idx >> MAC_ZC_NTB_LTS_RECORD_W_CNT_SHITF;
IOT_ASSERT(record_idx < ctxt->ntb_lts_sync.num);
record = &ctxt->ntb_lts_sync.record[record_idx];
#if (MAC_ZC_DBG_LOG_LEVEL >= 2)
iot_printf("[zc]ntb_to_lts. remote_ntb:%u, local_ts:%u, ppm:%d\n",
record->bcn_tx_ntb, record->bcn_rx_lts, record->ntb_ppm);
iot_printf("[zc]ntb_to_lts. ntb: ");
for (i = 0; i < len; i++) {
iot_printf("%u, ", ntb_buf[i]);
}
iot_printf("\n");
#endif
ntb_ppm = record->ntb_ppm;
if (IOT_ABS(ntb_ppm) > (MAC_ZC_CONVERT_TS_PPM_MAX
<< PLC_NTB_PPM_SHIFT)) {
ntb_ppm = (ntb_ppm < 0) ? -(MAC_ZC_CONVERT_TS_PPM_MAX
<< PLC_NTB_PPM_SHIFT) : (MAC_ZC_CONVERT_TS_PPM_MAX
<< PLC_NTB_PPM_SHIFT);
}
/* lts1 = delta_ntb + delta_ntb * ppm + lts0 */
if (ntb_ppm) {
for (i = 0; i < len; i++) {
delta = ntb_buf[i] - record->bcn_tx_ntb;
fix_delta = (int32_t)(((int64_t)delta * ntb_ppm)
>> (PPM_CALC_MILLION_SHIFT + PLC_NTB_PPM_SHIFT));
lts_buf[i] = delta + fix_delta + record->bcn_rx_lts;
}
} else {
delta = record->bcn_rx_lts - record->bcn_tx_ntb;
for (i = 0; i < len; i++) {
lts_buf[i] = ntb_buf[i] + delta;
}
}
#if (MAC_ZC_DBG_LOG_LEVEL >= 2)
iot_printf("[zc]ntb_to_lts. lts: ");
for (i = 0; i < len; i++) {
iot_printf("%u, ", lts_buf[i]);
}
iot_printf("\n");
#endif
}
static void mac_zc_dsr_hw(void)
{
#if (MAC_ZC_DBG_LOG_LEVEL >= 2)
iot_printf("%s. %u.\n",
__FUNCTION__, mac_sched_get_lts());
#endif
}
static uint8_t mac_zc_phase_is_active(mac_zc_ctxt_t *ctxt, uint8_t phase_id)
{
uint8_t id, ext_id;
id = mac_zc_phase_id_to_cap(ctxt, phase_id, 0);
if (ctxt->nv.is_double_collect) {
ext_id = mac_zc_phase_cap_to_ext(id);
return (ctxt->collect[id].is_collect
&& ctxt->collect[ext_id].is_collect);
} else {
return mac_zc_cap_is_support(ctxt, id)
? ctxt->collect[id].is_collect : 0;
}
}
static uint32_t mac_zc_phase_period_get(mac_zc_ctxt_t *ctxt, uint8_t phase_id)
{
uint8_t id;
if (mac_zc_phase_is_active(ctxt, phase_id)) {
id = mac_zc_phase_id_to_cap(ctxt, phase_id, 0);
return ctxt->collect[id].period;
} else {
return 0;
}
}
static void mac_zc_set_event(mac_zc_ctxt_t * ctxt)
{
uint8_t id;
uint32_t status;
mac_vdev_t *vdev;
if (!mac_zc_is_collecting(ctxt)) {
return;
}
vdev = get_vdev_ptr(ctxt->ref_pdev_id, PLC_DEFAULT_VDEV);
if (vdev && vdev->start_cfg.mac_zc_status_rpt_func) {
status = 0;
for (id = MAC_ZC_PHASE_A; id < MAC_ZC_PHASE_CNT; id++) {
status |= mac_zc_phase_is_active(ctxt, id) << id;
}
#if (MAC_ZC_DBG_LOG_LEVEL >= 2)
iot_printf("[zc]status_rpt_event: 0x%02x\n", status);
#endif
vdev->start_cfg.mac_zc_status_rpt_func(
vdev->start_cfg.mac_callback_arg, status);
}
mac_status_add_zc_event_cnt();
}
static void mac_zc_dsr_systick(void)
{
uint8_t id;
mac_zc_ctxt_t *ctxt;
for (id = 0; id < MAC_ZC_NUM_MAX; id++) {
ctxt = mac_zc_ctxt_get(id);
if (ctxt) {
mac_zc_state_machine(ctxt, MAC_ZC_TRIG_SYSTICK_INT);
}
}
}
static void mac_zc_set_hook(mac_zc_ctxt_t *ctxt, void *task_hdl, void *dsr_tbl,
void *dsr_set_fn, void *dsr_clr_fn)
{
IOT_ASSERT(ctxt);
ctxt->hook.hdl = task_hdl;
ctxt->hook.dsr_tbl = dsr_tbl;
ctxt->hook.dsr_set_entry = (mac_zc_dsr_set_entry_fn_t)dsr_set_fn;
ctxt->hook.dsr_clr = (mac_zc_dsr_clr_fn_t)dsr_clr_fn;
}
static uint32_t mac_zc_collect_info_init(mac_zc_ctxt_t *ctxt)
{
uint8_t id, offset, cap_bm;
uint32_t ring_sz, wr_bm_sz;
mac_zc_collect_info_t *collect;
cap_bm = (uint8_t)mac_zc_cap_support_bm_get(ctxt);
if (0 == cap_bm) {
//IOT_ASSERT(cap_bm);
return ERR_NOSUPP;
}
ring_sz = ctxt->nv.buf_sz / iot_bitops_cbs(cap_bm);
wr_bm_sz = iot_ceil(ring_sz, 8);
offset = 0;
while (cap_bm) {
id = iot_bitops_ffs(cap_bm) - 1;
cap_bm &= ~(1 << id);
collect = &ctxt->collect[id - MAC_ZC_HW_CAP0];
os_mem_set(collect, 0, sizeof(*collect));
/* init sw fifo info */
collect->ntb_fifo.buf = os_mem_malloc(PLC_MAC_ZC_MID,
MAC_ZC_CAP_SW_FIFO_SIZE * sizeof(uint32_t));
if (NULL == collect->ntb_fifo.buf) {
IOT_ASSERT(0);
return ERR_NOMEM;
}
collect->ntb_fifo.size = MAC_ZC_CAP_SW_FIFO_SIZE;
collect->ring.ring_id = id;
collect->ring.buf = ctxt->nv.buffer + (offset * ring_sz);
collect->ring.size = ring_sz;
collect->ring.wr_bitmap = os_mem_malloc(PLC_MAC_ZC_MID, wr_bm_sz);
if (NULL == collect->ring.wr_bitmap) {
IOT_ASSERT(0);
return ERR_NOMEM;
}
collect->ring.wr_bm_sz = wr_bm_sz;
offset++;
#if (MAC_ZC_DBG_LOG_LEVEL >= 2)
iot_printf("[zc]id:%d,ring:0x%08x,size:%u\n",
id, (uint32_t)collect->ring.buf, collect->ring.size);
#endif
}
if (ctxt->nv.is_ntb_collect) {
ctxt->ntb_lts_sync.num = 0;
ctxt->ntb_lts_sync.record = NULL;
} else {
ctxt->ntb_lts_sync.num = iot_ceil(ring_sz,
MAC_ZC_NTB_LTS_RECORD_W_CNT);
ctxt->ntb_lts_sync.record = os_mem_malloc(PLC_MAC_ZC_MID,
ctxt->ntb_lts_sync.num * sizeof(*ctxt->ntb_lts_sync.record));
if (NULL == ctxt->ntb_lts_sync.record) {
IOT_ASSERT(0);
return ERR_NOMEM;
}
}
return ERR_OK;
}
static void mac_zc_system_status_log(mac_zc_ctxt_t *ctxt)
{
uint8_t id;
uint16_t offset, size;
char *str_buf;
str_buf = (char *)ctxt->collect_buf;
size = sizeof(ctxt->collect_buf);
offset = iot_snprintf(str_buf, size, "zc:sts-%d-ena:0x%x-",
ctxt->sm.cur_state, ctxt->nv.ena_cap_bitmap);
for (id = MAC_ZC_HW_CAP0; id < MAC_ZC_HW_CAP_CNT; id++) {
offset += iot_snprintf(str_buf + offset, size - offset,
"[%d:%d:%d:%d-%d]",
id,
ctxt->nv.map[id].phase_id,
ctxt->nv.map[id].gpio,
ctxt->nv.map[id].is_ext,
ctxt->collect[id].is_collect);
}
offset += iot_snprintf(str_buf + offset, size - offset,
"-%d", ctxt->is_power_collapsed);
iot_printf("%s\n", str_buf);
}
static void mac_zc_system_start(mac_zc_ctxt_t *ctxt)
{
uint32_t id;
iot_printf("zc:sys_start-0x%x\n", (uint32_t)ctxt);
/* clear dsr event */
/* re-config mac zc hw */
mac_zc_hw_init(0, (uint8_t)ctxt->nv.cap_edge);
/* enable mac zc dsr */
ctxt->hook.dsr_set_entry(ctxt->hook.dsr_tbl, MAC_DSR_ZERO_CROSS_ID,
mac_zc_dsr_hw);
/* clear dsr event */
ctxt->hook.dsr_clr(MAC_DSR_ZERO_CROSS_ID);
/* enable mac zc systick dsr */
ctxt->hook.dsr_set_entry(ctxt->hook.dsr_tbl, MAC_DSR_ZC_SYSTIC_TRIG_CB_ID,
mac_zc_dsr_systick);
/* clear dsr event */
ctxt->hook.dsr_clr(MAC_DSR_ZC_SYSTIC_TRIG_CB_ID);
for (id = MAC_ZC_HW_CAP0; id < MAC_ZC_HW_CAP_CNT; id++) {
if (mac_zc_cap_is_support(ctxt, id)) {
/* clear hw capture data buffer */
mac_zc_hw_cap_data_clr(id);
/* enable mac zc hw capture */
mac_zc_hw_cap_enable_set(id + MAC_ZC_HW_CAP0, 1);
/* clear collect sw fifo buffer */
mac_zc_collect_sw_fifo_clr(ctxt, 1 << id);
/* reset collect ring buffer */
mac_zc_collect_ring_reset(ctxt, 1 << id);
/* reset collect context info */
mac_zc_collect_info_reset(ctxt, 1 << id);
}
}
ctxt->ntb_lts_sync.cur_idx = (uint16_t)(-1);
#if MAC_ZC_START_FOLLOW_VDEV
ctxt->ntb_lts_sync.is_start = ctxt->nv.is_ntb_collect ? 1 : 0;
#else
ctxt->ntb_lts_sync.is_start = 1;
#endif
/* enable systick */
ctxt->systick.is_ena = 1;
/* set systick check period */
ctxt->systick.check_period = (MAC_ZC_PERIOD_DEF_GOLDON_GAP_NTB
* MAC_ZC_SYSTICK_PERIOD_CNT) + MAC_ZC_PERIOD_JITTER_GAP_NTB;
ctxt->daemon.lts_to_ntb_log_cnt = 0;
}
static void mac_zc_system_stop(mac_zc_ctxt_t *ctxt)
{
uint32_t id;
iot_printf("zc:sys_stop-0x%x\n", (uint32_t)ctxt);
/* stop daemon */
ctxt->systick.is_ena = 0;
/* disable isr */
for (id = MAC_ZC_HW_CAP0; id < MAC_ZC_HW_CAP_CNT; id++) {
/* disable mac zc hw capture */
mac_zc_hw_cap_enable_set(id + MAC_ZC_HW_CAP0, 0);
/* disable isr */
mac_isr_ext1_disable(id + MAC_ISR_EXT1_ZC0_CAP_ID);
}
/* clear dsr event */
ctxt->hook.dsr_clr(MAC_DSR_ZERO_CROSS_ID);
ctxt->hook.dsr_clr(MAC_DSR_ZC_SYSTIC_TRIG_CB_ID);
/* disable dsr */
ctxt->hook.dsr_set_entry(ctxt->hook.dsr_tbl, MAC_DSR_ZERO_CROSS_ID, NULL);
ctxt->hook.dsr_set_entry(ctxt->hook.dsr_tbl, MAC_DSR_ZC_SYSTIC_TRIG_CB_ID,
NULL);
}
/* 0 - fail, 1 - success */
static uint8_t mac_zc_collect_ring_widx_check(mac_zc_ctxt_t *ctxt)
{
uint8_t id, cap_bm;
uint32_t min_idx, max_idx, delta;
mac_zc_collect_info_t *collect;
min_idx = 0xFFFFFFFF;
max_idx = 0;
cap_bm = (uint8_t)mac_zc_cap_support_bm_get(ctxt);
while (cap_bm) {
id = iot_bitops_ffs(cap_bm) - 1;
cap_bm &= ~(1 << id);
collect = &ctxt->collect[id];
if (!collect->is_collect) {
continue;
}
#if (MAC_ZC_DBG_LOG_LEVEL >= 2)
iot_printf("[zc]status_chk-%d,is_collect:%d,idx:%u\n",
id, collect->is_collect, collect->ring.wr_idx);
#endif
if (max_idx < collect->ring.wr_idx) {
max_idx = collect->ring.wr_idx;
}
if (min_idx > collect->ring.wr_idx) {
min_idx = collect->ring.wr_idx;
}
delta = (uint32_t)(max_idx - min_idx);
if (delta > (collect->ring.size >> 1)) {
delta = min_idx + collect->ring.size - max_idx;
}
if (delta > 1) {
IOT_ASSERT_DUMP(0, (uint32_t *)ctxt, iot_ceil(sizeof(*ctxt), 4));
return 0;
}
}
/* update ntb lts convert sync info */
mac_zc_collect_ntb_lts_record(ctxt, min_idx);
return 1;
}
static uint8_t mac_zc_phase_repeat_get(mac_zc_ctxt_t *ctxt, uint8_t phase_id)
{
uint8_t cap_id;
cap_id = mac_zc_phase_id_to_cap(ctxt, phase_id, 0);
if (!mac_zc_cap_is_support(ctxt, cap_id)) {
return phase_id;
}
if (!ctxt->collect[cap_id].is_collect) {
if (ctxt->nv.is_double_collect) {
/* check ext cap id */
cap_id = mac_zc_phase_cap_to_ext(cap_id);
if (!ctxt->collect[cap_id].is_collect) {
cap_id = MAC_ZC_HW_CAP_CNT;
}
} else {
cap_id = MAC_ZC_HW_CAP_CNT;
}
}
return (MAC_ZC_HW_CAP_CNT == cap_id) ? phase_id
: mac_zc_cap_id_to_phase(ctxt, ctxt->collect[cap_id].repeat_id);
}
static void mac_zc_collect_repeat_set(mac_zc_ctxt_t *ctxt)
{
uint8_t chk_id, chk_bm, tmp_id, tmp_bm;
int16_t ntb_jitter_degree, chk_degree;
mac_zc_collect_info_t *chk_collect, *base_collect;
chk_bm = (uint8_t)mac_zc_cap_support_bm_get(ctxt);
if (ctxt->nv.is_double_collect) {
chk_bm &= (1 << MAC_ZC_PHASE_CNT) - 1;
}
/* get all active collect */
tmp_bm = chk_bm;
while (tmp_bm) {
tmp_id = iot_bitops_ffs(tmp_bm) - 1;
tmp_bm &= ~(1 << tmp_id);
if (!ctxt->collect[tmp_id].is_collect) {
chk_bm &= ~(1 << tmp_id);
}
}
if (0 == chk_bm) {
return;
}
base_collect = &ctxt->collect[iot_bitops_ffs(chk_bm) - 1];
ntb_jitter_degree = mac_zc_ntb_get_degree(MAC_ZC_PERIOD_JITTER_GAP_NTB,
base_collect->period);
while (chk_bm) {
chk_id = iot_bitops_fls(chk_bm) - 1;
chk_bm &= ~(1 << chk_id);
chk_collect = &ctxt->collect[chk_id];
tmp_bm = chk_bm;
while (tmp_bm) {
tmp_id = iot_bitops_ffs(tmp_bm) - 1;
tmp_bm &= ~(1 << tmp_id);
base_collect = &ctxt->collect[tmp_id];
chk_degree = mac_zc_ntb_get_degree((int32_t)(base_collect->last_ts
- chk_collect->last_ts), chk_collect->period);
#if (MAC_ZC_DBG_LOG_LEVEL >= 2)
iot_printf("[zc]repeat. chk[%d]-%u, base[%d]-%u, period:%d, "
"degree:%d-%d\n",
chk_id, chk_collect->last_ts,
tmp_id, base_collect->last_ts, chk_collect->period,
ntb_jitter_degree, chk_degree);
#endif
if (IOT_ABS(chk_degree) <= IOT_ABS(ntb_jitter_degree)) {
chk_collect->repeat_id = tmp_id;
} else {
/* set to self collect id */
chk_collect->repeat_id = chk_id;
}
iot_printf("zc:repeat. cap %d-%d. ",
chk_id, chk_collect->repeat_id);
if (ctxt->nv.is_double_collect) {
tmp_id = mac_zc_phase_cap_to_ext(chk_id);
ctxt->collect[tmp_id].repeat_id =
mac_zc_phase_cap_to_ext(chk_collect->repeat_id);
iot_printf("%d-%d", tmp_id, ctxt->collect[tmp_id].repeat_id);
}
iot_printf("\n");
if (chk_collect->repeat_id != chk_id) {
break;
}
}
}
}
/* set collect status to active or inactive */
static uint8_t mac_zc_collect_status_set(mac_zc_ctxt_t *ctxt)
{
uint8_t id, bm, collect_bm, loss_bm, restore_bm;
uint16_t base_idx;
int32_t delta;
uint32_t max_ts, min_ts;
mac_zc_collect_info_t *collect;
collect_bm = 0;
loss_bm = 0;
restore_bm = 0;
bm = (uint8_t)mac_zc_cap_support_bm_get(ctxt);
while (bm) {
id = iot_bitops_ffs(bm) - 1;
bm &= ~(1 << id);
collect = &ctxt->collect[id];
if (collect->is_collect) {
if (collect->collect_cnt <= MAC_ZC_COLLECT_LOSS_MARGIN) {
loss_bm |= 1 << id;
} else {
collect_bm |= 1 << id;
}
} else {
if (collect->collect_cnt >= (MAC_ZC_COLLECT_SUCCESS_CNT
- MAC_ZC_COLLECT_SUCCESS_MARGIN)) {
restore_bm |= 1 << id;
}
}
}
iot_printf("zc:sts_set. collect:0x%02x, loss:0x%02x, restore:0x%02x\n",
collect_bm, loss_bm, restore_bm);
mac_zc_collect_info_reset(ctxt, loss_bm);
if (restore_bm) {
mac_zc_collect_ring_reset(ctxt, restore_bm);
if (collect_bm) {
/* find collect min write index as as the reference base index */
base_idx = 0;
bm = collect_bm;
while (bm) {
id = iot_bitops_ffs(bm) - 1;
bm &= ~(1 << id);
collect = &ctxt->collect[id];
iot_printf("zc:sts_set.collect:%d,widx:%d,ts:%u\n",
id, collect->ring.wr_idx, collect->last_ts);
if (id == (iot_bitops_ffs(collect_bm) - 1)) {
base_idx = mac_zc_collect_ring_last_idx_get(
&ctxt->collect[id].ring);
continue;
}
delta = base_idx - mac_zc_collect_ring_last_idx_get(
&collect->ring);
if (0 == delta) {
continue;
}
if ((IOT_ABS(delta) > (collect->ring.size >> 1))
^ (delta > 0)) {
base_idx = mac_zc_collect_ring_last_idx_get(
&ctxt->collect[id].ring);
}
}
iot_printf("zc:sts_set.collect_base_idx=%d\n", base_idx);
/* find collect base index max/min ts */
max_ts = 0;
min_ts = (uint32_t)(-1);
bm = collect_bm;
while (bm) {
id = iot_bitops_ffs(bm) - 1;
bm &= ~(1 << id);
collect = &ctxt->collect[id];
if (id == (iot_bitops_ffs(collect_bm) - 1)) {
max_ts = ctxt->collect[id].ring.buf[base_idx];
min_ts = max_ts;
continue;
}
if (mac_zc_ntb_is_larger_base(max_ts,
collect->ring.buf[base_idx])) {
max_ts = collect->ring.buf[base_idx];
}
if (mac_zc_ntb_is_larger_base(collect->ring.buf[base_idx],
min_ts)) {
min_ts = collect->ring.buf[base_idx];
}
}
iot_printf("zc:sts_set.collect.max:%u,min:%u\n", max_ts, min_ts);
/* base on collect max/min ts update restore min ts */
bm = restore_bm;
while (bm) {
id = iot_bitops_ffs(bm) - 1;
bm &= ~(1 << id);
collect = &ctxt->collect[id];
if (mac_zc_ntb_is_larger_base(max_ts, collect->last_ts)) {
continue;
}
do {
delta = (uint32_t)(max_ts - collect->last_ts);
if (delta < (collect->period
- MAC_ZC_PERIOD_JITTER_GAP_NTB)) {
if (mac_zc_ntb_is_larger_base(collect->last_ts,
min_ts)) {
min_ts = collect->last_ts;
iot_printf("zc:sts_set.restore min_ts[%d]=%u\n",
id, min_ts);
}
break;
}
collect->last_ts += collect->period;
} while(1);
}
/* base on min ts update restore ts to ring buffer */
bm = restore_bm;
while (bm) {
id = iot_bitops_ffs(bm) - 1;
bm &= ~(1 << id);
collect = &ctxt->collect[id];
delta = collect->last_ts - min_ts;
IOT_ASSERT_DUMP(delta >= 0, (uint32_t *)ctxt,
iot_ceil(sizeof(*ctxt), 4));
if (delta > (collect->period + MAC_ZC_PERIOD_JITTER_GAP_NTB)) {
collect->ring.wr_idx = base_idx + 1;
if (collect->ring.wr_idx >= collect->ring.size) {
collect->ring.wr_idx = collect->ring.wr_idx
- collect->ring.size;
}
} else {
collect->ring.wr_idx = base_idx;
}
iot_printf("zc:sts_set.restore:%d,widx:%u,ts:%u,d:%d\n",
id, collect->ring.wr_idx, collect->last_ts, delta);
collect->is_collect = 1;
mac_zc_collect_ring_write(&collect->ring, collect->last_ts);
}
} else {
/* find restore max last_ts as the reference */
max_ts = 0;
bm = restore_bm;
while (bm) {
id = iot_bitops_ffs(bm) - 1;
bm &= ~(1 << id);
collect = &ctxt->collect[id];
iot_printf("zc:sts_set.restore:%d,ts:%u,max:%u\n",
id, collect->last_ts, max_ts);
if ((id == (iot_bitops_ffs(restore_bm) - 1))
|| mac_zc_ntb_is_larger_base(max_ts, collect->last_ts)) {
max_ts = collect->last_ts;
}
}
/* base on max ts update restore ts to ring buffer */
bm = restore_bm;
while (bm) {
id = iot_bitops_ffs(bm) - 1;
bm &= ~(1 << id);
collect = &ctxt->collect[id];
do {
delta = max_ts - collect->last_ts;
if (delta < (collect->period
- MAC_ZC_PERIOD_JITTER_GAP_NTB)) {
break;
}
collect->last_ts += collect->period;
} while (1);
collect->ring.wr_idx = 0;
iot_printf("zc:sts_set.restore:%d,widx:%u,ts:%u\n",
id, collect->ring.wr_idx, collect->last_ts);
collect->is_collect = 1;
mac_zc_collect_ring_write(&collect->ring, collect->last_ts);
}
}
}
ctxt->is_power_collapsed = (collect_bm | restore_bm) ? 0 : 1;
#if (MAC_ZC_DBG_LOG_LEVEL >= 2)
iot_printf("[zc]power_collapsed:%d\n", ctxt->is_power_collapsed);
#endif
mac_zc_collect_repeat_set(ctxt);
mac_zc_set_event(ctxt);
bm = restore_bm | loss_bm;
for (id = MAC_ZC_PHASE_A; id < MAC_ZC_PHASE_CNT; id++) {
/* update mac status */
mac_status_zc_status_para_update(mac_zc_phase_is_active(ctxt, id), id);
if ((1 <<mac_zc_phase_id_to_cap(ctxt, id, 0)) & bm) {
mac_status_add_zc_phase_chg_cnt(id);
}
}
mac_zc_system_status_log(ctxt);
return (collect_bm | restore_bm);
}
/* return is need check collect status */
static uint8_t mac_zc_collect_cnt_set(mac_zc_collect_info_t *collect,
int8_t set_cnt)
{
uint8_t is_need_chk = 0;
set_cnt += (uint8_t)collect->collect_cnt;
if (set_cnt >= MAC_ZC_COLLECT_SUCCESS_CNT) {
collect->collect_cnt = MAC_ZC_COLLECT_SUCCESS_CNT;
if (!collect->is_collect) {
is_need_chk = 1;
}
} else if (set_cnt <= 0) {
collect->collect_cnt = 0;
if (collect->is_collect) {
is_need_chk = 1;
}
} else {
collect->collect_cnt = set_cnt;
}
return is_need_chk;
}
static uint8_t mac_zc_train_period(mac_zc_ctxt_t *ctxt)
{
uint8_t id, cap_bm, num;
uint8_t pos, collect_cnt;
uint8_t trained_bm;
int32_t delta;
uint32_t period;
uint32_t *buf = ctxt->collect_buf;
mac_zc_collect_info_t *collect;
mac_zc_collect_info_reset(ctxt, (1 << MAC_ZC_HW_CAP_CNT) - 1);
trained_bm = 0;
cap_bm = (uint8_t)mac_zc_cap_support_bm_get(ctxt);
while (cap_bm) {
id = iot_bitops_ffs(cap_bm) - 1;
cap_bm &= ~(1 << (id - MAC_ZC_HW_CAP0));
collect = &ctxt->collect[id];
num = mac_zc_sw_fifo_elements(&collect->ntb_fifo);
/* min of 4 data, then 3 period to check valid */
if (num < 4) {
continue;
}
num = mac_zc_sw_fifo_gets(&collect->ntb_fifo, buf,
MAC_ZC_COLLECT_BUF_SIZE);
mac_zc_dbg_collect_print(id, num, buf);
collect_cnt = 0;
/* calculate period */
for (pos = 1; pos < num; pos++) {
period = (uint32_t)(buf[pos] - buf[pos - 1]);
delta = (int32_t)(collect->period - period);
if (period > MAC_ZC_PERIOD_JITTER_GAP_NTB) {
if (0 == collect_cnt) {
/* first period */
collect->period = period;
collect_cnt++;
} else {
if (IOT_ABS(delta) > MAC_ZC_PERIOD_JITTER_GAP_NTB) {
break;
} else {
collect->period = mac_zc_period_update(collect->period,
period);
collect_cnt++;
/* all of collect period valid */
if (collect_cnt >= (num - 1)) {
collect->last_ts = buf[pos];
collect->collect_cnt = num;
trained_bm |= 1 << id;
}
}
}
}
}
#if (MAC_ZC_DBG_LOG_LEVEL >= 2)
iot_printf("[zc]train_period.%d, period:%u,ts:%u,bm:0x%x\n",
id, collect->period, collect->last_ts, trained_bm);
#endif
}
return trained_bm;
}
static void mac_zc_collect_pre_update(mac_zc_ctxt_t *ctxt)
{
uint8_t cap_bm, id;
mac_zc_collect_info_t *collect;
mac_zc_pre_update_info_t *pre_info;
cap_bm = (uint8_t)mac_zc_cap_support_bm_get(ctxt);
while (cap_bm) {
id = iot_bitops_ffs(cap_bm) - 1;
cap_bm &= ~(1 << id);
collect = &ctxt->collect[id];
pre_info = &ctxt->daemon.pre_info[id];
pre_info->is_collect = collect->is_collect;
pre_info->period = collect->period;
pre_info->collect_cnt = collect->collect_cnt;
pre_info->last_ts = collect->last_ts;
pre_info->ring_wr_idx = collect->ring.wr_idx;
}
}
/* return need check current capture is active or not */
static uint8_t mac_zc_collect_update(mac_zc_ctxt_t *ctxt, uint8_t is_update)
{
uint8_t id, cap_bm, num, pos, is_valid_last, is_reload;
uint8_t need_chk_bm;
int8_t cnt;
int32_t delta;
uint32_t period, last_collect_ts;
uint32_t *buf = ctxt->collect_buf;
mac_zc_collect_info_t *collect;
if (ctxt->nv.is_ntb_collect) {
ctxt->daemon.enter_collect_ts = mac_sched_get_ntb(NULL);
} else {
ctxt->daemon.enter_collect_ts = mac_sched_get_lts();
}
need_chk_bm = 0;
is_valid_last = 0;
last_collect_ts = 0;
ctxt->daemon.collect_reload_cnt = 0;
collect_reload:
is_reload = 0;
cap_bm = (uint8_t)mac_zc_cap_support_bm_get(ctxt);
while (cap_bm) {
id = iot_bitops_ffs(cap_bm) - 1;
cap_bm &= ~(1 << id);
collect = &ctxt->collect[id];
num = mac_zc_sw_fifo_gets(&collect->ntb_fifo, buf,
MAC_ZC_COLLECT_BUF_SIZE);
mac_zc_dbg_collect_print(id, num, buf);
if (0 == num) {
continue;
}
/* only called once */
if (0 == ctxt->daemon.collect_reload_cnt) {
mac_zc_collect_pre_update(ctxt);
}
is_reload = 1;
/* train period done or restore collect */
if (0 == collect->collect_cnt) {
if (0 == collect->period) {
/* restore collect */
collect->period = mac_zc_collect_ref_period_get(ctxt);
}
collect->last_ts = buf[0];
collect->collect_cnt = 1;
pos = 1;
} else {
pos = 0;
}
cnt = 0;
while (pos < num) {
period = buf[pos] - collect->last_ts;
delta = (int32_t)(collect->period - period);
#if (MAC_ZC_DBG_LOG_LEVEL >= 2)
iot_printf("[zc]%d.data[%d]=%u,last_ts=%u,period=%u-%u,"
"delta=%d,cnt=%d-%d,is_collect=%d\n",
id, pos, buf[pos], collect->last_ts, period,
collect->period, delta, collect->collect_cnt, cnt,
collect->is_collect);
#endif
if (IOT_ABS(delta) > MAC_ZC_PERIOD_JITTER_GAP_NTB) {
if (delta > 0) {
/* delta of the interval between 2 colloct data too
* short, this data is noise.
*/
pos++;
continue;
} else {
/* miss collect, not update check position */
cnt--;
collect->last_ts += collect->period;
IOT_ASSERT(mac_zc_ntb_is_larger_base(collect->last_ts,
ctxt->nv.is_ntb_collect ? mac_sched_get_ntb(NULL)
: mac_sched_get_lts()));
}
} else {
collect->last_ts = buf[pos];
collect->period = mac_zc_period_update(collect->period,
period);
pos++;
cnt++;
}
if (is_update && collect->is_collect) {
mac_zc_collect_ring_write(&collect->ring, collect->last_ts);
}
}
need_chk_bm |= mac_zc_collect_cnt_set(collect, cnt) << id;
if (collect->is_collect) {
if (!is_valid_last) {
last_collect_ts = collect->last_ts;
is_valid_last = 1;
} else if (mac_zc_ntb_is_larger_base(last_collect_ts,
collect->last_ts)) {
last_collect_ts = collect->last_ts;
}
#if (MAC_ZC_DBG_LOG_LEVEL >= 2)
iot_printf("[zc]last_collect_ts:%u\n", last_collect_ts);
#endif
}
ctxt->daemon.pre_info[id].cur_last_ts = collect->last_ts;
}
if (ctxt->nv.is_ntb_collect) {
ctxt->daemon.exit_collect_ts = mac_sched_get_ntb(NULL);
} else {
ctxt->daemon.exit_collect_ts = mac_sched_get_lts();
}
if (is_reload) {
IOT_ASSERT_DUMP(ctxt->daemon.collect_reload_cnt < 3,
(uint32_t *)ctxt, iot_ceil(sizeof(*ctxt), 4));
ctxt->daemon.collect_reload_cnt++;
goto collect_reload;
}
if (is_valid_last) {
ctxt->daemon.last_collect_ts = last_collect_ts;
cap_bm = (uint8_t)mac_zc_cap_support_bm_get(ctxt);
while (cap_bm) {
id = iot_bitops_ffs(cap_bm) - 1;
cap_bm &= ~(1 << id);
collect = &ctxt->collect[id];
if (!collect->is_collect) {
continue;
}
period = (uint32_t)(last_collect_ts - collect->last_ts);
cnt = period / collect->period;
if (0 == cnt) {
continue;
}
if (is_update) {
for (pos = 0; pos < cnt; pos++) {
collect->last_ts += collect->period;
mac_zc_collect_ring_write(&collect->ring, collect->last_ts);
}
} else {
collect->last_ts += cnt * collect->period;
}
#if (MAC_ZC_DBG_LOG_LEVEL >= 2)
iot_printf("[zc]comp:%d,ts:%u,period:%u, cnt:%d-%d\n",
id, collect->last_ts, collect->period,
collect->collect_cnt, cnt);
#endif
cnt = -cnt;
need_chk_bm |= mac_zc_collect_cnt_set(collect, cnt) << id;
}
if (is_update) {
mac_zc_collect_ring_widx_check(ctxt);
}
} else {
last_collect_ts = mac_sched_get_ntb(NULL);
period = (uint32_t)(last_collect_ts
- ctxt->daemon.last_collect_ts);
cnt = period / MAC_ZC_PERIOD_DEF_GOLDON_GAP_NTB;
/* not data collect for long time, set all active collect as inactive */
if (cnt > MAC_ZC_COLLECT_SUCCESS_CNT) {
cnt = -MAC_ZC_COLLECT_SUCCESS_CNT;
cap_bm = (uint8_t)mac_zc_cap_support_bm_get(ctxt);
while (cap_bm) {
id = iot_bitops_ffs(cap_bm) - 1;
cap_bm &= ~(1 << id);
collect = &ctxt->collect[id];
if (!collect->is_collect) {
continue;
}
need_chk_bm |= mac_zc_collect_cnt_set(collect, cnt) << id;
}
}
}
return need_chk_bm;
}
static uint8_t mac_zc_get_ntb_valid_collect(mac_zc_ctxt_t *ctxt,
uint8_t is_get_full)
{
uint8_t cap_bm, collect_bm, id, tmp_id, is_chk_ext;
collect_bm = 0;
cap_bm = (uint8_t)mac_zc_cap_support_bm_get(ctxt);
if (is_get_full || (!is_get_full && !ctxt->nv.is_double_collect)) {
/* only check is_ext = 0 collect */
cap_bm &= (1 << MAC_ZC_PHASE_CNT) - 1;
is_chk_ext = 0;
} else {
is_chk_ext = 1;
}
while (cap_bm) {
id = iot_bitops_ffs(cap_bm) - 1;
if (is_chk_ext) {
IOT_ASSERT(!ctxt->nv.map[id].is_ext);
tmp_id = mac_zc_phase_cap_to_ext(id);
if (ctxt->collect[id].is_collect
&& ctxt->collect[tmp_id].is_collect) {
#if !MAC_ZC_GET_RPT_REPEAT_ENA
if (!mac_zc_cap_is_repeat(ctxt, id))
#endif
{
collect_bm |= (1 << id) | (1 << tmp_id);
}
}
cap_bm &= ~((1 << id) | (1 << tmp_id));
} else {
if (ctxt->collect[id].is_collect) {
#if !MAC_ZC_GET_RPT_REPEAT_ENA
if (!mac_zc_cap_is_repeat(ctxt, id))
#endif
{
collect_bm |= (1 << id);
}
}
cap_bm &= ~(1 << id);
}
}
return collect_bm;
}
static void mac_zc_get_ntb_fill_rpt_buf(mac_zc_ctxt_t *ctxt, uint32_t *buf,
uint32_t count, uint32_t *start_idx, uint8_t collect_bm,
uint8_t is_sw_fill_reverse)
{
uint8_t cap_bm, id, collect_cnt;
uint32_t idx[MAC_ZC_HW_CAP_CNT], pos, next_idx, reverse_pos;
collect_cnt = iot_bitops_cbs(collect_bm);
os_mem_cpy(idx, start_idx, sizeof(idx));
id = 0;
pos = 0; /* report buffer position */
while (1) {
cap_bm = collect_bm;
while (cap_bm) {
id = iot_bitops_ffs(cap_bm) - 1;
cap_bm &= ~(1 << id);
if (pos >= count) {
goto out; /* fill count */
}
buf[pos] = ctxt->collect[id].ring.buf[idx[id]];
if (is_sw_fill_reverse) {
/* sw fill report reverse edge index */
reverse_pos = pos + collect_cnt;
if (reverse_pos < count) {
/* next ring buffer index */
next_idx = mac_zc_collect_ring_legal_idx_get(
&ctxt->collect[id].ring, idx[id] + 1);
buf[reverse_pos] = ((ctxt->collect[id].ring.buf[next_idx]
- ctxt->collect[id].ring.buf[idx[id]]) >> 1) +
ctxt->collect[id].ring.buf[idx[id]];
}
}
pos++;
idx[id] = mac_zc_collect_ring_legal_idx_get(&ctxt->collect[id].ring,
(int32_t)(idx[id] + 1));
}
if (is_sw_fill_reverse) {
pos += collect_cnt;
}
}
out:
if (!ctxt->nv.is_ntb_collect) {
id = iot_bitops_ffs(collect_bm) - 1;
mac_zc_collect_lts_to_ntb(ctxt, start_idx[id], buf, count, buf);
}
}
/* return fill buffer count */
static uint32_t mac_zc_get_ntb_history(mac_zc_ctxt_t *ctxt, uint32_t *buf,
uint32_t count, uint32_t target_ntb, uint8_t is_full_period)
{
uint8_t cap_bm, collect_bm, ext_ref_ts_valid = 0;;
uint8_t id, ref_id, is_sw_fill_reverse, find = 0;
uint32_t idx, last_idx, ref_idx;
uint32_t tmp, cnt;
uint32_t target_ts, ref_ts, ext_ref_ts = 0, std_ts = 0;
uint32_t cnt_per_line = 0, cnt_per_line_fix = 0;
uint32_t start_idx[MAC_ZC_HW_CAP_CNT] = { 0 };
mac_zc_collect_info_t *collect;
int32_t search_of = 0;
/* get valid collect bitmap */
collect_bm = mac_zc_get_ntb_valid_collect(ctxt, is_full_period);
if (0 == collect_bm) {
#if (MAC_ZC_DBG_LOG_LEVEL >= 2)
iot_printf("[zc]his. not found:%d\n", __LINE__);
#endif
return 0; /* not found */
}
cap_bm = collect_bm;
while (cap_bm) {
id = iot_bitops_ffs(cap_bm) - 1;
cap_bm &= ~(1 << id);
collect = &ctxt->collect[id];
cnt = mac_zc_collect_ring_elements(&collect->ring);
if (!cnt_per_line || cnt < cnt_per_line) {
cnt_per_line = cnt;
}
}
/* always take the first active phase line as the reference phase line */
cap_bm = collect_bm;
ref_id = iot_bitops_ffs(cap_bm) - 1;
cap_bm &= ~(1 << ref_id);
collect = &ctxt->collect[ref_id];
last_idx = mac_zc_collect_ring_last_idx_get(&collect->ring);
if (!ctxt->nv.is_ntb_collect) {
mac_zc_collect_ntb_to_lts(ctxt, last_idx, &target_ntb, 1, &target_ts);
} else {
target_ts = target_ntb;
}
iot_printf("zc:his. cnt:%d, start_ts:%u-%u, cur_ts:%u-%u\n",
cnt_per_line, target_ntb, target_ts,
mac_sched_get_ntb(NULL), mac_sched_get_lts());
cnt = (uint32_t)(collect->ring.buf[last_idx] - target_ts) / collect->period;
/* the ref collect ring buffer has enough data to search */
if (cnt < cnt_per_line) {
idx = mac_zc_collect_ring_legal_idx_get(&collect->ring,
(int32_t)(last_idx - cnt + 1));
/* adjust the left boundary of the lookup range */
if (mac_zc_ntb_is_larger_base(target_ts, collect->ring.buf[idx])) {
tmp = cnt_per_line - cnt;
tmp = min(tmp, MAC_ZC_SEARCH_MAX_CNT);
cnt_per_line = cnt + tmp;
idx = mac_zc_collect_ring_legal_idx_get(&collect->ring,
(int32_t)(last_idx - cnt_per_line + 1));
}
} else {
idx = mac_zc_collect_ring_legal_idx_get(&collect->ring,
(int32_t)(last_idx - cnt_per_line + 1));
}
/* get search start index and count */
find = 0;
for (cnt = MAC_ZC_SEARCH_MAX_CNT; cnt > 0 && cnt_per_line > 0;
cnt--) {
tmp = IOT_ABS((int32_t)(target_ts - collect->ring.buf[idx]));
if (tmp < (collect->period + MAC_ZC_PERIOD_JITTER_GAP_NTB)) {
find = 1;
ref_ts = collect->ring.buf[idx];
ref_idx = idx;
iot_printf("zc:his. get_bm:0x%x, ref_id:%d, cnt:%d, start[%d]:%u\n",
collect_bm, ref_id, cnt_per_line, idx, ref_ts);
break;
}
cnt_per_line--;
idx = mac_zc_collect_ring_legal_idx_get(&collect->ring, idx + 1);
}
if (!find) {
iot_printf("zc:his. not found:%d\n", __LINE__);
return 0; /* not found */
}
if (!ctxt->nv.is_ntb_collect
&& !mac_zc_collect_record_is_valid(ctxt, idx)) {
iot_printf("zc:his. record invalid\n");
return 0;
}
start_idx[ref_id] = idx;
cnt_per_line_fix = cnt_per_line;
/* always take the first active phase line as the reference phase line */
while (cap_bm) {
id = iot_bitops_ffs(cap_bm) - 1;
cap_bm &= ~(1 << id);
collect = &ctxt->collect[id];
/* adjust the index of the first reported sample of the non reference
* phase line to ensure that after the reference time.
*/
cnt = cnt_per_line;
if (mac_zc_phase_cap_is_ext(id) && ext_ref_ts_valid) {
std_ts = ext_ref_ts;
} else {
std_ts = ref_ts;
}
find = 0;
for (search_of = -MAC_ZC_NO_REF_PHASE_START_MAX_ADJ_CNT;
search_of <= MAC_ZC_NO_REF_PHASE_START_MAX_ADJ_CNT &&
search_of < (int32_t)cnt_per_line; search_of++) {
idx = mac_zc_collect_ring_legal_idx_get(&collect->ring,
(int32_t)(ref_idx + search_of));
if (!mac_zc_collect_ring_idx_is_valid(&collect->ring, idx)) {
continue;
}
if (mac_zc_ntb_is_larger_base(std_ts, collect->ring.buf[idx])) {
find = 1;
start_idx[id] = idx;
cnt = mac_zc_collect_ring_idx2widx_interval(&collect->ring,
idx);
if (mac_zc_phase_cap_is_ext(id) && !ext_ref_ts_valid) {
ext_ref_ts = collect->ring.buf[idx];
ext_ref_ts_valid = 1;
if (mac_zc_phase_ext_to_cap(id) != ref_id) {
IOT_ASSERT(0);
}
}
iot_printf("zc:his. id:%d, cnt:%d, start[%d]:%u\n",
id, cnt, idx, collect->ring.buf[idx]);
break;
}
}
if (!find) {
IOT_ASSERT(0);
collect_bm &= ~(1 << id);
} else if (cnt < cnt_per_line_fix) {
cnt_per_line_fix = cnt;
}
}
/* calculate the maximum number of samples supported after adjustment */
is_sw_fill_reverse = !ctxt->nv.is_double_collect && !is_full_period;
cnt = cnt_per_line_fix * iot_bitops_cbs(collect_bm);
if (is_sw_fill_reverse) {
cnt += (cnt_per_line_fix - 1) * collect_bm;
}
if (count > cnt) {
count = cnt;
}
mac_zc_get_ntb_fill_rpt_buf(ctxt, buf, count, start_idx, collect_bm,
is_sw_fill_reverse);
return count;
}
static uint32_t mac_zc_get_ntb_real(mac_zc_ctxt_t *ctxt, uint32_t *buf,
uint32_t count, uint8_t is_full_period)
{
uint8_t cap_bm, collect_bm, ext_ref_ts_valid = 0;
uint8_t id, ref_id, collect_cnt, is_sw_fill_reverse, find = 0;
uint32_t idx, ref_idx;
uint32_t cnt, tmp;
uint32_t ref_ts = 0, ext_ref_ts = 0, std_ts = 0;
mac_zc_collect_info_t *collect;
uint32_t start_idx[MAC_ZC_HW_CAP_CNT] = { 0 };
uint32_t cnt_per_line = 0, cnt_per_line_fix = 0;
int32_t search_of = 0;
/* get valid collect bitmap */
collect_bm = mac_zc_get_ntb_valid_collect(ctxt, is_full_period);
cap_bm = collect_bm;
while (cap_bm) {
id = iot_bitops_ffs(cap_bm) - 1;
cap_bm &= ~(1 << id);
cnt = mac_zc_collect_ring_elements(&ctxt->collect[id].ring);
if (cnt <= (MAC_ZC_NO_REF_PHASE_START_MAX_ADJ_CNT * 2)) {
tmp = 1 << id;
if (ctxt->nv.is_double_collect) {
if (mac_zc_phase_cap_is_ext(id)) {
tmp |= 1 << mac_zc_phase_ext_to_cap(id);
} else {
tmp |= 1 << mac_zc_phase_cap_to_ext(id);
}
}
iot_printf("zc:real. bm:0x%08x-0x%08x, id:%d, cnt:%d too small\n",
collect_bm, tmp, id, cnt);
tmp = ~tmp;
collect_bm &= (uint8_t)tmp;
cap_bm &= (uint8_t)tmp;
}
}
if (0 == collect_bm) {
iot_printf("zc:real. not found:%d\n", __LINE__);
return 0; /* not found */
}
cap_bm = collect_bm;
collect_cnt = iot_bitops_cbs(collect_bm);
while (cap_bm) {
id = iot_bitops_ffs(cap_bm) - 1;
cap_bm &= ~(1 << id);
collect = &ctxt->collect[id];
cnt = mac_zc_collect_ring_elements(&collect->ring);
if (!cnt_per_line || cnt < cnt_per_line) {
cnt_per_line = cnt;
}
}
/* get source support max report data count */
is_sw_fill_reverse = !ctxt->nv.is_double_collect && !is_full_period;
cnt = cnt_per_line * collect_cnt;
if (is_sw_fill_reverse) {
cnt += (cnt_per_line - 1) * collect_cnt;
}
if (count > cnt) {
count = cnt;
} else {
if (is_sw_fill_reverse) {
tmp = iot_ceil(count - collect_cnt, collect_cnt << 1);
} else {
tmp = iot_ceil(count, collect_cnt);
}
if ((cnt_per_line - tmp) > MAC_ZC_NO_REF_PHASE_START_MAX_ADJ_CNT * 2) {
cnt_per_line = tmp + MAC_ZC_NO_REF_PHASE_START_MAX_ADJ_CNT * 2;
}
}
/* always take the first active phase line as the reference phase line */
cap_bm = collect_bm;
ref_id = iot_bitops_ffs(cap_bm) - 1;
cap_bm &= ~(1 << ref_id);
collect = &ctxt->collect[ref_id];
idx = mac_zc_collect_ring_last_idx_get(&collect->ring);
ref_idx = mac_zc_collect_ring_legal_idx_get(&collect->ring,
(int32_t)(idx - cnt_per_line + 1));
if (!ctxt->nv.is_ntb_collect
&& !mac_zc_collect_record_is_valid(ctxt, ref_idx)) {
iot_printf("zc:real. record invalid\n");
return 0;
}
ref_ts = collect->ring.buf[ref_idx];
start_idx[ref_id] = ref_idx;
cnt_per_line_fix = cnt_per_line;
iot_printf("zc:real. get_bm:0x%x, ref_id:%d, cnt:%d, start[%d]:%u\n",
collect_bm, ref_id, cnt_per_line, ref_idx, ref_ts);
while (cap_bm) {
id = iot_bitops_ffs(cap_bm) - 1;
cap_bm &= ~(1 << id);
collect = &ctxt->collect[id];
/* adjust the index of the first reported sample of the non reference
* phase line to ensure that after the reference time.
*/
cnt = cnt_per_line;
if (mac_zc_phase_cap_is_ext(id) && ext_ref_ts_valid) {
std_ts = ext_ref_ts;
} else {
std_ts = ref_ts;
}
find = 0;
for (search_of = -MAC_ZC_NO_REF_PHASE_START_MAX_ADJ_CNT;
search_of <= MAC_ZC_NO_REF_PHASE_START_MAX_ADJ_CNT &&
search_of < (int32_t)cnt_per_line; search_of++) {
idx = mac_zc_collect_ring_legal_idx_get(&collect->ring,
(int32_t)(ref_idx + search_of));
if (!mac_zc_collect_ring_idx_is_valid(&collect->ring, idx)) {
continue;
}
if (mac_zc_ntb_is_larger_base(std_ts, collect->ring.buf[idx])) {
find = 1;
start_idx[id] = idx;
cnt = mac_zc_collect_ring_idx2widx_interval(&collect->ring,
idx);
if (mac_zc_phase_cap_is_ext(id) && !ext_ref_ts_valid) {
ext_ref_ts = collect->ring.buf[idx];
ext_ref_ts_valid = 1;
if (mac_zc_phase_ext_to_cap(id) != ref_id) {
IOT_ASSERT(0);
}
}
iot_printf("zc:real. id:%d, cnt:%d, start[%d]:%u\n",
id, cnt, idx, collect->ring.buf[idx]);
break;
}
}
if (!find) {
IOT_ASSERT(0);
collect_bm &= ~(1 << id);
} else if (cnt < cnt_per_line_fix) {
cnt_per_line_fix = cnt;
}
}
/* calculate the maximum number of samples supported after adjustment */
cnt = cnt_per_line_fix * iot_bitops_cbs(collect_bm);
if (is_sw_fill_reverse) {
cnt += (cnt_per_line_fix - 1) * collect_bm;
}
if (count > cnt) {
count = cnt;
}
mac_zc_get_ntb_fill_rpt_buf(ctxt, buf, count, start_idx, collect_bm,
is_sw_fill_reverse);
return count;
}
#if MAC_ZC_DBG_LOG_LEVEL >= 2
static void mac_zc_rpt_info_dump(mac_zc_ntb_rpt_t *rpt)
{
uint32_t collec_cnt;
uint32_t pos, idx;
uint8_t line_conn_ind = 0, temp;
uint8_t phase_of, phase = 0;
line_conn_ind |= (rpt->phase_a_valid ? (1 << 0) : 0);
line_conn_ind |= (rpt->phase_b_valid ? (1 << 1) : 0);
line_conn_ind |= (rpt->phase_c_valid ? (1 << 2) : 0);
if (rpt->is_full_period) {
collec_cnt = rpt->phase_cnt;
} else {
collec_cnt = rpt->phase_cnt << 1;
}
for (idx = 0; idx < collec_cnt; idx++) {
phase_of = idx % rpt->phase_cnt;
phase_of += 1;
temp = line_conn_ind;
while (phase_of-- > 0) {
phase = iot_bitops_ffs(temp) - 1;
temp &= ~ (1 << phase);
}
iot_printf("[zc]phase%lu%s_ntb: ", phase, idx >= rpt->phase_cnt ?
"-" : "+");
for (pos = idx; pos < rpt->ntb_cnt; pos += collec_cnt) {
iot_printf("%lu,", rpt->ntb[pos]);
}
iot_printf("\n");
iot_printf("[zc]phase%lu%s_period: ", phase, idx >= rpt->phase_cnt ?
"-" : "+");
for (pos = idx + collec_cnt; pos < rpt->ntb_cnt;
pos += collec_cnt) {
iot_printf("%lu,", (uint32_t)(rpt->ntb[pos] -
rpt->ntb[pos - collec_cnt]));
}
iot_printf("\n");
}
}
#else
#define mac_zc_rpt_info_dump(rpt)
#endif
/* 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)
{
uint8_t idx;
uint32_t tar_ntb;
uint32_t err_no, ret = ERR_OK;
uint32_t fill_cnt;
mac_zc_ctxt_t *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_ts:%u-%u\n",
count, is_full_period, is_history_ntb, nid, ntb,
mac_sched_get_lts(), mac_sched_get_ntb(NULL));
#endif
err_no = 0;
fill_cnt = 0;
do {
if (!ctxt || !rpt) {
IOT_ASSERT(0);
err_no = __LINE__;
ret = ERR_INVAL;
break;
}
if (!mac_zc_is_collecting(ctxt)) {
err_no = __LINE__;
ret = ERR_NOT_READY;
break;
}
if (0 == count) {
break;
}
tar_ntb = ntb;
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,
&tar_ntb, 1)) {
err_no = __LINE__;
ret = ERR_NOT_EXIST;
break;
}
}
}
if (is_history_ntb) {
fill_cnt = mac_zc_get_ntb_history(ctxt, rpt->ntb, count, tar_ntb,
is_full_period);
} else {
fill_cnt = mac_zc_get_ntb_real(ctxt, rpt->ntb, count,
is_full_period);
}
if (PLC_NID_INVALID != nid) {
if (ERR_OK != mac_myntb_to_other_ntb(id, nid, rpt->ntb, fill_cnt)) {
ret = ERR_NOT_EXIST;
err_no = __LINE__;
break;
}
}
} while(0);
if ((ERR_INVAL != ret) && (ERR_NOT_READY != ret)) {
rpt->is_full_period = !!is_full_period;
rpt->ntb_cnt = fill_cnt;
rpt->phase_a_repeat = mac_zc_phase_id_zc_to_plc(
mac_zc_phase_repeat_get(ctxt, MAC_ZC_PHASE_A));
rpt->phase_b_repeat = mac_zc_phase_id_zc_to_plc(
mac_zc_phase_repeat_get(ctxt, MAC_ZC_PHASE_B));
rpt->phase_c_repeat = mac_zc_phase_id_zc_to_plc(
mac_zc_phase_repeat_get(ctxt, MAC_ZC_PHASE_C));
rpt->is_repeat_phase = (rpt->phase_a_repeat != PLC_PHASE_A)
|| (rpt->phase_b_repeat != PLC_PHASE_B)
|| (rpt->phase_c_repeat != PLC_PHASE_C);
#if MAC_ZC_GET_RPT_REPEAT_ENA
rpt->phase_a_valid = mac_zc_phase_is_active(ctxt, MAC_ZC_PHASE_A);
rpt->phase_b_valid = mac_zc_phase_is_active(ctxt, MAC_ZC_PHASE_B);
rpt->phase_c_valid = mac_zc_phase_is_active(ctxt, MAC_ZC_PHASE_C);
#else
rpt->phase_a_valid = mac_zc_phase_is_active(ctxt, MAC_ZC_PHASE_A)
&& (rpt->phase_a_repeat == PLC_PHASE_A);
rpt->phase_b_valid = mac_zc_phase_is_active(ctxt, MAC_ZC_PHASE_B)
&& (rpt->phase_b_repeat == PLC_PHASE_B);
rpt->phase_c_valid = mac_zc_phase_is_active(ctxt, MAC_ZC_PHASE_C)
&& (rpt->phase_c_repeat == PLC_PHASE_C);
#endif
rpt->phase_cnt = rpt->phase_a_valid + rpt->phase_b_valid
+ rpt->phase_c_valid;
for (idx = MAC_ZC_PHASE_A; idx < MAC_ZC_PHASE_CNT; idx++) {
rpt->avg_period[idx] = mac_zc_phase_period_get(ctxt, idx);
}
}
iot_printf("zc:rpt-%d:%u.cnt-%d:%d,v-%d:%d:%d,full=%d,repeat:%d-%d:%d:%d,"
"cur:%u\n",
ret, err_no, 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, rpt->phase_a_repeat,
rpt->phase_b_repeat, rpt->phase_c_repeat, mac_sched_get_ntb(NULL));
if (rpt->ntb_cnt) {
iot_printf("ntb=%u:%u\n",
rpt->ntb[0], rpt->ntb[rpt->ntb_cnt - 1]);
mac_zc_rpt_info_dump(rpt);
}
return ret;
}
static mac_zc_state_id_t mac_zc_sm_idle(mac_zc_ctxt_t *ctxt,
mac_zc_trigger_id_t trig_id)
{
uint8_t bm, id, ref_id;
mac_zc_collect_info_t *collect;
mac_zc_state_id_t next_state = MAC_ZC_STATE_IDLE;
IOT_ASSERT(ctxt);
switch (trig_id) {
case MAC_ZC_TRIG_SYS_START_REQ:
mac_zc_system_start(ctxt);
//TODO: add daemon code
break;
case MAC_ZC_TRIG_SYSTICK_INT:
bm = mac_zc_train_period(ctxt);
if (bm) {
ref_id = iot_bitops_ffs(bm) - 1;
ctxt->systick.check_period = (ctxt->collect[ref_id].period
* MAC_ZC_SYSTICK_PERIOD_CNT) + MAC_ZC_PERIOD_JITTER_GAP_NTB;
for (id = MAC_ZC_HW_CAP0; id < MAC_ZC_HW_CAP_CNT; id++) {
if (!mac_zc_cap_is_support(ctxt, id)) {
continue;
}
collect = &ctxt->collect[id];
if (0 == collect->collect_cnt) {
collect->last_ts = ctxt->collect[ref_id].last_ts;
//TODO: all of capture periods are the same
collect->period = ctxt->collect[ref_id].period;
}
#if (MAC_ZC_DBG_LOG_LEVEL >= 2)
iot_printf("[zc]state:%d,cap:%d,last_ts:%u,period:%d\n",
MAC_ZC_STATE_IDLE, id, ctxt->collect[id].last_ts,
ctxt->collect[id].period);
#endif
}
next_state = MAC_ZC_STATE_TRAINING;
}
break;
case MAC_ZC_TRIG_SYS_STOP_REQ:
mac_zc_system_stop(ctxt);
break;
default:
IOT_ASSERT_DUMP(0, (uint32_t *)ctxt, iot_ceil(sizeof(*ctxt), 4));
break;
}
return next_state;
}
static mac_zc_state_id_t mac_zc_sm_training(mac_zc_ctxt_t *ctxt,
mac_zc_trigger_id_t trig_id)
{
mac_zc_state_id_t next_state = MAC_ZC_STATE_TRAINING;
IOT_ASSERT(ctxt);
switch (trig_id) {
case MAC_ZC_TRIG_SYSTICK_INT:
if (mac_zc_collect_update(ctxt, 0)) {
if (mac_zc_collect_status_set(ctxt)) {
if (!ctxt->ntb_lts_sync.is_start) {
IOT_ASSERT_DUMP(!ctxt->nv.is_ntb_collect, (uint32_t *)ctxt,
iot_ceil(sizeof(*ctxt), 4));
next_state = MAC_ZC_STATE_TRAINED;
} else {
ctxt->daemon.last_collect_ts = mac_sched_get_ntb(NULL);
ctxt->ntb_lts_sync.cur_idx = (uint16_t)(-1);
next_state = MAC_ZC_STATE_COLLECT;
}
} else {
mac_zc_set_func_cmd(ctxt->ref_pdev_id,
MAC_ZC_FUNC_CMD_DELAY_RESET_HW, NULL);
}
}
break;
case MAC_ZC_TRIG_SYS_STOP_REQ:
mac_zc_system_stop(ctxt);
next_state = MAC_ZC_STATE_IDLE;
break;
default:
IOT_ASSERT_DUMP(0, (uint32_t *)ctxt, iot_ceil(sizeof(*ctxt), 4));
break;
}
return next_state;
}
static mac_zc_state_id_t mac_zc_sm_trained(mac_zc_ctxt_t *ctxt,
mac_zc_trigger_id_t trig_id)
{
mac_zc_state_id_t next_state = MAC_ZC_STATE_TRAINED;
switch (trig_id) {
case MAC_ZC_TRIG_SYSTICK_INT:
if (mac_zc_collect_update(ctxt, 0)) {
if (mac_zc_collect_status_set(ctxt)) {
if (ctxt->ntb_lts_sync.is_start) {
next_state = MAC_ZC_STATE_COLLECT;
}
} else {
mac_zc_set_func_cmd(ctxt->ref_pdev_id,
MAC_ZC_FUNC_CMD_DELAY_RESET_HW, NULL);
}
} else {
if (ctxt->ntb_lts_sync.is_start) {
next_state = MAC_ZC_STATE_COLLECT;
}
}
if (next_state != MAC_ZC_STATE_TRAINED) {
ctxt->daemon.last_collect_ts = mac_sched_get_ntb(NULL);
ctxt->ntb_lts_sync.cur_idx = (uint16_t)(-1);
}
break;
case MAC_ZC_TRIG_SYS_STOP_REQ:
mac_zc_system_stop(ctxt);
next_state = MAC_ZC_STATE_IDLE;
break;
default:
IOT_ASSERT_DUMP(0, (uint32_t *)ctxt, iot_ceil(sizeof(*ctxt), 4));
break;
}
return next_state;
}
static mac_zc_state_id_t mac_zc_sm_collect(mac_zc_ctxt_t *ctxt,
mac_zc_trigger_id_t trig_id)
{
mac_zc_state_id_t next_state = MAC_ZC_STATE_COLLECT;
IOT_ASSERT(ctxt);
switch (trig_id) {
case MAC_ZC_TRIG_SYSTICK_INT:
if (mac_zc_collect_update(ctxt, 1)) {
if (0 == mac_zc_collect_status_set(ctxt)) {
mac_zc_set_func_cmd(ctxt->ref_pdev_id,
MAC_ZC_FUNC_CMD_DELAY_RESET_HW, NULL);
}
}
break;
case MAC_ZC_TRIG_SYS_STOP_REQ:
mac_zc_system_stop(ctxt);
next_state = MAC_ZC_STATE_IDLE;
break;
default:
IOT_ASSERT_DUMP(0, (uint32_t *)ctxt, iot_ceil(sizeof(*ctxt), 4));
break;
}
return next_state;
}
static void mac_zc_state_machine(mac_zc_ctxt_t *ctxt,
mac_zc_trigger_id_t trig_id)
{
mac_zc_state_id_t cur_state, next_state;
IOT_ASSERT(ctxt);
cur_state = ctxt->sm.cur_state;
#if (MAC_ZC_DBG_LOG_LEVEL >= 2)
iot_printf("[zc]sm:%d,trig:%d\n", cur_state, trig_id);
#endif
switch (cur_state) {
case MAC_ZC_STATE_IDLE:
next_state = mac_zc_sm_idle(ctxt, trig_id);
break;
case MAC_ZC_STATE_TRAINING:
next_state = mac_zc_sm_training(ctxt, trig_id);
break;
case MAC_ZC_STATE_TRAINED:
next_state = mac_zc_sm_trained(ctxt, trig_id);
break;
case MAC_ZC_STATE_COLLECT:
next_state = mac_zc_sm_collect(ctxt, trig_id);
break;
default:
IOT_ASSERT_DUMP(0, (uint32_t *)ctxt, iot_ceil(sizeof(*ctxt), 4));
next_state = MAC_ZC_STATE_IDLE;
break;
}
if (next_state != cur_state)
{
iot_printf("zc:state %d to %d. trig:%d, is_power_collapsed=%d\n",
(uint8_t)cur_state, (uint8_t)next_state, trig_id,
mac_zc_is_power_collapsed((uint8_t)ctxt->ref_pdev_id));
ctxt->sm.prev_state = cur_state;
ctxt->sm.cur_state = next_state;
}
}
static uint32_t mac_zc_load_nv_info(mac_zc_ctxt_t *ctxt)
{
uint8_t idx, offset;
uint32_t size, mtype;
mac_zc_map_info_t *map;
mtype = iot_oem_get_module_type();
/* alloc total collect buffer. start { */
switch (mtype) {
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);
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 */
ctxt->nv.buffer = os_mem_malloc(PLC_MAC_ZC_MID,
size * sizeof(uint32_t));
if (NULL == ctxt->nv.buffer) {
/* memory must be allocated successfully */
IOT_ASSERT(0);
return ERR_NOMEM;
}
ctxt->nv.buf_sz = size;
/* alloc total collect buffer. end } */
#if (HW_PLATFORM == HW_PLATFORM_SILICON)
ctxt->nv.is_double_collect = (GPIO_NO_VALID
== iot_board_get_gpio(GPIO_PA_ZC_EXT)) ? 0 : 1;
#else
ctxt->nv.is_double_collect = (MODULE_TYPE_CCO == mtype) ? 1 : 0;
#endif
ctxt->nv.is_ntb_collect = (MODULE_TYPE_CCO == mtype) ? 1 : 0;
/* get phase gpio map. start { */
ctxt->nv.ena_cap_bitmap = 0;
for (idx = 0; idx < MAC_ZC_HW_CAP_CNT; idx++) {
map = &ctxt->nv.map[idx];
map->cap_id = idx;
map->is_ext = !(idx < MAC_ZC_PHASE_CNT);
if (map->is_ext) {
offset = idx - MAC_ZC_PHASE_CNT;
map->gpio = iot_board_get_gpio(GPIO_PA_ZC_EXT + offset);
} else {
offset = idx;
map->gpio = iot_board_get_gpio(GPIO_PA_ZC + offset);
}
map->phase_id = offset + MAC_ZC_PHASE_A;
#if (HW_PLATFORM == HW_PLATFORM_SILICON)
if (GPIO_NO_VALID != map->gpio) {
#if MAC_ZC_SELF_MAP_GPIO_ENA
gpio_sig_info_t info = {0};
info.sig_type = 1;
info.CFG[0].type = IO_TYPE_IN;
info.CFG[0].func = 0;
info.CFG[0].gpio = map->gpio;
info.CFG[0].inid = MAC_ZC_HW_SIG0_ID + idx;
info.CFG[0].outid = 0xFF;
gpio_module_pin_select(&info);
gpio_module_sig_select(&info, GPIO_MTX_MODE_MATRIX);
#endif
ctxt->nv.ena_cap_bitmap |= 1 << idx;
}
#else /* HW_PLATFORM == HW_PLATFORM_SILICON */
/* Note: for FPGA, mac zc capture signal connected to
* the mac zc signal is directly connected with the plc sub board,
* without passing through the kl3 chip GPIO.
*/
if (ctxt->nv.is_double_collect) {
ctxt->nv.ena_cap_bitmap |= 1 << idx;
} else {
ctxt->nv.ena_cap_bitmap |= 1 << offset;
}
#endif /* HW_PLATFORM == HW_PLATFORM_SILICON */
iot_printf("zc:cap%d,phase%d,gpio%d,ext:%d\n",
map->cap_id, map->phase_id, map->gpio, map->is_ext);
}
/* get phase gpio map. end } */
//TODO: fix base on hw version
ctxt->nv.cap_edge = MAC_ZC_HW_CAP_EDGE_RISE;
/* save nv info into flash */
mac_status_zc_nv_para_update(0, (uint8_t)ctxt->nv.cap_edge,
(uint8_t)ctxt->nv.ena_cap_bitmap, (uint8_t)ctxt->nv.is_double_collect);
iot_printf("zc:cap_ena-0x%x,edge:%d,double_collect:%d,ntb_collect:%d,"
"buf_size:%u\n",
ctxt->nv.ena_cap_bitmap, ctxt->nv.cap_edge, ctxt->nv.is_double_collect,
ctxt->nv.is_ntb_collect, ctxt->nv.buf_sz);
return ERR_OK;
}
static uint32_t mac_zc_daemon_init(mac_zc_ctxt_t *ctxt)
{
ctxt->daemon.last_collect_ts = mac_sched_get_ntb(NULL);
return ERR_OK;
}
void IRAM_ATTR mac_zc_systic_trig(void)
{
uint8_t cap_bm, id, num;
uint32_t cur_ts;
mac_zc_ctxt_t *ctxt;
ctxt = mac_zc_ctxt_get(PLC_PDEV_ID);
if (!ctxt->systick.is_ena || !ctxt->systick.check_period) {
return;
}
cur_ts = mac_sched_get_lts();
if ((uint32_t)(cur_ts - ctxt->systick.ts) > ctxt->systick.check_period) {
cap_bm = mac_zc_cap_support_bm_get(ctxt);
while (cap_bm) {
id = iot_bitops_ffs(cap_bm) - 1;
cap_bm &= ~(1 << id);
if (ctxt->nv.is_ntb_collect) {
num = mac_zc_hw_cap_ntb_read(id,
IOT_ARRAY_CNT(ctxt->systick.isr_buf),
ctxt->systick.isr_buf);
} else {
num = mac_zc_hw_cap_lts_read(id,
IOT_ARRAY_CNT(ctxt->systick.isr_buf),
ctxt->systick.isr_buf);
}
if (num) {
if (mac_zc_sw_fifo_puts(&ctxt->collect[id].ntb_fifo,
ctxt->systick.isr_buf, num) < num) {
ctxt->collect[id].ntb_fifo.is_overflow = 1;
}
}
}
os_set_task_event_with_v_from_isr(ctxt->hook.hdl,
(uint32_t)(0x1 << MAC_DSR_ZC_SYSTIC_TRIG_CB_ID));
ctxt->systick.ts = cur_ts;
}
}
void mac_zc_train_hw_timeout_internal(uint32_t id, void *arg)
{
(void)id;
(void)arg;
}
void mac_zc_set_func_cmd_internal(uint8_t zc_id, uint8_t cmd, void *arg)
{
mac_zc_ctxt_t *ctxt;
(void)arg;
ctxt = mac_zc_ctxt_get(zc_id);
switch ((mac_zc_func_cmd_id_t)cmd) {
case MAC_ZC_FUNC_CMD_DELAY_RESET_HW:
/* stop mac zc system */
mac_zc_state_machine(ctxt, MAC_ZC_TRIG_SYS_STOP_REQ);
/* start mac zc system */
mac_zc_state_machine(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 *ctxt;
mac_msg_t *msg;
(void)arg;
ctxt = mac_zc_ctxt_get(zc_id);
IOT_ASSERT(ctxt);
iot_printf("zc:set_cmd-%u\n", cmd);
switch (cmd) {
case MAC_ZC_FUNC_CMD_RESET_HW:
/* stop mac zc system */
mac_zc_state_machine(ctxt, MAC_ZC_TRIG_SYS_STOP_REQ);
/* start mac zc system */
mac_zc_state_machine(ctxt, MAC_ZC_TRIG_SYS_START_REQ);
mac_status_add_zc_reset_hw_cnt();
break;
case MAC_ZC_FUNC_CMD_COLLECT_STOP:
/* stop mac zc system */
mac_zc_state_machine(ctxt, MAC_ZC_TRIG_SYS_STOP_REQ);
break;
case MAC_ZC_FUNC_CMD_DELAY_RESET_HW:
msg = mac_alloc_msg();
IOT_ASSERT(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);
break;
case MAC_ZC_FUNC_CMD_NTB_STABLE_NOTIF:
ctxt->ntb_lts_sync.is_start = 1;
break;
default:
break;
}
#else
(void)zc_id;
(void)cmd;
(void)arg;
#endif
}
uint8_t mac_zc_is_power_collapsed(uint8_t pdev_id)
{
mac_zc_ctxt_t *ctxt = mac_zc_ctxt_get(pdev_id);
return (uint8_t)ctxt->is_power_collapsed;
}
uint32_t mac_zc_system_init(uint8_t id, void *task_hdl, void *dsr_tbl,
void *dsr_set_fn, void *dsr_clr_fn)
{
uint32_t err_no = 0;
mac_zc_ctxt_t *ctxt;
if (id >= MAC_ZC_NUM_MAX) {
return ERR_INVAL;
}
do {
ctxt = mac_zc_ctxt_get(id);
if (NULL == ctxt) {
err_no = __LINE__;
IOT_ASSERT(ctxt);
break;
}
/* clean zc ctxt data */
os_mem_set(ctxt, 0, sizeof(*ctxt));
ctxt->ref_pdev_id = id;
mac_zc_set_hook(ctxt, task_hdl, dsr_tbl, dsr_set_fn, dsr_clr_fn);
if (ERR_OK != mac_zc_load_nv_info(ctxt)) {
err_no = __LINE__;
break;
}
if (ERR_OK != mac_zc_daemon_init(ctxt)) {
err_no = __LINE__;
break;
}
if (ERR_OK != mac_zc_collect_info_init(ctxt)) {
err_no = __LINE__;
break;
}
} while (0);
if (0 == err_no) {
mac_zc_system_stop(ctxt);
ctxt->sm.cur_state = MAC_ZC_STATE_IDLE;
ctxt->sm.prev_state = MAC_ZC_STATE_IDLE;
ctxt->is_power_collapsed = 0;
}
iot_printf("zc:sys_init-%d.ena:%d,%u\n",
id, MAC_ZC_ENABLE, mac_sched_get_ntb(NULL));
return (err_no ? ERR_FAIL : ERR_OK);
}
#else /* 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)
{
(void)id;
(void)task_hdl;
(void)dsr_tbl;
(void)dsr_set_fn;
(void)dsr_clr_fn;
iot_printf("zc:sys_init-%d.ena:%d,%u\n",
id, MAC_ZC_ENABLE, mac_sched_get_ntb(NULL));
return ERR_NOSUPP;
}
#endif /* MAC_ZC_ENABLE */