/*
	Take an array of measumrements representing summaries of different channels.
	Return a recomended channel.
	Interference is evil, get rid of that first.
	Then hunt for lowest Other bss traffic.
	Don't forget that channels with low duration times may not have accurate readings.
	For the moment, do not overwrite input array.
*/
int
cca_analyze(cca_congest_channel_req_t *input[], int num_chans, uint flags, chanspec_t *answer)
{
	uint8 bitmap[CEIL(MAX_CCA_CHANNELS, NBBY)];	/* 38 Max channels needs 5 bytes  = 40 */
	int i, left, winner;
	uint32 min_obss = 1 << 30;

	ASSERT(num_chans < MAX_CCA_CHANNELS);
	for (i = 0; i < (int)sizeof(bitmap); i++)
		bitmap[i] = 0;

	/* Initially, all channels are up for consideration */
	for (i = 0; i < num_chans; i++) {
		if (input[i]->chanspec)
			setbit(bitmap, i);
	}
	cca_info(bitmap, num_chans, &left, &i);
	if (!left)
		return CCA_ERRNO_TOO_FEW;

	/* Filter for 2.4 GHz Band */
	if (flags & CCA_FLAG_2G_ONLY) {
		for (i = 0; i < num_chans; i++) {
			if (!CHSPEC_IS2G(input[i]->chanspec))
				clrbit(bitmap, i);
		}
	}
	cca_info(bitmap, num_chans, &left, &i);
	if (!left)
		return CCA_ERRNO_BAND;

	/* Filter for 5 GHz Band */
	if (flags & CCA_FLAG_5G_ONLY) {
		for (i = 0; i < num_chans; i++) {
			if (!CHSPEC_IS5G(input[i]->chanspec))
				clrbit(bitmap, i);
		}
	}
	cca_info(bitmap, num_chans, &left, &i);
	if (!left)
		return CCA_ERRNO_BAND;

	/* Filter for Duration */
	if (!(flags & CCA_FLAG_IGNORE_DURATION)) {
		for (i = 0; i < num_chans; i++) {
			if (input[i]->secs[0].duration < CCA_THRESH_MILLI)
				clrbit(bitmap, i);
		}
	}
	cca_info(bitmap, num_chans, &left, &i);
	if (!left)
		return CCA_ERRNO_DURATION;

	/* Filter for 1 6 11 on 2.4 Band */
	if (flags &  CCA_FLAGS_PREFER_1_6_11) {
		int tmp_channel = spec_to_chan(input[i]->chanspec);
		int is2g = CHSPEC_IS2G(input[i]->chanspec);
		for (i = 0; i < num_chans; i++) {
			if (is2g && tmp_channel != 1 && tmp_channel != 6 && tmp_channel != 11)
				clrbit(bitmap, i);
		}
	}
	cca_info(bitmap, num_chans, &left, &i);
	if (!left)
		return CCA_ERRNO_PREF_CHAN;

	/* Toss high interference interference */
	if (!(flags & CCA_FLAG_IGNORE_INTERFER)) {
		for (i = 0; i < num_chans; i++) {
			if (input[i]->secs[0].interference > CCA_THRESH_INTERFERE)
				clrbit(bitmap, i);
		}
		cca_info(bitmap, num_chans, &left, &i);
		if (!left)
			return CCA_ERRNO_INTERFER;
	}

	/* Now find lowest obss */
	winner = 0;
	for (i = 0; i < num_chans; i++) {
		if (isset(bitmap, i) && input[i]->secs[0].congest_obss < min_obss) {
			winner = i;
			min_obss = input[i]->secs[0].congest_obss;
		}
	}
	*answer = input[winner]->chanspec;

	return 0;
}
/*
	Take an array of measumrements representing summaries of different channels.
	Return a recomended channel.
	Interference is evil, get rid of that first.
	Then hunt for lowest Other bss traffic.
	Don't forget that channels with low duration times may not have accurate readings.
	For the moment, do not overwrite input array.
*/
int
cca_analyze(cca_congest_channel_req_t *input[], int num_chans, uint flags, chanspec_t *answer)
{
	uint8 *bitmap = NULL;	/* 38 Max channels needs 5 bytes  = 40 */
	int i, left, winner, ret_val = 0;
	uint32 min_obss = 1 << 30;
	uint bitmap_sz;

	bitmap_sz = CEIL(num_chans, NBBY);
	bitmap = (uint8 *)malloc(bitmap_sz);
	if (bitmap == NULL) {
		printf("unable to allocate memory\n");
		return BCME_NOMEM;
	}

	memset(bitmap, 0, bitmap_sz);
	/* Initially, all channels are up for consideration */
	for (i = 0; i < num_chans; i++) {
		if (input[i]->chanspec)
			setbit(bitmap, i);
	}
	cca_info(bitmap, num_chans, &left, &i);
	if (!left) {
		ret_val = CCA_ERRNO_TOO_FEW;
		goto f_exit;
	}

	/* Filter for 2.4 GHz Band */
	if (flags & CCA_FLAG_2G_ONLY) {
		for (i = 0; i < num_chans; i++) {
			if (!CHSPEC_IS2G(input[i]->chanspec))
				clrbit(bitmap, i);
		}
	}
	cca_info(bitmap, num_chans, &left, &i);
	if (!left) {
		ret_val = CCA_ERRNO_BAND;
		goto f_exit;
	}

	/* Filter for 5 GHz Band */
	if (flags & CCA_FLAG_5G_ONLY) {
		for (i = 0; i < num_chans; i++) {
			if (!CHSPEC_IS5G(input[i]->chanspec))
				clrbit(bitmap, i);
		}
	}
	cca_info(bitmap, num_chans, &left, &i);
	if (!left) {
		ret_val = CCA_ERRNO_BAND;
		goto f_exit;
	}

	/* Filter for Duration */
	if (!(flags & CCA_FLAG_IGNORE_DURATION)) {
		for (i = 0; i < num_chans; i++) {
			if (input[i]->secs[0].duration < CCA_THRESH_MILLI)
				clrbit(bitmap, i);
		}
	}
	cca_info(bitmap, num_chans, &left, &i);
	if (!left) {
		ret_val = CCA_ERRNO_DURATION;
		goto f_exit;
	}

	/* Filter for 1 6 11 on 2.4 Band */
	if (flags &  CCA_FLAGS_PREFER_1_6_11) {
		int tmp_channel = spec_to_chan(input[i]->chanspec);
		int is2g = CHSPEC_IS2G(input[i]->chanspec);
		for (i = 0; i < num_chans; i++) {
			if (is2g && tmp_channel != 1 && tmp_channel != 6 && tmp_channel != 11)
				clrbit(bitmap, i);
		}
	}
	cca_info(bitmap, num_chans, &left, &i);
	if (!left) {
		ret_val = CCA_ERRNO_PREF_CHAN;
		goto f_exit;
	}

	/* Toss high interference interference */
	if (!(flags & CCA_FLAG_IGNORE_INTERFER)) {
		for (i = 0; i < num_chans; i++) {
			if (input[i]->secs[0].interference > CCA_THRESH_INTERFERE)
				clrbit(bitmap, i);
		}
		cca_info(bitmap, num_chans, &left, &i);
		if (!left) {
			ret_val = CCA_ERRNO_INTERFER;
			goto f_exit;
		}
	}

	/* Now find lowest obss */
	winner = 0;
	for (i = 0; i < num_chans; i++) {
		if (isset(bitmap, i) && input[i]->secs[0].congest_obss < min_obss) {
			winner = i;
			min_obss = input[i]->secs[0].congest_obss;
		}
	}
	*answer = input[winner]->chanspec;
	f_exit:
	free(bitmap);	/* free the allocated memory for bitmap */
	return ret_val;
}