CTR-Pia  5.4.3
Game Communication Engine
 全て クラス ネームスペース 関数 変数 型定義 列挙型 列挙型の値 ページ
transport_ReliableBroadcastProtocol.h
1 /*--------------------------------------------------------------------------------*
2  Copyright (C)Nintendo All rights reserved.
3 
4  These coded instructions, statements, and computer programs contain proprietary
5  information of Nintendo and/or its licensed developers and are protected by
6  national and international copyright laws. They may not be disclosed to third
7  parties or copied or duplicated in any form, in whole or in part, without the
8  prior written consent of Nintendo.
9 
10  The content herein is highly confidential and should be handled accordingly.
11  *--------------------------------------------------------------------------------*/
12 
13 
14 #pragma once
15 
16 #include <nn/pia/transport/transport_Definitions.h>
17 
18 #include <nn/pia/transport/transport_Protocol.h>
19 #include <nn/pia/common/common_Time.h>
20 
21 
22 namespace nn
23 {
24 namespace pia
25 {
26 namespace transport
27 {
28 class ProtocolMessageWriter;
29 class ProtocolMessageReader;
30 }
31 }
32 }
33 
34 
35 namespace nn
36 {
37 namespace pia
38 {
39 namespace transport
40 {
41 
42 
43 /*!
44  @brief 大きなデータを全員に一斉送信するプロトコルです。
45 
46  */
48 {
49 public:
50  PIA_PROTOCOL_TYPE_INFO(ProtocolTypeReliableBroadcast);
51 
52  static const uint32_t ThroughputLimitMax = 0x0FFFFFFF; //!< SetThroughputLimit() で設定できる値の最大値です。
53 
54  /*!
55  @cond PRIVATE
56  @brief デフォルトコンストラクタです。
57 
58  @details アプリケーションプログラムは、このコンストラクタを直接呼び出してはいけません。
59  インスタンスの作成は、 @ref Transport::CreateProtocol を利用してください。
60  */
62  //! @endcond
63 
64 
65  /*!
66  @cond PRIVATE
67  @brief デストラクタです。
68 
69  @details アプリケーションプログラムは、このデストラクタを直接呼び出してはいけません。
70  インスタンスの破棄は、 @ref Transport::DestroyProtocol を利用してください。
71  */
72  virtual ~ReliableBroadcastProtocol();
73  //! @endcond
74 
75 
76  /*!
77  @brief インスタンスを初期化します。 BeginSetup() ~ EndSetup() 間で呼び出す必要があります。
78 
79  @return 成功すれば、 IsSuccess() が true を返す Result が返されます。この関数がエラーを返さないようにアプリケーションを実装する必要があります。
80 
81  @retval ResultAlreadyInitialized 既に初期化されています。プログラミングエラーです。このエラーが返らないようにソースコードを修正してください。
82 
83  @see Finalize
84  */
86 
87 
88  /*!
89  @brief 終了処理を行います。
90  @see Initialize
91  */
92  void Finalize();
93 
94 
95  /*!
96  @cond PRIVATE
97  @brief 通信を開始します。
98 
99  @param[in] localStationAddress 自分の StationAddress です。
100 
101  @return 成功すれば、 IsSuccess() が true を返す Result が返されます。
102 
103  @retval ResultNotInitialized 初期化されていません。プログラミングエラーです。このエラーが返らないようにソースコードを修正してください。
104  @retval ResultInvalidState 既に通信中です。プログラミングエラーです。このエラーが返らないようにソースコードを修正してください。
105  @retval ResultInvalidArgument 引数が誤っています。プログラミングエラーです。このエラーが返らないようにソースコードを修正してください。
106  */
107  virtual Result StartupWithStationAddress(const common::StationAddress& localStationAddress);
108  //! @endcond
109 
110 
111  /*!
112  @cond PRIVATE
113  @brief 通信を終了します。
114  */
115  virtual void CleanupWithStationAddress();
116  //! @endcond
117 
118 
119  /*!
120  @cond PRIVATE
121  @brief メインの処理です。
122 
123  @return ResultSuccess が返されます。
124  */
125  virtual Result Dispatch();
126  //! @endcond
127 
128 
129  /*!
130  @cond PRIVATE
131  @brief 接続状態の切り替え。
132 
133  @param[in] event 操作内容を表すイベントです。
134 
135  @return 成功すれば、 IsSuccess() が true を返す Result が返されます。
136 
137  @retval ResultInvalidState 通信中ではありません。プログラミングエラーです。このエラーが返らないようにソースコードを修正してください。
138  @retval ResultInvalidArgument 引数が誤っています。プログラミングエラーです。このエラーが返らないようにソースコードを修正してください。
139  */
140  virtual Result UpdateProtocolEvent(const transport::ProtocolEvent& event);
141  //! @endcond
142 
143 private:
144  /*!
145  @cond PRIVATE
146  @brief プロトコルの動作モードを表します。
147  */
148  enum Mode
149  {
150  Mode_Invalid = 0x00000000,
151  Mode_Wait = 0x01000000,
152  Mode_Send = 0x02000000,
153  Mode_Receive = 0x03000000
154  };
155  //! @endcond
156 
157 
158  /*!
159  @cond PRIVATE
160  @brief プロトコルの動作の進行状況を表します。
161  */
162  enum Condition
163  {
164  Condition_Wait = 0x00010000,
165  Condition_InProgress = 0x00020000,
166  Condition_Success = 0x00030000,
167  Condition_Failure = 0x00040000
168  };
169  //! @endcond
170 
171 
172  /*!
173  @cond PRIVATE
174  @brief 現在の動作モードを取得します。
175  @return 現在の動作モードです。
176  */
177  Mode GetMode() const
178  {
179  return static_cast<Mode>(m_State & 0xFF000000);
180  }
181  //! @endcond
182 
183 
184  /*!
185  @cond PRIVATE
186  @brief 現在の進行状況を取得します。
187  @return 現在の進行状況です。
188  */
189  Condition GetCondition() const
190  {
191  return static_cast<Condition>(m_State & 0x00FF0000);
192  }
193  //! @endcond
194 
195 
196 public:
197  /*!
198  @brief 動作状態を表します。
199  */
200  enum State
201  {
202  State_Invalid = Mode_Invalid | Condition_Wait, //!< セッションに参加していません。
203  State_Wait = Mode_Wait | Condition_Wait, //!< 何も行っていません。
204  State_Sending = Mode_Send | Condition_InProgress, //!< 送信中です。
205  State_SendSuccess = Mode_Send | Condition_Success, //!< 送信に成功しました。
206  State_SendFailure = Mode_Send | Condition_Failure, //!< 送信に失敗しました。
207  State_Receiving = Mode_Receive | Condition_InProgress, //!< 受信中です。
208  State_ReceiveSuccess = Mode_Receive | Condition_Success, //!< 受信に成功しました。
209  State_ReceiveFailure = Mode_Receive | Condition_Failure, //!< 受信に失敗しました。
210 
211  // 以下内部管理用
212  //! @cond PRIVATE
213  State_SendCanceling = State_Sending | 0x1, // 送信を自分でキャンセル
214  State_SendRejecting = State_Sending | 0x2, // 受信者が拒否して送信をキャンセル
215  State_SendAbandoning = State_Sending | 0x3, // 他人の送信を優先してキャンセル
216  State_SendCompleting = State_Sending | 0x4, // データが全員に届いて完了通知中
217  State_SendCanceled = State_SendFailure | 0x1, // 自分で送信を中断
218  State_SendRejected = State_SendFailure | 0x2, // 送信先に受信拒否された
219  State_SendAbandoned = State_SendFailure | 0x3, // 送信優先度の調停により中断
220  State_ReceiveReady = State_Receiving | 0x1, // 受信待ち状態
221  State_ReceiveCanceling = State_Receiving | 0x2, // 受信キャンセル中
222  State_ReceiveCanceledBeforeStart = State_ReceiveFailure | 0x1, // 自分で受信を中断(受信開始前)
223  State_ReceiveCanceled = State_ReceiveFailure | 0x2, // 自分で受信を中断
224  State_ReceiveInterrupted = State_ReceiveFailure | 0x3, // 送信側が送信を中断して受信失敗
225  State_ReceiveMismatch = State_ReceiveFailure | 0x4 // リクエストと受信設定が合致しない
226  //! @endcond
227  };
228 
229 
230  /*!
231  @brief 現在の動作状態を取得します。
232  @return 現在の動作状態です。
233  */
234  State GetState() const
235  {
236  return static_cast<State>(m_State & 0xFFFF0000);
237  }
238 
239 
240  /*!
241  @brief 送受信の非同期処理実行中かどうかを取得します。
242 
243  @details GetState() が State_Sending または State_Receiving を返す時に true になります。
244  <br>
245  @return 送受信の非同期処理実行中なら true を返します。
246  @see GetState
247  */
248  bool IsRunning() const
249  {
250  return (GetCondition() == Condition_InProgress);
251  }
252 
253 
254  /*!
255  @brief データ転送の動作方式を表します。
256 
257  @details 設定の組み合わせによっては意味のないものであったりする場合もありますので、
258  典型的なケースではあらかじめ用意された定数をそのまま使う事をお勧めします。
259  */
261  {
262  public:
263  /*!
264  @brief デフォルトコンストラクタです。
265  CurrentConnectionSync と同じ値で初期化されます。
266  */
268  : m_Value(CurrentConnectionSync.m_Value)
269  {
270  }
271 
272  /*!
273  @cond PRIVATE
274  @brief uint16_t からの変換
275  */
276  Configuration(uint16_t config)
277  : m_Value(config)
278  {
279  }
280  //! @endcond
281 
282 
283  /*!
284  @cond PRIVATE
285  @brief uint16_t への変換
286  */
287  operator uint16_t() const
288  {
289  return m_Value;
290  }
291  //! @endcond
292 
293 
294  /*!
295  @brief 途中合流したステーションに対しても送信するかどうかの設定を取得します。
296  @return true の場合、送信中に新たにセッションに参加したステーションに対しても送信します。
297  false の場合は送信開始時にセッション内に存在するステーションのみに対して送信します。
298  @see SetSendToNewcomer
299  */
300  bool IsSendToNewcomer() const
301  {
302  return IsFlagOn(Flag_SendToNewcomer);
303  }
304 
305  /*!
306  @brief 受信完了を同期するかどうかの設定を取得します。
307  @return true の場合、受信している全てのステーションが受信完了してから State_ReceiveSuccess となります。
308  false の場合、全てのデータを受信したステーションごとに随時 State_ReceiveSuccess となります。
309  @see SetSynchronizeCompletion
310  */
312  {
313  return IsFlagOn(Flag_SyncronizeCompletion);
314  }
315 
316  /*!
317  @brief 全ての送信先に送信が完了しても State_Sending を継続するかどうかの設定を取得します。
318 
319  @details true とした場合そのままでは State_SendSuccess になることはありません。
320  ReliableBroadcastProtocol::FinishSendEndless() を呼ぶと、それ以降 false を設定した場合と同様の動作をするようになり、
321  全ての送信先に送信を終えた後 State_SendSuccess に遷移します。
322 
323  @return true の場合、すべての送信先に送信が完了しても State_Sending 状態を維持し、送信先が追加された場合はそちらにも送信します。
324  false の場合、全ての送信先に送信が完了すると State_SendSuccess に遷移して送信を終了します。
325 
326  @see SetSendEndless
327  */
328  bool IsSendEndless() const
329  {
330  return IsFlagOn(Flag_SendEndless);
331  }
332 
333  /*!
334  @brief 送信先に受信拒否された場合、送信失敗として送信を中断するかどうかの設定を取得します。
335  @return true の場合、受信拒否されると State_SendFailure となり、送信全体が失敗したことになります。
336  false の場合、受信拒否したステーションだけを送信対象から除外し、他の送信先への送信は継続します。
337  @see SetFailIfRejected
338  */
339  bool IsFailIfRejected() const
340  {
341  return IsFlagOn(Flag_FailIfRejected);
342  }
343 
344  /*!
345  @brief 2つのステーションが同時にお互いに送信しようとした場合に、自動的に一方を送信失敗にするかどうかの設定を取得します。
346 
347  @details この設定が true の送信同士が衝突した場合は、送信元の StationIndex の値の大きい方の送信が失敗になります。
348  一方が true 、もう一方が false の送信の場合は、 true の方の送信が失敗になります。
349  両方とも false の場合はどちらも State_Sending を維持してお互いに相手が受信してくれるのを待ち続けるため、
350  アプリケーションで適切に処理しないとどちらの送信も完了しなくなってしまいますので注意してください。
351 
352  @return true の場合、IsMediateRequest() が false の受信要求や自分より StationIndex の小さい送信先からの受信要求が届いた場合は、
353  送信を中断し State_SendFailure に遷移します。
354  false の場合、送信先からの受信要求によって自動的に State_SendFailure になることはありません。
355 
356  @see SetMediateRequest
357  */
358  bool IsMediateRequest() const
359  {
360  return IsFlagOn(Flag_MediateRequest);
361  }
362 
363 
364  /*!
365  @brief 途中合流したステーションに対しても送信するかどうかの設定を指定します。
366 
367  @details 設定の意味の詳細は IsSendToNewcomer() を参照してください。
368  <br>
369  @param[in] isOn true なら設定を有効にします。
370  @see IsSendToNewcomer
371  */
372  void SetSendToNewcomer(bool isOn)
373  {
374  SetFlag(Flag_SendToNewcomer, isOn);
375  }
376 
377  /*!
378  @brief 受信完了を同期するかどうかの設定を指定します。
379 
380  @details 設定の意味の詳細は IsSynchronizeCompletion() を参照してください。
381  <br>
382  @param[in] isOn true なら設定を有効にします。
383  @see IsSynchronizeCompletion
384  */
385  void SetSynchronizeCompletion(bool isOn)
386  {
387  SetFlag(Flag_SyncronizeCompletion, isOn);
388  }
389 
390  /*!
391  @brief 全ての送信先に送信が完了しても State_Sending を継続するかどうかの設定を指定します。
392 
393  @details 設定の意味の詳細は IsSendEndless() を参照してください。
394  <br>
395  @param[in] isOn true なら設定を有効にします。
396  @see IsSendEndless
397  */
398  void SetSendEndless(bool isOn)
399  {
400  SetFlag(Flag_SendEndless, isOn);
401  }
402 
403  /*!
404  @brief 送信先に受信拒否された場合、送信失敗として送信を中断するかどうかの設定を指定します。
405 
406  @details 設定の意味の詳細は IsFailIfRejected() を参照してください。
407  <br>
408  @param[in] isOn true なら設定を有効にします。
409  @see IsFailIfRejected
410  */
411  void SetFailIfRejected(bool isOn)
412  {
413  SetFlag(Flag_FailIfRejected, isOn);
414  }
415 
416  /*!
417  @brief 2つのステーションが同時にお互いに送信しようとした場合に、自動的に一方を送信失敗にするかどうかの設定を指定します。
418 
419  @details 設定の意味の詳細は IsMediateRequest() を参照してください。
420  <br>
421  @param[in] isOn true なら設定を有効にします。
422  @see IsMediateRequest
423  */
424  void SetMediateRequest(bool isOn)
425  {
426  SetFlag(Flag_MediateRequest, isOn);
427  }
428 
429 
430  /*!
431  @brief 現在接続しているステーションに同期送信する設定です。
432 
433  @details セッション参加を締め切った後、誰かがデータを全員に送信して、全員に届いたら次のシーケンスに進むという使い方を想定した設定です。
434  <br>
435  @li IsSendToNewcomer() : false
436  @li IsSynchronizeCompletion() : true
437  @li IsSendEndless() : false
438  @li IsFailIfRejected() : true
439  @li IsMediateRequest() : true
440  */
442 
443  /*!
444  @brief 現在接続しているステーションに非同期送信する設定です。
445 
446  @details CurrentConnectionSync に対して、受信側は他の受信者にも届いたことを待たなくていい場合を想定した設定です。
447  <br>
448  @li IsSendToNewcomer() : false
449  @li IsSynchronizeCompletion() : false
450  @li IsSendEndless() : false
451  @li IsFailIfRejected() : false
452  @li IsMediateRequest() : true
453  */
455 
456  /*!
457  @brief 現在接続しているステーションだけでなく合流してきたステーションに対しても送信し、全員が受信し終わるのを待つ設定です。
458 
459  @details マッチング中の待ち時間のうちにあらかじめ共有しておくデータを送っておき、
460  マッチング終了後に FinishSendEndless で送信を終了させて
461  そろって次のシーケンスに進むという使い方を想定した設定です。
462 
463  @li IsSendToNewcomer() : true
464  @li IsSynchronizeCompletion() : true
465  @li IsSendEndless() : true
466  @li IsFailIfRejected() : true
467  @li IsMediateRequest() : false
468  */
470 
471  /*!
472  @brief 現在接続しているステーションだけでなく合流してきたステーションに対してもそれぞれ送信し続ける設定です。
473 
474  @details セッションに参加してきたステーションにまず一定のデータを送信して、
475  そのデータを受け取ったステーションから順に次のシーケンスに進むという使い方を想定した設定です。
476 
477  @li IsSendToNewcomer() : true
478  @li IsSynchronizeCompletion() : false
479  @li IsSendEndless() : true
480  @li IsFailIfRejected() : false
481  @li IsMediateRequest() : false
482  */
484 
485 
486  private:
487  enum Flag
488  {
489  Flag_SendToNewcomer = 1 << 0,
490  Flag_SyncronizeCompletion = 1 << 1,
491  Flag_SendEndless = 1 << 2,
492  Flag_FailIfRejected = 1 << 3,
493  Flag_MediateRequest = 1 << 4
494  };
495 
496  bool IsFlagOn(Flag flag) const
497  {
498  return ((m_Value & flag) == flag);
499  }
500  void SetFlag(Flag flag, bool isOn)
501  {
502  if (isOn)
503  {
504  m_Value |= flag;
505  }
506  else
507  {
508  m_Value &= ~flag;
509  }
510  }
511 
512  uint16_t m_Value;
513  };
514 
515 
516  /*!
517  @brief データ転送の設定情報を表します。
518  */
520  {
521  StationIndex m_SourceStationIndex; //!< 送信元の StationIndex です。
522  uint32_t m_DataSize; //!< 転送データのサイズ(バイト)です。
523  uint32_t m_UserData; //!< 送信者が設定したユーザー情報です。
524  Configuration m_Configuration; //!< データ転送の動作方式です。
525  StationId GetSourceStationId() const; //!< 送信元の StationId を取得します。
526  };
527 
528 
529  /*!
530  @brief 現在のデータ転送の設定情報を取得します。
531 
532  @return 送信中および送信後ならその送信の設定が、受信中および受信後ならその受信の設定が取得できます。
533  受信要求が来る前に受信開始した時や、その状態のまま Cancel() した時など、データを全く受け取っていない場合は NULL を返します。
534  */
536 
537 
538  /*!
539  @brief 指定したステーションが現在の送信の送信対象とされているかどうかを取得します。
540 
541  @details 通常はセッションに参加している自分以外の全てのステーションが送信対象になります。
542  @ref Configuration::IsSendToNewcomer() が false の場合は、送信開始以降にセッションに参加したステーションは送信対象になりません。
543  @ref Configuration::IsFailIfRejected() が false の場合は、その送信に対して受信拒否したり受信を中断したステーションは送信対象から外されます。
544 
545  @param[in] stationId 送信対象かどうか調べたいステーションの StationId です。
546 
547  @return 指定したステーションが送信対象なら true を、そうでなければ false を返します。
548  送信中、送信後でないときは false を返します。
549  */
550  bool IsSendTarget(StationId stationId) const;
551 
552  /*!
553  @cond PRIVATE
554  @brief 現在のデータ転送の設定情報を取得します。
555  */
556  bool IsSendTarget(StationIndex stationIndex) const;
557  //! @endcond
558 
559 
560  /*!
561  @brief 送受信の進捗状況を取得します。
562 
563  @details 送信中の進捗は、送信対象となるステーションの増減によって途中で値が小さくなる場合がありますので注意してください。
564  <br>
565  @return 送受信が完了したデータサイズ(バイト)です。
566  送信中、送信後は送信対象としているステーションに対して送信したデータサイズの平均値が取得できます。
567  受信中、受信後は自分が受け取ったデータサイズが取得できます。
568  */
569  uint32_t GetProgress() const;
570 
571 
572  /*!
573  @brief 特定の送信先への送信の進捗状況を取得します。
574 
575  @param[in] stationId 進捗状況を調べたいステーションの StationId です。
576 
577  @return 指定したステーションに送信が完了したデータサイズ(バイト)です。
578  送信中、送信後でないときや無効な StationId が指定された場合は 0 を返します。
579  */
580  uint32_t GetSendProgress(StationId stationId) const;
581 
582 
583  /*!
584  @cond PRIVATE
585  @brief 特定の送信先への送信の進捗状況を取得します。
586  */
587  uint32_t GetSendProgress(StationIndex stationIndex) const;
588  //! @endcond
589 
590 
591  /*!
592  @brief 送信を開始します。
593 
594  @details この関数に成功すれば State_Sending に遷移します。
595  ResultInvalidArgument で失敗した場合は Reset() されます。
596 
597  @details ジョイントセッション処理をまたいでデータを送信することはできません。
598 
599  @param[in] cpData 送信するデータへのポインタです。
600  State_Sending の間( IsRunning() が true の間)は指定したバッファを保持しておく必要があります。
601  データの先頭から順に送信される保証はありませんので、先頭から GetProgress() バイトは書き換えて大丈夫という事もありません。
602  @param[in] dataSize 送信するデータのサイズです。
603  @param[in] configuration このデータ転送における動作方式を指定します。
604  @param[in] userData 送信データに付ける付加情報です。
605  受信側のアプリケーションが受信開始前に参照することができ、データを識別するためなどに使用できます。
606 
607  @return 成功すれば、 IsSuccess() が true を返す Result が返されます。この関数がエラーを返さないようにアプリケーションを実装する必要があります。
608 
609  @retval ResultInvalidState セッションに参加していないか、他の送受信を実行中です。プログラミングエラーです。このエラーが返らないようにソースコードを修正してください。
610  @retval ResultInvalidArgument 引数が誤っています。プログラミングエラーです。このエラーが返らないようにソースコードを修正してください。
611  @retval ResultTemporaryUnavailable セッション移行処理中のため、一時的に API を利用できない状態です。ジョイントセッション機能使用時にのみ返ります。アプリケーションで適切にハンドリングしてください。
612  */
613  Result StartSend(const void* cpData, uint32_t dataSize, Configuration configuration, uint32_t userData = 0);
614 
615 
616  /*!
617  @brief Configuration::IsSendEndless() が true となる設定で実行している送信を終了させます。
618  動作の詳細は Configuration::IsSendEndless() を参照してください。
619 
620  @return 成功すれば、 IsSuccess() が true を返す Result が返されます。この関数がエラーを返さないようにアプリケーションを実装する必要があります。
621 
622  @retval ResultInvalidState 送信実行中ではないか、@ref nn::pia::transport::ReliableBroadcastProtocol::Configuration::IsSendEndless() "Configuration::IsSendEndless()" が true となる設定ではありません。プログラミングエラーです。このエラーが返らないようにソースコードを修正してください。
623 
624  @see Configuration::IsSendEndless
625  */
627 
628 
629  /*!
630  @brief 受信を開始します。
631 
632  @details GetRequest() を受けてそのデータを受信する場合はその設定に合わせた引数を指定して呼び出す必要があります。
633  アプリケーションのシーケンスなどによりどういう受信をするかあらかじめ分かっている場合は、
634  受信要求が来る前にこの関数を呼んでおくと、受信要求を待つ場合に比べて無駄なく受信が開始できます。
635  この関数が成功すると State_Receiving に遷移します。
636  ResultInvalidArgument で失敗した場合は Reset() されます。
637 
638  @details ジョイントセッション処理をまたいでデータを受信することはできません。
639 
640  @param[out] pBuffer 受信データを受け取るバッファです。
641  State_Receiving の間( IsRunning() が true の間)はまだデータを参照できません。
642  データの先頭から順に受信される保証はありませんので、先頭から GetProgress() バイトは参照できるという事もありません。
643  @param[in] bufferSize 受信バッファのサイズです。
644  受信要求のデータサイズがこの値より大きい場合は、この関数は成功しますが State_ReceiveFailure に遷移します。
645  @param[in] sourceStationId この送信者からのデータを受信します。
646 
647  @return 成功すれば、 IsSuccess() が true を返す Result が返されます。この関数がエラーを返さないようにアプリケーションを実装する必要があります。
648 
649  @retval ResultInvalidState セッションに参加していないか、他の送受信を実行中です。プログラミングエラーです。このエラーが返らないようにソースコードを修正してください。
650  @retval ResultInvalidArgument 引数が誤っています。プログラミングエラーです。このエラーが返らないようにソースコードを修正してください。
651  @retval ResultTemporaryUnavailable セッション移行処理中のため、一時的に API を利用できない状態です。ジョイントセッション機能使用時にのみ返ります。アプリケーションで適切にハンドリングしてください。
652 
653  @see GetRequest
654  */
655  Result StartReceive(void* pBuffer, uint32_t bufferSize, StationId sourceStationId);
656 
657 
658  /*!
659  @cond PRIVATE
660  @brief 受信を開始します。
661  */
662  Result StartReceive(void* pBuffer, uint32_t bufferSize, StationIndex sourceStationIndex);
663  //! @endcond
664 
665 
666  /*!
667  @brief 送受信を中断します。
668 
669  @details State_Sending 中にこの関数を呼ぶと、その後の common::Scheduler::Dispatch() でキャンセル処理を行った後、通常は State_SendFailure に遷移します。
670  ただし、タイミングによっては State_SendSuccess に遷移する場合もあります。
671  受信側のステーションも State_ReceiveFailure (または State_ReceiveSuccess )に遷移します。
672 
673  State_Receiving 中にこの関数を呼ぶと、その後の common::Scheduler::Dispatch() でキャンセル処理を行った後、通常は State_ReceiveFailure に遷移します。
674  ただし、タイミングによっては State_ReceiveSuccess に遷移する場合もあり、その場合は受信したデータを参照できます。
675  Configuration::IsFailIfRejected() が true となる設定で動作させている場合は、その送信自体が中断されます。
676 
677  @return 成功すれば、 IsSuccess() が true を返す Result が返されます。この関数がエラーを返さないようにアプリケーションを実装する必要があります。
678 
679  @retval ResultInvalidState 送受信中ではありません。プログラミングエラーです。このエラーが返らないようにソースコードを修正してください。
680 
681  @see StartSend, StartReceive
682  */
683  Result Cancel();
684 
685 
686  /*!
687  @brief 送受信結果の情報を破棄して State_Wait に戻ります。
688 
689  @details 送受信実行中は失敗しますので、その状態で呼び出したい場合は先に Cancel() して送受信を中断させてからこの関数を呼ぶ必要があります。
690  この関数は必ずしも使用する必要は無く、 State_SendSuccess, State_SendFailure, State_ReceiveSuccess, State_ReceiveFailure の状態から
691  直接次の送受信を開始することも可能です。
692 
693  @return 成功すれば、 IsSuccess() が true を返す Result が返されます。この関数がエラーを返さないようにアプリケーションを実装する必要があります。
694 
695  @retval ResultInvalidState セッションに参加していないか、送受信を実行中です。プログラミングエラーです。このエラーが返らないようにソースコードを修正してください。
696  */
697  Result Reset();
698 
699 
700  /*!
701  @brief 届いている受信要求を取得します。
702 
703  @details このデータを受け取る場合は必要なサイズのバッファを用意して StartReceive() を行う必要があります。
704  このデータを受け取らない場合は RejectRequest() を呼ぶ必要があります。
705  複数の受信要求が届いている場合は、最も優先度の高い( Configuration::IsMediateRequest() の値に関係なく、送信者の StationIndex が小さい)受信要求が取得できます。
706 
707  @return 受信要求のポインタです。
708  受信要求が届いてない場合は NULL が返されます。
709 
710  @see StartReceive, RejectRequest
711  */
712  const TransferSetting* GetRequest() const;
713 
714 
715  /*!
716  @brief 特定のステーションからの受信要求を取得します。
717 
718  @details このデータを受け取る場合は必要なサイズのバッファを用意して StartReceive() を行う必要があります。
719  <br>
720  @param[in] stationId 取得したい受信要求の StationId です。
721 
722  @return 受信要求のポインタです。
723  受信要求が届いてない場合は NULL が返されます。
724 
725  @see StartReceive, RejectRequest
726  */
727  const TransferSetting* GetRequest(StationId stationId) const;
728 
729 
730  /*!
731  @cond PRIVATE
732  @brief 特定のステーションからの受信要求を取得します。
733  */
734  const TransferSetting* GetRequest(StationIndex stationIndex) const;
735  //! @endcond
736 
737 
738  /*!
739  @brief GetRequest() で取得される受信要求を拒否します。
740 
741  @details この受信要求の動作方式が @ref Configuration::IsFailIfRejected() が true となる設定の場合は、その送信自体が中断されます。
742  現在受信中の受信要求に対してこの関数を呼んだ場合は Cancel() と同等の処理を行います。
743 
744  @return 成功すれば、 IsSuccess() が true を返す Result が返されます。この関数がエラーを返さないようにアプリケーションを実装する必要があります。
745 
746  @retval ResultInvalidState GetRequest() が NULL を返しています。プログラミングエラーです。このエラーが返らないようにソースコードを修正してください。
747 
748  @see GetRequest
749  */
751 
752 
753  /*!
754  @brief @ref GetRequest ( nn::pia::StationId ) で取得される受信要求を拒否します。
755 
756  @details この受信要求の動作方式が @ref Configuration::IsFailIfRejected() が true となる設定の場合は、その送信自体が中断されます。
757  現在受信中の受信要求に対してこの関数を呼んだ場合は Cancel() と同等の処理を行います。
758 
759  @param[in] stationId 拒否したい受信要求の StationId です。
760 
761  @return 成功すれば、 IsSuccess() が true を返す Result が返されます。この関数がエラーを返さないようにアプリケーションを実装する必要があります。
762 
763  @retval ResultInvalidState GetRequest ( nn::pia::StationId ) が NULL を返しています。プログラミングエラーです。このエラーが返らないようにソースコードを修正してください。
764 
765  @see GetRequest
766  */
767  Result RejectRequest(StationId stationId);
768 
769 
770  /*!
771  @cond PRIVATE
772  @brief @ref GetRequest ( StationIndex ) で取得される受信要求を拒否します。
773  */
774  Result RejectRequest(StationIndex stationIndex);
775  //! @endcond
776 
777 
778  /*!
779  @brief common::Scheduler::Dispatch の 1 回の呼び出しあたりにこのプロトコルが送信するデータ量の上限を指定します。
780 
781  @details このプロトコルが common::Scheduler::Dispatch の 1 回あたりに送信するデータ量の平均値が
782  この関数で設定した値以下になるように制限されます。
783  瞬間的にはここで設定した値以上のサイズの送信が行われることもあります。
784 
785  この関数に 0 を指定することでこのプロトコルはデータ送信を行わなくなりますので、
786  送信を一時停止させたい場合は、送信側で 0 を指定する必要があります。
787  その後送信を再開させる場合は、改めて正の値を設定する必要があります。
788  一時停止したまま Cancel() で中断したい場合でも、0 を指定したままだと中断することの通知も行えず、
789  中断処理が完了しなくなってしまいますので、注意してください。
790  一方、受信側も応答パケットなど若干のデータの送信が行われますので、
791  受信側で 0 を指定しても処理が進まなくなってしまう点に注意してください。
792 
793  設定できる値の最大値は @ref ThroughputLimitMax です。これより大きな値を設定した場合は、@ref ThroughputLimitMax を設定したものと扱います。
794 
795  デフォルト値は @ref ThroughputLimitMax です。
796  セッション作成時や参加時にデフォルト値にリセットされますので、その後に設定する必要があります。
797 
798  通信環境によっては、上限を適切に設定した方が、@ref ThroughputLimitMax を設定した場合よりもスループットが高くなる可能性があります。
799  @if CTR_DOC 特に CTR でのインターネット通信時には、アプリケーションで想定するステーション数や通信環境等に合わせて上限値を調整することを推奨します。 @endif
800 
801  @param[in] throughputLimit 設定する送信データ量のサイズ(バイト)です。
802 
803  @see GetThroughputLimit
804  */
805  void SetThroughputLimit(uint32_t throughputLimit);
806 
807 
808  /*!
809  @brief common::Scheduler::Dispatch の 1 回の呼び出しあたりにこのプロトコルが送信するデータ量の上限を取得します。
810 
811  @return common::Scheduler::Dispatch の 1 回の呼び出しあたりにこのプロトコルが送信するデータ量です。
812 
813  @see SetThroughputLimit
814  */
815  uint32_t GetThroughputLimit() const
816  {
817  return m_ThroughputLimit;
818  }
819 
820 
821  /*!
822  @brief デバッグに有用な情報をプリントします。
823 
824  @param[in] flag トレースフラグの論理和。詳細は @ref TraceFlag 型を参照してください。
825  */
826  virtual void Trace(uint64_t flag) const;
827 
828 
829 private:
830  static const uint16_t InvalidMessageIdx = 0xffff;
831 
832  // 進捗を管理
833  class Progress
834  {
835  public:
836  uint32_t GetCount() const;
837  bool IsOn(uint32_t idx) const;
838  bool IsAllOff() const;
839  bool IsComplete() const
840  {
841  return m_FirstOffIdx >= m_UnitNum;
842  }
843 
844  protected:
845  static const uint32_t FlagBlockNum = 4;
846  uint32_t m_UnitNum;
847  uint32_t m_FirstOffIdx;
848  uint32_t m_Flag[FlagBlockNum];
849  };
850 
851  // 受信時の進捗を管理
852  class ReceiverProgress : public Progress
853  {
854  public:
855  void Clear(uint32_t unitNum);
856  bool Raise(uint32_t idx);
857  void Get(uint32_t* pOffset, uint64_t* pFlag) const;
858  };
859 
860  // 送信時の進捗を管理
861  class SenderProgress : public Progress
862  {
863  public:
864  void Clear(uint32_t unitNum);
865  bool Update(uint32_t offset, uint64_t flag);
866  bool IsReceivable(uint32_t offset) const;
867  void UpdateMessageIdx(uint32_t unitIdx, uint16_t messageIdx);
868  uint32_t GetFirstOffIdx() const
869  {
870  return m_FirstOffIdx;
871  }
872  uint32_t GetUnitNum() const
873  {
874  return m_UnitNum;
875  }
876  uint16_t GetSendMessageIdx(uint32_t unitIdx) const;
877 
878  private:
879  static const uint32_t DataSize = FlagBlockNum * 32;
880 
881  uint16_t m_SendMessageIdx[DataSize];
882  };
883 
884 
885  // メッセージの種類
886  enum MessageType
887  {
888  MessageType_Invalid = 0x00,
889  MessageType_Request = 0x11,
890  MessageType_Data = 0x12,
891  MessageType_Cancel = 0x18,
892  MessageType_Complete = 0x19,
893  MessageType_DataAck = 0x21,
894  MessageType_CommandAck = 0x28,
895  MessageType_Reject = 0x29
896  };
897 
898 
899  // メッセージへのアクセス
900  class MessageAccessor
901  {
902  public:
903  MessageAccessor()
904  : m_Type(MessageType_Invalid)
905  {
906  }
907  bool IsSenderMessage() const
908  {
909  return (m_Type & 0xf0) == 0x10;
910  }
911  bool IsReceiverMessage() const
912  {
913  return (m_Type & 0xf0) == 0x20;
914  }
915  bool IsDataMessage() const
916  {
917  return m_Type == MessageType_Data;
918  }
919 
920  uint32_t GetMessageSize() const;
921  static bool Unpack(MessageAccessor* pAccessor, const ProtocolMessageReader& reader, uint32_t* pMessageIdx);
922  static bool Pack(ProtocolMessageWriter* pWriter, const MessageAccessor& accessor, uint32_t messageIdx);
923 
924  public:
925  MessageType m_Type;
926  uint16_t m_Id;
927 
928  uint32_t m_TotalSize;
929  uint16_t m_UnitSize;
930  uint32_t m_UserData;
931  Configuration m_Configuration;
932 
933  uint32_t m_Index;
934  const void* m_cpPayload;
935  uint16_t m_PayloadSize;
936 
937  uint32_t m_AckOffset;
938  uint64_t m_AckFlag;
939  };
940 
941 
942  // 転送設定の内部管理
943  struct InnerTransferSetting : public TransferSetting
944  {
945  public:
946  bool IsValid() const
947  {
948  return (m_DataSize > 0);
949  }
950  bool IsPriorTo(const TransferSetting& setting) const;
951 
952  public:
953  uint16_t m_Id;
954  uint16_t m_UnitSize;
955  uint32_t m_UnitNum;
956  };
957 
958 
959  // 送信者としてのステーションの状態
960  enum SenderState
961  {
962  SenderState_Nothing,
963  SenderState_Sending,
964  SenderState_Rejected,
965  SenderState_Finished
966  };
967 
968  // 受信者としてのステーションの状態
969  enum ReceiverState
970  {
971  ReceiverState_Nothing,
972  ReceiverState_Receiving,
973  ReceiverState_Rejecting,
974  ReceiverState_Finished,
975  ReceiverState_Rejected
976  };
977 
978  // 各通信相手の状態を管理
979  class Station
980  {
981  public:
982  Station();
983  void Initialize(ReliableBroadcastProtocol* pProtocol);
984 
985  void Startup(StationIndex stationId);
986  void Cleanup();
987 
988  void HandleMessage(const MessageAccessor& accessor);
989  bool SendAck();
990 
991  void ForceReserveReject()
992  {
993  m_ReservedAckFlag |= ReservedAckFlag_Reject;
994  }
995 
996  void RejectSend();
997 
998  void ClearReceiverState()
999  {
1000  m_ReceiverState = ReceiverState_Nothing;
1001  }
1002  void StartReceive(uint16_t receiveId, uint32_t unitNum);
1003 
1004  bool IsConnected() const
1005  {
1006  return MyStationIndex() != StationIndex_Invalid;
1007  }
1008  StationIndex GetStationIndex() const
1009  {
1010  return MyStationIndex();
1011  }
1012  SenderState GetSenderState() const
1013  {
1014  return m_SenderState;
1015  }
1016  ReceiverState GetReceiverState() const
1017  {
1018  return m_ReceiverState;
1019  }
1020  const InnerTransferSetting& GetRequest() const
1021  {
1022  return m_Request;
1023  }
1024  const SenderProgress* GetProgress() const
1025  {
1026  return &m_Progress;
1027  }
1028 
1029  uint16_t GetReturnedMessageIdx() const
1030  {
1031  return m_ReturnedMessageIdx;
1032  }
1033  uint16_t GetReceivedMessageIdx() const
1034  {
1035  return m_ReceivedMessageIdx;
1036  }
1037 
1038  void HandleMessageIdx(uint32_t messageIdx);
1039 
1040  uint32_t GetNextSendUnitIndex(bool isOnlyPrior, uint32_t dispatchCount) const;
1041 
1042  bool IsNeedSendRequest() const
1043  {
1044  return (GetReceiverState() == ReceiverState_Receiving) && m_IsNeedSendRequest;
1045  }
1046 
1047  void RecordSendData(uint32_t dispatchCount, uint16_t unitIdx, uint16_t messageIdx);
1048 
1049  private:
1050  void UpdateRequest(const MessageAccessor& accessor);
1051  bool CheckRequest(const MessageAccessor& accessor) const;
1052 
1053  StationIndex& MyStationIndex()
1054  {
1055  return m_Request.m_SourceStationIndex;
1056  }
1057  StationIndex MyStationIndex() const
1058  {
1059  return m_Request.m_SourceStationIndex;
1060  }
1061  uint16_t& SenderSequenceId()
1062  {
1063  return m_Request.m_Id;
1064  }
1065  uint16_t SenderSequenceId() const
1066  {
1067  return m_Request.m_Id;
1068  }
1069 
1070  private:
1071  ReliableBroadcastProtocol* m_pProtocol;
1072 
1073  InnerTransferSetting m_Request;
1074  SenderState m_SenderState;
1075 
1076  enum ReservedAckFlag
1077  {
1078  ReservedAckFlag_None = 0x0,
1079  ReservedAckFlag_Request = 0x1,
1080  ReservedAckFlag_Data = 0x2,
1081  ReservedAckFlag_Reject = 0x4,
1082  ReservedAckFlag_Command = 0x8
1083  };
1084  uint32_t m_ReservedAckFlag;
1085 
1086  SenderProgress m_Progress;
1087  uint16_t m_ReceivingId;
1088  ReceiverState m_ReceiverState;
1089 
1090  uint16_t m_ReturnedMessageIdx;
1091  uint16_t m_ReceivedMessageIdx;
1092 
1093  bool m_IsNeedSendRequest;
1094 
1095  uint32_t m_LastSentDataDispatchCount;
1096  };
1097 
1098  // 有効な相手か?
1099  bool IsValidStation(StationIndex stationIndex) const
1100  {
1101  return (stationIndex >= StationIndex_1) && (stationIndex < static_cast<StationIndex>(m_MaxConnections)) && (stationIndex != m_LocalStationIndex);
1102  }
1103 
1104  // 相手の情報の取得
1105  Station* GetStation(StationIndex stationIndex)
1106  {
1107  PIA_ASSERT(IsValidStation(stationIndex));
1108  return &m_paStation[stationIndex < m_LocalStationIndex ? stationIndex : stationIndex - 1];
1109  }
1110 
1111  // 相手の情報の取得
1112  const Station* GetStation(StationIndex stationIndex) const
1113  {
1114  PIA_ASSERT(IsValidStation(stationIndex));
1115  return &m_paStation[stationIndex < m_LocalStationIndex ? stationIndex : stationIndex - 1];
1116  }
1117 
1118  static uint32_t CalcProgress(const InnerTransferSetting& transferSetting, const Progress& progress);
1119 
1120  void UpdateState();
1121  bool DispatchSendAck();
1122  bool DispatchSendCommand();
1123  bool DispatchSendData();
1124  void DispatchOnReceiveCanceling();
1125 
1126  void PushRequest(const MessageAccessor& accessor, const Station& sender);
1127  bool PushData(const MessageAccessor& accessor, const Station& sender);
1128  void PushComplete(const MessageAccessor& accessor, const Station& sender);
1129  void PushCancel(const MessageAccessor& accessor, const Station& sender);
1130 
1131  bool CreateMessage(const MessageAccessor& accessor, Station* pDestinationStation);
1132  uint32_t IssueMessageIdx(const Station* cpDestStation);
1133 
1134  static bool IsSameSetting(const InnerTransferSetting& setting, const MessageAccessor& accessor);
1135 
1136 
1137  uint32_t m_MaxConnections;
1138 
1139  State m_State;
1140  StationIndex m_LocalStationIndex;
1141 
1142  InnerTransferSetting m_TransferSetting;
1143 
1144  void* m_pReceiveBuffer;
1145  ReceiverProgress m_ReceiveProgress;
1146 
1147  const void* m_cpSendBuffer;
1148  uint16_t m_NextSendId;
1149  uint32_t m_NextSendCommandStationIndex;
1150  uint32_t m_NextSendDataStationIndex;
1151  bool m_IsFinishSendEndless;
1152 
1153  uint32_t m_NextSendAckStationIndex;
1154 
1155  uint16_t m_SentMessageIdx;
1156 
1157  uint32_t m_ThroughputLimit;
1158  uint32_t m_RestThroughputLimit;
1159 
1160  uint32_t m_DispatchCount;
1161 
1162  Station* m_paStation;
1163 
1164  common::Time m_StartSendTime;
1165 
1166  static const uint32_t cDefaultPacketNumPerDispatch;
1167 };
1168 }
1169 }
1170 } // end of namespace nn::pia::transport