1 /*---------------------------------------------------------------------------*
2 Project: Horizon
3 File: cec_Main.cpp
4
5 Copyright (C)2009-2012 Nintendo Co., Ltd. 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 $Rev: 47558 $
14 *---------------------------------------------------------------------------*/
15
16 #include <nn.h>
17 #include <nn/fs.h>
18 #include <nn/os.h>
19 #include <nn/dbg.h>
20 #include <ctype.h>
21
22 #include <nn/cec.h>
23 #include <nn/ndm.h>
24 #include <nn/applet.h>
25 #include "message.h"
26 #include "sleep.h"
27 #include "demo.h"
28
29 using namespace nn;
30 using namespace nn::fnd;
31 using namespace nn::os;
32
33 static bool threadAlive = false;
34 static Event recvEvent;
35
36 const u32 FONT_SIZE = 8; // Font size
37 const f32 LINE_WIDTH = 0.f; // Line width
38
39 // Render color definition
40 #define WHITE_COLOR 1.f, 1.f, 1.f
41 #define RED_COLOR 1.f, 0.f, 0.f
42 #define GREEN_COLOR 0.f, 1.f, 0.f
43
44 #define INBOX_MAXNUM 25
45 #define OUTBOX_MAXNUM 1
46 #define BOTTOM_DISP 29
47
48 #define TITLE_LENGTH 26
49 #define BODY_LENGTH 1024
50
51 NN_DEFINE_RESULT_CONST(ResultApplicationSuccess,\
52 nn::Result::LEVEL_SUCCESS,\
53 nn::Result::SUMMARY_SUCCESS,\
54 nn::Result::MODULE_APPLICATION,\
55 nn::Result::DESCRIPTION_SUCCESS);
56
57 enum MODE
58 {
59 CREATE_MODE = 0,
60 WRITE_MODE,
61 READ_MODE
62 };
63
64 enum DISP
65 {
66 NON_DISP = 0,
67 CREATE_DISP,
68 WRITE_DISP,
69 READ_DISP
70 };
71
72 struct Data
73 {
74 nn::fnd::DateTimeParameters date;
75 wchar_t title[TITLE_LENGTH];
76 wchar_t body[BODY_LENGTH];
77 };
78
79 struct BoxBuffer
80 {
81 s32 inMessNum;
82 u32 outMessNum;
83 struct Data inMessData[INBOX_MAXNUM];
84 struct Data outMessData[OUTBOX_MAXNUM];
85 s32 sentCount;
86 };
87
88 static enum MODE s_Mode;
89 static enum DISP s_Disp;
90 static BoxBuffer s_Box = {0};
91
92 static nn::os::CriticalSection s_CriticalSection;
93
94 //Settings for MessageBox information
95 static u32 TITLEID = nn::cec::MakeCecTitleId(0x00026); // StreetPass ID (a fixed value)
96 static u32 PRIVATEID = 0xabababab; // Card-specific ID (a different value for each card and for each instance of save data)
97 static char HMACKEY[] = "12345678901234567890123456789012";
98
99 //Settings for Message information
100 static wchar_t s_Title[TITLE_LENGTH] = TITLE_0;
101 static wchar_t s_Body[BODY_LENGTH] = BODY_0;
102 static const wchar_t *s_ContentTitle[CONTENT_NUM] = {
103 TITLE_0, TITLE_1, TITLE_2, TITLE_3, TITLE_4,
104 TITLE_5, TITLE_6, TITLE_7, TITLE_8, TITLE_9};
105 static const wchar_t *s_ContentBody[CONTENT_NUM] = {
106 BODY_0, BODY_1, BODY_2, BODY_3, BODY_4,
107 BODY_5, BODY_6, BODY_7, BODY_8, BODY_9};
108
109 //------------------------------------------------------------
110 // Allocator used by the CEC library
111 class CecTestAllocator : public nn::fnd::IAllocator
112 {
113 private:
114 nn::fnd::ExpHeap expHeap;
115 bool isInitialized;
116 NN_PADDING3;
117
118 public:
CecTestAllocator()119 CecTestAllocator(){isInitialized = false;};
~CecTestAllocator()120 virtual ~CecTestAllocator(){};
121
InitExpHeap()122 void InitExpHeap()
123 {
124 if(isInitialized == false)
125 {
126 expHeap.Initialize(
127 nn::os::GetDeviceMemoryAddress(),
128 1024 * 1024 );
129 isInitialized = true;
130 }
131 }
132
133 /* Please see man pages for details
134
135 */
Allocate(size_t size,s32 alignment=4)136 virtual void* Allocate(size_t size, s32 alignment = 4)
137 {
138 if(isInitialized == true)
139 {
140 return expHeap.Allocate(size, alignment);
141 }
142 return NULL;
143 }
144
145 /* Please see man pages for details
146
147 */
Free(void * p)148 virtual void Free(void* p)
149 {
150 if(isInitialized == true)
151 {
152 expHeap.Free(p);
153 }
154 }
155
156 };
157
158 CecTestAllocator allocator;
159
SaveSendMessage(nn::cec::MessageBox * pCecMessBox)160 nn::Result SaveSendMessage(nn::cec::MessageBox* pCecMessBox)
161 {
162 // Try to open a box
163 nn::Result result = pCecMessBox->OpenMessageBox(TITLEID, PRIVATEID);
164 if(result.IsFailure()) return result;
165
166 // Save messages to the buffer from which they will be sent
167 s_Box.outMessNum= pCecMessBox->GetBoxMessageNum(nn::cec::CEC_BOXTYPE_OUTBOX);
168 for(int i=0; i<s_Box.outMessNum; i++)
169 {
170 u8 *buf;
171 nn::cec::MessageId messId;
172 nn::cec::Message cecMess;
173
174 // Get the message ID
175 pCecMessBox->GetMessageId(&messId, nn::cec::CEC_BOXTYPE_OUTBOX, i);
176
177 // Get the size
178 size_t messSize = pCecMessBox->GetMessageSize(nn::cec::CEC_BOXTYPE_OUTBOX, i);
179
180 // Allocate a buffer for reading data
181 buf = reinterpret_cast<u8*>(allocator.Allocate(messSize));
182 if(buf==NULL) NN_LOG("Malloc Error\n");
183
184 // Read the message
185 result = pCecMessBox->ReadMessage(cecMess, buf, messSize, nn::cec::CEC_BOXTYPE_OUTBOX, messId);
186 if(result.IsFailure())
187 {
188 NN_LOG("### [Message %d]ReadMessage Error\n", i-1);
189 allocator.Free(buf);
190 continue;
191 }
192
193 //InfoText
194 const wchar_t* pInfoText;
195 size_t infoTextLen;
196 if(cecMess.GetInfoText(&pInfoText, &infoTextLen).IsSuccess())
197 {
198 std::memset(s_Box.outMessData[i].title,0,TITLE_LENGTH*sizeof(wchar_t));
199 std::memcpy(&s_Box.outMessData[i].title, pInfoText, infoTextLen);
200 }
201
202 //body
203 void* pBody;
204 size_t bodyLen;
205 cecMess.GetMessageBodyPointer(&pBody,&bodyLen);
206 std::memcpy(&s_Box.outMessData[i].body, pBody, bodyLen);
207
208 //CreateDate
209 s_Box.outMessData[i].date = cecMess.GetCreateDate();
210
211 allocator.Free(buf);
212 }
213 pCecMessBox->CloseMessageBox();
214 return result;
215 }
216
CreateBox(nn::cec::MessageBox & cecMessBox)217 nn::Result CreateBox(nn::cec::MessageBox& cecMessBox)
218 {
219 nn::Result result;
220 /* --------------------------------------------------------
221 Create a box
222 --------------------------------------------------------*/
223 // Try to open a box
224 result = cecMessBox.OpenMessageBox(TITLEID, PRIVATEID);
225 if(result.IsFailure())
226 {
227 if(result != nn::cec::MakeResultNoData())return result;
228
229 // Set the BoxName
230 wchar_t boxName[64] = L"CEC_DEMO_BOX"; //Box Name
231
232 // Set the icon
233 u8 boxIcon[48*48*2];
234 std::memset(boxIcon, 0x55, sizeof(boxIcon));//Fill it in randomly
235
236 //Create a box
237 result = cecMessBox.CreateMessageBox(
238 TITLEID,\
239 PRIVATEID,\
240 HMACKEY,\
241 boxIcon,\
242 sizeof(boxIcon),\
243 boxName,\
244 sizeof(boxName),\
245 nn::cec::CEC_INBOX_SIZE_DEFAULT,\
246 nn::cec::CEC_OUTBOX_SIZE_DEFAULT,\
247 INBOX_MAXNUM,\
248 OUTBOX_MAXNUM,\
249 nn::cec::CEC_MESSSIZEMAX_DEFAULT);
250 }
251 cecMessBox.CloseMessageBox();
252 return result;
253 }
254
DeleteBox(nn::cec::MessageBox * pCecMessBox)255 void DeleteBox(nn::cec::MessageBox* pCecMessBox)
256 {
257 // Try to open a box
258 if(pCecMessBox->OpenMessageBox(TITLEID, PRIVATEID).IsSuccess())
259 {
260 pCecMessBox->DeleteMessageBox();
261 }
262 else
263 {
264 pCecMessBox->DeleteMessageBox(TITLEID);
265 }
266 }
267
DeleteMessage(nn::cec::MessageBox * pCecMessBox,nn::cec::CecBoxType cecBoxType)268 nn::Result DeleteMessage(nn::cec::MessageBox* pCecMessBox, nn::cec::CecBoxType cecBoxType)
269 {
270 nn::Result result = pCecMessBox->OpenMessageBox(TITLEID, PRIVATEID);
271 if(result.IsFailure())return result;
272 //Delete messages
273 result=pCecMessBox->DeleteAllMessages(cecBoxType);
274 if(cecBoxType == nn::cec::CEC_BOXTYPE_INBOX)
275 {
276 //Delete the inbox buffer
277 std::memset(&s_Box,0,sizeof(s_Box));
278 }
279 pCecMessBox->CloseMessageBox();
280 return result;
281 }
282
SetSendMessage(nn::cec::MessageBox * pCecMessBox)283 nn::Result SetSendMessage(nn::cec::MessageBox* pCecMessBox)
284 {
285 nn::Result result;
286 nn::cec::Message newMess;
287 u8 icon[40*40*2] = {0};
288 nn::cec::MessageId mssid;
289
290 // Try to open a box
291 result = pCecMessBox->OpenMessageBox(TITLEID, PRIVATEID);
292 if(result.IsFailure()) return result;
293
294 /* --------------------------------------------------------
295 Create a message
296 --------------------------------------------------------*/
297 newMess.NewMessage( TITLEID, // CecTitleId
298 0, // Group ID
299 nn::cec::MESSAGE_TYPEFLAG_NON_FRIEND\
300 |nn::cec::MESSAGE_TYPEFLAG_FRIEND, // Message Type Flag
301 nn::cec::CEC_SENDMODE_SENDRECV, // Send Mode
302 nn::cec::MESSAGE_SENDCOUNT_ONCE, // Send Count
303 nn::cec::MESSAGE_PROPAGATIONCOUNT_ONCE // Propagation Count
304 );
305
306 // Set the data itself (the body)
307 newMess.SetMessageBody(s_Body, sizeof(s_Body));
308
309 // Set the icon
310 std::memset(icon, 0x55, sizeof(icon));//Fill it in randomly
311 newMess.SetIcon(icon, sizeof(icon));
312
313 // Set the InfoText
314 newMess.SetInfoText(s_Title, sizeof(s_Title));
315
316 // Save the message in the outbox
317 result = pCecMessBox->WriteMessage(newMess, nn::cec::CEC_BOXTYPE_OUTBOX, mssid);
318 if(result.IsFailure())
319 {
320 //The messages in the box have exceeded the maximum value
321 if(result.GetDescription() == nn::cec::DESCRIPTION_BOXMESSNUM_FULL)
322 {
323 //Delete all messages to be sent
324 pCecMessBox->DeleteAllMessages(nn::cec::CEC_BOXTYPE_OUTBOX);
325 }
326 pCecMessBox->CloseMessageBox();
327 return result;
328 }
329 pCecMessBox->CloseMessageBox();
330
331 //Save messages to the buffer from which they will be sent
332 return SaveSendMessage(pCecMessBox);
333 }
334
ReceiveEventThread(u32 * pIsExistNewMess)335 static void ReceiveEventThread(u32* pIsExistNewMess)
336 {
337 nn::cec::CecNotificationData notificationData;
338 nn::cec::CecControl::GetCecRecvEventHandle(&recvEvent);
339
340 do{
341 recvEvent.Wait();
342
343 NN_LOG("============= Receive Check!!!!!! ============= \n");
344
345 // Get information received from the daemon
346 nn::cec::CTR::CecControl::GetCecInfoBuffer(TITLEID, reinterpret_cast<u8*>(¬ificationData), sizeof(notificationData));
347 NN_LOG(" Recv Count:[%d] Num:[%d] \n", notificationData.count, notificationData.num);
348
349 // Determine whether information has been received
350 if(notificationData.num > 0)
351 {
352 nn::os::CriticalSection::ScopedLock locker(s_CriticalSection);
353 nn::cec::MessageBox messBox;
354
355 // Open the box
356 nn::cec::CecControl::StopScanning();
357 nn::Result result = messBox.OpenMessageBox(TITLEID, PRIVATEID);
358 if(result.IsFailure())
359 {
360 NN_LOG(" ### Cannot Open Box(Deleted?) [0x%08x/0x%08x]\n", TITLEID, PRIVATEID);
361 NN_DBG_PRINT_RESULT(result);
362 continue;
363 }
364
365 u32 inboxMessNum = messBox.GetBoxMessageNum(nn::cec::CEC_BOXTYPE_INBOX);
366 if(inboxMessNum == 0)
367 {
368 NN_LOG(" ### No Message(Deleted?) [0x%08x/0x%08x]\n", TITLEID, PRIVATEID);
369 messBox.CloseMessageBox();
370 continue;
371 }
372
373 nn::cec::MessageId recvMessId;
374
375 // Determine whether the inbox has messages with the MessageId values that were received
376 NN_LOG("%s(%d): notificationData check\n",__FUNCTION__,__LINE__);
377 for(int i=0; i < notificationData.num; i++)
378 {
379 // Determine whether there is data in the inbox
380 nn::cec::MessageId inboxMessId;
381 for(int j=0; j<inboxMessNum; j++)
382 {
383 messBox.GetMessageId(&inboxMessId, nn::cec::CEC_BOXTYPE_INBOX, j);
384 if(inboxMessId.IsEqual(notificationData.param[i].messageId))
385 {
386 NN_LOG(" <<< New Message >>>\n"); // There is a message in the inbox
387
388 //Set a flag indicating that there is a new message
389 *pIsExistNewMess = 1;
390 break;
391 }
392 }
393
394 }
395 messBox.CloseMessageBox();
396
397 }
398 NN_LOG("=============================================== \n");
399 /*
400 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).
401 To restart communications in a short time interval, you must enable StartScanning(true).
402 To enable the StartScanning(true) included in this demo program, use the executable file that is used for the Development build.
403
404 */
405 nn::cec::CecControl::StartScanning(true);
406 }while(threadAlive);
407 recvEvent.Finalize();
408 }
409
410 // Update the box
UpdateCreation(nn::hid::PadStatus * pPadStatus,nn::cec::MessageBox * pCecMessBox)411 nn::Result UpdateCreation(nn::hid::PadStatus* pPadStatus, nn::cec::MessageBox* pCecMessBox)
412 {
413 nn::Result result;
414 if(pPadStatus->trigger & nn::hid::BUTTON_A)
415 {
416 // Create a box
417 result = CreateBox(*pCecMessBox);
418 if(result.IsSuccess())
419 {
420 //Enter a mode in which outgoing messages are set
421 s_Mode = WRITE_MODE;
422 s_Disp = WRITE_DISP;
423 }
424 else
425 {
426 //Display error information
427 s_Disp = CREATE_DISP;
428 }
429 return result;
430 }
431 return ResultApplicationSuccess();
432 }
433
434 // Display box information
DisplayCreation(demo::RenderSystemDrawing * pRenderSystem,nn::Result * result)435 void DisplayCreation(demo::RenderSystemDrawing* pRenderSystem, nn::Result* result)
436 {
437 u16 x,y;
438
439 //Display a message prompting the user to create a box
440 x = 0; y = 0;
441 pRenderSystem->SetRenderTarget(NN_GX_DISPLAY0);
442 pRenderSystem->Clear();
443 pRenderSystem->SetColor(WHITE_COLOR);
444 pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "PRESS A TO CREATE MESSAGEBOX");
445
446 //Display error information
447 if(result->IsFailure())
448 {
449 pRenderSystem->SetColor(RED_COLOR);
450 if(*result == nn::cec::MakeResultBoxNumFull()) //The maximum box count has been reached
451 {
452 pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "ERROR:MESSAGEBOX NUM IS FULL");
453 }
454 else if(*result == nn::cec::MakeResultNotAuthorized()) //The private IDs do not match
455 {
456 pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "ERROR:PRIVATEID DO NOT MATCH");
457 }
458 else if(result->GetDescription() == Result::DESCRIPTION_BUSY)
459 {
460 pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "ERROR:BUSY");
461 }
462 else
463 {
464 pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "ERROR:");
465 }
466 }
467 pRenderSystem->SwapBuffers();
468
469 //Display controls
470 x = 0; y = BOTTOM_DISP;
471 pRenderSystem->SetRenderTarget(NN_GX_DISPLAY1);
472 pRenderSystem->Clear();
473 pRenderSystem->SetColor(WHITE_COLOR);
474 pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y, "A:CREATE_BOX");
475 pRenderSystem->SwapBuffers();
476 }
477
478 // Set messages to be sent
UpdateWriting(nn::hid::PadStatus * pPadStatus,nn::cec::MessageBox * pCecMessBox,u8 * pSelected)479 nn::Result UpdateWriting(nn::hid::PadStatus* pPadStatus, nn::cec::MessageBox* pCecMessBox, u8* pSelected)
480 {
481 nn::Result result;
482 if(pPadStatus->trigger & nn::hid::BUTTON_A)
483 {
484 // Create a message to send
485 result = SetSendMessage(pCecMessBox);
486 if(result.IsSuccess())
487 {
488 //Enter a mode in which outgoing messages are set
489 s_Mode = READ_MODE;
490 s_Disp = READ_DISP;
491 }
492 else
493 {
494 //Display error information
495 s_Disp = WRITE_DISP;
496 }
497 return result;
498 }
499 //Return to the previous screen
500 if(pPadStatus->trigger & nn::hid::BUTTON_B)
501 {
502 DeleteBox(pCecMessBox);
503 s_Mode = CREATE_MODE;
504 s_Disp = CREATE_DISP;
505 }
506 //Choose the message content
507 if(pPadStatus->trigger & nn::hid::BUTTON_RIGHT)
508 {
509 if(*pSelected<CONTENT_NUM-1)
510 *pSelected = *pSelected + 1;
511 }
512 if(pPadStatus->trigger & nn::hid::BUTTON_LEFT)
513 {
514 if(0<*pSelected)
515 *pSelected = *pSelected - 1;
516 }
517 if(pPadStatus->trigger & nn::hid::BUTTON_RIGHT\
518 ||pPadStatus->trigger & nn::hid::BUTTON_LEFT)
519 {
520 //Set the content of the message to be sent
521 std::memcpy(&s_Title,s_ContentTitle[*pSelected],sizeof(s_Title));
522 std::memcpy(&s_Body,s_ContentBody[*pSelected], sizeof(s_Body));
523 s_Disp = WRITE_DISP;
524 }
525 return ResultApplicationSuccess();
526 }
527
528 // Display a screen for setting the message to be sent
DisplayWriting(demo::RenderSystemDrawing * pRenderSystem,nn::Result * result)529 void DisplayWriting(demo::RenderSystemDrawing* pRenderSystem, nn::Result* result)
530 {
531 u16 x;
532 u16 y;
533
534 x = 0; y = 0;
535 pRenderSystem->SetRenderTarget(NN_GX_DISPLAY0);
536 pRenderSystem->Clear();
537 pRenderSystem->SetColor(WHITE_COLOR);
538 pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "AT FIRST, PRESS LEFT/RIGHT TO SELECT CONTENT");
539 pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "AT SECOND, PRESS A TO SET SEND MESSAGE");
540
541 if(result->IsFailure()) //Display error information
542 {
543 pRenderSystem->SetColor(RED_COLOR);
544 if(result->GetDescription() == nn::cec::DESCRIPTION_NOT_AGREE_EULA)
545 {
546 pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "ERROR:YOU DID NOT AGREE EULA");
547 }
548 if(result->GetDescription() == nn::cec::DESCRIPTION_PARENTAL_CONTROL_CEC)
549 {
550 pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "ERROR:PARENTAL CONTROL BANED");
551 }
552 if(result->GetDescription() == nn::cec::DESCRIPTION_BOXMESSNUM_FULL)
553 {
554 pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "ERROR:SEND MESSAGENUM IS FULL");
555 pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "APPLICATION DELETED ALL OUTBOX MESSAGE");
556 }
557 }
558
559 pRenderSystem->SwapBuffers();
560
561 //Display the message box
562 x = 0; y = 0;
563 pRenderSystem->SetRenderTarget(NN_GX_DISPLAY1);
564 pRenderSystem->Clear();
565 pRenderSystem->SetColor(WHITE_COLOR);
566 pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "TITLE:%ls",s_Title);
567 pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "------------------BODY------------------");
568 wchar_t *line, *ptr, body[BODY_LENGTH];
569 std::memcpy(body,s_Body,sizeof(s_Body));
570 line=std::wcstok(body,L"\n",&ptr);
571 while(line!=NULL)
572 {
573 pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "%ls",line);
574 line=std::wcstok(NULL,L"\n",&ptr);
575 }
576 pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * (BOTTOM_DISP-1), "A:SET_MESSAGE B:DELETE_BOX");
577 pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * BOTTOM_DISP, "LEFT/RIGHT:SELECT_CONTENT");
578 pRenderSystem->SwapBuffers();
579 }
580
GetRecvMessage(nn::cec::MessageBox * pCecMessBox)581 nn::Result GetRecvMessage(nn::cec::MessageBox* pCecMessBox){
582 nn::Result result ;
583 // Try to open a box
584 result = pCecMessBox->OpenMessageBox(TITLEID, PRIVATEID);
585 if(result.IsFailure()) return result;
586
587 //----------------------------------
588 {
589 // Get the number of messages in the inbox
590 nn::cec::MessageId messId[INBOX_MAXNUM]; // Message ID
591
592 u32 messNum = pCecMessBox->GetBoxMessageNum(nn::cec::CEC_BOXTYPE_INBOX);
593
594 // Create a list of message IDs for the inbox
595 for(u32 i=messNum; i!=0; i--)
596 {
597 pCecMessBox->GetMessageId(&messId[i-1], nn::cec::CEC_BOXTYPE_INBOX, i-1);
598 }
599
600 // Read messages from the inbox
601 for(u32 i=messNum; i!=0; i--)
602 {
603 u8 *buf;
604 nn::cec::Message cecMess;
605
606 // Get the size
607 size_t messSize = pCecMessBox->GetMessageSize(nn::cec::CEC_BOXTYPE_INBOX, i-1);
608
609 // Allocate a buffer for reading data
610 buf = reinterpret_cast<u8*>(allocator.Allocate(messSize));
611 if(buf==NULL) NN_LOG("Malloc Error\n");
612
613 // Read the message
614 result = pCecMessBox->ReadMessage(cecMess, buf, messSize, nn::cec::CEC_BOXTYPE_INBOX, messId[i-1]);
615 if(result.IsFailure())
616 {
617 NN_LOG("### [Message %d]ReadMessage Error\n", i-1);
618 allocator.Free(buf);
619 continue;
620 }
621
622 //------------------------------
623 //Save all kinds of messages in the application
624 if(s_Box.inMessNum < INBOX_MAXNUM)
625 {
626 //InfoText
627 const wchar_t* pInfoText;
628 size_t infoTextLen;
629 if(cecMess.GetInfoText(&pInfoText, &infoTextLen).IsSuccess())
630 {
631 std::memset(s_Box.inMessData[s_Box.inMessNum].title,0,TITLE_LENGTH*sizeof(wchar_t));
632 std::memcpy(&s_Box.inMessData[s_Box.inMessNum].title, pInfoText, infoTextLen);
633 }
634
635 //body
636 void* pBody;
637 size_t bodyLen;
638 cecMess.GetMessageBodyPointer(&pBody,&bodyLen);
639 std::memcpy(&s_Box.inMessData[s_Box.inMessNum].body, pBody, bodyLen);
640
641 //ReceiveData
642 s_Box.inMessData[s_Box.inMessNum].date = cecMess.GetRecvDate();
643
644 s_Box.inMessNum++;
645 }
646 else
647 {
648 // Exceeded the number of messages that can be saved
649 NN_LOG("### MailBox Full.\n");
650 }
651 allocator.Free(buf);
652 }
653 pCecMessBox->DeleteAllMessages(nn::cec::CEC_BOXTYPE_INBOX);
654 NN_LOG("Delete Inbox Messages.\n");
655 }
656
657 //----------------------------------
658 {
659 // Get the number of messages in the outbox
660 s_Box.outMessNum = pCecMessBox->GetBoxMessageNum(nn::cec::CEC_BOXTYPE_OUTBOX);
661 nn::cec::MessageId messId[OUTBOX_MAXNUM]; // Message SID
662 u32 sendCount[OUTBOX_MAXNUM]; // Send Count
663
664 // Create a list of message IDs for the outbox
665 for(u32 i=0; i<s_Box.outMessNum; i++)
666 {
667 pCecMessBox->GetMessageId(&messId[i], nn::cec::CEC_BOXTYPE_OUTBOX, i);
668 sendCount[i] = pCecMessBox->GetMessageSendCount(nn::cec::CEC_BOXTYPE_OUTBOX, i);
669 }
670
671 // Delete messages that have already been sent
672 for(u32 i=0; i<s_Box.outMessNum; i++)
673 {
674 if(sendCount[i] == 0)
675 {
676 s_Box.sentCount++; // Send count
677 s_Box.outMessNum--;
678 pCecMessBox->DeleteMessage(nn::cec::CEC_BOXTYPE_OUTBOX, messId[i]);
679 NN_LOG("Delete Sent Message [%s].\n",nn::cec::MessageId(messId[i]).GetString());
680 }
681 }
682 }
683 pCecMessBox->CloseMessageBox();
684 //Save messages to the buffer from which they will be sent
685 return SaveSendMessage(pCecMessBox);
686 }
687
688 //Update messages
UpdateReading(nn::hid::PadStatus * pPadStatus,nn::cec::MessageBox * pCecMessBox,u8 * pSelected,u32 * pIsExistNewMess)689 void UpdateReading(nn::hid::PadStatus* pPadStatus, nn::cec::MessageBox* pCecMessBox, u8* pSelected, u32* pIsExistNewMess)
690 {
691 nn::Result result;
692 //Delete all messages that have been received
693 if(pPadStatus->trigger & nn::hid::BUTTON_X)
694 {
695 DeleteMessage(pCecMessBox, nn::cec::CEC_BOXTYPE_INBOX);
696 }
697 //Get messages that have been received
698 if(pPadStatus->trigger & nn::hid::BUTTON_Y)
699 {
700 GetRecvMessage(pCecMessBox);
701 *pIsExistNewMess = 0;
702 }
703 //Go to the previous screen
704 if(pPadStatus->trigger & nn::hid::BUTTON_B)
705 {
706 DeleteMessage(pCecMessBox, nn::cec::CEC_BOXTYPE_OUTBOX);
707 s_Mode = WRITE_MODE;
708 s_Disp = WRITE_DISP;
709 }
710 //Select a received message
711 if(pPadStatus->trigger & nn::hid::BUTTON_UP)
712 {
713 if(0<*pSelected)*pSelected = *pSelected - 1;
714 }
715 if(pPadStatus->trigger & nn::hid::BUTTON_DOWN)
716 {
717 if(*pSelected<s_Box.inMessNum-1)*pSelected = *pSelected + 1;
718 }
719 //Update the screen if there was a valid key event
720 if(pPadStatus->trigger & nn::hid::BUTTON_X\
721 ||pPadStatus->trigger & nn::hid::BUTTON_Y\
722 ||pPadStatus->trigger & nn::hid::BUTTON_UP\
723 ||pPadStatus->trigger & nn::hid::BUTTON_DOWN)
724 {
725 s_Disp = READ_DISP;
726 }
727 }
728
GetWeekString(nn::fnd::Week week)729 char* GetWeekString(nn::fnd::Week week)
730 {
731 switch(week)
732 {
733 case nn::fnd::WEEK_SUNDAY:
734 return "SUN";
735 case nn::fnd::WEEK_MONDAY:
736 return "MON";
737 case nn::fnd::WEEK_TUESDAY:
738 return "TUE";
739 case nn::fnd::WEEK_WEDNESDAY:
740 return "WED";
741 case nn::fnd::WEEK_THURSDAY:
742 return "THR";
743 case nn::fnd::WEEK_FRIDAY:
744 return "FRI";
745 case nn::fnd::WEEK_SATURDAY:
746 return "SAT";
747 }
748 return "NUL";
749 }
750
751 //Display messages
DisplayReading(demo::RenderSystemDrawing * pRenderSystem,u8 selected,u32 * pIsExistNewMess)752 void DisplayReading(demo::RenderSystemDrawing* pRenderSystem, u8 selected, u32* pIsExistNewMess)
753 {
754 u16 x,y;
755
756 //------------------------------------------------------------
757 //Display a list of messages
758 //------------------------------------------------------------
759 //Display received messages
760 x = 0; y = 0;
761 pRenderSystem->SetRenderTarget(NN_GX_DISPLAY0);
762 pRenderSystem->Clear();
763 pRenderSystem->SetColor(WHITE_COLOR);
764 pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "---------------------------------------------INBOX");
765 pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "TITLE ReceiveDate");
766 for(int i=0; i<s_Box.inMessNum; i++)
767 {
768 if(selected==y-2&&selected<INBOX_MAXNUM)pRenderSystem->SetColor(GREEN_COLOR);
769 else pRenderSystem->SetColor(WHITE_COLOR);
770 pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y, "%ls",s_Box.inMessData[i].title);
771 pRenderSystem->DrawText(FONT_SIZE * (x+TITLE_LENGTH+1), FONT_SIZE * y++, "%04d/%02d/%02d %02d:%02d %02d.%03d",\
772 s_Box.inMessData[i].date.year,s_Box.inMessData[i].date.month,s_Box.inMessData[i].date.day,s_Box.inMessData[i].date.hour,\
773 s_Box.inMessData[i].date.minute,s_Box.inMessData[i].date.second,s_Box.inMessData[i].date.milliSecond);
774 }pRenderSystem->SetColor(WHITE_COLOR);
775
776 y = INBOX_MAXNUM+2;
777 pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "--------------------------------------------OUTBOX");
778 //Display messages to be sent
779 pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "TITLE CreateDate");
780 for(int i=0; i<s_Box.outMessNum; i++)
781 {
782 if(selected==y&&selected>OUTBOX_MAXNUM)pRenderSystem->SetColor(GREEN_COLOR);
783 else pRenderSystem->SetColor(WHITE_COLOR);
784 pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y, "%ls",s_Box.outMessData[i].title);
785 pRenderSystem->DrawText(FONT_SIZE * (x+TITLE_LENGTH+1), FONT_SIZE * y++, "%04d/%02d/%02d %02d:%02d %02d.%03d",\
786 s_Box.outMessData[i].date.year,s_Box.outMessData[i].date.month,s_Box.outMessData[i].date.day,\
787 s_Box.outMessData[i].date.hour,s_Box.outMessData[i].date.minute,s_Box.outMessData[i].date.second,\
788 s_Box.outMessData[i].date.milliSecond);
789 }
790 pRenderSystem->SwapBuffers();
791
792 //----------------------------------------------------------------
793 //Display the message box
794 x = 0; y = 0;
795 pRenderSystem->SetRenderTarget(NN_GX_DISPLAY1);
796 pRenderSystem->Clear();
797 pRenderSystem->SetColor(WHITE_COLOR);
798 pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "TITLE:%ls",s_Box.inMessData[selected].title);
799 pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "------------------BODY------------------");
800 if(*pIsExistNewMess) //Display an alert message informing to the user that there is a new message
801 {
802 switch(*pIsExistNewMess%3)
803 {
804 case 0:
805 pRenderSystem->DrawText(FONT_SIZE * 9, FONT_SIZE * 10,"////NEW MESSAGE////");
806 break;
807 case 1:
808 pRenderSystem->DrawText(FONT_SIZE * 9, FONT_SIZE * 10,"----NEW MESSAGE----");
809 break;
810 case 2:
811 pRenderSystem->DrawText(FONT_SIZE * 9, FONT_SIZE * 10,"\\\\\\\\NEW MESSAGE\\\\\\\\");
812 break;
813 }
814 pRenderSystem->DrawText(FONT_SIZE * 6, FONT_SIZE * 11,"PRESS Y TO RECEIVE MESSAGE");
815 *pIsExistNewMess = *pIsExistNewMess+1;
816 }
817 else //Display the content of the message
818 {
819 wchar_t *line, *ptr, body[BODY_LENGTH];
820 std::memcpy(body,s_Box.inMessData[selected].body,sizeof(body));
821 line=std::wcstok(body,L"\n",&ptr);
822 while(line!=NULL)
823 {
824 pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "%ls",line);
825 line=std::wcstok(NULL,L"\n",&ptr);
826 }
827 }
828 pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * (BOTTOM_DISP-1),"Y:RECEIVE_MESSAGE X:DELETE_MESSAGE");
829 pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * BOTTOM_DISP, "B:BACK UP/DOWN:SELECT_MESSAGE");
830 pRenderSystem->SwapBuffers();
831 }
832
nnMain(void)833 extern "C" void nnMain( void )
834 {
835 nn::Result result;
836 nn::os::Thread thread;
837
838 // Use the FS library to get the EULA version to agree to for the application
839 nn::fs::Initialize();
840
841 // Initialize hid
842 result = nn::hid::Initialize();
843 NN_UTIL_PANIC_IF_FAILED(result);
844
845 // Initialize the CriticalSection
846 s_CriticalSection.Initialize();
847
848 // Initialize applets
849 SleepHandler::Initialize();
850
851 // Prepare pad
852 nn::hid::PadReader padReader;
853 nn::hid::PadStatus padStatus;
854
855 // Wait for HID input to stabilize
856 nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromSeconds(1));
857
858 // Allocator
859 allocator.InitExpHeap();
860
861 // Access the daemon
862 NN_LOG("Cec: nn::cec::Initialize()\n");
863 result = nn::cec::Initialize(allocator);
864 NN_UTIL_PANIC_IF_FAILED(result);
865
866 //Flag indicating whether there is a new message
867 u32 isExistNewMess = 0;
868 {
869 threadAlive = true;
870 result = thread.TryStartUsingAutoStack<u32*, u32*>(ReceiveEventThread, &isExistNewMess, 1024);
871 if(result.IsFailure())
872 {
873 NN_LOG("%s(%d):### TryStartUsingAutoStack Failed.\n",__FUNCTION__,__LINE__);
874 }
875 }
876 /*
877 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).
878 To restart communications in a short time interval, you must enable StartScanning(true).
879 To enable the StartScanning(true) included in this demo program, use the executable file that is used for the Development build.
880
881 */
882 nn::cec::CecControl::StartScanning(true);
883
884 // Allocate heap
885 nn::fnd::ExpHeap appHeap;
886 appHeap.Initialize(nn::os::GetDeviceMemoryAddress()+(1024*1024), nn::os::GetDeviceMemorySize() );
887
888 // Prepare RenderSystem
889 uptr heapForGx = reinterpret_cast<uptr> (appHeap.Allocate(0x800000));
890 demo::RenderSystemDrawing renderSystem;
891 renderSystem.Initialize(heapForGx, 0x800000);
892 renderSystem.SetClearColor(NN_GX_DISPLAY_BOTH, 0.f, 0.f, 0.f, 0.f);
893 renderSystem.SetFontSize(FONT_SIZE);
894 renderSystem.SetLineWidth(LINE_WIDTH);
895
896 nn::cec::MessageBox cecMessBox;
897 u8 selectedInBox = 0;
898 u8 selectedOutBox = 0;
899
900 // Try to open a box
901 result = cecMessBox.OpenMessageBox(TITLEID, PRIVATEID);
902 if(result.IsFailure())
903 {
904 //Go to the StreetPass box creation screen
905 s_Mode = CREATE_MODE;
906 s_Disp = CREATE_DISP;
907 }
908 else
909 {
910 //When there is a message in the inbox
911 if(cecMessBox.GetBoxMessageNum(nn::cec::CEC_BOXTYPE_INBOX))
912 {
913 //Set the new message flag
914 isExistNewMess = 1;
915 }
916 if(cecMessBox.GetBoxMessageNum(nn::cec::CEC_BOXTYPE_OUTBOX)==0)
917 {
918 //Go to the screen that writes messages to send
919 s_Mode = WRITE_MODE;
920 s_Disp = WRITE_DISP;
921 }
922 else
923 {
924 //Save messages to the buffer from which they will be sent
925 SaveSendMessage(&cecMessBox);
926
927 //Screen that reads received messages
928 s_Mode = READ_MODE;
929 s_Disp = READ_DISP;
930 }
931 cecMessBox.CloseMessageBox();
932 }
933 while(1)
934 {
935 // Get input
936 padReader.ReadLatest(&padStatus);
937 switch(s_Mode){
938 case CREATE_MODE: //StreetPass box creation screen
939 result = UpdateCreation(&padStatus, &cecMessBox);
940 if(s_Disp==CREATE_DISP)
941 {
942 DisplayCreation(&renderSystem,&result);
943 s_Disp = NON_DISP;
944 }
945 break;
946
947 case WRITE_MODE: //Screen that writes messages to send
948 result = UpdateWriting(&padStatus, &cecMessBox, &selectedOutBox);
949 if(s_Disp==WRITE_DISP)
950 {
951 DisplayWriting(&renderSystem, &result);
952 s_Disp = NON_DISP;
953 }
954 break;
955
956 case READ_MODE: //Screen that reads received messages
957 UpdateReading(&padStatus, &cecMessBox, &selectedInBox, &isExistNewMess);
958 if(s_Disp==READ_DISP||(isExistNewMess&&s_Disp==NON_DISP))
959 {
960 DisplayReading(&renderSystem,selectedInBox, &isExistNewMess);
961 s_Disp = NON_DISP;
962 }
963 break;
964 }
965
966 // Determination for System Sleep Mode
967 if ( SleepHandler::IsSleepRequested() )
968 {
969 NN_LOG("<<SLEEP>>\n");
970 s_CriticalSection.Enter();
971 SleepHandler::SleepSystem();
972 s_CriticalSection.Leave();
973 NN_LOG("<<AWAKE>>\n");
974 nn::gx::StartLcdDisplay();
975 }
976 nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromMilliSeconds(100));
977 }
978 }
979