1 /*---------------------------------------------------------------------------*
2 Project: Horizon
3 File: cec_Control.h
4
5 Copyright (C)2009 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: 33743 $
14 *---------------------------------------------------------------------------*/
15
16 #ifndef NN_CEC_CTR_CEC_CONTROL_H_
17 #define NN_CEC_CTR_CEC_CONTROL_H_
18 #include <nn/fnd.h>
19 #include <nn/cec/CTR/cec_Api.h>
20
21 namespace nn {
22 namespace cec {
23 namespace CTR {
24
25 struct CecAllocFunc
26 {
27 void* (*allocFunc)(size_t); //!< メモリアロケート関数へのポインタです。
28 void (*freeFunc)(void*); //!< メモリ解放関数へのポインタです。
29 };
30
31 //------------------------------------------------------------
32 // 通知用
33
34 /*!
35 @struct CecNotificationParam
36 @brief 受信情報のBOX個々の情報
37 */
38 struct CecNotificationParam
39 {
40 nn::fnd::DateTimeParameters recvDate; //!< 受信日時
41 u32 cecTitleId; //!< BOXの cecTitleId
42 u8 messageId[CEC_SIZEOF_MESSAGEID]; //!< 受信MessageのMessageID(先頭のMessageのみ)
43 };
44
45 /*!
46 @struct CecNotificationData
47 @brief 受信情報
48 */
49 struct CecNotificationData
50 {
51 size_t num; //!< 項目数
52 s32 count; //!< 受信回数(本体起動から) 通信が行われるとこの値が増加します。
53 CecNotificationParam param[MESSAGE_BOX_NUM_MAX]; //!< 個々のBOXの情報
54 };
55
56
57 /*!
58 @class CecControl
59 @brief Cecの状態を変更・情報の取得を行います。
60
61 Cecデーモンの状態はシステムに管理され、自動的に動作しています。<br>
62 MessageBoxへのアクセス(OpenMessageBox, ReadMessage, WriteMessage等)を行うと、
63 Cecデーモンの動作を中断してIDLE状態になります。<br>
64 <br>
65 通信を行うと、その相手を記憶し、平均 4 時間、最大 8 時間経過するまで再通信しません。<br>
66 相手を記憶するのは、1つ以上のデータの送受信があった場合、通信開始したが送受信すべきデータが無かった場合です。<br>
67 この情報は、電源をOFFにしても保持されます。<br>
68 好きなタイミングで相手にデータを届けるという使い方ができないことに注意してください。<br>
69 デバッグ用として、通信を行った相手の情報をリセットし、同じ相手と再度通信することを可能にする手段が用意されています。StartScanning の引数にtrueを指定することでリセットが行われます。この機能はReleaseビルドでは使用できません。
70 */
71
72 class CecControl {
73
74 public:
75
76 enum ChangeDaemonState{
77 DAEMON_CHANGE_STATE_READY ,
78 DAEMON_CHANGE_STATE_STARTSCAN ,
79 DAEMON_CHANGE_STATE_STOP,
80 DAEMON_CHANGE_STATE_STOP_DAEMON,
81 DAEMON_CHANGE_STATE_START_DAEMON,
82 DAEMON_CHANGE_STATE_RESET_FILTER,
83
84 DAEMON_CHANGE_STATE_NDM_RESUME,
85 DAEMON_CHANGE_STATE_NDM_SUSPEND
86
87 };
88
89 /*!
90 @brief @ref GetCecState で取得される、Cecの状態を示す値です。DAEMON_STATE_IDLE のときしか BOXにアクセスすることはできません。
91 */
92 enum DaemonState
93 {
94 DAEMON_STATE_STOP, //!< 動作していません
95 DAEMON_STATE_IDLE, //!< 停止中
96 DAEMON_STATE_BUSY, //!< 処理中
97 DAEMON_STATE_SCAN, //!< スキャン中
98 DAEMON_STATE_READY, //!< READY状態(インターネット通信など、別の通信をしており、すれちがい通信に入っていない状態)
99 DAEMON_STATE_COMMUNICATING //!< 通信中
100 };
101
102
103 CecControl(size_t bufSize);
104 CecControl();
105 ~CecControl();
106
107 /*!
108 :private
109 * @brief cec に接続します。cec にアクセスするために最初に呼ぶ必要があります。
110 * @return nn::Result
111 */
112 static nn::Result Initialize();
113 //static nn::Result Initialize(CecAllocFunc& cecAllocFunc);
114 static nn::Result Initialize(nn::fnd::IAllocator& cecAllocFunc);
115 #if 0
116 static nn::Result InitializeSys();
117 #endif
118
119 /*!
120 :private
121 * @brief cec へのアクセスを終了します。
122 * @return nn::Result
123 */
124 static nn::Result Finalize();
125
126 #if 0
127 static nn::Result FinalizeSys();
128 #endif
129
130
131 static bool IsInitialized();
132 #if 0
133 static bool IsInitializedSys();
134 #endif
135
136 /*!
137 :private
138 * @brief cec を Ready 状態に移行させます。nn::cec::Initialize() ~ Finalize() の間は呼ぶことはできません。
139 (暫定的に用意されたAPIです。今後のバージョンでは、cecの状態を直接変更するAPIは削除されます。)
140 * @return nn::Result
141 */
142 static nn::Result ReadyDaemon();
143
144 /*!
145 * @brief cec の動作を開始させます。
146
147 MessageBox::CloseMessageBox の中で、 StartScanning(reset = false) が呼ばれます。
148
149 * @param[in] reset true をセットすると、BOXの内容を読み直して Scan を開始します。<br>
150 また、記憶していた通信相手のリストも消去され、同じ相手と再接続することが可能になります。このとき、設定中のボックスだけでなく、全てのボックス(アプリ)のデータが、再度交換される可能性があります。<br>
151 Releaseビルドでは true に設定してもリセット動作は行われませんのでご注意ください。
152
153 * @return nn::Result
154 * @retval ResultSuccess 成功しました。
155 * @retval ResultStateBusy Initialize が行われていないなどの理由で動作開始しませんでした。
156 * @retval 上記以外 失敗しました。
157 */
158 static nn::Result StartScanning(bool reset = false);
159
160 /*!
161 :private
162 * @brief ndmからcecをSuspendさせます。
163
164 * @return nn::Result
165 * @retval ResultSuccess 成功しました。
166 * @retval ResultStateBusy 停止処理を行いましたが、停止ステートになりませんでした。
167 * @retval 上記以外 失敗しました。
168 */
169 static nn::Result Suspend();
170
171 /*!
172 * @brief cec の動作を手動で停止します。
173
174 通信途中だった場合、通信を中断して停止(IDLE)ステータスに移行します。<br>
175 バックグラウンドで行われている通信が中断される可能性があることに注意してください。<br>
176 事前に GetCecState で DAEMON_STATE_COMMUNICATING, DAEMON_STATE_BUSY ではないことを確認してから停止するのが安全です。<br>
177 <br>
178 MessageBox にアクセスするには、停止状態である必要があります。<br>
179 MessageBox::OpenMessageBox の中で、 StopScanning(b_Immediate = true) が呼ばれるため、
180 意識して停止する必要はありませんが、<br>
181 事前にStopScanning(b_Immediate = false)を使用することで、データの保存を中断させず、停止状態になるのを待つことができます。<br><br>
182 b_Asyncにtrueをセットしたとき、複数回呼んでキャンセルが発生したときなど、この関数から抜けたときに停止ステータスになっていない可能性があります。<br>
183 この関数を呼んだ後に WriteMessage などを呼んでも、BUSY状態であるためにエラーになる可能性があるので注意してください。
184
185 * @param[in] b_Immediate true をセットすると、通信途中のデータの保存もキャンセルして停止させます。
186 * @param[in] b_Async true をセットすると、即座に返ります。
187 * @return nn::Result
188 * @retval ResultSuccess 成功しました。
189 * @retval ResultStateBusy 停止処理を行いましたが、停止ステートになりませんでした。
190 * @retval 上記以外 失敗しました。
191 */
192 static nn::Result StopScanning(bool b_Immediate = false, bool b_Async = false);
193
194 /*!
195 :private
196 * @brief CecDaemon を 停止させます。
197 (暫定的に用意されたAPIです。今後のバージョンでは、cecの状態を直接変更するAPIは削除されます。)
198
199 停止後は StartScanning を呼んでも動作開始しません。
200 * @return nn::Result
201 */
202 static nn::Result StopDaemon();
203
204 /*!
205 :private
206 * @brief CecDaemon を 動作開始させます。
207 (暫定的に用意されたAPIです。今後のバージョンでは、cecの状態を直接変更するAPIは削除されます。)
208 * @return nn::Result
209 */
210 static nn::Result StartDaemon();
211
212 /*!
213 :private
214 * @brief 受信したMessageの情報を取得します。
215 * @param[in] cecTitleId すれちがい通信ID を指定します。
216 * @param[out] pCecInfoBuffer CecNotificationData を受け取るバッファを指定します。
217 * @param[in] size バッファのサイズを指定します。
218 * @return nn::Result
219 */
220 static nn::Result GetCecInfoBuffer( u32 cecTitleId, u8 pCecInfoBuffer[], size_t size );
GetCecInfoBuffer(u8 pCecInfoBuffer[],size_t size)221 static nn::Result GetCecInfoBuffer( u8 pCecInfoBuffer[], size_t size )
222 {
223 return GetCecInfoBuffer( 0, pCecInfoBuffer, size );
224 };
225
226 /*!
227 * @brief CECの状態を取得します。
228 * @param[out] state 状態を示す @ref DaemonState が格納されます。 DAEMON_STATE_IDLE のときのみ、BOXにアクセス可能です。IDLE 以外の状態の遷移は外部から変更できない為、それぞれの状態をハンドリングする必要はありません。
229 * @return nn::Result
230 * @retval ResultSuccess 成功しました。
231 */
232 static nn::Result GetCecState( DaemonState* state );
233 static nn::Result GetCecState( u32* state );
234
235 static bool IsDaemonBusy(void);
236
237 /*!
238 :private
239 * @brief 受信の通知を受ける Event をセットします。
240 * @param[out] event 受信があったときに Signal される Event です。
241 * @return nn::Result
242 */
243 static nn::Result GetCecRecvEventHandle( nn::os::Event* event );
244
245 static nn::Result GetChangeStateEventHandle( nn::os::Event& event );
246
247 static nn::cec::CTR::TitleId MakeCecTitleId(bit32 id, bit8 variation = 0x0);
248
249 /* @brief NAND上の CECのBOX保存領域をフォーマットします。デバッグ用です。 */
250 static nn::Result FormatSaveData();
251
252 /*!
253 :private
254 * @brief 排他モードに入ります。(デバッグ用)
255 バックグラウンド通信をすれちがい通信専用にします。<br>
256 他のプロセスが既に排他モードに切り替えていたとき、ローカル通信を行っているときはエラーとなります。<br>
257 排他モードを終えるときは LeaveExclusiveState を呼んでください。<br>
258
259 ※ システムの通信ポリシーを変更してしまう API ですので、デバッグ用途のみの利用に限定し、製品版に組み込まれることが無いようにしてください。
260
261 * @return nn::Result
262 */
263 static nn::Result EnterExclusiveState();
264
265 /*!
266 :private
267 * @brief 排他モードを終了します。(デバッグ用)
268 * @return nn::Result
269 */
270 static nn::Result LeaveExclusiveState();
271
272 private:
273 static bool s_Initialized;
274 static bool s_NdmSuspended;
275 static bool s_EnterExclusiveState;
276 static nn::os::CriticalSection m_Cs;
277
278 };
279
280
281
282
283 //! @name Initialize / Finalize
284 //@{
285
286
287 /*!
288 * @brief CEC Daemon に接続します。CEC MessageBox にアクセスするために最初に呼ぶ必要があります。
289
290 * @param[in] cecAllocFunc CEC ライブラリが使用するアロケータを指定します。
291
292 CEC ライブラリのMessageデータ処理に必要なメモリを確保するために
293 使用されます。最大で扱うMessageデータサイズ × 2 程度のメモリが使用されます。
294 * @return nn::Result
295 */
296 nn::Result Initialize(nn::fnd::IAllocator& cecAllocFunc);
297
298 /*!
299 * @brief CEC Daemon に接続します。CEC MessageBox にアクセスするために最初に呼ぶ必要があります。
300
301 * @return nn::Result
302 * @retval ResultSuccess 成功しました。
303 * @retval 上記以外 失敗しました。
304 */
305 nn::Result Initialize();
306
Initialize()307 inline nn::Result Initialize()
308 {
309 return CecControl::Initialize();
310 }
311
312 nn::Result Initialize(nn::cec::CTR::CecAllocFunc& cecAllocFunc);
313
Initialize(nn::fnd::IAllocator & cecAllocFunc)314 inline nn::Result Initialize(nn::fnd::IAllocator& cecAllocFunc)
315 {
316 return CecControl::Initialize(cecAllocFunc);
317 }
318
319 /*!
320 * @brief CEC Daemon へのアクセスを終了します。
321 * @return nn::Result
322 * @retval ResultSuccess 成功しました。
323 * @retval 上記以外 失敗しました。
324 */
325 nn::Result Finalize();
326
Finalize()327 inline nn::Result Finalize()
328 {
329 return CecControl::Finalize();
330 }
331
332 //@}
333
334 //! @name 受信通知
335 //@{
336
337 /*!
338 * @brief 受信の通知を受ける Event を指定します。
339
340 すれちがい通信が発生したときにSignalされるEventです。<br>
341 通信したことをリアルタイムに知りたいときに使用することができます。<br>
342 フォアグラウンドのアプリケーション宛のデータがあるかどうかは、
343 @ref GetCecInfoBuffer 等で確認することができます。
344
345 * @param[out] event 受信があったときに Signal される Event です。
346 * @return nn::Result
347 * @retval ResultSuccess 成功しました。
348 */
349 nn::Result GetCecRecvEventHandle( nn::os::Event* event );
GetCecRecvEventHandle(nn::os::Event * event)350 inline nn::Result GetCecRecvEventHandle( nn::os::Event* event )
351 {
352 return CecControl::GetCecRecvEventHandle( event );
353 }
354
355
356 /*!
357 * @brief 直前の通信で受信したMessageの情報を取得します。
358
359 @ref GetCecRecvEventHandle を使用して受信の通知を受け取った後、
360 フォアグラウンドのアプリケーション宛のデータがあるかどうかを調べる時等に使用できます。<br>
361 取得できる情報は、直前の1回のもののみで、それ以前の通信で受信したデータについては、
362 この関数で取得することはできません。<br>
363 また、この関数で取得できるのは受信時の情報であり、それ以後のボックスの変化は反映されていません。<br>
364 グルーピングされた複数のMessageを受け取ったときでも、取得できる情報は1メッセージ分だけです。
365 (CecNotificationData.numは最大 1 になります。)<br>
366 また、重複していたために破棄された受信データの情報は入りません。<br>
367 CecNotificationData のcountの値は、すれちがい通信が発生する度に増加します。
368 この値の変化を調べることで、通信の有無を知ることも可能です。
369
370 * @param[in] cecTitleId すれちがい通信ID を指定します。
371 * @param[out] pCecInfoBuffer CecNotificationData を受け取るバッファを指定します。
372 * @param[in] size バッファのサイズを指定します。
373 * @return nn::Result
374 * @retval ResultSuccess 成功しました。
375 * @retval ResultNoData 取得できるデータがありませんでした。
376 */
377 nn::Result GetCecInfoBuffer( u32 cecTitleId, u8 pCecInfoBuffer[], size_t size );
378 nn::Result GetCecInfoBuffer( u8 pCecInfoBuffer[], size_t size );
379
GetCecInfoBuffer(u32 cecTitleId,u8 pCecInfoBuffer[],size_t size)380 inline nn::Result GetCecInfoBuffer( u32 cecTitleId, u8 pCecInfoBuffer[], size_t size )
381 {
382 return CecControl::GetCecInfoBuffer(cecTitleId, pCecInfoBuffer, size );
383 }
384
GetCecInfoBuffer(u8 pCecInfoBuffer[],size_t size)385 inline nn::Result GetCecInfoBuffer( u8 pCecInfoBuffer[], size_t size )
386 {
387 return CecControl::GetCecInfoBuffer(0, pCecInfoBuffer, size );
388 }
389
390 //@}
391
392
393 /*!
394 @brief 20bit のユニーク ID から、すれちがい通信で使用する
395 32bit の すれちがい通信ID(CecTitleId) を生成します。
396
397 そのアプリに指定された ID を使用してください。<br>
398 すれちがい通信では、同じ すれちがい通信ID のMessageが登録されている相手を検索します。(リージョンが異なっていても通信可能です。)
399
400 @param[in] id 20bit の ユニークID です。複数タイトル間で共通のボックスを使用して通信したい場合は、どちらか片方のユニーク ID を指定してください。
401 @param[in] variation 使用しません。
402 * @return CecTitleId
403 */
404 nn::cec::CTR::TitleId MakeCecTitleId(bit32 id, bit8 variation = 0x0);
MakeCecTitleId(bit32 id,bit8 variation)405 inline nn::cec::CTR::TitleId MakeCecTitleId(bit32 id, bit8 variation)
406 {
407 return CecControl::MakeCecTitleId(id, variation);
408 }
409
410 } // end of namespace CTR
411 } // end of namespace cec
412 } // end of namespace nn
413
414
415
416 #endif // ifndef NN_CEC_CTR_CEC_CONTROL_H_
417