/* Cesar project {{{ * * Copyright (C) 2009 Spidcom * * <<>> * * }}} */ /** * \file mac/pbproc/src/fsm_rx_sound.c * \brief FSM RX SOUND part. * \ingroup mac_pbproc */ #include "common/std.h" #include "inc/context.h" #include "inc/fc.h" #include "inc/fsm_rx_sound.h" #include "hal/phy/pbdma.h" /** * Restart VCS for next MPDU and go to next state. * \param ctx pbproc context */ static void pbproc_frso_next (pbproc_t *ctx); void pbproc_frso_init (pbproc_t *ctx) { dbg_assert (ctx); ctx->fsm.states[PBPROC_FSM_STATE_RX_SOUND].pbdma_cb = pbproc_frso__rx_sound__pbdma; } void ARCH_ILRAM pbproc_frso__handle (pbproc_t *ctx, u32 rx_date, const pbproc_fc_sound_t *sound) { dbg_claim (ctx); dbg_claim (sound); const bool hybrid = ctx->alloc.hybrid; /* Get tonemap. */ tonemap_t *tm; phy_mod_t mod = sound->pbsz ? PHY_MOD_MINI_ROBO : PHY_MOD_ROBO; tm = &ctx->config->tonemask_info.tonemap_robo[mod]; /* Compute symbol number. */ phy_pb_size_t pb_size = sound->pbsz ? PHY_PB_SIZE_136 : PHY_PB_SIZE_520; uint fl_tck = MAC_FL_TO_TCK (sound->fl_av); uint bits_per_pb = tm->bits_per_pb[pb_size]; uint symb_nb = (1 * bits_per_pb + tm->bits_per_symbol - 1) / tm->bits_per_symbol; /* Save early needed received MPDU parameters. */ ctx->recv_mpdu.mpdu_cnt = sound->mpdu_cnt; ctx->recv_mpdu.ack_date = rx_date + ctx->times[hybrid].pre_fcs_tck + fl_tck; /* Ignore frames ending after the allocation. */ if (less_mod2p32 (ctx->alloc.end_date, rx_date + 2 * ctx->times[hybrid].pre_fcs_tck + fl_tck + MAC_CIFS_TCK)) { /* Unblock hardware. */ phy_rx_prepare_short (ctx->phy); /* Prepare for next. */ pbproc_frso_next (ctx); /* Stop now. */ return; } /* May skip channel data reception. */ bool chandata = ctx->chandata_nb && ctx->rx_pool_size >= 1 + ctx->chandata_nb; /* Default to true to keep the sender to flood with SOUND frames. */ bool sound_complete = true; if (chandata) { /* Unblock hardware. */ phy_rx_prepare_sound (ctx->phy, 1, tm->phy_combo_params[pb_size], tm->gil, symb_nb); /* Is sound completed? */ sta_t *sta = mac_store_sta_get (ctx->store, sound->stei); if (sta) { if (sta->rx_tonemaps->sound_frame_counter) sta->rx_tonemaps->sound_frame_counter--; sound_complete = sta->rx_tonemaps->sound_frame_counter == 0; blk_release (sta); } } else { /* Skip frame. */ phy_rx_prepare_short (ctx->phy); } /* Save received MPDU parameters. */ ctx->recv_mpdu.rx_params.preamble_ntb = rx_date + ctx->config->ntb_offset_tck; ctx->recv_mpdu.rx_params.tei = sound->stei; ctx->recv_mpdu.rx_params.lid = sound->lid; ctx->recv_mpdu.rx_params.snid = sound->snid; ctx->recv_mpdu.rx_params.bcast = false; ctx->recv_mpdu.rx_params.cfp = sound->cfs; ctx->recv_mpdu.rx_params.multi_net_bcast = false; ctx->recv_mpdu.rx_params.sound = true; ctx->recv_mpdu.rx_params.eks = MAC_EKS_CLEAR; ctx->recv_mpdu.rx_params.pending_seg_nb = sound->ppb; ctx->recv_mpdu.rx_params.ble = 0; ctx->recv_mpdu.rx_params.tmi_av = mod; ctx->recv_mpdu.rx_params.mpdu_cnt = sound->mpdu_cnt; ctx->recv_mpdu.rx_params.bdf = sound->bdf; ctx->recv_mpdu.rx_params.hp10df = false; ctx->recv_mpdu.rx_params.hp11df = false; ctx->recv_mpdu.rx_params.mfs_cmd_data = MFS_FSM_CMD_NOP; ctx->recv_mpdu.rx_params.mfs_cmd_mme = MFS_FSM_CMD_NOP; ctx->recv_mpdu.rx_params.sound_src = sound->src; ctx->recv_mpdu.rx_params.sound_req_tm = sound->req_tm; ctx->recv_mpdu.rx_params.sound_complete = sound_complete; ctx->recv_mpdu.pb_nb = 0; /* Keep a block to store received MPDU parameters. */ dbg_assert (ctx->rx_pool_size >= 1); pb_t *last = ctx->rx_pool_head; ctx->recv_mpdu.rx_desc = (pbproc_rx_desc_t *) last; /* Prepare channel data blocks and give them to PB DMA. */ if (chandata) { uint i; /* Take from RX pool. */ ctx->recv_mpdu.chandata_head = last->next; ctx->recv_mpdu.chandata_nb = ctx->chandata_nb; /* Fill configuration. */ for (i = 0; i < ctx->chandata_nb; i++) { last = last->next; last->phy_pb.chandata.conf = ctx->chandata_conf[i]; } /* Start PB DMA. */ phy_pbdma_start_chandata ( ctx->phy, &ctx->recv_mpdu.chandata_head->phy_pb.chandata); /* Unchain used blocks. */ slist_slice (ctx->rx_pool_, last, 1 + ctx->recv_mpdu.chandata_nb, paste_size); } else { ctx->recv_mpdu.chandata_head = NULL; ctx->recv_mpdu.chandata_nb = 0; } /* Wait end of frame if receiving channel data, else continue now. */ if (chandata) pbproc_fsm_change_state (ctx, PBPROC_FSM_STATE_RX_SOUND); else pbproc_frso__rx_sound__pbdma (ctx); } void ARCH_ILRAM pbproc_frso__rx_sound__pbdma (pbproc_t *ctx) { dbg_claim (ctx); const bool hybrid = ctx->alloc.hybrid; if (ctx->recv_mpdu.mpdu_cnt == 0) { /* Anticipate FC 1.0. */ if (hybrid) phy_tx_fc10 (ctx->phy, ctx->recv_mpdu.ack_date, 0); /* Prepare SOUND acknowledgment. */ pbproc_fc_t fc; fc.words[0] = BF_FILL ( PBPROC_FC_SOUND_W0, (DT_AV, PBPROC_FC_DT_SOUND), (ACCESS, false), (SNID, ctx->alloc.snid), (STEI, ctx->config->tei), (DTEI, ctx->recv_mpdu.rx_params.tei), (LID, ctx->recv_mpdu.rx_params.lid)); fc.words[1] = BF_FILL ( PBPROC_FC_SOUND_W1, (CFS, ctx->recv_mpdu.rx_params.cfp), (PBSZ, false), (BDF, false), /* TODO */ (SAF, true), (SCF, ctx->recv_mpdu.rx_params.sound_complete), (REQ_TM, 0), (FL_AV, 0), (MPDU_CNT, 0), (RESERVED0, 0), (PPB, 0)); fc.words[2] = BF_FILL ( PBPROC_FC_SOUND_W2, (SRC, 0), (RESERVED1, 0)); fc.words[3] = BF_FILL ( PBPROC_FC_SOUND_W3, (RESERVED2, 0)); /* Send it. */ phy_tx_param_short (ctx->phy, PHY_FC_MODE (hybrid, ctx->config->fc_symbols_nb)); phy_tx_frame (ctx->phy, ctx->recv_mpdu.ack_date, false, false, fc.words); } /* Received frame is given to upper layer in DSR. */ if (ctx->recv_mpdu.chandata_nb) { pbproc_rx_desc_t *rx = ctx->recv_mpdu.rx_desc; rx->rx->params = ctx->recv_mpdu.rx_params; rx->rx->mfs = NULL; rx->rx->mfs_mme = NULL; rx->rx->pb_first = NULL; rx->rx->pb_last = NULL; rx->rx->pb_nb = 0; rx->rx->chandata_first = ctx->recv_mpdu.chandata_head; rx->rx->chandata_nb = ctx->recv_mpdu.chandata_nb; slist_push_back (ctx->commit.rx_, rx); pbproc_fsm_schedule_deferred (ctx); dbg_invalid_ptr (ctx->recv_mpdu.chandata_head); } /* Prepare for next. */ pbproc_frso_next (ctx); } static void ARCH_ILRAM pbproc_frso_next (pbproc_t *ctx) { dbg_claim (ctx); const bool hybrid = ctx->alloc.hybrid; /* Restart VCS. */ if (ctx->recv_mpdu.mpdu_cnt == 0) { ca_access_vcs_restart (ctx->ca, ctx->recv_mpdu.ack_date, ctx->times[hybrid].pre_fcs_tck + MAC_CIFS_TCK, PBPROC_ANTICIP_TCK, false); } else { ca_access_vcs_restart (ctx->ca, ctx->recv_mpdu.ack_date, ctx->times[hybrid].eifs_tck, PBPROC_ANTICIP_TCK, true); phy_rx_activate (ctx->phy, false, ctx->recv_mpdu.ack_date, true); } /* Return to IDLE. */ pbproc_fsm_change_state (ctx, PBPROC_FSM_STATE_IDLE); }