/*---------------------------------------------------------------------------* 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: 47228 $ *---------------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include #include "sleep.h" using namespace nn; using namespace nn::fnd; using namespace nn::os; static bool threadAlive = false; static Event recvEvent; u32 TEST_TITLEID = nn::cec::MakeCecTitleId(0x12233) ; // StreetPass ID (a fixed value) // (created from a 20-bit unique ID) u32 TEST_PRIVATEID = 0xaabbccdd ; // Card-specific ID (a different value for each card and for each instance of save data) char TEST_HMACKEY[] = "12345678901234567890123456789012" ; //------------------------------------------------------------ // 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); } } }; void DateParam2Str(char* outStr, nn::fnd::DateTimeParameters date) { char tmpStr[32] = {0}; s32 strLen = 0; strLen = nn::nstd::TSPrintf(tmpStr, "%04d/%02d/%02d(%d) %02d:%02d:%02d.%04d", date.year, date.month, date.day, date.week, date.hour, date.minute, date.second, date.milliSecond); std::memcpy(outStr, tmpStr, strLen); } CecTestAllocator allocator; //------------------------------------------------------------ void BinaryDump(u8* data, u32 len, u8 type) { u32 i, j; NN_LOG(" Len[%d]----------\n ", len); for (i=0; i Create [0x%08x]\n",__FUNCTION__,__LINE__,cecTitleId); // When there is no message box // Box Name wchar_t name[64] = L"CEC_DEMO_BOX1"; // Box Icon u8 icon[48*48*2]; //Icon data // Create a message box result = cecMessBox.CreateMessageBox( cecTitleId, privateId, hmacKey, icon, sizeof(icon), name, sizeof(name)); if(result.IsFailure()) { if(result == nn::cec::ResultBoxAlreadyExists()) { // If we are told that a box already exists even though it can't be opened, there is a box whose lower 8 bits are different NN_LOG("%s(%d): ### BoxAlreadyExists[0x%08x]\n",__FUNCTION__,__LINE__,cecTitleId); } if(result == nn::cec::ResultBoxNumFull()) { NN_LOG("%s(%d): ### BoxNumFull[0x%08x]\n",__FUNCTION__,__LINE__,cecTitleId); // The maximum box count has been reached } return result; } // After we call CreateMessageBox, it is in the open state } else if(result == nn::cec::ResultNotAuthorized()) { // The private IDs do not match // Err NN_LOG("%s(%d): ### Invalid Private ID.\n",__FUNCTION__,__LINE__); return result; } else if(result == nn::cec::ResultStateBusy()) { NN_LOG("%s(%d): ### BUSY\n",__FUNCTION__,__LINE__); // Err return result; } else { NN_LOG("%s(%d): ### Error\n",__FUNCTION__,__LINE__); // Err return result; } } NN_LOG("%s(%d): Open Box [0x%08x]. \n",__FUNCTION__,__LINE__, cecTitleId); NN_LOG("%s : END\n",__FUNCTION__); return result; } void CecTest_CreateMessage( nn::cec::MessageBox& cecMessBox, u32 cecTitleId, u32 groupId, u8 messFlag, u8 sendMode, u8 sendCount, u8 propCount, size_t dataSize, nn::cec::MessageId& retMessId ) { nn::Result result; nn::cec::Message cecMess; u8* cecMessBody = NULL ; wchar_t info_str[64] = L"Message:CEC_DEMO_1"; u8 icon[40*40*2] = {0}; NN_LOG("%s : START\n",__FUNCTION__); /* -------------------------------------------------------- Create a message --------------------------------------------------------*/ cecMess.NewMessage( cecTitleId, // CecTitleId groupId, // Group ID messFlag, // Message Type Flag sendMode, // Send Mode sendCount, // Send Count propCount // Propagation Count ); // Set the data itself (the body) if(dataSize>0) { cecMessBody = reinterpret_cast(allocator.Allocate(dataSize)); if(cecMessBody == NULL){ NN_LOG("%s(%d): ### malloc failed.\n",__FUNCTION__,__LINE__); __breakpoint(0); } std::memset(cecMessBody, 0x04, dataSize); //Fill it in randomly cecMess.SetMessageBody(cecMessBody, dataSize); } // Set the icon std::memset(icon, 0x55, sizeof(icon)); //Fill it in randomly cecMess.SetIcon(icon, sizeof(icon)); // Set title_str cecMess.SetInfoText(info_str, sizeof(info_str)); // Save the message in the outbox result = cecMessBox.WriteMessage(cecMess, nn::cec::CEC_BOXTYPE_OUTBOX, retMessId); if(result.IsFailure()) { if(result.GetDescription() == nn::cec::DESCRIPTION_NOT_AGREE_EULA) { NN_LOG("%s(%d): ### Error NOT_AGREE_EULA\n",__FUNCTION__,__LINE__); } if(result.GetDescription() == nn::cec::DESCRIPTION_PARENTAL_CONTROL_CEC) { NN_LOG("%s(%d): ### Error PARENTAL_CONTROL\n",__FUNCTION__,__LINE__); } NN_LOG("%s(%d):Message Write Error\n",__FUNCTION__,__LINE__); NN_DBG_PRINT_RESULT(result); return; } // Display the message ID that was given when WriteMessage was called NN_LOG("Put Mess OutBox[%s] \n", retMessId.GetString()); if(dataSize>0) { allocator.Free(cecMessBody); } NN_LOG("%s : END\n",__FUNCTION__); } // Use the MessageBox class to display box information void CecTest_ShowBoxMessageList(nn::cec::MessageBox& cecMessBox) { // Display box information NN_LOG("GetMessageBoxInfoFlag: 0x%02x\n", cecMessBox.GetBoxFlag()); NN_LOG("GetBoxSizeMax: \t\tIN: %6d\t\tOUT: %6d\n", cecMessBox.GetBoxSizeMax(nn::cec::CEC_BOXTYPE_INBOX), cecMessBox.GetBoxSizeMax(nn::cec::CEC_BOXTYPE_OUTBOX)); NN_LOG("GetBoxSize: \t\tIN: %6d\t\tOUT: %6d\n", cecMessBox.GetBoxSize(nn::cec::CEC_BOXTYPE_INBOX), cecMessBox.GetBoxSize(nn::cec::CEC_BOXTYPE_OUTBOX)); NN_LOG("GetMessNumMax: \t\tIN: %6d\t\tOUT: %6d\n", cecMessBox.GetBoxMessageNumMax(nn::cec::CEC_BOXTYPE_INBOX), cecMessBox.GetBoxMessageNumMax(nn::cec::CEC_BOXTYPE_OUTBOX)); NN_LOG("GetMessNum: \t\tIN: %6d\t\tOUT: %6d\n", cecMessBox.GetBoxMessageNum(nn::cec::CEC_BOXTYPE_INBOX), cecMessBox.GetBoxMessageNum(nn::cec::CEC_BOXTYPE_OUTBOX)); NN_LOG("GetGroupNumMax:\t\tIN: %6d\t\tOUT: %6d\n", cecMessBox.GetBoxGroupNumMax(nn::cec::CEC_BOXTYPE_INBOX), cecMessBox.GetBoxGroupNumMax(nn::cec::CEC_BOXTYPE_OUTBOX)); // Display message information nn::cec::CecBoxType boxType[] = {nn::cec::CEC_BOXTYPE_INBOX, nn::cec::CEC_BOXTYPE_OUTBOX}; for(int type=0; type < sizeof(boxType)/sizeof(boxType[0]); type++) { for(int i=0; i 0) { // Get the first message ID messId = cecMessBox.GetMessageId(boxtype, 0); NN_LOG(" GetMessageMessId [%s]\n", messId.GetString()); // Delete the specified message ID result = cecMessBox.DeleteMessage(boxtype, messId); if(result.IsFailure()) { NN_LOG("### Delete Message Failed.\n"); return; } NN_LOG(" DeleteMessage [%s]\n", messId.GetString()); } } // Open and display messages in the inbox void CecTest_ShowInboxMessage(nn::cec::MessageBox& cecMessBox) { u32 inboxMessNum; // Number of messages u8* buf; nn::cec::MessageId messId; nn::Result result; nn::cec::CecBoxType boxType = nn::cec::CEC_BOXTYPE_INBOX; // Get the number of messages inboxMessNum = cecMessBox.GetBoxMessageNum(boxType); for(int i=0; i(allocator.Allocate(messSize)); if(buf==NULL) { NN_LOG("Malloc Error\n"); } // Read the message result = cecMessBox.ReadMessage(cecMessage, buf, messSize, boxType, messId); if(result.IsFailure()) { NN_LOG("### [Message %d]ReadMessage Error\n", i); allocator.Free(buf); continue; } // Display // Message ID NN_LOG(" ===== (%02d) messageId [%s]\n", i, messId.GetString()); // Icon void* p_icon; size_t iconSize; result = cecMessage.GetIcon(&p_icon, &iconSize); if(result.IsSuccess()) { NN_LOG(" Icon size:%d\n", iconSize); BinaryDump(reinterpret_cast(p_icon), 32, 1); // Dump only 32 bytes } // info_str const wchar_t* p_infoStr; size_t infoStrLen; result = cecMessage.GetInfoText(&p_infoStr, &infoStrLen); if(result.IsSuccess()) { NN_LOG(" Info Str: %ls\n", p_infoStr); } // Send Count NN_LOG(" Send Count: %d\n",cecMessage.GetSendCount()); // Propagation Count NN_LOG(" Propagation Count: %d\n",cecMessage.GetPropagationCount()); // Data u32 messBodySize = cecMessage.GetBodySize(); u8* messBodyBuf; NN_LOG(" Data body Size: %d\n", messBodySize); messBodyBuf = reinterpret_cast(allocator.Allocate(messBodySize));// Allocate buffer if(messBodyBuf == NULL) { NN_LOG("Malloc Error\n"); } cecMessage.GetMessageBody(messBodyBuf, messBodySize);// Get BinaryDump(messBodyBuf, 32, 1); // Dump only 32 bytes allocator.Free(messBodyBuf); allocator.Free(buf); } } static void ReceiveEventThread(uptr param) { NN_UNUSED_VAR(param) nn::cec::CecNotificationData notificationData; nn::cec::CecControl::GetCecRecvEventHandle(&recvEvent); do{ recvEvent.Wait(); { NN_LOG("============= Receive Check!!!!!! ============= \n"); nn::cec::CTR::CecControl::GetCecInfoBuffer(TEST_TITLEID, reinterpret_cast(¬ificationData), sizeof(notificationData)); #ifndef NN_BUILD_RELEASE NN_LOG(" Recv Count:[%d] Num:[%d] \n", notificationData.count, notificationData.num); for(int i=0; i < notificationData.num; i++) { char dateStr[32] = {0}; DateParam2Str(dateStr, notificationData.param[i].recvDate); NN_LOG("(%02d)[%s][0x%08x][%s]\n", i, dateStr, notificationData.param[i].cecTitleId, nn::cec::MessageId(notificationData.param[i].messageId).GetEncodedString()); } NN_LOG("=============================================== \n"); #endif } }while(threadAlive); recvEvent.Finalize(); } bool IsCecDaemonBusy() { u32 state; nn::cec::CecControl::GetCecState(&state); if(state != nn::cec::CecControl::DAEMON_STATE_IDLE) { return true; } return false; } extern "C" void nnMain( void ) { NN_LOG("START : %s @ %s (Build: %s %s)\n",__FUNCTION__,__FILE__,__DATE__, __TIME__); 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 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); { threadAlive = true; result = thread.TryStartUsingAutoStack(ReceiveEventThread, NULL, 4096); if(result.IsFailure()) { NN_LOG("%s(%d):### TryStartUsingAutoStack Failed.\n",__FUNCTION__,__LINE__); //NN_DBG_PRINT_RESULT(result); __breakpoint(0); } } NN_LOG("---- Cec Demo ----\n"); NN_LOG("A: Write data\n"); NN_LOG("B: Show box data\n"); NN_LOG("UP : Open Box\n"); NN_LOG("DOWN : Close Box\n"); NN_LOG("X : Delete OutBox Message\n"); NN_LOG("Y : Delete All InBox Messages\n"); NN_LOG("START: Delete Box and Exit\n"); NN_LOG("-------------------\n"); nn::cec::MessageBox cecMessBox; bool bMessBoxOpened = false; while(1) { // Get input padReader.ReadLatest(&padStatus); if(padStatus.hold & nn::hid::BUTTON_A) { // Create a message and write it to the outbox if(bMessBoxOpened) { nn::cec::MessageId messId; CecTest_CreateMessage( cecMessBox, TEST_TITLEID, 0, // Group ID nn::cec::MESSAGE_TYPEFLAG_NON_FRIEND|nn::cec::MESSAGE_TYPEFLAG_FRIEND, // MessageTypeFlag nn::cec::CEC_SENDMODE_SENDRECV, // SendMode nn::cec::MESSAGE_SENDCOUNT_UNLIMITED, // Send Count nn::cec::MESSAGE_PROPAGATIONCOUNT_ONCE, // Propagation Count 32*1024, // Data Size messId ); } else { NN_LOG("Cec: ### Box is not opened.\n"); } } if(padStatus.hold & nn::hid::BUTTON_X) { // Delete a single message from the outbox if(bMessBoxOpened) { NN_LOG("Cec: DeleteOutboxData\n"); CecTest_DeleteOneMessage(cecMessBox, nn::cec::CEC_BOXTYPE_OUTBOX); } else { NN_LOG("Cec: ### Box is not opened.\n"); } } if(padStatus.hold & nn::hid::BUTTON_Y) { // Delete all messages from the inbox if(bMessBoxOpened) { NN_LOG("Cec: Delete All InBox Messages.\n"); cecMessBox.DeleteAllMessages(nn::cec::CEC_BOXTYPE_INBOX); NN_LOG("Cec: Delete All InBox Messages. END\n"); } else { NN_LOG("Cec: ### Box is not opened.\n"); } } if(padStatus.hold & nn::hid::BUTTON_B) { // Displays the box's content if(bMessBoxOpened) { // Open and display messages in the inbox CecTest_ShowInboxMessage(cecMessBox); // Use the MessageBox class to get information CecTest_ShowBoxMessageList(cecMessBox); } else { NN_LOG("Cec: ### Box is not opened.\n"); } } if(padStatus.hold & nn::hid::BUTTON_UP) { //Open the box (or create one if it does not exist) NN_LOG("Cec: Open MessageBox\n"); result = CecTest_CreateAndOpenBox(cecMessBox, TEST_TITLEID, TEST_PRIVATEID, TEST_HMACKEY); if(result.IsSuccess()) { bMessBoxOpened = true; } } if(padStatus.hold & nn::hid::BUTTON_DOWN) { bMessBoxOpened = false; NN_LOG("Cec: Close MessageBox\n"); cecMessBox.CloseMessageBox(); } if(padStatus.hold & nn::hid::BUTTON_START) { // We can only access a box while the daemon is stopped. result = cecMessBox.OpenMessageBox(TEST_TITLEID, TEST_PRIVATEID); if(result.IsSuccess()) { // Delete the box and exit NN_LOG("Cec: delete Box\n"); cecMessBox.DeleteMessageBox(); } break; } // Determination for System Sleep Mode if ( SleepHandler::IsSleepRequested() ) { NN_LOG("<>\n"); SleepHandler::SleepSystem(); NN_LOG("<>\n"); } nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromMilliSeconds(100)); } // Sleep handler termination processing SleepHandler::Finalize(); nn::cec::Finalize(); NN_LOG("Cec: END : %s @ %s \n",__FUNCTION__,__FILE__); while(1){nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromMilliSeconds(1000));} }