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: 32865 $
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                     MessageBox にアクセスするには、停止状態である必要があります。<br>
176                     MessageBox::OpenMessageBox の中で、 StopScanning(b_Immediate = true) が呼ばれます。<br>
177                     事前にこの関数を使用することで、デーモンの動作を中断させず、停止状態になるのを待つことができます。<br><br>
178                     b_Asyncにtrueをセットしたとき、複数回呼んでキャンセルが発生したときなど、この関数から抜けたときに停止ステータスになっていない可能性があります。<br>
179                     この関数を呼んだ後に WriteMessage などを呼んでも、BUSY状態であるためにエラーになる可能性があるので注意してください。
180 
181      * @param[in]   b_Immediate   true をセットすると、通信途中のデータの保存もキャンセルして停止させます。
182      * @param[in]   b_Async   true をセットすると、即座に返ります。
183      * @return      nn::Result
184      * @retval       ResultSuccess      成功しました。
185      * @retval       ResultStateBusy    停止処理を行いましたが、停止ステートになりませんでした。
186      * @retval       上記以外           失敗しました。
187      */
188     static nn::Result  StopScanning(bool b_Immediate = false, bool b_Async = false);
189 
190     /*!
191      :private
192      * @brief       CecDaemon を 停止させます。
193                    (暫定的に用意されたAPIです。今後のバージョンでは、cecの状態を直接変更するAPIは削除されます。)
194 
195                    停止後は StartScanning を呼んでも動作開始しません。
196      * @return      nn::Result
197      */
198     static nn::Result  StopDaemon();
199 
200     /*!
201      :private
202      * @brief       CecDaemon を 動作開始させます。
203                    (暫定的に用意されたAPIです。今後のバージョンでは、cecの状態を直接変更するAPIは削除されます。)
204      * @return      nn::Result
205      */
206     static nn::Result  StartDaemon();
207 
208     /*!
209      :private
210      * @brief       受信したMessageの情報を取得します。
211      * @param[in]   cecTitleId              すれちがい通信ID を指定します。
212      * @param[out]  pCecInfoBuffer          CecNotificationData を受け取るバッファを指定します。
213      * @param[in]   size                    バッファのサイズを指定します。
214      * @return      nn::Result
215      */
216     static nn::Result GetCecInfoBuffer(  u32 cecTitleId, u8 pCecInfoBuffer[], size_t size );
GetCecInfoBuffer(u8 pCecInfoBuffer[],size_t size)217     static nn::Result GetCecInfoBuffer(  u8 pCecInfoBuffer[], size_t size )
218     {
219         return GetCecInfoBuffer(  0, pCecInfoBuffer, size );
220     };
221 
222     /*!
223      * @brief       CECの状態を取得します。
224      * @param[out]  state          状態を示す @ref DaemonState が格納されます。 DAEMON_STATE_IDLE のときのみ、BOXにアクセス可能です。IDLE 以外の状態の遷移は外部から変更できない為、それぞれの状態をハンドリングする必要はありません。
225      * @return      nn::Result
226      * @retval       ResultSuccess      成功しました。
227      */
228     static nn::Result GetCecState( DaemonState* state );
229     static nn::Result GetCecState( u32* state );
230 
231     static bool IsDaemonBusy(void);
232 
233     /*!
234      :private
235      * @brief       受信の通知を受ける Event をセットします。
236      * @param[out]  event          受信があったときに Signal される Event です。
237      * @return      nn::Result
238      */
239     static nn::Result GetCecRecvEventHandle( nn::os::Event* event );
240 
241     static nn::Result GetChangeStateEventHandle( nn::os::Event& event );
242 
243     static nn::cec::CTR::TitleId MakeCecTitleId(bit32 id, bit8 variation = 0x0);
244 
245     /* @brief       NAND上の CECのBOX保存領域をフォーマットします。デバッグ用です。 */
246     static nn::Result FormatSaveData();
247 
248     /*!
249      :private
250      * @brief       排他モードに入ります。(デバッグ用)
251                     バックグラウンド通信をすれちがい通信専用にします。<br>
252                     他のプロセスが既に排他モードに切り替えていたとき、ローカル通信を行っているときはエラーとなります。<br>
253                     排他モードを終えるときは LeaveExclusiveState を呼んでください。<br>
254 
255                     ※ システムの通信ポリシーを変更してしまう API ですので、デバッグ用途のみの利用に限定し、製品版に組み込まれることが無いようにしてください。
256 
257      * @return      nn::Result
258      */
259     static nn::Result   EnterExclusiveState();
260 
261     /*!
262      :private
263      * @brief       排他モードを終了します。(デバッグ用)
264      * @return      nn::Result
265      */
266     static nn::Result   LeaveExclusiveState();
267 
268 private:
269     static bool                s_Initialized;
270     static bool                s_NdmSuspended;
271     static bool                s_EnterExclusiveState;
272     static nn::os::CriticalSection    m_Cs;
273 
274 };
275 
276 
277 
278 
279 //! @name Initialize / Finalize
280 //@{
281 
282 
283 /*!
284  * @brief       CEC Daemon に接続します。CEC MessageBox にアクセスするために最初に呼ぶ必要があります。
285 
286  * @param[in]   cecAllocFunc        CEC ライブラリが使用するアロケータを指定します。
287 
288                                     CEC ライブラリのMessageデータ処理に必要なメモリを確保するために
289                                     使用されます。最大で扱うMessageデータサイズ × 2 程度のメモリが使用されます。
290  * @return      nn::Result
291  */
292 nn::Result  Initialize(nn::fnd::IAllocator& cecAllocFunc);
293 
294 /*!
295  * @brief       CEC Daemon に接続します。CEC MessageBox にアクセスするために最初に呼ぶ必要があります。
296 
297  * @return      nn::Result
298  * @retval       ResultSuccess      成功しました。
299  * @retval       上記以外           失敗しました。
300  */
301 nn::Result  Initialize();
302 
Initialize()303 inline nn::Result  Initialize()
304 {
305     return CecControl::Initialize();
306 }
307 
308 nn::Result  Initialize(nn::cec::CTR::CecAllocFunc& cecAllocFunc);
309 
Initialize(nn::fnd::IAllocator & cecAllocFunc)310 inline nn::Result  Initialize(nn::fnd::IAllocator& cecAllocFunc)
311 {
312     return CecControl::Initialize(cecAllocFunc);
313 }
314 
315 /*!
316  * @brief       CEC Daemon へのアクセスを終了します。
317  * @return      nn::Result
318  * @retval       ResultSuccess      成功しました。
319  * @retval       上記以外           失敗しました。
320  */
321 nn::Result  Finalize();
322 
Finalize()323 inline nn::Result  Finalize()
324 {
325     return CecControl::Finalize();
326 }
327 
328 //@}
329 
330 //! @name 受信通知
331 //@{
332 
333 /*!
334  * @brief       受信の通知を受ける Event を指定します。
335 
336                 すれちがい通信が発生したときにSignalされるEventです。<br>
337                 通信したことをリアルタイムに知りたいときに使用することができます。<br>
338                 フォアグラウンドのアプリケーション宛のデータがあるかどうかは、
339                 @ref GetCecInfoBuffer 等で確認することができます。
340 
341  * @param[out]  event          受信があったときに Signal される Event です。
342  * @return      nn::Result
343  * @retval       ResultSuccess      成功しました。
344  */
345 nn::Result GetCecRecvEventHandle( nn::os::Event* event );
GetCecRecvEventHandle(nn::os::Event * event)346 inline nn::Result GetCecRecvEventHandle( nn::os::Event* event )
347 {
348     return CecControl::GetCecRecvEventHandle( event );
349 }
350 
351 
352 /*!
353  * @brief       直前の通信で受信したMessageの情報を取得します。
354 
355                 @ref GetCecRecvEventHandle を使用して受信の通知を受け取った後、
356                 フォアグラウンドのアプリケーション宛のデータがあるかどうかを調べる時等に使用できます。<br>
357                 グルーピングされた複数のMessageを受け取ったときでも、取得できる情報は1つ分だけです。<br>
358                 また、重複していたために破棄された受信データの情報は入りません。<br>
359                 CecNotificationData のcountの値は、すれちがい通信が発生する度に増加します。
360                 この値の変化を調べることで、通信の有無を知ることも可能です。
361 
362   * @param[in]   cecTitleId              すれちがい通信ID を指定します。
363  * @param[out]  pCecInfoBuffer          CecNotificationData を受け取るバッファを指定します。
364  * @param[in]   size                    バッファのサイズを指定します。
365  * @return      nn::Result
366  * @retval       ResultSuccess      成功しました。
367  * @retval       ResultNoData      取得できるデータがありませんでした。
368  */
369 nn::Result GetCecInfoBuffer( u32 cecTitleId, u8 pCecInfoBuffer[], size_t size );
370 nn::Result GetCecInfoBuffer( u8 pCecInfoBuffer[], size_t size );
371 
GetCecInfoBuffer(u32 cecTitleId,u8 pCecInfoBuffer[],size_t size)372 inline nn::Result GetCecInfoBuffer( u32 cecTitleId, u8 pCecInfoBuffer[], size_t size )
373 {
374     return CecControl::GetCecInfoBuffer(cecTitleId, pCecInfoBuffer, size );
375 }
376 
GetCecInfoBuffer(u8 pCecInfoBuffer[],size_t size)377 inline nn::Result GetCecInfoBuffer( u8 pCecInfoBuffer[], size_t size )
378 {
379     return CecControl::GetCecInfoBuffer(0, pCecInfoBuffer, size );
380 }
381 
382 //@}
383 
384 
385 /*!
386   @brief        20bit のユニーク ID から、すれちがい通信で使用する
387                 32bit の すれちがい通信ID(CecTitleId) を生成します。
388 
389   @param[in]    id      20bit の ユニークID です。複数タイトル間で共通のボックスを使用して通信したい場合は、どちらか片方のユニーク ID を指定してください。
390   @param[in]    variation   使用しません。
391  * @return      CecTitleId
392 */
393 nn::cec::CTR::TitleId MakeCecTitleId(bit32 id, bit8 variation = 0x0);
MakeCecTitleId(bit32 id,bit8 variation)394 inline nn::cec::CTR::TitleId MakeCecTitleId(bit32 id, bit8 variation)
395 {
396     return CecControl::MakeCecTitleId(id, variation);
397 }
398 
399 } // end of namespace CTR
400 } // end of namespace cec
401 } // end of namespace nn
402 
403 
404 
405 #endif  // ifndef NN_CEC_CTR_CEC_CONTROL_H_
406