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