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