/*---------------------------------------------------------------------------* Project: TwlSDK - MB - demos - fake_child 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:: 2009-02-19#$ $Rev: 10047 $ $Author: nishimoto_takashi $ *---------------------------------------------------------------------------*/ #ifdef SDK_TWL #include #else #include #endif #include "common.h" #include "disp.h" #include "gmain.h" #include "wh.h" #define DEBUG_PRINT /* * This sample makes an entry as a child with demos/mb/multiboot-Model and participates in network communication with other DS Download Play children. * The target application is configured by the MB_FakeScanParent function's GGID argument. * * */ enum { MODE_TITLE, MODE_START_SCAN, MODE_SCANNING, MODE_ENTRY, MODE_RECONNECT, MODE_GMAIN, MODE_ERROR, MODE_CANCEL }; typedef struct { MBUserInfo info; u16 valid; u8 maxPlayerNum; // Max number of players u8 nowPlayerNum; // Current number of players u8 macAddr[6]; // MAC address } ParentInfo; #define WH_GGID (0x003FFF00 | (0x21)) static void PrintError(MBFakeScanErrorCallback *arg); static void ModeTitle(void); static void ModeStartScan(void); static void ModeScanning(void); static void ModeEntry(void); static void ModeError(void); static void ModeReconnect(void); static void ModeGMain(void); static void ModeCancel(void); static void NotifyScanParent(u16 type, void *arg); static void MBStateCallback(u32 status, void *arg); // Parent info list static ParentInfo parentInfo[MB_GAME_INFO_RECV_LIST_NUM]; static ParentInfo parentInfoBuf[MB_GAME_INFO_RECV_LIST_NUM]; static WMBssDesc sParentBssDesc; // BssDesc of entered parent static u8 *mbfBuf = NULL; static u8 *wmBuf = NULL; static s32 gFrame; // Frame counter static u16 sMode; enum { WSTATE_STOP, // Stop state WSTATE_INITIALIZE_BUSY, // Initializing wireless WSTATE_IDLE, // Idle state WSTATE_ERROR, // Error before starting/after stopping fake child WSTATE_FAKE_SCAN, // Scan state WSTATE_FAKE_END_SCAN, // End scan WSTATE_FAKE_ENTRY, // Entry to parent WSTATE_FAKE_BOOT_READY, // Entry to DS download play is complete WSTATE_FAKE_BOOT_END_BUSY, // DS download processing is now finishing WSTATE_FAKE_BOOT_END, WSTATE_FAKE_CANCEL_BUSY, // DS download canceling WSTATE_FAKE_ERROR // Error }; static u16 sWirelessState = WSTATE_STOP; static u16 sConnectIndex; // Index of parent devices to connect /******************************************************************************/ /* Functions */ #ifdef DEBUG_PRINT static void ChangeWirelessState(u16 wstate) { static const char *WSTATE_NAME[] = { "WSTATE_STOP", "WSTATE_INITIALIZE_BUSY", "WSTATE_IDLE", "WSTATE_ERROR", "WSTATE_FAKE_SCAN", "WSTATE_FAKE_END_SCAN", "WSTATE_FAKE_ENTRY", "WSTATE_FAKE_BOOT_READY", "WSTATE_FAKE_BOOT_END_BUSY", "WSTATE_FAKE_BOOT_END", "WSTATE_FAKE_CANCEL_BUSY", "WSTATE_FAKE_ERROR" }; if (sWirelessState != wstate) { OS_TPrintf("change sWirelessState %s -> %s\n", WSTATE_NAME[sWirelessState], WSTATE_NAME[wstate]); } #else static inline void ChangeWirelessState(u16 wstate) { #endif sWirelessState = wstate; } /* V-Blank interrupt process */ static void VBlankIntr(void) { //---- Interrupt check flag OS_SetIrqCheckFlag(OS_IE_V_BLANK); } /* Main */ #ifdef SDK_TWL void TwlMain() #else void NitroMain() #endif { // Initialize system CommonInit(); // Initialize screen DispInit(); // Initialize the heap InitAllocateSystem(); // Enable interrupts (void)OS_EnableIrq(); (void)OS_EnableInterrupts(); { /* FS initialization */ static u32 fs_tablework[0x100 / 4]; FS_Init(FS_DMA_NOT_USE); (void)FS_LoadTable(fs_tablework, sizeof(fs_tablework)); } // Clear buffer for data sharing GInitDataShare(); // To title screen sMode = MODE_TITLE; // LCD display start GX_DispOn(); GXS_DispOn(); // Debug string output OS_TPrintf("MB fake child: Simple DataSharing demo started.\n"); // Empty call for getting key input data (strategy for pressing A Button in the IPL) ReadKey(); /* Main loop */ for (gFrame = 0; TRUE; gFrame++) { // Get key input data ReadKey(); // Clear the screen BgClear(); switch (sMode) { case MODE_TITLE: // Display title screen ModeTitle(); break; case MODE_START_SCAN: // Start scan ModeStartScan(); break; case MODE_SCANNING: // Scanning MB parent ModeScanning(); break; case MODE_ENTRY: // Entry to MB parent ModeEntry(); break; case MODE_RECONNECT: // Reconnect to MB parent ModeReconnect(); break; case MODE_GMAIN: // Game main ModeGMain(); break; case MODE_ERROR: // Error processing ModeError(); break; case MODE_CANCEL: // Canceling ModeCancel(); break; } OS_WaitVBlankIntr(); } } /* ---------------------------------------------------------------------- Name: ModeTitle Description: Title screen Arguments: None. Returns: None. ---------------------------------------------------------------------- */ static void ModeTitle(void) { BgSetMessage(PLTT_WHITE, " Press Button A to start "); ChangeWirelessState(WSTATE_STOP); // When A Button is pressed, set wireless to ON and enter MB parent search mode if (IS_PAD_TRIGGER(PAD_BUTTON_A)) { sMode = MODE_START_SCAN; } } /* ---------------------------------------------------------------------- Name: ModeStartScan Description: Starts parent scan. Arguments: None. Returns: None. ---------------------------------------------------------------------- */ static void ModeStartScan(void) { BgSetMessage(PLTT_WHITE, "Now working.... "); switch (sWirelessState) { //-------------------------- // Start wireless communication case WSTATE_STOP: if (!WH_Initialize()) { ChangeWirelessState(WSTATE_ERROR); sMode = MODE_ERROR; return; } ChangeWirelessState(WSTATE_INITIALIZE_BUSY); break; //-------------------------- // Initializing wireless case WSTATE_INITIALIZE_BUSY: if (WH_GetSystemState() == WH_SYSSTATE_BUSY) { BgSetMessage(PLTT_WHITE, "Now working.... "); return; } if (WH_GetSystemState() != WH_SYSSTATE_IDLE) { ChangeWirelessState(WSTATE_ERROR); sMode = MODE_ERROR; return; } ChangeWirelessState(WSTATE_IDLE); // Don't break //-------------------------- // Start parent scan case WSTATE_IDLE: { // Set user info MBUserInfo userInfo; OSOwnerInfo info; OS_GetOwnerInfo(&info); userInfo.favoriteColor = info.favoriteColor; userInfo.nameLength = (u8)info.nickNameLength; MI_CpuCopy8(info.nickName, userInfo.name, (u32)(userInfo.nameLength * 2)); // Normally with MB child, playerNo will be 0, but by setting a value it can be passed to a parent as a parameter. userInfo.playerNo = 7; // Allocate work buffer for multiboot entries mbfBuf = (u8 *)OS_Alloc(MB_FakeGetWorkSize()); MB_FakeInit(mbfBuf, &userInfo); // Set the state transition notification callback function MB_FakeSetCStateCallback(MBStateCallback); // Clear parent list MI_CpuClear8(parentInfo, sizeof(parentInfo)); // Wireless state changes to scanning ChangeWirelessState(WSTATE_FAKE_SCAN); // Set GGID of the parent to scan and the notification callback function; start scanning MB_FakeStartScanParent(NotifyScanParent, WH_GGID); // Transition to scan mode sMode = MODE_SCANNING; } break; default: OS_TPanic("illegal state %d", sWirelessState); break; } } /* ---------------------------------------------------------------------- Name: ModeScanning Description: Parent scanning. Arguments: None. Returns: None. ---------------------------------------------------------------------- */ static void ModeScanning(void) { enum { STR_X = 4, STR_Y = 4, NUM_STR_X = 24 }; static u16 cursol_idx = 0; u16 i; // If error occurs, terminate if (sWirelessState == WSTATE_FAKE_ERROR) { sMode = MODE_ERROR; return; } // The parent information is copied to the temporary buffer before use, so that it won't be changed by an interrupt during rendering. // { OSIntrMode enabled = OS_DisableInterrupts(); MI_CpuCopy8(parentInfo, parentInfoBuf, sizeof(parentInfo)); (void)OS_RestoreInterrupts(enabled); } // Move cursor if (IS_PAD_TRIGGER(PAD_KEY_UP)) { cursol_idx = (u16)((cursol_idx - 1) & 0xF); } else if (IS_PAD_TRIGGER(PAD_KEY_DOWN)) { cursol_idx = (u16)((cursol_idx + 1) & 0xF); } // Display parent info BgPutString(10, 1, PLTT_RED, "Select Parent"); BgPutString(STR_X - 2, STR_Y + cursol_idx, PLTT_WHITE, ">"); for (i = 0; i < MB_GAME_INFO_RECV_LIST_NUM; i++) { if (parentInfoBuf[i].valid) { BgPrintStr(STR_X, STR_Y + i, PLTT_GREEN, "%02x:%02x:%02x:%02x:%02x:%02x", parentInfoBuf[i].macAddr[0], parentInfoBuf[i].macAddr[1], parentInfoBuf[i].macAddr[2], parentInfoBuf[i].macAddr[3], parentInfoBuf[i].macAddr[4], parentInfoBuf[i].macAddr[5]); BgPrintStr(NUM_STR_X, STR_Y + i, PLTT_GREEN, "%d/%d", parentInfoBuf[i].nowPlayerNum, parentInfoBuf[i].maxPlayerNum); } else { BgPutString(STR_X, STR_Y + i, PLTT_WHITE, "Searching..."); } } // Cancel communication if (IS_PAD_TRIGGER(PAD_BUTTON_B)) { ChangeWirelessState(WSTATE_FAKE_CANCEL_BUSY); sMode = MODE_CANCEL; MB_FakeEnd(); return; } // Select the parent to connect to if (IS_PAD_TRIGGER(PAD_BUTTON_A)) { if (!parentInfoBuf[cursol_idx].valid) { return; } // Get info from the parent to connect to sConnectIndex = cursol_idx; if (!MB_FakeReadParentBssDesc (sConnectIndex, &sParentBssDesc, WH_PARENT_MAX_SIZE, WH_CHILD_MAX_SIZE, FALSE, FALSE)) { // If the parent info is not valid, continue scan return; } sMode = MODE_ENTRY; } } /* ---------------------------------------------------------------------- Name: ModeEntry Description: Entry to parent device. Arguments: None. Returns: None. ---------------------------------------------------------------------- */ static void ModeEntry(void) { BgSetMessage(PLTT_WHITE, "Now Entrying... "); switch (sWirelessState) { //-------------------------- // If scanning case WSTATE_FAKE_SCAN: { // Terminate scan MB_FakeEndScan(); ChangeWirelessState(WSTATE_FAKE_END_SCAN); } break; //-------------------------- // Terminating scan case WSTATE_FAKE_END_SCAN: break; //-------------------------- // Start wireless communication case WSTATE_IDLE: { if (!MB_FakeEntryToParent(sConnectIndex)) { // If specified index is not valid, error OS_TPrintf("ERR: Illegal Parent index\n"); ChangeWirelessState(WSTATE_FAKE_ERROR); sMode = MODE_ERROR; return; } ChangeWirelessState(WSTATE_FAKE_ENTRY); } break; //-------------------------- // Undergoing entry case WSTATE_FAKE_ENTRY: // If entry has not been completed, cancel with B Button if (IS_PAD_TRIGGER(PAD_BUTTON_B)) { ChangeWirelessState(WSTATE_FAKE_CANCEL_BUSY); sMode = MODE_CANCEL; MB_FakeEnd(); return; } break; //-------------------------- // Complete entry processing case WSTATE_FAKE_BOOT_READY: { // Ending processing for entry processing ChangeWirelessState(WSTATE_FAKE_BOOT_END_BUSY); MB_FakeEnd(); } break; //-------------------------- // Wait for finish case WSTATE_FAKE_BOOT_END_BUSY: break; //-------------------------- // Complete processing for fake child case WSTATE_FAKE_BOOT_END: { // Align with parent and increment tgid sParentBssDesc.gameInfo.tgid++; // Start reconnection ChangeWirelessState(WSTATE_IDLE); sMode = MODE_RECONNECT; } break; //-------------------------- // Error complete case WSTATE_FAKE_ERROR: sMode = MODE_ERROR; break; default: OS_TPanic("illegal state %d\n", sWirelessState); } } /* ---------------------------------------------------------------------- Name: ModeReconnect Description: Title screen. Arguments: None. Returns: None. ---------------------------------------------------------------------- */ static void ModeReconnect(void) { BgSetMessage(PLTT_WHITE, "Connecting to Parent... "); switch (WH_GetSystemState()) { case WH_SYSSTATE_CONNECT_FAIL: { // If WM_StartConnect fails, the WM internal state is invalid. Use WM_Reset to reset the state to the IDLE state. // WH_Reset(); } break; case WH_SYSSTATE_IDLE: { (void)WH_ChildConnect(WH_CONNECTMODE_DS_CHILD, &sParentBssDesc); } break; case WH_SYSSTATE_ERROR: ChangeWirelessState(WSTATE_ERROR); sMode = MODE_ERROR; break; case WH_SYSSTATE_BUSY: break; case WH_SYSSTATE_CONNECTED: case WH_SYSSTATE_KEYSHARING: case WH_SYSSTATE_DATASHARING: sMode = MODE_GMAIN; break; } } /* ---------------------------------------------------------------------- Name: ModeGMain Description: Title screen Arguments: None. Returns: None. ---------------------------------------------------------------------- */ static void ModeGMain(void) { if (WH_GetSystemState() == WH_SYSSTATE_ERROR) { ChangeWirelessState(WSTATE_ERROR); sMode = MODE_ERROR; return; } GStepDataShare(gFrame); GMain(); } /* ---------------------------------------------------------------------- Name: ModeCancel Description: Canceling screen Arguments: None. Returns: None. ---------------------------------------------------------------------- */ static void ModeCancel(void) { switch (sWirelessState) { //------------------------- // End wireless after moving to idle state case WSTATE_IDLE: if (WH_GetSystemState() == WH_SYSSTATE_IDLE) { (void)WH_End(); return; } if (WH_GetSystemState() != WH_SYSSTATE_STOP) { return; } ChangeWirelessState(WSTATE_STOP); sMode = MODE_TITLE; break; //-------------------------- // Canceling case WSTATE_FAKE_CANCEL_BUSY: break; //-------------------------- // Error occurred case WSTATE_ERROR: ChangeWirelessState(WSTATE_IDLE); (void)WH_Finalize(); break; //-------------------------- // End processing default: ChangeWirelessState(WSTATE_IDLE); (void)WH_Finalize(); break; } } /* ---------------------------------------------------------------------- Name: ModeError Description: Error screen Arguments: None. Returns: None. ---------------------------------------------------------------------- */ static void ModeError(void) { BgPutString(4, 10, PLTT_RED, "========== ERROR =========="); if (IS_PAD_TRIGGER(PAD_BUTTON_B) || IS_PAD_TRIGGER(PAD_BUTTON_A)) { if (sWirelessState == WSTATE_FAKE_ERROR) { ChangeWirelessState(WSTATE_FAKE_CANCEL_BUSY); MB_FakeEnd(); } sMode = MODE_CANCEL; } } /* ---------------------------------------------------------------------- Name: NotifyScanParent Description: Parent scan state notification callback. Arguments: state: Scan state MB_FAKESCAN_PARENT_FOUND, MB_FAKESCAN_PARENT_LOST, MB_FAKESCAN_PARENT_FOUND, MB_FAKESCAN_PARENT_LOST, These 4 types of messages are indicated. arg: If MB_FAKESCAN_PARENT_FOUND or MB_FAKESCAN_PARENT_LOST, the information of the parent can be obtained Returns: None. ---------------------------------------------------------------------- */ static void NotifyScanParent(u16 type, void *arg) { static const char *MB_FAKESCAN_CALLBACK_TYPE_NAME[] = { "MB_FAKESCAN_PARENT_FOUND", "MB_FAKESCAN_PARENT_LOST", "MB_FAKESCAN_API_ERROR", "MB_FAKESCAN_END_SCAN", "MB_FAKESCAN_PARENT_BEACON", "MB_FAKESCAN_CONNECTED", "MB_FAKESCAN_ENTRY", "MB_FAKESCAN_DISCONNECTED", "MB_FAKESCAN_SUCCESS" }; OS_TPrintf("> %s\n", MB_FAKESCAN_CALLBACK_TYPE_NAME[type]); switch (type) { case MB_FAKESCAN_PARENT_BEACON: { MBFakeScanCallback *cb = (MBFakeScanCallback *)arg; WMBssDesc *bssdesc = cb->bssDesc; const u8 *volat_data = (const u8 *)MB_GetUserVolatData(&bssdesc->gameInfo); OS_TPrintf(" find MB-beacon MAC=(%04x%08x)\n", *(u16 *)(&bssdesc->bssid[4]), *(u32 *)(&bssdesc->bssid[0])); if (volat_data) { OS_TPrintf(" VOLAT=(%02x %02x %02x %02x %02x %02x %02x %02x)\n", volat_data[0], volat_data[1], volat_data[2], volat_data[3], volat_data[4], volat_data[5], volat_data[6], volat_data[7]); } } break; case MB_FAKESCAN_PARENT_FOUND: { MBFakeScanCallback *cb = (MBFakeScanCallback *)arg; WMBssDesc *bssdesc = cb->bssDesc; MBGameInfo *gameInfo = cb->gameInfo; OS_TPrintf(" find parent %04x%08x %d\n", *(u16 *)(&bssdesc->bssid[4]), *(u32 *)(&bssdesc->bssid[0]), cb->index); OS_TPrintf(" parentMaxSize = %d, childMaxSize = %d\n", bssdesc->gameInfo.parentMaxSize, bssdesc->gameInfo.childMaxSize); parentInfo[cb->index].valid = 1; parentInfo[cb->index].maxPlayerNum = gameInfo->fixed.maxPlayerNum; parentInfo[cb->index].nowPlayerNum = gameInfo->volat.nowPlayerNum; MI_CpuCopy8(&gameInfo->fixed.parent, &parentInfo[cb->index].info, sizeof(MBUserInfo)); WM_CopyBssid(bssdesc->bssid, parentInfo[cb->index].macAddr); } break; case MB_FAKESCAN_PARENT_LOST: { MBFakeScanCallback *cb = (MBFakeScanCallback *)arg; OS_TPrintf(" lost parent %d\n", cb->index); parentInfo[cb->index].valid = 0; } break; case MB_FAKESCAN_API_ERROR: { PrintError((MBFakeScanErrorCallback *)arg); OS_TPrintf("ERR : API Error occured\n"); ChangeWirelessState(WSTATE_FAKE_ERROR); } break; case MB_FAKESCAN_END_SCAN: { ChangeWirelessState(WSTATE_IDLE); } break; default: break; } } /* ---------------------------------------------------------------------- Name: MBStateCallback Description: Fake child state-transition notification callback. After MB_FakeEntryToParent is called, the sequence up to the child boot completion message will execute automatically. No special processing is needed. When all multiboot processing is complete, the MB_COMM_CSTATE_BOOT_READY callback will return. Arguments: status: Current state of the MB child arg: Callback argument Returns: None. ---------------------------------------------------------------------- */ static void MBStateCallback(u32 status, void *arg) { #pragma unused( arg ) switch (status) { case MB_COMM_CSTATE_INIT_COMPLETE: // Notification of connection to parent complete case MB_COMM_CSTATE_CONNECT: // Notification of connection to parent complete case MB_COMM_CSTATE_REQ_ENABLE: // Notification of MP communication with parent complete case MB_COMM_CSTATE_DLINFO_ACCEPTED: // Notification of completion of entry to parent case MB_COMM_CSTATE_RECV_PROCEED: // Notification of start of data transmission from parent case MB_COMM_CSTATE_RECV_COMPLETE: // Notification of completion of parent's data transmission case MB_COMM_CSTATE_BOOTREQ_ACCEPTED: // Notification of reception of boot request from parent // Special processing is unnecessary break; case MB_COMM_CSTATE_BOOT_READY: // Notiffication of disconnection from parent and MB processing complete { ChangeWirelessState(WSTATE_FAKE_BOOT_READY); } break; case MB_COMM_CSTATE_CANCELED: // Notification that an entry with a parent device was cancelled mid-process break; case MB_COMM_CSTATE_CONNECT_FAILED: // Notification of connection failure to parent case MB_COMM_CSTATE_DISCONNECTED_BY_PARENT: // Notification of disconnection from parent case MB_COMM_CSTATE_REQ_REFUSED: // Notification when request to parent was refused case MB_COMM_CSTATE_MEMBER_FULL: // Notification that the entry child number of the parent was exceeded case MB_COMM_CSTATE_ERROR: // Processing if abnormal transmission status occurred midway { OS_TPrintf("ERR : MB Error occured reason 0x%x\n", status); ChangeWirelessState(WSTATE_FAKE_ERROR); } break; case MB_COMM_CSTATE_FAKE_END: // Release the work passed to MB OS_Free(mbfBuf); mbfBuf = NULL; if (sWirelessState == WSTATE_FAKE_BOOT_END_BUSY) { ChangeWirelessState(WSTATE_FAKE_BOOT_END); } else { ChangeWirelessState(WSTATE_IDLE); } } } /* ---------------------------------------------------------------------- Name: PrintError Description: Outputs contents of the WM API error. Arguments: arg: Error callback for MB_FakeStartScanParent Returns: None. ---------------------------------------------------------------------- */ static void PrintError(MBFakeScanErrorCallback *arg) { #pragma unused( arg ) static const char *APIID_NAME[] = { "WM_APIID_INITIALIZE", "WM_APIID_RESET", "WM_APIID_END", "WM_APIID_ENABLE", "WM_APIID_DISABLE", "WM_APIID_POWER_ON", "WM_APIID_POWER_OFF", "WM_APIID_SET_P_PARAM", "WM_APIID_START_PARENT", "WM_APIID_END_PARENT", "WM_APIID_START_SCAN", "WM_APIID_END_SCAN", "WM_APIID_START_CONNECT", "WM_APIID_DISCONNECT", "WM_APIID_START_MP", "WM_APIID_SET_MP_DATA", "WM_APIID_END_MP", "WM_APIID_START_DCF", "WM_APIID_SET_DCF_DATA", "WM_APIID_END_DCF", "WM_APIID_SET_WEPKEY", "WM_APIID_START_KS", "WM_APIID_END_KS", "WM_APIID_GET_KEYSET", "WM_APIID_SET_GAMEINFO", "WM_APIID_SET_BEACON_IND", "WM_APIID_START_TESTMODE", "WM_APIID_STOP_TESTMODE", "WM_APIID_VALARM_MP", "WM_APIID_SET_LIFETIME", "WM_APIID_MEASURE_CHANNEL", "WM_APIID_INIT_W_COUNTER", "WM_APIID_GET_W_COUNTER", "WM_APIID_SET_ENTRY", "WM_APIID_AUTO_DEAUTH", "WM_APIID_SET_MP_PARAMETER", "WM_APIID_SET_BEACON_PERIOD", "WM_APIID_AUTO_DISCONNECT", "WM_APIID_START_SCAN_EX", "WM_APIID_KICK_MP_PARENT", "WM_APIID_KICK_MP_CHILD", "WM_APIID_KICK_MP_RESUME", "WM_APIID_ASYNC_KIND_MAX", "WM_APIID_INDICATION", "WM_APIID_PORT_SEND", "WM_APIID_PORT_RECV", "WM_APIID_READ_STATUS", "WM_APIID_UNKNOWN", }; static const char *ERRCODE_NAME[] = { "WM_ERRCODE_SUCCESS", "WM_ERRCODE_FAILED", "WM_ERRCODE_OPERATING", "WM_ERRCODE_ILLEGAL_STATE", "WM_ERRCODE_WM_DISABLE", "WM_ERRCODE_NO_DATASET", "WM_ERRCODE_INVALID_PARAM", "WM_ERRCODE_NO_CHILD", "WM_ERRCODE_FIFO_ERROR", "WM_ERRCODE_TIMEOUT", "WM_ERRCODE_SEND_QUEUE_FULL", "WM_ERRCODE_NO_ENTRY", "WM_ERRCODE_OVER_MAX_ENTRY", "WM_ERRCODE_INVALID_POLLBITMAP", "WM_ERRCODE_NO_DATA", "WM_ERRCODE_SEND_FAILED", "WM_ERRCODE_DCF_TEST", "WM_ERRCODE_WL_INVALID_PARAM", "WM_ERRCODE_WL_LENGTH_ERR", "WM_ERRCODE_FLASH_ERROR" }; OS_TPrintf("ERR: %s %s\n", APIID_NAME[arg->apiid], ERRCODE_NAME[arg->errcode]); }