/*---------------------------------------------------------------------------* Project: Horizon File: cec_Main.cpp Copyright (C)2009-2012 Nintendo Co., Ltd. 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. $Rev: 47558 $ *---------------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include #include "message.h" #include "sleep.h" #include "demo.h" using namespace nn; using namespace nn::fnd; using namespace nn::os; static bool threadAlive = false; static Event recvEvent; const u32 FONT_SIZE = 8; // Font size const f32 LINE_WIDTH = 0.f; // Line width // Render color definition #define WHITE_COLOR 1.f, 1.f, 1.f #define RED_COLOR 1.f, 0.f, 0.f #define GREEN_COLOR 0.f, 1.f, 0.f #define INBOX_MAXNUM 25 #define OUTBOX_MAXNUM 1 #define BOTTOM_DISP 29 #define TITLE_LENGTH 26 #define BODY_LENGTH 1024 NN_DEFINE_RESULT_CONST(ResultApplicationSuccess,\ nn::Result::LEVEL_SUCCESS,\ nn::Result::SUMMARY_SUCCESS,\ nn::Result::MODULE_APPLICATION,\ nn::Result::DESCRIPTION_SUCCESS); enum MODE { CREATE_MODE = 0, WRITE_MODE, READ_MODE }; enum DISP { NON_DISP = 0, CREATE_DISP, WRITE_DISP, READ_DISP }; struct Data { nn::fnd::DateTimeParameters date; wchar_t title[TITLE_LENGTH]; wchar_t body[BODY_LENGTH]; }; struct BoxBuffer { s32 inMessNum; u32 outMessNum; struct Data inMessData[INBOX_MAXNUM]; struct Data outMessData[OUTBOX_MAXNUM]; s32 sentCount; }; static enum MODE s_Mode; static enum DISP s_Disp; static BoxBuffer s_Box = {0}; static nn::os::CriticalSection s_CriticalSection; //Settings for MessageBox information static u32 TITLEID = nn::cec::MakeCecTitleId(0x00026); // StreetPass ID (a fixed value) static u32 PRIVATEID = 0xabababab; // Card-specific ID (a different value for each card and for each instance of save data) static char HMACKEY[] = "12345678901234567890123456789012"; //Settings for Message information static wchar_t s_Title[TITLE_LENGTH] = TITLE_0; static wchar_t s_Body[BODY_LENGTH] = BODY_0; static const wchar_t *s_ContentTitle[CONTENT_NUM] = { TITLE_0, TITLE_1, TITLE_2, TITLE_3, TITLE_4, TITLE_5, TITLE_6, TITLE_7, TITLE_8, TITLE_9}; static const wchar_t *s_ContentBody[CONTENT_NUM] = { BODY_0, BODY_1, BODY_2, BODY_3, BODY_4, BODY_5, BODY_6, BODY_7, BODY_8, BODY_9}; //------------------------------------------------------------ // Allocator used by the CEC library class CecTestAllocator : public nn::fnd::IAllocator { private: nn::fnd::ExpHeap expHeap; bool isInitialized; NN_PADDING3; public: CecTestAllocator(){isInitialized = false;}; virtual ~CecTestAllocator(){}; void InitExpHeap() { if(isInitialized == false) { expHeap.Initialize( nn::os::GetDeviceMemoryAddress(), 1024 * 1024 ); isInitialized = true; } } /* Please see man pages for details */ virtual void* Allocate(size_t size, s32 alignment = 4) { if(isInitialized == true) { return expHeap.Allocate(size, alignment); } return NULL; } /* Please see man pages for details */ virtual void Free(void* p) { if(isInitialized == true) { expHeap.Free(p); } } }; CecTestAllocator allocator; nn::Result SaveSendMessage(nn::cec::MessageBox* pCecMessBox) { // Try to open a box nn::Result result = pCecMessBox->OpenMessageBox(TITLEID, PRIVATEID); if(result.IsFailure()) return result; // Save messages to the buffer from which they will be sent s_Box.outMessNum= pCecMessBox->GetBoxMessageNum(nn::cec::CEC_BOXTYPE_OUTBOX); for(int i=0; iGetMessageId(&messId, nn::cec::CEC_BOXTYPE_OUTBOX, i); // Get the size size_t messSize = pCecMessBox->GetMessageSize(nn::cec::CEC_BOXTYPE_OUTBOX, i); // Allocate a buffer for reading data buf = reinterpret_cast(allocator.Allocate(messSize)); if(buf==NULL) NN_LOG("Malloc Error\n"); // Read the message result = pCecMessBox->ReadMessage(cecMess, buf, messSize, nn::cec::CEC_BOXTYPE_OUTBOX, messId); if(result.IsFailure()) { NN_LOG("### [Message %d]ReadMessage Error\n", i-1); allocator.Free(buf); continue; } //InfoText const wchar_t* pInfoText; size_t infoTextLen; if(cecMess.GetInfoText(&pInfoText, &infoTextLen).IsSuccess()) { std::memset(s_Box.outMessData[i].title,0,TITLE_LENGTH*sizeof(wchar_t)); std::memcpy(&s_Box.outMessData[i].title, pInfoText, infoTextLen); } //body void* pBody; size_t bodyLen; cecMess.GetMessageBodyPointer(&pBody,&bodyLen); std::memcpy(&s_Box.outMessData[i].body, pBody, bodyLen); //CreateDate s_Box.outMessData[i].date = cecMess.GetCreateDate(); allocator.Free(buf); } pCecMessBox->CloseMessageBox(); return result; } nn::Result CreateBox(nn::cec::MessageBox& cecMessBox) { nn::Result result; /* -------------------------------------------------------- Create a box --------------------------------------------------------*/ // Try to open a box result = cecMessBox.OpenMessageBox(TITLEID, PRIVATEID); if(result.IsFailure()) { if(result != nn::cec::MakeResultNoData())return result; // Set the BoxName wchar_t boxName[64] = L"CEC_DEMO_BOX"; //Box Name // Set the icon u8 boxIcon[48*48*2]; std::memset(boxIcon, 0x55, sizeof(boxIcon));//Fill it in randomly //Create a box result = cecMessBox.CreateMessageBox( TITLEID,\ PRIVATEID,\ HMACKEY,\ boxIcon,\ sizeof(boxIcon),\ boxName,\ sizeof(boxName),\ nn::cec::CEC_INBOX_SIZE_DEFAULT,\ nn::cec::CEC_OUTBOX_SIZE_DEFAULT,\ INBOX_MAXNUM,\ OUTBOX_MAXNUM,\ nn::cec::CEC_MESSSIZEMAX_DEFAULT); } cecMessBox.CloseMessageBox(); return result; } void DeleteBox(nn::cec::MessageBox* pCecMessBox) { // Try to open a box if(pCecMessBox->OpenMessageBox(TITLEID, PRIVATEID).IsSuccess()) { pCecMessBox->DeleteMessageBox(); } else { pCecMessBox->DeleteMessageBox(TITLEID); } } nn::Result DeleteMessage(nn::cec::MessageBox* pCecMessBox, nn::cec::CecBoxType cecBoxType) { nn::Result result = pCecMessBox->OpenMessageBox(TITLEID, PRIVATEID); if(result.IsFailure())return result; //Delete messages result=pCecMessBox->DeleteAllMessages(cecBoxType); if(cecBoxType == nn::cec::CEC_BOXTYPE_INBOX) { //Delete the inbox buffer std::memset(&s_Box,0,sizeof(s_Box)); } pCecMessBox->CloseMessageBox(); return result; } nn::Result SetSendMessage(nn::cec::MessageBox* pCecMessBox) { nn::Result result; nn::cec::Message newMess; u8 icon[40*40*2] = {0}; nn::cec::MessageId mssid; // Try to open a box result = pCecMessBox->OpenMessageBox(TITLEID, PRIVATEID); if(result.IsFailure()) return result; /* -------------------------------------------------------- Create a message --------------------------------------------------------*/ newMess.NewMessage( TITLEID, // CecTitleId 0, // Group ID nn::cec::MESSAGE_TYPEFLAG_NON_FRIEND\ |nn::cec::MESSAGE_TYPEFLAG_FRIEND, // Message Type Flag nn::cec::CEC_SENDMODE_SENDRECV, // Send Mode nn::cec::MESSAGE_SENDCOUNT_ONCE, // Send Count nn::cec::MESSAGE_PROPAGATIONCOUNT_ONCE // Propagation Count ); // Set the data itself (the body) newMess.SetMessageBody(s_Body, sizeof(s_Body)); // Set the icon std::memset(icon, 0x55, sizeof(icon));//Fill it in randomly newMess.SetIcon(icon, sizeof(icon)); // Set the InfoText newMess.SetInfoText(s_Title, sizeof(s_Title)); // Save the message in the outbox result = pCecMessBox->WriteMessage(newMess, nn::cec::CEC_BOXTYPE_OUTBOX, mssid); if(result.IsFailure()) { //The messages in the box have exceeded the maximum value if(result.GetDescription() == nn::cec::DESCRIPTION_BOXMESSNUM_FULL) { //Delete all messages to be sent pCecMessBox->DeleteAllMessages(nn::cec::CEC_BOXTYPE_OUTBOX); } pCecMessBox->CloseMessageBox(); return result; } pCecMessBox->CloseMessageBox(); //Save messages to the buffer from which they will be sent return SaveSendMessage(pCecMessBox); } static void ReceiveEventThread(u32* pIsExistNewMess) { nn::cec::CecNotificationData notificationData; nn::cec::CecControl::GetCecRecvEventHandle(&recvEvent); do{ recvEvent.Wait(); NN_LOG("============= Receive Check!!!!!! ============= \n"); // Get information received from the daemon nn::cec::CTR::CecControl::GetCecInfoBuffer(TITLEID, reinterpret_cast(¬ificationData), sizeof(notificationData)); NN_LOG(" Recv Count:[%d] Num:[%d] \n", notificationData.count, notificationData.num); // Determine whether information has been received if(notificationData.num > 0) { nn::os::CriticalSection::ScopedLock locker(s_CriticalSection); nn::cec::MessageBox messBox; // Open the box nn::cec::CecControl::StopScanning(); nn::Result result = messBox.OpenMessageBox(TITLEID, PRIVATEID); if(result.IsFailure()) { NN_LOG(" ### Cannot Open Box(Deleted?) [0x%08x/0x%08x]\n", TITLEID, PRIVATEID); NN_DBG_PRINT_RESULT(result); continue; } u32 inboxMessNum = messBox.GetBoxMessageNum(nn::cec::CEC_BOXTYPE_INBOX); if(inboxMessNum == 0) { NN_LOG(" ### No Message(Deleted?) [0x%08x/0x%08x]\n", TITLEID, PRIVATEID); messBox.CloseMessageBox(); continue; } nn::cec::MessageId recvMessId; // Determine whether the inbox has messages with the MessageId values that were received NN_LOG("%s(%d): notificationData check\n",__FUNCTION__,__LINE__); for(int i=0; i < notificationData.num; i++) { // Determine whether there is data in the inbox nn::cec::MessageId inboxMessId; for(int j=0; j>>\n"); // There is a message in the inbox //Set a flag indicating that there is a new message *pIsExistNewMess = 1; break; } } } messBox.CloseMessageBox(); } NN_LOG("=============================================== \n"); /* With StreetPass, to use StreetPass again with a partner with whom you have used StreetPass before, takes an average of 4 hours (maximum of 8 hours). To restart communications in a short time interval, you must enable StartScanning(true). To enable the StartScanning(true) included in this demo program, use the executable file that is used for the Development build. */ nn::cec::CecControl::StartScanning(true); }while(threadAlive); recvEvent.Finalize(); } // Update the box nn::Result UpdateCreation(nn::hid::PadStatus* pPadStatus, nn::cec::MessageBox* pCecMessBox) { nn::Result result; if(pPadStatus->trigger & nn::hid::BUTTON_A) { // Create a box result = CreateBox(*pCecMessBox); if(result.IsSuccess()) { //Enter a mode in which outgoing messages are set s_Mode = WRITE_MODE; s_Disp = WRITE_DISP; } else { //Display error information s_Disp = CREATE_DISP; } return result; } return ResultApplicationSuccess(); } // Display box information void DisplayCreation(demo::RenderSystemDrawing* pRenderSystem, nn::Result* result) { u16 x,y; //Display a message prompting the user to create a box x = 0; y = 0; pRenderSystem->SetRenderTarget(NN_GX_DISPLAY0); pRenderSystem->Clear(); pRenderSystem->SetColor(WHITE_COLOR); pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "PRESS A TO CREATE MESSAGEBOX"); //Display error information if(result->IsFailure()) { pRenderSystem->SetColor(RED_COLOR); if(*result == nn::cec::MakeResultBoxNumFull()) //The maximum box count has been reached { pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "ERROR:MESSAGEBOX NUM IS FULL"); } else if(*result == nn::cec::MakeResultNotAuthorized()) //The private IDs do not match { pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "ERROR:PRIVATEID DO NOT MATCH"); } else if(result->GetDescription() == Result::DESCRIPTION_BUSY) { pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "ERROR:BUSY"); } else { pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "ERROR:"); } } pRenderSystem->SwapBuffers(); //Display controls x = 0; y = BOTTOM_DISP; pRenderSystem->SetRenderTarget(NN_GX_DISPLAY1); pRenderSystem->Clear(); pRenderSystem->SetColor(WHITE_COLOR); pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y, "A:CREATE_BOX"); pRenderSystem->SwapBuffers(); } // Set messages to be sent nn::Result UpdateWriting(nn::hid::PadStatus* pPadStatus, nn::cec::MessageBox* pCecMessBox, u8* pSelected) { nn::Result result; if(pPadStatus->trigger & nn::hid::BUTTON_A) { // Create a message to send result = SetSendMessage(pCecMessBox); if(result.IsSuccess()) { //Enter a mode in which outgoing messages are set s_Mode = READ_MODE; s_Disp = READ_DISP; } else { //Display error information s_Disp = WRITE_DISP; } return result; } //Return to the previous screen if(pPadStatus->trigger & nn::hid::BUTTON_B) { DeleteBox(pCecMessBox); s_Mode = CREATE_MODE; s_Disp = CREATE_DISP; } //Choose the message content if(pPadStatus->trigger & nn::hid::BUTTON_RIGHT) { if(*pSelectedtrigger & nn::hid::BUTTON_LEFT) { if(0<*pSelected) *pSelected = *pSelected - 1; } if(pPadStatus->trigger & nn::hid::BUTTON_RIGHT\ ||pPadStatus->trigger & nn::hid::BUTTON_LEFT) { //Set the content of the message to be sent std::memcpy(&s_Title,s_ContentTitle[*pSelected],sizeof(s_Title)); std::memcpy(&s_Body,s_ContentBody[*pSelected], sizeof(s_Body)); s_Disp = WRITE_DISP; } return ResultApplicationSuccess(); } // Display a screen for setting the message to be sent void DisplayWriting(demo::RenderSystemDrawing* pRenderSystem, nn::Result* result) { u16 x; u16 y; x = 0; y = 0; pRenderSystem->SetRenderTarget(NN_GX_DISPLAY0); pRenderSystem->Clear(); pRenderSystem->SetColor(WHITE_COLOR); pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "AT FIRST, PRESS LEFT/RIGHT TO SELECT CONTENT"); pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "AT SECOND, PRESS A TO SET SEND MESSAGE"); if(result->IsFailure()) //Display error information { pRenderSystem->SetColor(RED_COLOR); if(result->GetDescription() == nn::cec::DESCRIPTION_NOT_AGREE_EULA) { pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "ERROR:YOU DID NOT AGREE EULA"); } if(result->GetDescription() == nn::cec::DESCRIPTION_PARENTAL_CONTROL_CEC) { pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "ERROR:PARENTAL CONTROL BANED"); } if(result->GetDescription() == nn::cec::DESCRIPTION_BOXMESSNUM_FULL) { pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "ERROR:SEND MESSAGENUM IS FULL"); pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "APPLICATION DELETED ALL OUTBOX MESSAGE"); } } pRenderSystem->SwapBuffers(); //Display the message box x = 0; y = 0; pRenderSystem->SetRenderTarget(NN_GX_DISPLAY1); pRenderSystem->Clear(); pRenderSystem->SetColor(WHITE_COLOR); pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "TITLE:%ls",s_Title); pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "------------------BODY------------------"); wchar_t *line, *ptr, body[BODY_LENGTH]; std::memcpy(body,s_Body,sizeof(s_Body)); line=std::wcstok(body,L"\n",&ptr); while(line!=NULL) { pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "%ls",line); line=std::wcstok(NULL,L"\n",&ptr); } pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * (BOTTOM_DISP-1), "A:SET_MESSAGE B:DELETE_BOX"); pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * BOTTOM_DISP, "LEFT/RIGHT:SELECT_CONTENT"); pRenderSystem->SwapBuffers(); } nn::Result GetRecvMessage(nn::cec::MessageBox* pCecMessBox){ nn::Result result ; // Try to open a box result = pCecMessBox->OpenMessageBox(TITLEID, PRIVATEID); if(result.IsFailure()) return result; //---------------------------------- { // Get the number of messages in the inbox nn::cec::MessageId messId[INBOX_MAXNUM]; // Message ID u32 messNum = pCecMessBox->GetBoxMessageNum(nn::cec::CEC_BOXTYPE_INBOX); // Create a list of message IDs for the inbox for(u32 i=messNum; i!=0; i--) { pCecMessBox->GetMessageId(&messId[i-1], nn::cec::CEC_BOXTYPE_INBOX, i-1); } // Read messages from the inbox for(u32 i=messNum; i!=0; i--) { u8 *buf; nn::cec::Message cecMess; // Get the size size_t messSize = pCecMessBox->GetMessageSize(nn::cec::CEC_BOXTYPE_INBOX, i-1); // Allocate a buffer for reading data buf = reinterpret_cast(allocator.Allocate(messSize)); if(buf==NULL) NN_LOG("Malloc Error\n"); // Read the message result = pCecMessBox->ReadMessage(cecMess, buf, messSize, nn::cec::CEC_BOXTYPE_INBOX, messId[i-1]); if(result.IsFailure()) { NN_LOG("### [Message %d]ReadMessage Error\n", i-1); allocator.Free(buf); continue; } //------------------------------ //Save all kinds of messages in the application if(s_Box.inMessNum < INBOX_MAXNUM) { //InfoText const wchar_t* pInfoText; size_t infoTextLen; if(cecMess.GetInfoText(&pInfoText, &infoTextLen).IsSuccess()) { std::memset(s_Box.inMessData[s_Box.inMessNum].title,0,TITLE_LENGTH*sizeof(wchar_t)); std::memcpy(&s_Box.inMessData[s_Box.inMessNum].title, pInfoText, infoTextLen); } //body void* pBody; size_t bodyLen; cecMess.GetMessageBodyPointer(&pBody,&bodyLen); std::memcpy(&s_Box.inMessData[s_Box.inMessNum].body, pBody, bodyLen); //ReceiveData s_Box.inMessData[s_Box.inMessNum].date = cecMess.GetRecvDate(); s_Box.inMessNum++; } else { // Exceeded the number of messages that can be saved NN_LOG("### MailBox Full.\n"); } allocator.Free(buf); } pCecMessBox->DeleteAllMessages(nn::cec::CEC_BOXTYPE_INBOX); NN_LOG("Delete Inbox Messages.\n"); } //---------------------------------- { // Get the number of messages in the outbox s_Box.outMessNum = pCecMessBox->GetBoxMessageNum(nn::cec::CEC_BOXTYPE_OUTBOX); nn::cec::MessageId messId[OUTBOX_MAXNUM]; // Message SID u32 sendCount[OUTBOX_MAXNUM]; // Send Count // Create a list of message IDs for the outbox for(u32 i=0; iGetMessageId(&messId[i], nn::cec::CEC_BOXTYPE_OUTBOX, i); sendCount[i] = pCecMessBox->GetMessageSendCount(nn::cec::CEC_BOXTYPE_OUTBOX, i); } // Delete messages that have already been sent for(u32 i=0; iDeleteMessage(nn::cec::CEC_BOXTYPE_OUTBOX, messId[i]); NN_LOG("Delete Sent Message [%s].\n",nn::cec::MessageId(messId[i]).GetString()); } } } pCecMessBox->CloseMessageBox(); //Save messages to the buffer from which they will be sent return SaveSendMessage(pCecMessBox); } //Update messages void UpdateReading(nn::hid::PadStatus* pPadStatus, nn::cec::MessageBox* pCecMessBox, u8* pSelected, u32* pIsExistNewMess) { nn::Result result; //Delete all messages that have been received if(pPadStatus->trigger & nn::hid::BUTTON_X) { DeleteMessage(pCecMessBox, nn::cec::CEC_BOXTYPE_INBOX); } //Get messages that have been received if(pPadStatus->trigger & nn::hid::BUTTON_Y) { GetRecvMessage(pCecMessBox); *pIsExistNewMess = 0; } //Go to the previous screen if(pPadStatus->trigger & nn::hid::BUTTON_B) { DeleteMessage(pCecMessBox, nn::cec::CEC_BOXTYPE_OUTBOX); s_Mode = WRITE_MODE; s_Disp = WRITE_DISP; } //Select a received message if(pPadStatus->trigger & nn::hid::BUTTON_UP) { if(0<*pSelected)*pSelected = *pSelected - 1; } if(pPadStatus->trigger & nn::hid::BUTTON_DOWN) { if(*pSelectedtrigger & nn::hid::BUTTON_X\ ||pPadStatus->trigger & nn::hid::BUTTON_Y\ ||pPadStatus->trigger & nn::hid::BUTTON_UP\ ||pPadStatus->trigger & nn::hid::BUTTON_DOWN) { s_Disp = READ_DISP; } } char* GetWeekString(nn::fnd::Week week) { switch(week) { case nn::fnd::WEEK_SUNDAY: return "SUN"; case nn::fnd::WEEK_MONDAY: return "MON"; case nn::fnd::WEEK_TUESDAY: return "TUE"; case nn::fnd::WEEK_WEDNESDAY: return "WED"; case nn::fnd::WEEK_THURSDAY: return "THR"; case nn::fnd::WEEK_FRIDAY: return "FRI"; case nn::fnd::WEEK_SATURDAY: return "SAT"; } return "NUL"; } //Display messages void DisplayReading(demo::RenderSystemDrawing* pRenderSystem, u8 selected, u32* pIsExistNewMess) { u16 x,y; //------------------------------------------------------------ //Display a list of messages //------------------------------------------------------------ //Display received messages x = 0; y = 0; pRenderSystem->SetRenderTarget(NN_GX_DISPLAY0); pRenderSystem->Clear(); pRenderSystem->SetColor(WHITE_COLOR); pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "---------------------------------------------INBOX"); pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "TITLE ReceiveDate"); for(int i=0; iSetColor(GREEN_COLOR); else pRenderSystem->SetColor(WHITE_COLOR); pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y, "%ls",s_Box.inMessData[i].title); pRenderSystem->DrawText(FONT_SIZE * (x+TITLE_LENGTH+1), FONT_SIZE * y++, "%04d/%02d/%02d %02d:%02d %02d.%03d",\ s_Box.inMessData[i].date.year,s_Box.inMessData[i].date.month,s_Box.inMessData[i].date.day,s_Box.inMessData[i].date.hour,\ s_Box.inMessData[i].date.minute,s_Box.inMessData[i].date.second,s_Box.inMessData[i].date.milliSecond); }pRenderSystem->SetColor(WHITE_COLOR); y = INBOX_MAXNUM+2; pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "--------------------------------------------OUTBOX"); //Display messages to be sent pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "TITLE CreateDate"); for(int i=0; iOUTBOX_MAXNUM)pRenderSystem->SetColor(GREEN_COLOR); else pRenderSystem->SetColor(WHITE_COLOR); pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y, "%ls",s_Box.outMessData[i].title); pRenderSystem->DrawText(FONT_SIZE * (x+TITLE_LENGTH+1), FONT_SIZE * y++, "%04d/%02d/%02d %02d:%02d %02d.%03d",\ s_Box.outMessData[i].date.year,s_Box.outMessData[i].date.month,s_Box.outMessData[i].date.day,\ s_Box.outMessData[i].date.hour,s_Box.outMessData[i].date.minute,s_Box.outMessData[i].date.second,\ s_Box.outMessData[i].date.milliSecond); } pRenderSystem->SwapBuffers(); //---------------------------------------------------------------- //Display the message box x = 0; y = 0; pRenderSystem->SetRenderTarget(NN_GX_DISPLAY1); pRenderSystem->Clear(); pRenderSystem->SetColor(WHITE_COLOR); pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "TITLE:%ls",s_Box.inMessData[selected].title); pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "------------------BODY------------------"); if(*pIsExistNewMess) //Display an alert message informing to the user that there is a new message { switch(*pIsExistNewMess%3) { case 0: pRenderSystem->DrawText(FONT_SIZE * 9, FONT_SIZE * 10,"////NEW MESSAGE////"); break; case 1: pRenderSystem->DrawText(FONT_SIZE * 9, FONT_SIZE * 10,"----NEW MESSAGE----"); break; case 2: pRenderSystem->DrawText(FONT_SIZE * 9, FONT_SIZE * 10,"\\\\\\\\NEW MESSAGE\\\\\\\\"); break; } pRenderSystem->DrawText(FONT_SIZE * 6, FONT_SIZE * 11,"PRESS Y TO RECEIVE MESSAGE"); *pIsExistNewMess = *pIsExistNewMess+1; } else //Display the content of the message { wchar_t *line, *ptr, body[BODY_LENGTH]; std::memcpy(body,s_Box.inMessData[selected].body,sizeof(body)); line=std::wcstok(body,L"\n",&ptr); while(line!=NULL) { pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "%ls",line); line=std::wcstok(NULL,L"\n",&ptr); } } pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * (BOTTOM_DISP-1),"Y:RECEIVE_MESSAGE X:DELETE_MESSAGE"); pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * BOTTOM_DISP, "B:BACK UP/DOWN:SELECT_MESSAGE"); pRenderSystem->SwapBuffers(); } extern "C" void nnMain( void ) { nn::Result result; nn::os::Thread thread; // Use the FS library to get the EULA version to agree to for the application nn::fs::Initialize(); // Initialize hid result = nn::hid::Initialize(); NN_UTIL_PANIC_IF_FAILED(result); // Initialize the CriticalSection s_CriticalSection.Initialize(); // Initialize applets SleepHandler::Initialize(); // Prepare pad nn::hid::PadReader padReader; nn::hid::PadStatus padStatus; // Wait for HID input to stabilize nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromSeconds(1)); // Allocator allocator.InitExpHeap(); // Access the daemon NN_LOG("Cec: nn::cec::Initialize()\n"); result = nn::cec::Initialize(allocator); NN_UTIL_PANIC_IF_FAILED(result); //Flag indicating whether there is a new message u32 isExistNewMess = 0; { threadAlive = true; result = thread.TryStartUsingAutoStack(ReceiveEventThread, &isExistNewMess, 1024); if(result.IsFailure()) { NN_LOG("%s(%d):### TryStartUsingAutoStack Failed.\n",__FUNCTION__,__LINE__); } } /* With StreetPass, to use StreetPass again with a partner with whom you have used StreetPass before, takes an average of 4 hours (maximum of 8 hours). To restart communications in a short time interval, you must enable StartScanning(true). To enable the StartScanning(true) included in this demo program, use the executable file that is used for the Development build. */ nn::cec::CecControl::StartScanning(true); // Allocate heap nn::fnd::ExpHeap appHeap; appHeap.Initialize(nn::os::GetDeviceMemoryAddress()+(1024*1024), nn::os::GetDeviceMemorySize() ); // Prepare RenderSystem uptr heapForGx = reinterpret_cast (appHeap.Allocate(0x800000)); demo::RenderSystemDrawing renderSystem; renderSystem.Initialize(heapForGx, 0x800000); renderSystem.SetClearColor(NN_GX_DISPLAY_BOTH, 0.f, 0.f, 0.f, 0.f); renderSystem.SetFontSize(FONT_SIZE); renderSystem.SetLineWidth(LINE_WIDTH); nn::cec::MessageBox cecMessBox; u8 selectedInBox = 0; u8 selectedOutBox = 0; // Try to open a box result = cecMessBox.OpenMessageBox(TITLEID, PRIVATEID); if(result.IsFailure()) { //Go to the StreetPass box creation screen s_Mode = CREATE_MODE; s_Disp = CREATE_DISP; } else { //When there is a message in the inbox if(cecMessBox.GetBoxMessageNum(nn::cec::CEC_BOXTYPE_INBOX)) { //Set the new message flag isExistNewMess = 1; } if(cecMessBox.GetBoxMessageNum(nn::cec::CEC_BOXTYPE_OUTBOX)==0) { //Go to the screen that writes messages to send s_Mode = WRITE_MODE; s_Disp = WRITE_DISP; } else { //Save messages to the buffer from which they will be sent SaveSendMessage(&cecMessBox); //Screen that reads received messages s_Mode = READ_MODE; s_Disp = READ_DISP; } cecMessBox.CloseMessageBox(); } while(1) { // Get input padReader.ReadLatest(&padStatus); switch(s_Mode){ case CREATE_MODE: //StreetPass box creation screen result = UpdateCreation(&padStatus, &cecMessBox); if(s_Disp==CREATE_DISP) { DisplayCreation(&renderSystem,&result); s_Disp = NON_DISP; } break; case WRITE_MODE: //Screen that writes messages to send result = UpdateWriting(&padStatus, &cecMessBox, &selectedOutBox); if(s_Disp==WRITE_DISP) { DisplayWriting(&renderSystem, &result); s_Disp = NON_DISP; } break; case READ_MODE: //Screen that reads received messages UpdateReading(&padStatus, &cecMessBox, &selectedInBox, &isExistNewMess); if(s_Disp==READ_DISP||(isExistNewMess&&s_Disp==NON_DISP)) { DisplayReading(&renderSystem,selectedInBox, &isExistNewMess); s_Disp = NON_DISP; } break; } // Determination for System Sleep Mode if ( SleepHandler::IsSleepRequested() ) { NN_LOG("<>\n"); s_CriticalSection.Enter(); SleepHandler::SleepSystem(); s_CriticalSection.Leave(); NN_LOG("<>\n"); nn::gx::StartLcdDisplay(); } nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromMilliSeconds(100)); } }