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