1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     savedata.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: 46365 $
14  *---------------------------------------------------------------------------*/
15 
16 #include <nn/fs.h>
17 #include <nn/dbg.h>
18 #include "savedata.h"
19 #include "applet.h"
20 
21 const char*  SaveDataDemo::SAVEDATA_ARCHIVE  = "data:";
22 const char*  SaveDataDemo::SAVEDATA_FILENAME = "data:/test.txt";
23 
Initialize(demo::RenderSystemDrawing * p_RenderSystem,nn::fnd::ExpHeap *)24 void SaveDataDemo::Initialize(demo::RenderSystemDrawing* p_RenderSystem, nn::fnd::ExpHeap*)
25 {
26     Device::Initialize(p_RenderSystem);
27 
28     const size_t    maxFiles        = 8;
29     const size_t    maxDirectories  = 8;
30     const bool      isDuplicateAll  = true; // Duplicates the entire save data region
31 
32     m_IsFormatted    = false;
33     m_IsMounted      = true;
34 
35     // Mount and format save data
36     nn::Result result = nn::fs::MountSaveData();
37     if(result.IsFailure())
38     {
39         if((result <= nn::fs::ResultNotFormatted()) ||
40            (result <= nn::fs::ResultBadFormat()) ||
41            (result <= nn::fs::ResultVerificationFailed()))
42         {
43             // Save data needs to be formatted
44             NN_LOG("Format save data.\n");
45             m_IsFormatted = true;
46             result = nn::fs::FormatSaveData(maxFiles, maxDirectories, isDuplicateAll);
47             if(result.IsFailure())
48             {
49                 NN_LOG("Cannot format save data!\n");
50                 NN_ERR_THROW_FATAL_ALL(result);
51             }
52         }
53         else
54         {
55             // Unexpected error
56             NN_ERR_THROW_FATAL_ALL(result);
57         }
58 
59         // If mounting fails here, the save data cannot be used
60         result = nn::fs::MountSaveData();
61         if(result.IsFailure())
62         {
63             NN_LOG("Cannot use save data!\n");
64             NN_ERR_THROW_FATAL_ALL(result);
65             m_IsMounted = false;
66         }
67     }
68 }
69 
Finalize(void)70 void SaveDataDemo::Finalize(void)
71 {
72     if (m_IsMounted)
73     {
74         // Since it is duplicated, commit the save data region
75         nn::Result result = nn::fs::CommitSaveData();
76         if(result.IsFailure())
77         {
78             NN_LOG("Cannot commit save data!\n");
79         }
80 
81         // Unmount save data
82         result = nn::fs::Unmount(SAVEDATA_ARCHIVE);
83         if(result.IsFailure())
84         {
85             NN_LOG("Cannot unmount save data!\n");
86         }
87     }
88 
89     Device::Finalize();
90 }
91 
Start(void)92 void SaveDataDemo::Start(void)
93 {
94     Device::Start();
95 
96     m_ExitEvent.Initialize(false);
97 
98 
99     // Simple program to create, open, write to, and load a file for save data
100 
101     // Open file (creates one if one does not exist)
102     nn::Result result = m_SaveDataFile.TryInitialize(
103         SAVEDATA_FILENAME,
104         nn::fs::OPEN_MODE_READ | nn::fs::OPEN_MODE_WRITE | nn::fs::OPEN_MODE_CREATE
105     );
106 
107     m_IsAvailable = result.IsSuccess();
108 
109     if ( m_IsAvailable )
110     {
111         // After creating with TryInitialize, performs SetSize since the size is 0
112         result = m_SaveDataFile.TrySetSize(SAVEDATA_SIZE);
113         if(result.IsFailure())
114         {
115             return;
116         }
117 
118         // Load the content of the saved save data to the display buffer
119         result = m_SaveDataFile.TrySeek(0, nn::fs::POSITION_BASE_BEGIN);
120         if(result.IsFailure())
121         {
122             NN_LOG("TrySeek error\n");
123             NN_DBG_PRINT_RESULT(result);
124             return;
125         }
126 
127         // Sometimes, verification failure occurs with the first Read
128         s32 readSize;
129         result = m_SaveDataFile.TryRead(&readSize, m_SaveDataBuffer, SAVEDATA_SIZE);
130         if(result.IsFailure() && !(result <= nn::fs::ResultVerificationFailed()))
131         {
132             NN_LOG("TryRead error\n");
133             NN_DBG_PRINT_RESULT(result);
134             return;
135         }
136 
137         // Prepare data to write
138         for ( s32 i = 0; i < SAVEDATA_SIZE; i++ )
139         {
140             m_WriteFileBuffer[i] = static_cast<char>(i);
141         }
142 
143         // Write to data
144         result = m_SaveDataFile.TrySeek(0, nn::fs::POSITION_BASE_BEGIN);
145         if(result.IsFailure())
146         {
147             return;
148         }
149 
150         s32 writeSize;
151         result = m_SaveDataFile.TryWrite(&writeSize, m_WriteFileBuffer, SAVEDATA_SIZE, true);
152         if(result.IsFailure())
153         {
154             return;
155         }
156 
157         // Commit written content
158         result = nn::fs::CommitSaveData();
159         if(result.IsFailure())
160         {
161             return;
162         }
163 
164         // Load data
165         result = m_SaveDataFile.TrySeek(0, nn::fs::POSITION_BASE_BEGIN);
166         if(result.IsFailure())
167         {
168             return;
169         }
170 
171         result = m_SaveDataFile.TryRead(&readSize, m_ReadFileBuffer, SAVEDATA_SIZE);
172         if(result.IsFailure())
173         {
174             return;
175         }
176 
177         for ( s32 i = 0; i < SAVEDATA_SIZE; i++ )
178         {
179             NN_ASSERT(m_WriteFileBuffer[i] == m_ReadFileBuffer[i]);
180         }
181 
182         m_Thread.Start(SaveDataDemo::ThreadFunc, this, m_Stack);
183     }
184     else
185     {
186         NN_LOG("[DEMO1] Failed to open '%s'.\n",SAVEDATA_FILENAME);
187     }
188 }
189 
End(void)190 void SaveDataDemo::End(void)
191 {
192     if ( m_IsAvailable )
193     {
194         m_ExitEvent.Signal();
195         m_Thread.Join();
196 
197         // Close the file
198         m_SaveDataFile.Finalize();
199     }
200 
201     Device::End();
202 }
203 
DrawFrame(void)204 void SaveDataDemo::DrawFrame(void)
205 {
206     mp_RenderSystem->SetRenderTarget(NN_GX_DISPLAY0);
207     mp_RenderSystem->DrawText(10, 220, "Savedata %s", m_IsFormatted ? "is formatted" : "already exists");
208     mp_RenderSystem->DrawText(10, 230, "data:%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
209                               m_SaveDataBuffer[0], m_SaveDataBuffer[1], m_SaveDataBuffer[2], m_SaveDataBuffer[3], m_SaveDataBuffer[4],
210                               m_SaveDataBuffer[5], m_SaveDataBuffer[6], m_SaveDataBuffer[7], m_SaveDataBuffer[8], m_SaveDataBuffer[9],
211                               m_SaveDataBuffer[10], m_SaveDataBuffer[11], m_SaveDataBuffer[12], m_SaveDataBuffer[13], m_SaveDataBuffer[14],
212                               m_SaveDataBuffer[15]);
213 }
214 
ThreadFuncImpl()215 void SaveDataDemo::ThreadFuncImpl()
216 {
217     nn::Result result;
218 
219     while ( !m_ExitEvent.TryWait() )
220     {
221         TransitionHandler::Lock();
222         {
223             // Load save data
224             // Because processing automatically stops in Sleep Mode, we do not need an exclusive lock of some kind.
225             result = m_SaveDataFile.TrySeek(0, nn::fs::POSITION_BASE_BEGIN);
226             if(result.IsFailure())
227             {
228                 return;
229             }
230 
231             s32 readSize;
232             result = m_SaveDataFile.TryRead(&readSize, m_ReadFileBuffer, SAVEDATA_SIZE);
233             for ( s32 i = 0; i < SAVEDATA_SIZE; i++ )
234             {
235                 NN_ASSERT(m_WriteFileBuffer[i] == m_ReadFileBuffer[i]);
236             }
237         }
238         TransitionHandler::Unlock();
239 
240         nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromMilliSeconds(100));
241 
242         // Write save data
243         // The application must explicitly get an exclusive lock of some kind in Sleep Mode
244         TransitionHandler::Lock();
245         TransitionHandler::LockForSleep();
246         {
247             result = m_SaveDataFile.TrySeek(0, nn::fs::POSITION_BASE_BEGIN);
248             if(result.IsFailure())
249             {
250                 return;
251             }
252 
253             s32 writeSize;
254             result = m_SaveDataFile.TryWrite(&writeSize, m_WriteFileBuffer, SAVEDATA_SIZE, true);
255             if(result.IsFailure())
256             {
257                 return;
258             }
259 
260             // Commit written content
261             result = nn::fs::CommitSaveData();
262             if(result.IsFailure())
263             {
264                 return;
265             }
266         }
267         TransitionHandler::UnlockForSleep();
268         TransitionHandler::Unlock();
269 
270         nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromMilliSeconds(100));
271     }
272 }
273 
ThreadFunc(SaveDataDemo * saveDataDemo)274 void SaveDataDemo::ThreadFunc(SaveDataDemo* saveDataDemo)
275 {
276     saveDataDemo->ThreadFuncImpl();
277 }
278 
279 /*---------------------------------------------------------------------------*
280   End of file
281  *---------------------------------------------------------------------------*/
282