/* Cesar project {{{ * * Copyright (C) 2009 Spidcom * * <<>> * * }}} */ /** * \file ce/rx/cp/src/mme.c * \brief Generation of MME for the CE in RX (declaration part). * \ingroup ce_rx_cp * * Sending the MME for the CE in RX from the CP context can be quite * complicated. */ #include "common/std.h" #include "lib/bitstream.h" #include "cp/inc/context.h" #include "cp/msg/msg.h" #include "mac/common/timings.h" #include "ce/common/mme.h" #include "ce/rx/cp/mme.h" #include "ce/rx/cp/inc/mme.h" #include "ce/rx/cp/inc/cp.h" /** * Macro to through each tone of two tone maps, using a mask and read two * tones. * \param tm1 the first tone map to read (tonemap_t). * \param tm2 the second tone map to read (tonemap_t). * \param tonemask the tone map to read (u32 *). * \param tone1 the first tone read. * \param tone2 the second tone read. * This macro is divided in two macros. Here is an example of to use it. * \code * tonemap_t *tm_old; * tonemap_t *tm_new; * tonemask_info_t ti; * uint t1, t2; * CE_RX_CP_READ_BEGIN (tm_old, tm_new, ti.tonemask, t1, t2) * { * printf ("%d\n", tone); * } * CE_RX_CP_READ_END; * \endcode */ #define CE_RX_CP_READ_BEGIN(tm1, tm2, tonemask, tone1, tone2) \ do { \ /* Store tone map. */ \ tonemap_t *tonemap_[2]; \ tonemap_[0] = (tm1); \ tonemap_[1] = (tm2); \ /* Index in the tone map in term of tone words. */ \ uint tm_tone_word_index_; \ /* Maximum index in the tone map in term of tone words. \ * This will evolve during the loop (because the block will change). */ \ uint tm_tone_word_max_; \ /* Index by group of 8 tones. A mask is stored on 1 bit. Every 32 bits, \ * of tone masks, we have 32 tones. A tone is stored on 4 bits. On a \ * word of tone map, we have 8 tones. This index represents the current \ * words (of 8 tones) of the tone map by group of 4. */ \ uint tm_tone_group_by_word_mask_; \ /* Pointer to the current word of 4 tones of the tone map. */ \ u32 *tm_[2]; \ /* Pointer to the current word of 32 tones mask. */ \ u32 *tk_; \ \ /* Initialization. */ \ tm_[0] = (u32 *) tonemap_[0]->tmdma_desc_head->data; \ tm_[1] = (u32 *) tonemap_[1]->tmdma_desc_head->data; \ tk_ = (tonemask); \ \ /* This loop will go through each block. So basically, it will be run \ * only two times. */ \ for (tm_tone_word_index_ = 0, tm_tone_word_max_ = BLK_SIZE / 4; \ tm_tone_word_index_ < PHY_TONEMAP_WORDS; \ /* After the list loop is over, second loop must be called until no \ * more word remains. */ \ tm_tone_word_max_ = PHY_TONEMAP_WORDS) \ { \ /* Loop on the whole current block until we have read all the words \ of tone. */ \ for (; tm_tone_word_index_ < tm_tone_word_max_;) \ { \ /* Current 32 masks. */ \ u32 tk_cur_ = *tk_; \ /* This loop goes through each word of tone map by group of 4. \ */ \ for (tm_tone_group_by_word_mask_ = 0; \ tm_tone_group_by_word_mask_ < 4; \ /* Increase tm_tone_word_index_ too. */ \ tm_tone_group_by_word_mask_++, tm_tone_word_index_++) \ { \ /* Index of a tone in a word of tones. */ \ uint tm_tone_index_; \ /* The 8 tones of the word. */ \ u32 tm_tone_[2]; \ tm_tone_[0] = *tm_[0]; \ tm_tone_[1] = *tm_[1]; \ for (tm_tone_index_ = 8; \ tm_tone_index_ > 0; \ tm_tone_index_--) \ { \ if (!(tk_cur_ & 0x1)) \ { \ (tone1) = tm_tone_[0] & 0xF; \ (tone2) = tm_tone_[1] & 0xF; #define CE_RX_CP_READ_END \ } \ /* Next tone. */ \ tm_tone_[0] >>= 4; \ tm_tone_[1] >>= 4; \ /* Next tone mask bit. */ \ tk_cur_ >>= 1; \ } \ /* Next group of tone (grouped by word). */ \ tm_[0]++; \ tm_[1]++; \ } \ /* Next group of 32 masks. */ \ tk_++; \ } \ /* Get next block. */ \ tm_[0] = (u32 *) tonemap_[0]->tmdma_desc_head->next->data; \ tm_[1] = (u32 *) tonemap_[1]->tmdma_desc_head->next->data; \ } \ } while (0) u16 ce_rx_cp_mme_tone_map_size_with_rle (tonemap_t *tm, tonemask_info_t *tonemask) { /* Check parameters. */ dbg_assert (tm); dbg_assert (tonemask); u8 modulation; s8 prev_modulation = -1; u8 count = 0; uint size = 0; TONEMAP_READ_BEGIN (tm, tonemask->tonemask, modulation) { /* Initialisation of first loop. */ if (prev_modulation == -1) prev_modulation = modulation; if ((prev_modulation == modulation) && (count < 74)) { count++; } else { /* New modulation is different, increase size. */ size += ce_rx_cp_mme_rle_size (count); /* Reset counter. */ count = 1; /* Update previous modulation. */ prev_modulation = modulation; } } TONEMAP_READ_END; /* Commit last count. */ size += ce_rx_cp_mme_rle_size (count); /* Return computed size. */ return size; } u16 ce_rx_cp_mme_tone_map_size_with_update (tonemap_t *old_tm, tonemap_t *new_tm, tonemask_info_t *tonemask) { /* Check parameters. */ dbg_assert (old_tm); dbg_assert (new_tm); dbg_assert (tonemask); u16 size = 0; u8 mod1, mod2; CE_RX_CP_READ_BEGIN (old_tm, new_tm, tonemask->tonemask, mod1, mod2) { if (mod1 != mod2) size += 16; } CE_RX_CP_READ_END; /* Return computed size. */ return size; } void ce_rx_mme_send_cm_chan_est_ind (cp_t *ctx, cp_sta_t *sta, tonemaps_t *tms, bool initial_ce, u8 new_tmi, u8 default_tmi, u32 tmi_list, tonemap_intervals_t *int_list) { /* Check parameters. */ dbg_assert (ctx); dbg_assert (sta); dbg_assert (tms); dbg_assert ((new_tmi >> 5) == 0x000); dbg_assert ((default_tmi >> 5) == 0x000); dbg_assert (int_list); /* Get peer. */ cp_mme_peer_t peer; cp_sta_get_peer (sta, &peer); /* Build MME. */ cp_mme_tx_t *mme = cp_msg_mme_init (ctx, &peer, CM_CHAN_EST_IND); dbg_assert (mme); bitstream_write (&mme->bitstream, tms->max_fl_av, 16); bitstream_write (&mme->bitstream, tms->rifs_av_one_sym_tck / MAC_TCK_PER_FL, 8); bitstream_write (&mme->bitstream, tms->rifs_av_two_sym_tck / MAC_TCK_PER_FL, 8); bitstream_write (&mme->bitstream, tms->rifs_av_g2_sym_tck / MAC_TCK_PER_FL, 8); if (initial_ce) bitstream_write (&mme->bitstream, 0, 8); else bitstream_write (&mme->bitstream, 1, 8); bitstream_write (&mme->bitstream, tms->max_tm, 8); bitstream_write (&mme->bitstream, default_tmi, 8); bitstream_write (&mme->bitstream, tms->scl_cp, 8); bitstream_write (&mme->bitstream, tms->scl_cfp, 8); /* TMI AV valid list. */ u8 tm_count = 0; uint i; for (i = TONEMAP_INDEX_NEGOTIATED_FIRST; i < TONEMAP_INDEX_NB ; i++) { if (tmi_list & (1 << i)) tm_count++; } dbg_assert (tm_count || default_tmi < PHY_MOD_ROBO_NB); bitstream_write (&mme->bitstream, tm_count, 8); for (i = TONEMAP_INDEX_NEGOTIATED_FIRST; i < TONEMAP_INDEX_NB; i++) if (tmi_list & (1 << i)) { bitstream_write (&mme->bitstream, i, 8); tm_count--; } dbg_assert (tm_count == 0); /* Intervals. */ bitstream_write (&mme->bitstream, int_list->intervals_nb, 8); for (i = 0; i < int_list->intervals_nb; i++) { bitstream_write (&mme->bitstream, int_list->interval[i].end_offset_atu, 16); bitstream_write (&mme->bitstream, int_list->interval[i].tmi, 8); } /* New TMI? */ bitstream_write (&mme->bitstream, new_tmi, 8); if (new_tmi) { /* Get tone map. */ tonemap_t *tm = tms->tm[new_tmi]; dbg_assert (tm); bitstream_write (&mme->bitstream, tm->cpf, 8); bitstream_write (&mme->bitstream, tm->fecrate, 8); bitstream_write (&mme->bitstream, tm->gil, 8); /* Always use RLE. */ bitstream_write (&mme->bitstream, 1, 8); /* Copy position in the bitstream. */ uint cbd_len_pos = bitstream_written_bits (&mme->bitstream); /* CBD length. */ bitstream_write (&mme->bitstream, 0, 16); /* Write tone map in RLE. */ s8 modulation = -1; s8 prev_modulation = -1; u16 cbd_length = 0; u8 count = 0; TONEMAP_READ_BEGIN (tm, ctx->mac_config->tonemask_info.tonemask, modulation) { /* Initialisation of first loop. */ if (prev_modulation == -1) prev_modulation = modulation; /* Same modulation and not over max RLE? */ if ((prev_modulation == modulation) && (count < 74)) { count++; } else { /* We need to write the modulation. */ if (count < 3) { /* Write modulation required times. */ uint k; for (k = 0; k < count; k++) bitstream_write (&mme->bitstream, prev_modulation, 4); } else { /* Use RLE. */ /* Sanity check. */ dbg_assert (count <= 74); /* Write modulation. */ bitstream_write (&mme->bitstream, prev_modulation, 4); /* Write one or two nibbles. */ bitstream_write (&mme->bitstream, ce_rx_cp_mme_get_rle (count), count < 11 ? 4 : 8); } /* Increase size. */ cbd_length += ce_rx_cp_mme_rle_size (count); /* Reset counter. */ count = 1; /* Update previous modulation. */ prev_modulation = modulation; } } TONEMAP_READ_END; dbg_assert (modulation != -1); dbg_assert (prev_modulation != -1); /* Let's write last modulation. */ if (count < 3) { /* Not in RLE. */ /* Write modulation required times. */ uint k; for (k = 0; k < count; k++) bitstream_write (&mme->bitstream, modulation, 4); } else { /* Use RLE. */ /* Sanity check. */ dbg_assert (count <= 74); /* Write modulation. */ bitstream_write (&mme->bitstream, prev_modulation, 4); /* Write one or two nibbles. */ bitstream_write (&mme->bitstream, ce_rx_cp_mme_get_rle (count), count < 11 ? 4 : 8); } /* Increase size. */ cbd_length += ce_rx_cp_mme_rle_size (count); /* Check computed length is correct. */ dbg_assert (cbd_length % 4 == 0); dbg_assert (bitstream_written_bits (&mme->bitstream) - cbd_len_pos - 16 == cbd_length); /* Write CBD length. */ bitstream_direct_write (mme->p_mme, cbd_len_pos, cbd_length / 4, 16); /* PAD if required. */ if ((cbd_length / 4) % 2) bitstream_write (&mme->bitstream, 0, 4); } /* Send. */ cp_msg_mme_send (ctx, mme); /* Restart expiration timer. */ tms->expiration_s = TONEMAPS_LIFE_DURATION_S - 1; } void ce_rx_mme_send_cm_tm_update_ind (cp_t *ctx, cp_sta_t *sta, tonemaps_t *tms, u8 new_tmi, u8 old_tmi, u8 default_tmi, u32 tmi_list, tonemap_intervals_t *int_list) { /* Check parameters. */ dbg_assert (ctx); dbg_assert (sta); dbg_assert (tms); dbg_assert ((new_tmi >> 5) == 0x000); dbg_assert ((old_tmi >> 5) == 0x000); dbg_assert ((default_tmi >> 5) == 0x000); dbg_assert (int_list); cp_mme_peer_t peer; cp_sta_get_peer (sta, &peer); /* Build MME. */ cp_mme_tx_t *mme = cp_msg_mme_init (ctx, &peer, CM_TM_UPDATE_IND); dbg_assert (mme); bitstream_write (&mme->bitstream, default_tmi, 8); /* TMI AV valid list. */ u8 tm_count = 0; uint i; for (i = TONEMAP_INDEX_NEGOTIATED_FIRST; i < TONEMAP_INDEX_NB ; i++) { if (tmi_list & (1 << i)) tm_count++; } dbg_assert (tm_count || default_tmi < PHY_MOD_ROBO_NB); bitstream_write (&mme->bitstream, tm_count, 8); for (i = TONEMAP_INDEX_NEGOTIATED_FIRST; i < TONEMAP_INDEX_NB; i++) if (tmi_list & (1 << i)) { bitstream_write (&mme->bitstream, i, 8); tm_count--; } dbg_assert (tm_count == 0); /* Intervals. */ bitstream_write (&mme->bitstream, int_list->intervals_nb, 8); for (i = 0; i < int_list->intervals_nb; i++) { bitstream_write (&mme->bitstream, int_list->interval[i].end_offset_atu, 16); bitstream_write (&mme->bitstream, int_list->interval[i].tmi, 8); } /* Old TMI. */ bitstream_write (&mme->bitstream, old_tmi, 8); /* New TMI. */ bitstream_write (&mme->bitstream, new_tmi, 8); if (new_tmi) { /* Get tone map. */ tonemap_t *new_tm = tms->tm[new_tmi]; dbg_assert (new_tm); tonemap_t *old_tm = tms->tm[old_tmi]; dbg_assert (old_tm); bitstream_write (&mme->bitstream, new_tm->cpf, 8); bitstream_write (&mme->bitstream, new_tm->fecrate, 8); bitstream_write (&mme->bitstream, new_tm->gil, 8); /* Copy position in the bitstream. */ uint cbd_len_pos = bitstream_written_bits (&mme->bitstream); /* CBD length. */ bitstream_write (&mme->bitstream, 0, 16); u16 pos = 0, count = 0; u8 mod1, mod2; CE_RX_CP_READ_BEGIN (old_tm, new_tm, ctx->mac_config->tonemask_info.tonemask, mod1, mod2) { if (mod1 != mod2) { /* Compute and write CBUD: [count:new_mod]. */ bitstream_write (&mme->bitstream, (pos << 4) || mod2, 16); count++; } pos++; } CE_RX_CP_READ_END; bitstream_direct_write (mme->p_mme, cbd_len_pos, count, 16); } bitstream_write_finalise (&mme->bitstream); /* Send. */ cp_msg_mme_send (ctx, mme); /* Restart expiration timer. */ tms->expiration_s = TONEMAPS_LIFE_DURATION_S - 1; } void ce_rx_cp_mme_send_tone_map (cp_t *ctx, cp_sta_t *sta, u32 tmi_list, u8 default_tmi, tonemap_intervals_t *int_list, u8 new_tmi, u8 old_tmi, tonemaps_t *tms, bool initial_ce) { /* Check parameters. */ dbg_assert (ctx); dbg_assert (sta); dbg_assert (tmi_list); dbg_assert ((default_tmi >> 5) == 0x000); dbg_assert (int_list); dbg_assert ((new_tmi >> 5) == 0x000); dbg_assert ((old_tmi >> 5) == 0x000); dbg_assert (tms); /* Not based on old tone map? */ if (!old_tmi) { /* Use CM_CHAN_EST.IND. */ ce_rx_mme_send_cm_chan_est_ind (ctx, sta, tms, initial_ce, new_tmi, default_tmi, tmi_list, int_list); } else { dbg_assert (initial_ce == false); /* Compute and use best one. */ if (ce_rx_cp_mme_tone_map_size_with_rle (tms->tm[new_tmi], &ctx->mac_config->tonemask_info) > ce_rx_cp_mme_tone_map_size_with_update (tms->tm[old_tmi], tms->tm[new_tmi], &ctx->mac_config->tonemask_info)) { /* Use CM_TM_UPDATE.IND. */ ce_rx_mme_send_cm_tm_update_ind (ctx, sta, tms, new_tmi, old_tmi, default_tmi, tmi_list, int_list); } else { /* Use CM_CHAN_EST.IND. */ ce_rx_mme_send_cm_chan_est_ind (ctx, sta, tms, initial_ce, new_tmi, default_tmi, tmi_list, int_list); } } /* Set refresh counter when there is some TMI enabled. */ if (tmi_list) tms->refresh_counter_s = CE_RX_REFRESH_TONE_MAP_S; else tms->refresh_counter_s = 0; } void ce_rx_mme_refresh_tone_map_list (cp_t *ctx, cp_sta_t *sta, u32 tmi_list, u8 default_tmi, tonemap_intervals_t *int_list, tonemaps_t *tms) { ce_rx_mme_send_cm_tm_update_ind (ctx, sta, tms, 0, default_tmi, default_tmi, tmi_list, int_list); /* Set refresh counter when there is some TMI enabled. */ if (tmi_list) tms->refresh_counter_s = CE_RX_REFRESH_TONE_MAP_S; else tms->refresh_counter_s = 0; } void ce_rx_mme_restart_initial_ce (cp_t *ctx, cp_sta_t *sta, tonemaps_t *tms) { ce_rx_mme_send_cm_tm_update_ind (ctx, sta, tms, 0, 0, 0, 0, tms->intervals); /* Disable expiration timer. */ tms->refresh_counter_s = 0; }