1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - MB - demos - mbm
3 File: mb_measure_channel.c
4
5 Copyright 2006-2008 Nintendo. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Date:: 2008-09-18#$
14 $Rev: 8573 $
15 $Author: okubata_ryoma $
16 *---------------------------------------------------------------------------*/
17
18 #include <nitro/wm.h>
19
20 #include "mb_measure_channel.h"
21
22 #define MBM_DEBUG
23
24 #ifdef MBM_DEBUG
25 #define PRINTF OS_TPrintf
26 #else
27 #define PRINTF(...) ((void)0)
28 #endif
29
30 #define MBM_MEASURE_DMA_NO 2
31
32 // Random number macro
33 #define RAND() ( sRand = sRand + 69069UL + 12345 )
34 #define RAND_INIT(x) ( sRand = (u32)(x) )
35
36 enum
37 {
38 MBM_STATE_INIT, // Initial state
39 MBM_STATE_MEASURING, // Start state
40 MBM_STATE_END_MEASURE, // End measuring
41 MBM_STATE_END, // State with wireless communications off
42 MBM_STATE_ERR // Error
43 };
44
45
46 enum
47 {
48 ERRCODE_SUCCESS = 0, // Success
49 ERRCODE_NOMORE_CHANNEL, // No more channels can be found
50 ERRCODE_API_ERR // WM API execution error
51 };
52
53 //===========================================================================
54 // Variable Declarations
55 //===========================================================================
56
57 static u32 sRand;
58
59 static MBMCallbackFunc sUserCallbackFunc = NULL;
60 static int mbm_measure_state = MBM_STATE_END;
61 // For communication channel storage
62 static s16 sChannel;
63 static u16 sChannelBitmap;
64 static u16 sChannelBusyRatio;
65
66 static BOOL sUseInIdle = FALSE;
67
68
69 //===========================================================================
70 // Function Prototype Declarations
71 //===========================================================================
72
73 static int wmi_measure_channel(WMCallbackFunc callback, u16 channel);
74 static void wm_callback(void *arg);
75 static void start_measure_channel(void);
76 static u16 state_in_measure_channel(u16 channel);
77 static void state_out_measure_channel(void *arg);
78 static void state_in_wm_end(void);
79 static void user_callback(s16 num);
80 static void change_mbm_state(u16 state);
81 static void callback_ready(s16 result);
82 static s16 select_channel(u16 bitmap);
83
84 //===========================================================================
85 // Function Definitions
86 //===========================================================================
87
88 /* ----------------------------------------------------------------------
89 Checks the signal use rate
90 ---------------------------------------------------------------------- */
wmi_measure_channel(WMCallbackFunc callback,u16 channel)91 static inline int wmi_measure_channel(WMCallbackFunc callback, u16 channel)
92 {
93 #define MBM_MEASURE_TIME 30 // The time interval in ms for picking up the signal to carry out communication for one frame
94 #define MBM_MEASURE_CS_OR_ED 3 // The logical OR of the carrier sense and the ED value
95 #define MBM_MEASURE_ED_THRESHOLD 17 // The recommended ED threshold value that has been empirically shown to be effective
96
97 /*
98 * A value considered to be empirically valid is used as a parameter for getting the wireless activity ratio
99 *
100 */
101 return WM_MeasureChannel(callback, // Callback settings
102 MBM_MEASURE_CS_OR_ED, // CS or ED
103 MBM_MEASURE_ED_THRESHOLD, // Invalid when only carrier sense
104 channel, // One of the channels obtained with WM_GetAllowedChannel
105 MBM_MEASURE_TIME); //The search time per channel (in ms)
106 }
107
108
109
110 /*---------------------------------------------------------------------------*
111 Name: MBM_MeasureChannel
112
113 Description: Searches for the channel with the lowest usage rate.
114 Call in the wireless OFF state.
115 Returns a callback after internally measuring the radio and setting it to a wireless OFF state.
116
117 Arguments: wm_buffer: WM work memory
118 callback: Designates the user callback to call when the search has finished
119
120 Returns: None.
121 *---------------------------------------------------------------------------*/
MBM_MeasureChannel(u8 * wm_buffer,MBMCallbackFunc callback)122 void MBM_MeasureChannel(u8 *wm_buffer, MBMCallbackFunc callback)
123 {
124 sUseInIdle = FALSE;
125 sUserCallbackFunc = callback;
126
127 // Starts the initialization sequence
128 if (mbm_measure_state != MBM_STATE_END)
129 {
130 user_callback(MBM_MEASURE_ERROR_ILLEGAL_STATE);
131 return;
132 }
133
134 if (WM_Initialize(wm_buffer, wm_callback, MBM_MEASURE_DMA_NO) != WM_ERRCODE_OPERATING)
135 {
136 user_callback(MBM_MEASURE_ERROR_INIT_API);
137 return;
138 }
139 }
140
141 /*---------------------------------------------------------------------------*
142 Name: MBM_MeasureChannelInIdle
143
144 Description: Searches for the channel with the lowest usage rate.
145 Call in the idle state.
146 Returns a callback after internally measuring and setting the radio to the IDLE state.
147
148 Arguments: callback: Designates the user callback to call when the search has finished
149
150 Returns: None.
151 *---------------------------------------------------------------------------*/
MBM_MeasureChannelInIdle(MBMCallbackFunc callback)152 void MBM_MeasureChannelInIdle(MBMCallbackFunc callback)
153 {
154 sUseInIdle = TRUE;
155 sUserCallbackFunc = callback;
156
157 // Starts the initialization sequence
158 if (mbm_measure_state != MBM_STATE_END)
159 {
160 user_callback(MBM_MEASURE_ERROR_ILLEGAL_STATE);
161 return;
162 }
163
164 start_measure_channel();
165 }
166
167 /* ----------------------------------------------------------------------
168 WM callback
169 ---------------------------------------------------------------------- */
wm_callback(void * arg)170 static void wm_callback(void *arg)
171 {
172 WMCallback *cb = (WMCallback *)arg;
173
174 switch (cb->apiid)
175 {
176 case WM_APIID_INITIALIZE:
177 /* WM_Initialize callback */
178 {
179 WMCallback *cb = (WMCallback *)arg;
180 if (cb->errcode != WM_ERRCODE_SUCCESS)
181 {
182 user_callback(MBM_MEASURE_ERROR_INIT_CALLBACK);
183 return;
184 }
185 }
186 change_mbm_state(MBM_STATE_INIT);
187 start_measure_channel();
188 break;
189
190 case WM_APIID_MEASURE_CHANNEL:
191 /* WM_MeasureChannel callback */
192 state_out_measure_channel(arg);
193 break;
194
195 case WM_APIID_END:
196 change_mbm_state(MBM_STATE_END);
197 user_callback(sChannel);
198 break;
199
200 default:
201 OS_TPanic("Get illegal callback");
202
203 break;
204 }
205 }
206
207 /* ----------------------------------------------------------------------
208 Begin searching for the radio usage rate
209 ---------------------------------------------------------------------- */
start_measure_channel(void)210 static void start_measure_channel(void)
211 {
212 #define MAX_RATIO 100 // The channel use rate is between 0 and 100
213 u16 result;
214 u8 macAddr[6];
215
216 OS_GetMacAddress(macAddr);
217 RAND_INIT(OS_GetVBlankCount() + *(u16 *)&macAddr[0] + *(u16 *)&macAddr[2] + *(u16 *)&macAddr[4]); // Random number initialization
218 RAND();
219
220 sChannel = 0;
221 sChannelBitmap = 0;
222 sChannelBusyRatio = MAX_RATIO + 1;
223
224 result = state_in_measure_channel(1); // Check in order from channel 1
225
226 if (result == ERRCODE_NOMORE_CHANNEL)
227 {
228 // There are not any channels available
229 callback_ready(MBM_MEASURE_ERROR_NO_ALLOWED_CHANNEL);
230 return;
231 }
232
233 if (result == ERRCODE_API_ERR)
234 {
235 // Error complete
236 callback_ready(MBM_MEASURE_ERROR_MEASURECHANNEL_API);
237 return;
238 }
239
240 // Begin measuring the radio usage rate
241 change_mbm_state(MBM_STATE_MEASURING);
242 }
243
244
245 /*---------------------------------------------------------------------------*
246 Name: state_in_measure_channel
247
248 Arguments: channel: The channel number to start the search at
249
250 Returns: ERRCODE_SUCCESS - Searching
251 ERRCODE_NOMORE_CHANNEL - There are no more channels to search
252 ERRCODE_API_ERR - WM_MeasureChannel API callback error
253 *---------------------------------------------------------------------------*/
state_in_measure_channel(u16 channel)254 static u16 state_in_measure_channel(u16 channel)
255 {
256 u16 allowedCannel;
257
258 allowedCannel = WM_GetAllowedChannel();
259
260 while (((1 << (channel - 1)) & allowedCannel) == 0)
261 {
262 channel++;
263 if (channel > 16)
264 {
265 /* When finished searching all allowed channels */
266 return ERRCODE_NOMORE_CHANNEL;
267 }
268 }
269
270 if (wmi_measure_channel(wm_callback, channel) != WM_ERRCODE_OPERATING)
271 {
272 return ERRCODE_API_ERR;
273 }
274 return ERRCODE_SUCCESS;
275 }
276
277
state_out_measure_channel(void * arg)278 static void state_out_measure_channel(void *arg)
279 {
280 u16 result;
281 u16 channel;
282 WMMeasureChannelCallback *cb = (WMMeasureChannelCallback *)arg;
283
284 if (cb->errcode != WM_ERRCODE_SUCCESS)
285 {
286 callback_ready(MBM_MEASURE_ERROR_MEASURECHANNEL_CALLBACK);
287 return;
288 }
289
290 channel = cb->channel;
291 PRINTF("CH%d = %d\n", cb->channel, cb->ccaBusyRatio);
292
293 if (cb->ccaBusyRatio < sChannelBusyRatio)
294 {
295 sChannelBusyRatio = cb->ccaBusyRatio;
296 sChannelBitmap = (u16)(1 << (channel - 1));
297 }
298 else if (cb->ccaBusyRatio == sChannelBusyRatio)
299 {
300 sChannelBitmap |= (u16)(1 << (channel - 1));
301 }
302
303 result = state_in_measure_channel(++channel);
304
305 if (result == ERRCODE_NOMORE_CHANNEL)
306 {
307 // The channel search ends
308 callback_ready(select_channel(sChannelBitmap));
309 return;
310 }
311
312 if (result == ERRCODE_API_ERR)
313 {
314 // Error complete
315 callback_ready(MBM_MEASURE_ERROR_MEASURECHANNEL_API);
316 return;
317 }
318
319 // Do nothing if ERRCODE_SUCCESS
320
321 }
322
323
324 /* ----------------------------------------------------------------------
325 Turn off wireless before the callback
326 ---------------------------------------------------------------------- */
callback_ready(s16 result)327 static void callback_ready(s16 result)
328 {
329 sChannel = result;
330 if (sUseInIdle)
331 {
332 change_mbm_state(MBM_STATE_END);
333 user_callback(result);
334 }
335 else
336 {
337 state_in_wm_end();
338 change_mbm_state(MBM_STATE_END_MEASURE);
339 }
340 }
341
342 /* ----------------------------------------------------------------------
343 End WM
344 ---------------------------------------------------------------------- */
state_in_wm_end(void)345 static void state_in_wm_end(void)
346 {
347 if (WM_End(wm_callback) != WM_ERRCODE_OPERATING)
348 {
349 OS_TPanic("fail WM_End");
350 }
351 }
352
353
354 /* ----------------------------------------------------------------------
355 Change the MBM internal state
356 ---------------------------------------------------------------------- */
change_mbm_state(u16 state)357 static void change_mbm_state(u16 state)
358 {
359 #ifdef MBM_DEBUG
360 static const char *STATE_STR[] = {
361 "INIT",
362 "MEASURING", // Start state
363 "END_MEASURE", // End measuring
364 "END", // State with wireless communications off
365 "ERR" // Error
366 };
367 #endif
368
369 PRINTF("%s -> ", STATE_STR[mbm_measure_state]);
370 mbm_measure_state = state;
371 PRINTF("%s\n", STATE_STR[mbm_measure_state]);
372 }
373
374 /* ----------------------------------------------------------------------
375 Determine the channel
376 ---------------------------------------------------------------------- */
select_channel(u16 bitmap)377 static s16 select_channel(u16 bitmap)
378 {
379 s16 i;
380 s16 channel = 0;
381 u16 num = 0;
382 u16 select;
383
384 for (i = 0; i < 16; i++)
385 {
386 if (bitmap & (1 << i))
387 {
388 channel = (s16)(i + 1);
389 num++;
390 }
391 }
392
393 if (num <= 1)
394 {
395 return channel;
396 }
397
398 // If there are multiple channels of the same signal usage rate
399 select = (u16)(((RAND() & 0xFF) * num) / 0x100);
400
401 channel = 1;
402
403 for (i = 0; i < 16; i++)
404 {
405 if (bitmap & 1)
406 {
407 if (select == 0)
408 {
409 return (s16)(i + 1);
410 }
411 select--;
412 }
413 bitmap >>= 1;
414 }
415
416 return 0;
417 }
418
419 /* ----------------------------------------------------------------------
420 Call the user callback
421 ---------------------------------------------------------------------- */
user_callback(s16 type)422 static void user_callback(s16 type)
423 {
424 MBMCallback arg;
425
426 if (!sUserCallbackFunc)
427 {
428 return;
429 }
430
431 if (type > 0)
432 {
433 arg.errcode = MBM_MEASURE_SUCCESS;
434 arg.channel = (u16)type;
435 }
436 else
437 {
438 arg.errcode = type;
439 arg.channel = 0;
440 }
441 sUserCallbackFunc(&arg);
442 }
443