1 /*---------------------------------------------------------------------------*
2 Project: WPAD Health Demo Program
3 File: handling_weight.c
4
5 Copyright (C) 2007 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 $Log: $
14 *---------------------------------------------------------------------------*/
15 #include <stdlib.h>
16 #include <string.h>
17 #include <stddef.h>
18 #include <stdarg.h>
19 #include <stdio.h>
20 #include <ctype.h>
21
22 #include <revolution.h>
23 #include <revolution/wpad.h>
24 #include <revolution/wpadBalance.h>
25 #include <revolution/wbc.h>
26
27 #define DEMO_USE_MEMLIB=1 // This turns on the DEMO library's MEM heaps.
28 #include <demo.h>
29
30 /*---------------------------------------------------------------------------*
31 * Local Definitions
32 *---------------------------------------------------------------------------*/
33
34 #define SCREEN_WIDTH 320
35 #define SCREEN_HEIGHT 240
36 #define FONT_HEIGHT 8
37
38 GXColor smoke_clr = { 61, 61, 61, 255 } ;
39 GXColor red_clr = { 237, 28, 36, 255 } ;
40 GXColor blue_clr = { 0, 84,166, 255 } ;
41 GXColor yellow_clr = { 255,242, 0, 255 } ;
42 GXColor peagreen_clr = { 141,198, 63, 255 } ;
43
44 WPADBLStatus status;
45
46
47 u8 rxBuf[128] ATTRIBUTE_ALIGN(32);
48 u8 txBuf[128] ATTRIBUTE_ALIGN(32);
49
50
51 /*---------------------------------------------------------------------------*
52 * Function prototypes
53 *---------------------------------------------------------------------------*/
54
55
56 // MEM2 memory allocation routines. The application must provide these to
57 // WPAD, so it can setup the data transfer buffer. This buffer must reside
58 // in MEM2.
59 static void *myAlloc ( u32 size );
60 static u8 myFree ( void *ptr );
61
62
63 // Callbacks for CONNECT and EXTENSION events.
64 void connectCallback ( s32 chan, s32 reason );
65 void extensionCallback ( s32 chan, s32 result );
66
67 // Internal functions
68 static void initialize ( void );
69 static void renderStatus ( void );
70 static void init_draw_graphic ( u16 fb_width, u16 fb_height );
71 static void draw_line ( f32 x1, f32 y1, f32 x2, f32 y2, GXColor clr, f32 width );
72 static void draw_box ( f32 x1, f32 y1, f32 x2, f32 y2, GXColor clr, f32 width );
73
74 static double zero_point[WPAD_PRESS_UNITS];
75 static double sum;
76 static double ave;
77 static u32 counter;
78 static BOOL get_weight_flag = FALSE;
79 static BOOL set_zero_flag = FALSE;
80
81 #define NSAMPLES_2SEC 120
82
83 /*===========================================================================*
84 * F U N C T I O N D E F I N I T I O N S
85 *===========================================================================*/
86 /*---------------------------------------------------------------------------*
87 * Name : main()
88 * Description :
89 * Arguments : None.
90 * Returns : None.
91 *---------------------------------------------------------------------------*/
ctrlWbc(s32 chan,s32 result)92 static void ctrlWbc( s32 chan, s32 result )
93 {
94 OSReport("chan%d [%d]\n", chan, result);
95 }
96
WaitMilliTime(s32 msec)97 static void WaitMilliTime(s32 msec)
98 {
99 OSTime t=OSGetTime();
100 while(OSTicksToMilliseconds(OSGetTime()-t) < msec)
101 ;
102 }
103
104
ZeroSetStart2(s32 chan,s32 result)105 static void ZeroSetStart2( s32 chan, s32 result )
106 {
107 #pragma unused(chan, result)
108
109 // Very rarely, the AD value fluctuates wildly after the temperature value is updated, so we wait a little here (200ms).
110
111 WaitMilliTime(200);
112
113
114 // Start zero-point compensation.
115 set_zero_flag = TRUE;
116 counter = 0;
117 zero_point[0] = 0;
118 zero_point[1] = 0;
119 zero_point[2] = 0;
120 zero_point[3] = 0;
121 }
122
123
ZeroSetStart(s32 chan,s32 result)124 static void ZeroSetStart( s32 chan, s32 result )
125 {
126 #pragma unused(chan, result)
127
128 // Check temperature.
129 WPADRead(WPAD_CHAN3, &status);
130
131
132 if((status.temp == 127) || (status.temp == -128))
133 {
134 // If it couldn't be obtained completely, make another attempt to update temperature.
135 WPADControlBLC(WPAD_CHAN3, WPAD_BLCMD_UPDATE_TEMP, ZeroSetStart2);
136 }
137 else
138 {
139 // Very rarely, the AD value fluctuates wildly after the temperature value is updated, so we wait a little here (200ms).
140
141 WaitMilliTime(200);
142
143 // Start zero-point compensation.
144 set_zero_flag = TRUE;
145 counter = 0;
146 zero_point[0] = 0;
147 zero_point[1] = 0;
148 zero_point[2] = 0;
149 zero_point[3] = 0;
150 }
151 }
152
main(void)153 int main( void )
154 {
155
156 initialize();
157
158 WPADRegisterAllocator(myAlloc, myFree);
159
160 WPADInit();
161
162 WPADSetConnectCallback(WPAD_CHAN3, connectCallback);
163
164 while (WPAD_STATE_SETUP != WPADGetStatus())
165 {
166 ;
167 }
168
169 while(1)
170 {
171 DEMOPadRead();
172
173 if (DEMOPadGetButtonDown(0) & PAD_BUTTON_A)
174 {
175 // Turns on power to the Wii Balance Board.
176 WPADControlBLC(WPAD_CHAN3, WPAD_BLCMD_ON, ctrlWbc);
177 }
178 if (DEMOPadGetButtonDown(0) & PAD_BUTTON_B)
179 {
180 // Turns off power to the Wii Balance Board.
181 WPADControlBLC(WPAD_CHAN3, WPAD_BLCMD_OFF, ctrlWbc);
182 }
183 if (DEMOPadGetButtonDown(0) & PAD_TRIGGER_Z)
184 {
185 // Updates the Wii Balance Board temperature value.
186 WPADControlBLC(WPAD_CHAN3, WPAD_BLCMD_UPDATE_TEMP, ctrlWbc);
187 }
188 if (DEMOPadGetButtonDown(0) & PAD_BUTTON_MENU)
189 {
190 if((set_zero_flag == FALSE) && (get_weight_flag == FALSE))
191 {
192 // Updates the Wii Balance Board temperature value immediately before producing a zero-point.
193 WPADControlBLC(WPAD_CHAN3, WPAD_BLCMD_UPDATE_TEMP, ZeroSetStart);
194 }
195 }
196 if (DEMOPadGetButtonDown(0) & PAD_BUTTON_LEFT)
197 {
198 if((set_zero_flag == FALSE) && (get_weight_flag == FALSE))
199 {
200 // Gets the 2-second average of the weight conversion value.
201 get_weight_flag = TRUE;
202 counter = 0;
203 sum = 0;
204 }
205 }
206
207
208 // Caption
209 DEMOInitCaption( DM_FT_XLU, SCREEN_WIDTH, SCREEN_HEIGHT );
210 GXSetZMode( GX_ENABLE, GX_ALWAYS, GX_ENABLE );
211 GXSetBlendMode( GX_BM_BLEND, GX_BL_ONE, GX_BL_ONE, GX_LO_CLEAR );
212
213 DEMOBeforeRender();
214 renderStatus();
215 DEMODoneRender();
216 }
217
218 } // End main()
219
220 /*---------------------------------------------------------------------------*
221 * Name : connectCallback()
222 *
223 * Description : This callback is invoked when a controller is connected or
224 * disconnected.
225 *
226 * Arguments : The channel (chan) for which the event has occurred.
227 * The channel status (reason):
228 * WPAD_ERR_NONE means a controller has been connected.
229 * WPAD_ERR_NO_CONTROLLER means a controller disconnected.
230 *
231 * Returns : None.
232 *---------------------------------------------------------------------------*/
connectCallback(s32 chan,s32 reason)233 void connectCallback(s32 chan, s32 reason)
234 {
235 u32 type;
236
237 if (reason == WPAD_ERR_NONE)
238 {
239 // 4P is reserved for the Wii Balance Board, so anything else is disconnected.
240
241 WPADProbe(chan, &type);
242 if (chan == WPAD_CHAN3 && type != WPAD_DEV_BALANCE_CHECKER)
243 {
244 OSReport("Channel%d is reserved for the balance checker.\n", chan);
245 WPADDisconnect(chan);
246 }
247 else
248 {
249 // Reads the calibration value for calculating a weight.
250 if(WPAD_ERR_NONE != WBCSetupCalibration())
251 {
252 OSHalt("WBC FATAL ERROR!!\n");
253 }
254
255 OSReport("Channel%d is connected.\n", chan);
256 WPADSetExtensionCallback(chan, extensionCallback);
257 }
258 }
259 else
260 {
261 OSReport("Channel%d is disconnected.\n", chan);
262 }
263 } // End connectCallback()
264
265 /*---------------------------------------------------------------------------*
266 * Name : extensionCallback()
267 *
268 * Description : This callback is invoked when an Extension has been attached.
269 *
270 * Arguments : The channel (chan) for which the extension event occurred.
271 * The device type (result):
272 *
273 * WPAD_DEV_UNKNOWN means that something has been attached, but
274 * it's being initialized, and we won't know what it is until
275 * initialization is complete.
276 *
277 * WPAD_DEV_CORE means that an extension has been removed and
278 * we're back to just the core device.
279 *
280 * WPAD_DEV_FREESTYLE means that the "NUNCHAK" extension has
281 * been attached and initialized.
282 *
283 * WPAD_DEV_CLASSIC means that the "CLASSIC" extension has been
284 * attached and initialized.
285 *
286 * Returns : None.
287 *---------------------------------------------------------------------------*/
extensionCallback(s32 chan,s32 result)288 void extensionCallback(s32 chan, s32 result)
289 {
290 switch(result)
291 {
292 case WPAD_DEV_UNKNOWN:
293 OSReport("Initializing extension on channel%d...\n", chan);
294 break;
295
296 case WPAD_DEV_CORE:
297 WPADControlDpd(chan, WPAD_DPD_EXP, NULL);
298 WPADSetDataFormat(chan, WPAD_FMT_CORE_ACC_DPD);
299
300 OSReport("Extension removed on channel%d.\n", chan);
301 break;
302
303 case WPAD_DEV_NOT_SUPPORTED:
304 case WPAD_DEV_FUTURE:
305 WPADControlDpd(chan, WPAD_DPD_EXP, NULL);
306 WPADSetDataFormat(chan, WPAD_FMT_CORE_ACC_DPD);
307
308 OSReport("Extension is not useful on channel%d.\n", chan);
309 break;
310
311 case WPAD_DEV_FREESTYLE:
312 WPADControlDpd(chan, WPAD_DPD_STD, NULL);
313 WPADSetDataFormat(chan, WPAD_FMT_FREESTYLE_ACC_DPD);
314
315 OSReport("Freestyle initialized on channel%d.\n", chan);
316 break;
317
318 case WPAD_DEV_CLASSIC:
319 WPADControlDpd(chan, WPAD_DPD_STD, NULL);
320 WPADSetDataFormat(chan, WPAD_FMT_CLASSIC_ACC_DPD);
321
322 OSReport("Classicstyle initialized on channel%d.\n", chan);
323 break;
324
325 case WPAD_DEV_BALANCE_CHECKER:
326 WPADControlDpd(chan, WPAD_DPD_OFF, NULL);
327 WPADSetDataFormat(chan, WPAD_FMT_BALANCE_CHECKER);
328 WPADControlBLC(chan, WPAD_BLCMD_ON, NULL);
329
330 OSReport("Balance checker initialized on channel%d.\n", chan);
331 break;
332
333 default:
334 // Here is WPAD_DEV_NOT_FOUND.
335 // If the controller is disconnected while the extension is initializing
336 // it reaches here. There is nothing to do.
337 break;
338
339 } // End
340
341 } // End extensionCallback()
342
343 /*---------------------------------------------------------------------------*
344 * Name : myAlloc()
345 * Description : Callback needed by WPAD to allocate mem from MEM2 heap.
346 * Arguments : size of block, in bytes.
347 * Returns : pointer to allocated block.
348 *---------------------------------------------------------------------------*/
myAlloc(u32 size)349 static void *myAlloc(u32 size)
350 {
351 void *ptr;
352
353 ptr = MEMAllocFromAllocator(&DemoAllocator2, size);
354 ASSERTMSG(ptr, "Memory allocation failed\n");
355
356 return(ptr);
357
358 } // myAlloc()
359
360 /*---------------------------------------------------------------------------*
361 * Name : myFree()
362 * Description : Callback needed by WPAD to free mem from MEM2 heap.
363 * Arguments : None.
364 * Returns : Always 1.
365 *---------------------------------------------------------------------------*/
myFree(void * ptr)366 static u8 myFree(void *ptr)
367 {
368
369 MEMFreeToAllocator(&DemoAllocator2, ptr);
370
371 // we should ensure that memory is free'd properly, but oh well
372 return(1);
373
374 } // myFree()
375
376
renderStatus(void)377 static void renderStatus(void)
378 {
379 u32 type;
380 s32 isExist = 0;
381
382 if (WPADProbe(WPAD_CHAN3, &type) == WPAD_ERR_NO_CONTROLLER)
383 {
384 if (WPADIsRegisteredBLC())
385 {
386 DEMOPrintf( 50, 100, 0, "WBC is not connected.");
387 }
388 else
389 {
390 DEMOPrintf( 20, 100, 0, "WBC is not registered.");
391 DEMOPrintf( 20, 110, 0, "Please regist WBC with SYNC button.");
392 }
393 }
394 else
395 {
396 if (type == WPAD_DEV_BALANCE_CHECKER)
397 {
398 double weight[WPAD_PRESS_UNITS];
399 double all;
400
401
402 WPADRead(WPAD_CHAN3, &status);
403
404 DEMOPrintf( 95, 40, 0, "%5d", status.press[0]);
405 DEMOPrintf( 95, 110, 0, "%5d", status.press[1]);
406 DEMOPrintf( 10, 40, 0, "%5d", status.press[2]);
407 DEMOPrintf( 10, 110, 0, "%5d", status.press[3]);
408
409 isExist = WBCRead(&status, weight, (u32)(sizeof(weight) / sizeof(weight[0])));
410 all = (double)(weight[0] + weight[1] + weight[2] + weight[3]);
411
412
413
414 if((get_weight_flag || set_zero_flag) && counter < NSAMPLES_2SEC)
415 {
416 counter++;
417 sum += all;
418 zero_point[0] += status.press[0];
419 zero_point[1] += status.press[1];
420 zero_point[2] += status.press[2];
421 zero_point[3] += status.press[3];
422 }
423
424
425 if(counter == NSAMPLES_2SEC)
426 {
427 ave = sum / NSAMPLES_2SEC;
428 zero_point[0] /= NSAMPLES_2SEC;
429 zero_point[1] /= NSAMPLES_2SEC;
430 zero_point[2] /= NSAMPLES_2SEC;
431 zero_point[3] /= NSAMPLES_2SEC;
432 get_weight_flag = FALSE;
433
434 if(set_zero_flag)
435 {
436 //Sets the zero point internally in the Library.
437 if(0 == WBCSetZEROPoint( zero_point,(u32)(sizeof(zero_point) / sizeof(zero_point[0])) ))
438 {
439 //Succeeded
440 set_zero_flag = FALSE;
441 }
442 else
443 {
444 //Retries if it failed.
445 counter = 0;
446 zero_point[0] = 0;
447 zero_point[1] = 0;
448 zero_point[2] = 0;
449 zero_point[3] = 0;
450 }
451 }
452 }
453
454
455 if(get_weight_flag || set_zero_flag)
456 {
457 DEMOPrintf( 95, 55, 0, "wait...");
458 DEMOPrintf( 95, 125, 0, "wait...");
459 DEMOPrintf( 10, 55, 0, "wait...");
460 DEMOPrintf( 10, 125, 0, "wait...");
461
462 if(get_weight_flag)
463 {
464 DEMOPrintf(175, 60, 0, "Wt :WAIT");
465 DEMOPrintf(175, 70, 0, "Wt(TGC):WAIT");
466 }
467 else
468 {
469 DEMOPrintf(175, 60, 0, "Wt :%3.1f[kg]", ave);
470 DEMOPrintf(175, 70, 0, "Wt(TGC):%3.1f[kg]", WBCGetTGCWeight(ave, &status));
471 }
472 }
473 else
474 {
475 DEMOPrintf( 95, 55, 0, "%3.1f", weight[0]);
476 DEMOPrintf( 95, 125, 0, "%3.1f", weight[1]);
477 DEMOPrintf( 10, 55, 0, "%3.1f", weight[2]);
478 DEMOPrintf( 10, 125, 0, "%3.1f", weight[3]);
479 DEMOPrintf(175, 60, 0, "Wt :%3.1f[kg]", ave);
480 DEMOPrintf(175, 70, 0, "Wt(TGC):%3.1f[kg]", WBCGetTGCWeight(ave, &status));
481 DEMOPrintf(175, 80, 0, "Setup :%s", WBCGetCalibrationStatus()==TRUE ? "OK":"NG");
482 }
483
484 DEMOPrintf(175, 20, 0, "Temp %d", status.temp);
485 DEMOPrintf(175, 30, 0, "Batt %d/Level %d", status.battery, WBCGetBatteryLevel(status.battery));
486 DEMOPrintf(175, 40, 0, "IsEXIST = %s", isExist == 1 ? "EXIST" : "NONE");
487
488 DEMOPrintf( 10, 160, 0, "A: Turn On SENSOR");
489 DEMOPrintf( 10, 170, 0, "B: Turn Off SENSOR");
490 DEMOPrintf( 10, 180, 0, "MENU: Set ZERO point");
491 DEMOPrintf( 10, 190, 0, "LEFT: Get AVE Weight");
492 DEMOPrintf( 10, 220, 0, "Z: Update the current temperature");
493
494 init_draw_graphic(SCREEN_WIDTH, SCREEN_HEIGHT);
495 draw_box(-143, -100, -68, -50, peagreen_clr, 2);
496 init_draw_graphic(SCREEN_WIDTH, SCREEN_HEIGHT);
497 draw_box(-143, -30, -68, 20, yellow_clr, 2);
498 init_draw_graphic(SCREEN_WIDTH, SCREEN_HEIGHT);
499 draw_box(-63, -100, 12, -50, blue_clr, 2);
500 init_draw_graphic(SCREEN_WIDTH, SCREEN_HEIGHT);
501 draw_box(-63, -30, 12, 20, red_clr, 2);
502 }
503 else
504 {
505 DEMOPrintf(50, 100, 0, "No balance checker is attached.");
506 }
507 }
508
509 } // End renderStatus()
510
511
initialize(void)512 static void initialize( void )
513 {
514 OSInit();
515
516 DEMOInit( &GXNtsc480IntDf );
517
518 GXSetCopyClear( smoke_clr, GX_MAX_Z24 );
519 GXCopyDisp( DEMOGetCurrentBuffer(), GX_TRUE );
520
521 DEMOPadInit();
522 } // End
523
524
init_draw_graphic(u16 fb_width,u16 fb_height)525 static void init_draw_graphic( u16 fb_width, u16 fb_height )
526 {
527 Mtx44 proj_mtx ;
528 Mtx view_mtx ;
529 f32 canvas_wd, canvas_ht ;
530
531 // CANVAS
532 canvas_wd = fb_width * 0.91346f ;
533 canvas_ht = fb_height ;
534
535 // MTX
536 MTXOrtho( proj_mtx, canvas_ht * -0.5f,canvas_ht * 0.5f, canvas_wd * -0.5f,canvas_wd * 0.5f, -10.0f,10.0f ) ;
537 GXSetProjection( proj_mtx, GX_ORTHOGRAPHIC ) ;
538
539 MTXIdentity( view_mtx ) ;
540 GXLoadPosMtxImm( view_mtx, GX_PNMTX0 ) ;
541 GXSetCurrentMtx( GX_PNMTX0 ) ;
542
543 // VERTEX
544 GXClearVtxDesc() ;
545 GXSetVtxDesc( GX_VA_POS, GX_DIRECT ) ;
546 GXSetVtxAttrFmt( GX_VTXFMT0, GX_VA_POS, GX_POS_XY, GX_F32, 0 ) ;
547
548 // CHANNEL
549 GXSetNumChans( 1 ) ;
550 GXSetChanCtrl( GX_COLOR0A0, GX_DISABLE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE ) ;
551 GXSetChanCtrl( GX_COLOR1A1, GX_DISABLE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE ) ;
552
553 // TEXTURE
554 GXSetNumTexGens( 0 ) ;
555
556 // TEV
557 GXSetNumTevStages( 1 ) ;
558 GXSetTevOrder( GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL ) ;
559 GXSetTevColorIn( GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_C0 ) ;
560 GXSetTevColorOp( GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV ) ;
561 GXSetTevAlphaIn( GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_A0 ) ;
562 GXSetTevAlphaOp( GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV ) ;
563 GXSetAlphaCompare( GX_ALWAYS,0, GX_AOP_OR, GX_ALWAYS,0 ) ;
564
565 // SCREEN
566 GXSetBlendMode( GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_NOOP ) ;
567 GXSetAlphaUpdate( GX_DISABLE ) ;
568
569 GXSetZMode( GX_DISABLE, GX_ALWAYS, GX_DISABLE ) ;
570 GXSetCullMode( GX_CULL_BACK ) ;
571 }
572
573 /*******************************************************************************
574 Draw object
575 *******************************************************************************/
draw_line(f32 x1,f32 y1,f32 x2,f32 y2,GXColor clr,f32 width)576 static void draw_line( f32 x1, f32 y1, f32 x2, f32 y2, GXColor clr, f32 width )
577 {
578 GXSetTevColor( GX_TEVREG0, clr ) ;
579 GXSetLineWidth( (u8)(s32)(width * 6.0f + 0.5f), GX_TO_ZERO ) ;
580
581 GXBegin( GX_LINES, GX_VTXFMT0, 2 ) ;
582 GXPosition2f32( x1, y1 ) ;
583 GXPosition2f32( x2, y2 ) ;
584 GXEnd() ;
585 }
586
draw_box(f32 x1,f32 y1,f32 x2,f32 y2,GXColor clr,f32 width)587 static void draw_box( f32 x1, f32 y1, f32 x2, f32 y2, GXColor clr, f32 width )
588 {
589 draw_line(x1, y1, x2, y1, clr, width);
590 draw_line(x2, y1, x2, y2, clr, width);
591 draw_line(x2, y2, x1, y2, clr, width);
592 draw_line(x1, y2, x1, y1, clr, width);
593 }
594
595