/*---------------------------------------------------------------------------* Project: TwlSDK - PRC - demo - characterRecognition-2 File: main.c Copyright 2007-2008 Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Date:: 2008-09-17#$ $Rev: 8556 $ $Author: okubata_ryoma $ *---------------------------------------------------------------------------*/ #include #include #include #include #include #include "patterns.h" //----- Specify how many places to output recognition result #define RESULT_NUM 3 //----- Maximum number of points per input //----- * As a standard, 60 points are entered each second #define POINT_PER_INPUT_MAX 1024 //----- Maximum stroke count per input #define STROKE_PER_INPUT_MAX 20 //----- Maximum number of points after resampling #define POINT_AFTER_RESAMPLING_MAX 40 #define VRAM_BASE_ADDR ((u16*)HW_LCDC_VRAM_C) #define VRAM_LINE_SIZE 256 #define DRAW_COLOR 0 #define MEMORY_MAIN_MAX_HEAPS 1 #define MEMORY_MAIN_HEAP_SIZE 0x200000 #define N_INPUT_PARAM 8 static void InitOS(void); static void InitTP(void); static void InitDisplay(void); static void DrawLine(int x1, int y1, int x2, int y2, u16 col); static void PutDot(int x, int y, u16 col); static void ClearScreen(void); void DrawStrokes(const PRCStrokes *strokes, int sx, int sy); static void PrintRecognitionResult(const char *name, PRCPrototypeEntry **result, fx32 *scores); static void VBlankIntr(void); void PrintStrokesAsEntryData(const PRCStrokes *strokes, const char *name, u32 kind, fx16 correction, int normalizeSize); static int sInputPatternParamThresholds[N_INPUT_PARAM][3] = { {6, 2048, 1}, {8, 3072, 2}, {12, 4096, 3}, {16, 6144, 4}, {24, 8192, 5}, {32, 12288, 8}, {48, 16384, 12}, {64, 21846, 16}, }; void NitroMain(void) { InitOS(); InitDisplay(); InitTP(); OS_InitTick(); OS_InitAlarm(); OS_InitThread(); { PRCPrototypeDB_Common protoDB; int normalizeSize; PRCPoint points[POINT_PER_INPUT_MAX]; PRCStrokes strokes; u16 prevKey, currKey, trgKey; BOOL touching = FALSE; TPData prevSample = { 0, 0, 0, 0 }; void *prototypeListBuffer; void *patternBuffer; void *recognitionBuffer; int dictIndex = 0; int inputParamIndex = N_INPUT_PARAM / 2; BOOL fDictShown = FALSE; int maxPointCount; PRC_Init(); // Expand the sample database // PrototypeList is a list of the sample patterns defined in a separate file { // Store the entry number in entry.data to facilitate subsequent reverse lookup int iEntry; for (iEntry = 0; iEntry < PrototypeList.entrySize; iEntry++) { ((PRCPrototypeEntry *)&PrototypeList.entries[iEntry])->data = (void *)iEntry; } } { u32 size; size = PRC_GetPrototypeDBBufferSize_Common(&PrototypeList); OS_Printf("required buffer for InitPrototypeDB: %d bytes\n", size); if (size == 0) size = 1; prototypeListBuffer = OS_Alloc(size); SDK_ASSERT(prototypeListBuffer); } if (!PRC_InitPrototypeDB_Common(&protoDB, prototypeListBuffer, &PrototypeList)) { OS_Printf("cannot initialize the prototype DB.\n"); OS_Terminate(); } normalizeSize = protoDB.normalizeSize; maxPointCount = POINT_AFTER_RESAMPLING_MAX; while (TRUE) { { u32 size, maxSize;; size = PRC_GetInputPatternBufferSize_Common(maxPointCount, STROKE_PER_INPUT_MAX); OS_Printf("maxPointCount: %d, maxStrokeCount: %d\n", maxPointCount, STROKE_PER_INPUT_MAX); OS_Printf("required buffer for InitInputPattern: %d bytes\n", size); if (size == 0) size = 1; patternBuffer = OS_Alloc(size); if (patternBuffer == NULL) { OS_Printf("OS_Alloc failed.\n"); maxPointCount = POINT_AFTER_RESAMPLING_MAX; continue; } size = PRC_GetRecognitionBufferSize_Light(maxPointCount, STROKE_PER_INPUT_MAX, &protoDB); OS_Printf("required buffer for Recognition of 'Light': %d bytes\n", size); maxSize = size; size = PRC_GetRecognitionBufferSize_Standard(maxPointCount, STROKE_PER_INPUT_MAX, &protoDB); OS_Printf("required buffer for Recognition of 'Standard': %d bytes\n", size); if (maxSize < size) maxSize = size; size = PRC_GetRecognitionBufferSize_Fine(maxPointCount, STROKE_PER_INPUT_MAX, &protoDB); OS_Printf("required buffer for Recognition of 'Fine': %d bytes\n", size); if (maxSize < size) maxSize = size; size = PRC_GetRecognitionBufferSize_Superfine(maxPointCount, STROKE_PER_INPUT_MAX, &protoDB); OS_Printf("required buffer for Recognition of 'Superfine': %d bytes\n", size); if (maxSize < size) maxSize = size; if (maxSize == 0) maxSize = 1; recognitionBuffer = OS_Alloc(maxSize); if (recognitionBuffer == NULL) { OS_Printf("OS_Alloc failed.\n"); maxPointCount = POINT_AFTER_RESAMPLING_MAX; OS_Free(patternBuffer); continue; } } PRC_InitStrokes(&strokes, points, POINT_PER_INPUT_MAX); ClearScreen(); fDictShown = FALSE; //---- Dummy READ workaround for pushing 'A' at IPL currKey = PAD_Read(); while (TRUE) { BOOL fClearScreen = FALSE; BOOL fClearScreenAfterRecognition = FALSE; BOOL fRecognizeChar = FALSE; BOOL fShowPrototypeList = FALSE; BOOL fPrintPattern = FALSE; TPData sample; prevKey = currKey; currKey = PAD_Read(); trgKey = (u16)(currKey & ~prevKey); (void)TP_RequestCalibratedSampling(&sample); if (sample.touch && (sample.validity == 0)) { // Pen is touching the screen if (!PRC_IsFull(&strokes)) { if (touching) { // Writing DrawLine(prevSample.x, prevSample.y, sample.x, sample.y, DRAW_COLOR); } else { // The moment pen touches the screen PutDot(sample.x, sample.y, DRAW_COLOR); touching = TRUE; } // Store stroke data PRC_AppendPoint(&strokes, sample.x, sample.y); } } else { // Pen is off the screen if (touching) { // The moment the pen comes off the screen if (!PRC_IsFull(&strokes)) { PRC_AppendPenUpMarker(&strokes); } touching = FALSE; } } // Recognition begins when A button is pressed if (trgKey & PAD_BUTTON_A) { fRecognizeChar = TRUE; fClearScreenAfterRecognition = TRUE; } // Clear screen when B button is pressed if (trgKey & (PAD_BUTTON_START | PAD_BUTTON_B)) { fClearScreen = TRUE; } // If the X Button is pressed, although recognition occurs, the screen is not cleared if (trgKey & PAD_BUTTON_X) { fRecognizeChar = TRUE; } // If the Y Button is pressed, pattern data is exported to debug while being recognized if (trgKey & PAD_BUTTON_Y) { fRecognizeChar = TRUE; fPrintPattern = TRUE; } // Pressing L button displays the previous entry in the sample DB if (trgKey & PAD_BUTTON_L) { if (fDictShown) { dictIndex--; if (dictIndex < 0) { dictIndex = protoDB.patternCount - 1; } } fShowPrototypeList = TRUE; } // Pressing R button displays the next entry in the sample DB if (trgKey & PAD_BUTTON_R) { if (fDictShown) { dictIndex++; if (dictIndex >= protoDB.patternCount) { dictIndex = 0; } } fShowPrototypeList = TRUE; } // If UP key is pressed, increment maxPointCount by 4 if (trgKey & PAD_KEY_UP) { maxPointCount += 4; break; } // If DOWN key is pressed, decrement maxPointCount by 4 if (trgKey & PAD_KEY_DOWN) { maxPointCount -= 4; if (maxPointCount < 4) { maxPointCount = 4; } break; } // If RIGHT key is pressed, change the resampling parameter to coarser if (trgKey & PAD_KEY_RIGHT) { if (inputParamIndex < N_INPUT_PARAM - 1) { inputParamIndex++; OS_Printf("change InputPatternParam.\n"); } if (!PRC_IsEmpty(&strokes)) { // If there is input, perform recognition fRecognizeChar = TRUE; } } // If LEFT key is pressed, change the resampling parameter to finer if (trgKey & PAD_KEY_LEFT) { if (inputParamIndex > 0) { inputParamIndex--; OS_Printf("change InputPatternParam.\n"); } if (!PRC_IsEmpty(&strokes)) { // If there is input, perform recognition fRecognizeChar = TRUE; } } if (fRecognizeChar) { if (PRC_IsEmpty(&strokes)) { OS_Printf("***********************************************\n"); OS_Printf("No input.\n"); } else { // Pattern Recognition int iParamType; OSTick start, end, initPatternTime, recognizeTime_Light, recognizeTime_Standard, recognizeTime_Fine, recognizeTime_Superfine; PRCInputPattern_Common inputPattern; PRCInputPatternParam_Common inputParam; PRCPrototypeEntry *results[RESULT_NUM]; fx32 scores[RESULT_NUM]; fx32 maxScore; int maxDictIndex; ClearScreen(); fDictShown = FALSE; if (!fClearScreenAfterRecognition) { DrawStrokes(&strokes, 0, 0); } maxScore = 0; maxDictIndex = -1; OS_Printf("***********************************************\n"); for (iParamType = 0; iParamType < 3; iParamType++) { OS_Printf("===============================================\n"); inputParam.normalizeSize = normalizeSize; switch (iParamType) { case 0: inputParam.resampleMethod = PRC_RESAMPLE_METHOD_DISTANCE; inputParam.resampleThreshold = sInputPatternParamThresholds[inputParamIndex][iParamType]; OS_Printf("Resample Method: PRC_RESAMPLE_METHOD_DISTANCE\n"); break; case 1: inputParam.resampleMethod = PRC_RESAMPLE_METHOD_ANGLE; inputParam.resampleThreshold = sInputPatternParamThresholds[inputParamIndex][iParamType]; OS_Printf("Resample Method: PRC_RESAMPLE_METHOD_ANGLE\n"); break; case 2: inputParam.resampleMethod = PRC_RESAMPLE_METHOD_RECURSIVE; inputParam.resampleThreshold = sInputPatternParamThresholds[inputParamIndex][iParamType]; OS_Printf("Resample Method: PRC_RESAMPLE_METHOD_RECURSIVE\n"); break; } OS_Printf("Resample Threshold: %d\n", inputParam.resampleThreshold); start = OS_GetTick(); if (PRC_InitInputPatternEx_Common (&inputPattern, patternBuffer, &strokes, maxPointCount, STROKE_PER_INPUT_MAX, &inputParam) == FALSE) { end = OS_GetTick(); initPatternTime = end - start; OS_Printf(" time: %lldus.\n", OS_TicksToMicroSeconds(initPatternTime)); OS_Printf(" fail to initialize the input pattern.\n"); continue; } end = OS_GetTick(); initPatternTime = end - start; OS_Printf(" time: %lldus.\n", OS_TicksToMicroSeconds(initPatternTime)); if (fPrintPattern) { PRCStrokes outputStrokes; PRC_GetInputPatternStrokes(&outputStrokes, &inputPattern); PrintStrokesAsEntryData( &outputStrokes, (fDictShown) ? PatternName[PrototypeList.entries[dictIndex].code] : "", (fDictShown) ? PrototypeList.entries[dictIndex].kind : 1, (fx16)((fDictShown) ? PrototypeList.entries[dictIndex].correction : 0), normalizeSize); } else { // Compare prototypeList and inputPattern and perform recognition start = OS_GetTick(); (void)PRC_GetRecognizedEntriesEx_Light(results, scores, RESULT_NUM, recognitionBuffer, &inputPattern, &protoDB, PRC_KIND_ALL, NULL); end = OS_GetTick(); recognizeTime_Light = end - start; PrintRecognitionResult("Light", results, scores); OS_Printf(" time: %lldus ( + %lldus (resample) ).\n", OS_TicksToMicroSeconds(recognizeTime_Light), OS_TicksToMicroSeconds(initPatternTime)); start = OS_GetTick(); (void)PRC_GetRecognizedEntriesEx_Standard(results, scores, RESULT_NUM, recognitionBuffer, &inputPattern, &protoDB, PRC_KIND_ALL, NULL); end = OS_GetTick(); recognizeTime_Standard = end - start; PrintRecognitionResult("Standard", results, scores); OS_Printf(" time: %lldus ( + %lldus (resample) ).\n", OS_TicksToMicroSeconds(recognizeTime_Standard), OS_TicksToMicroSeconds(initPatternTime)); start = OS_GetTick(); (void)PRC_GetRecognizedEntriesEx_Fine(results, scores, RESULT_NUM, recognitionBuffer, &inputPattern, &protoDB, PRC_KIND_ALL, NULL); end = OS_GetTick(); recognizeTime_Fine = end - start; PrintRecognitionResult("Fine", results, scores); OS_Printf(" time: %lldus ( + %lldus (resample) ).\n", OS_TicksToMicroSeconds(recognizeTime_Fine), OS_TicksToMicroSeconds(initPatternTime)); if (results[0] != NULL && scores[0] > maxScore) { maxScore = scores[0]; maxDictIndex = (int)results[0]->data; } start = OS_GetTick(); (void)PRC_GetRecognizedEntriesEx_Superfine(results, scores, RESULT_NUM, recognitionBuffer, &inputPattern, &protoDB, PRC_KIND_ALL, NULL); end = OS_GetTick(); recognizeTime_Superfine = end - start; PrintRecognitionResult("Superfine", results, scores); OS_Printf(" time: %lldus ( + %lldus (resample) ).\n", OS_TicksToMicroSeconds(recognizeTime_Superfine), OS_TicksToMicroSeconds(initPatternTime)); if (results[0] != NULL && scores[0] > maxScore) { maxScore = scores[0]; maxDictIndex = (int)results[0]->data; } } { PRCStrokes drawingStrokes; PRC_GetInputPatternStrokes(&drawingStrokes, &inputPattern); DrawStrokes(&drawingStrokes, iParamType * 64, 0); // normalizeSize <= 128 } } if (maxDictIndex >= 0) { PRCStrokes drawingStrokes; dictIndex = maxDictIndex; PRC_GetEntryStrokes(&drawingStrokes, &PrototypeList, &PrototypeList.entries[dictIndex]); DrawStrokes(&drawingStrokes, 256 - normalizeSize, 0); fDictShown = TRUE; } if (fClearScreenAfterRecognition) { PRC_Clear(&strokes); } } } if (fShowPrototypeList && PrototypeList.entrySize > 0) { // Display the sample pattern PRCStrokes drawingStrokes; ClearScreen(); PRC_Clear(&strokes); PRC_GetEntryStrokes(&drawingStrokes, &PrototypeList, &PrototypeList.entries[dictIndex]); DrawStrokes(&drawingStrokes, 256 - normalizeSize, 0); OS_Printf("***********************************************\n"); OS_Printf("#%d: '%s'\n", dictIndex, PatternName[PrototypeList.entries[dictIndex].code]); // PRCi_PrintPatternData_Common(&protoDB.patterns[dictIndex].data); fDictShown = TRUE; } if (fPrintPattern && fDictShown && PrototypeList.entrySize > 0) { PRCStrokes outputStrokes; PRC_GetEntryStrokes(&outputStrokes, &PrototypeList, &PrototypeList.entries[dictIndex]); OS_Printf("===============================================\n"); OS_Printf("Original PrototypeList:\n"); PrintStrokesAsEntryData(&outputStrokes, PatternName[PrototypeList.entries[dictIndex].code], PrototypeList.entries[dictIndex].kind, PrototypeList.entries[dictIndex].correction, normalizeSize); } // Wait for V-Blank interrupt OS_WaitVBlankIntr(); if (fClearScreen) { ClearScreen(); fDictShown = FALSE; PRC_Clear(&strokes); } prevSample = sample; } OS_Free(recognitionBuffer); OS_Free(patternBuffer); } OS_Free(prototypeListBuffer); } } void InitOS(void) { void *nstart; void *heapStart; OSHeapHandle handle; OS_Init(); nstart = OS_InitAlloc(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi(), MEMORY_MAIN_MAX_HEAPS); OS_SetMainArenaLo(nstart); heapStart = OS_AllocFromMainArenaLo(MEMORY_MAIN_HEAP_SIZE, 32); handle = OS_CreateHeap(OS_ARENA_MAIN, heapStart, (void *)((u32)heapStart + MEMORY_MAIN_HEAP_SIZE)); (void)OS_SetCurrentHeap(OS_ARENA_MAIN, handle); } void InitDisplay(void) { GX_Init(); FX_Init(); GX_DispOff(); GXS_DispOff(); GX_SetDispSelect(GX_DISP_SELECT_SUB_MAIN); OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr); (void)OS_EnableIrqMask(OS_IE_V_BLANK); (void)GX_VBlankIntr(TRUE); // To generate V-Blank interrupt request (void)OS_EnableIrq(); GX_SetBankForLCDC(GX_VRAM_LCDC_ALL); MI_CpuClearFast((void *)HW_LCDC_VRAM, HW_LCDC_VRAM_SIZE); MI_CpuFillFast((void *)HW_OAM, 192, HW_OAM_SIZE); // Clear OAM MI_CpuClearFast((void *)HW_PLTT, HW_PLTT_SIZE); // Clear the standard palette MI_CpuFillFast((void *)HW_DB_OAM, 192, HW_DB_OAM_SIZE); // Clear OAM MI_CpuClearFast((void *)HW_DB_PLTT, HW_DB_PLTT_SIZE); // Clear the standard palette MI_DmaFill32(3, (void *)HW_LCDC_VRAM_C, 0x7FFF7FFF, 256 * 192 * sizeof(u16)); GX_SetGraphicsMode(GX_DISPMODE_VRAM_C, // VRAM mode (GXBGMode)0, // Dummy (GXBG0As)0); // Dummy OS_WaitVBlankIntr(); // Waiting for the end of the V-Blank interrupt GX_DispOn(); } void InitTP(void) { TPCalibrateParam calibrate; TP_Init(); // Get CalibrateParameter from FlashMemory if (!TP_GetUserInfo(&calibrate)) { OS_Panic("Can't get Calibration Parameter from NVRAM\n"); } else { OS_Printf("Get Calibration Parameter from NVRAM\n"); } TP_SetCalibrateParam(&calibrate); } void DrawLine(int x1, int y1, int x2, int y2, u16 col) { u16 sx, sy, ey, wx, wy; u16 i; int err, plus, minus; u16 *point = VRAM_BASE_ADDR; SDK_ASSERT(x1 >= 0 && y1 >= 0 && x2 >= 0 && y2 >= 0); // Swap (x1, y1) <-> (x2, y2) if x1 > x2 if (x1 <= x2) { sx = (u16)x1; sy = (u16)y1; ey = (u16)y2; wx = (u16)(x2 - x1); // Width } else { sx = (u16)x2; sy = (u16)y2; ey = (u16)y1; wx = (u16)(x1 - x2); // Width } point += sy * VRAM_LINE_SIZE + sx; if (sy <= ey) { /* Line goes to upper */ wy = (u16)(ey - sy); // Height if (wx > wy) { /* If (X size > Y size) draw a Dot per Xdot */ plus = wy * 2; minus = -wx * 2; err = -wx; for (i = 0; i <= wx; i++) { *point = col; // PutDot ++point; err += plus; if (err >= 0) { point += VRAM_LINE_SIZE; err += minus; } } } else { /* If (X size <= Y size) draw a Dot per Ydot */ plus = wx * 2; minus = -wy * 2; err = -wy; for (i = 0; i <= wy; i++) { *point = col; // PutDot point += VRAM_LINE_SIZE; err += plus; if (err >= 0) { ++point; err += minus; } } } } else { /* line goes to lower */ wy = (u16)(sy - ey); // Height if (wx > wy) { /* If (X size > Y size) draw a Dot per Xdot */ plus = wy * 2; minus = -wx * 2; err = -wx; for (i = 0; i <= wx; i++) { *point = col; // PutDot ++point; err += plus; if (err >= 0) { point -= VRAM_LINE_SIZE; err += minus; } } } else { /* If (X size <= Y size) draw a Dot per Ydot */ plus = wx * 2; minus = -wy * 2; err = -wy; for (i = 0; i <= wy; i++) { *point = col; // PutDot point -= VRAM_LINE_SIZE; err += plus; if (err >= 0) { ++point; err += minus; } } } } } void PutDot(int x, int y, u16 col) { *(u16 *)((u32)VRAM_BASE_ADDR + y * 256 * 2 + x * 2) = col; } void ClearScreen(void) { MI_DmaFill32(3, (void *)HW_LCDC_VRAM_C, 0x7FFF7FFF, 256 * 192 * sizeof(u16)); } void DrawStrokes(const PRCStrokes *strokes, int sx, int sy) { int iPoint; PRCPoint prev; BOOL newFlag; const PRCPoint *point; newFlag = TRUE; point = strokes->points; for (iPoint = 0; iPoint < strokes->size; iPoint++, point++) { if (!PRC_IsPenUpMarker(point)) { if (newFlag) { PutDot(sx + point->x, sy + point->y, 1); } else { DrawLine(sx + prev.x, sy + prev.y, sx + point->x, sy + point->y, 1); } prev = *point; newFlag = FALSE; } else { newFlag = TRUE; } } } void PrintRecognitionResult(const char *name, PRCPrototypeEntry **results, fx32 *scores) { int iResult; (void)name; (void)scores; OS_Printf("-----------------------------------------------\n"); OS_Printf("Result(%s):\n", name); // PRCi_PrintPatternData_Common(&inputPattern.data); // Recognition results output if (results[0] == NULL) { OS_Printf(" can't recognize as char\n"); } else { for (iResult = 0; iResult < RESULT_NUM; iResult++) { int code; if (results[iResult] == NULL) break; code = PRC_GetEntryCode(results[iResult]); OS_Printf(" '%s' (score: %d.%03d)\n", PatternName[code], FX_Whole(scores[iResult]), (scores[iResult] & FX16_DEC_MASK) * 1000 / (1 << FX16_DEC_SIZE)); } } } void PrintStrokesAsEntryData(const PRCStrokes *strokes, const char *name, u32 kind, fx16 correction, int normalizeSize) { int iPoint; BOOL newFlag; const PRCPoint *point; (void)name; (void)kind; (void)correction; (void)normalizeSize; OS_Printf("\"%s\" %d %d %d |", name, kind, correction, normalizeSize); newFlag = TRUE; point = strokes->points; for (iPoint = 0; iPoint < strokes->size; iPoint++, point++) { if (!PRC_IsPenUpMarker(point)) { OS_Printf(" (%d, %d)", point->x, point->y); newFlag = FALSE; } else { OS_Printf(" |"); newFlag = TRUE; } } if (!newFlag) { OS_Printf(" |"); } OS_Printf("\n"); } void VBlankIntr(void) { // Set IRQ check flag OS_SetIrqCheckFlag(OS_IE_V_BLANK); }