コンピュータを楽しもう!!

今、自分が面白くていろいろやってみたことを書き綴りたいと思います。連絡先はtarosa.yでgmail.comです。

DSとDSをLANで接続する(2)

昨日のブログで、「特に重くも無く」と書いたのですが、処理重いです。でも、もっと間欠にデータを送れば軽くなると思います。
昨日のプログラムを少し改造して、4バイトのデータを送受信するようにしました。4バイトとはタッチ座標X,Yの2バイトとボタンなどで2バイトの計4バイトです。

DSとDSの通信処理

下記がプログラムです。簡単に説明します。最初のwhile(true)ループが処理の中身です。
キーを見て、押されていれば処理し、タッチがあれば線を引きます。そして、keyが0でないときは4バイトの情報を送ります。
 scanKeys();
 key = keysHeld();
で取得すると、タッチも含めて全ての入力情報が取得できるので、タッチしたかどうかもkeyだけ見ていればOKです。
受信側はプログラムリストの後に書きます。

//**************************************************
// 2台を通信させて線を引きます
// 4バイトのデータを送受信しています
//**************************************************
void	communicate( int sockNum )
{
int		key, recvd_len;
u8		sendText[4];	//ペンX座標,ペンY座標,ボタン2バイト
u8		recvText[4];	//ペンX座標,ペンY座標,ボタン2バイト
int		i;
int 	gx0, gy0, gx1, gy1;
int 	tx0, ty0, tx1, ty1;
int		tflg = 0;

  gx0 = gy0 = 0;
  tx0 = ty0 = 0;
  for( i=0; i<4; i++ ){	sendText[i] = 0;	}
	
  while( true ){
    scanKeys();
    key = keysHeld();
		
    if( (key&KEY_A)!=0 ){		//[A]ボタンで両画面クリア
      ClearBGL( SubScreenA,   RGB(31,31,31) );
    }
    else if( (key&KEY_B)!=0 ){	//[B]ボタンで自分の画面クリア
      ClearBGL( SubScreenA,   RGB(31,31,31) );
    }
    else if( (key&KEY_SELECT)!=0 ){	//[SELECT]ボタンで終了
      break;
    }

    if( key==0 ){	//キーもペンもタッチ無し
      if( sendText[2]!=0 || sendText[3]!=0 ){	//直前までタッチ有りだった
        sendText[0] = LastPenX;
        sendText[1] = LastPenY;
        sendText[2] = (u8)(key&0xff);
        sendText[3] = (u8)(key>>8);
        send( sockNum, sendText, 4, 0 );	//相手機にペンアップを送信
      }
      sendText[2] = 0;
      sendText[3] = 0;
    }
    else{
      if( (key&KEY_TOUCH)!=0 ){
        //ペンタッチ有り
        TouchPenStatus();			//タッチペン座標取得
        if( (sendText[3]&0x10)==0 ){	//直前までタッチ無しだった
          gx0 = LastPenX;		//一つ前ペン座標の初期化
          gy0 = LastPenY;		//一つ前ペン座標の初期化
        }
        gx1 = LastPenX;			//今のペン座標のセット
        gy1 = LastPenY;			//今のペン座標のセット
        LineL( SubScreenA, gx0, gy0, gx1, gy1, RGB(0,0,0) );		//線を引く
        gx0 = gx1;				//今のペン座標を退避
        gy0 = gy1;				//今のペン座標を退避
      }
      //今のペン座標とペンタッチ有りを送信
      sendText[0] = LastPenX;
      sendText[1] = LastPenY;
      sendText[2] = (u8)(key&0xff);
      sendText[3] = (u8)(key>>8);
      send( sockNum, sendText, 4, 0 );	//相手機に送信
    }

    //データ受信
    recvd_len = getRecvData( sockNum, recvText, 4, 0, 40000L );
    if( recvd_len==4 ){		
      //受信データが有り、且つ、相手のペンタッチデータがあるとき。
      if( (recvText[3]&0x10)==0 ){	//相手のペンがスクリーンから離れた
        tflg = 0;
        swiWaitForVBlank(); //このwaitが無いと、相手が切断したときこっちがずっこける
      }
      else{	//相手のペンがタッチ有り
        if( tflg==0 ){			//直前までタッチ無しだった
          tx0 = recvText[0];	//一つ前ペン座標の初期化
          ty0 = recvText[1];	//一つ前ペン座標の初期化
        }
        tx1 = recvText[0];		//今のペン座標のセット
        ty1 = recvText[1];		//今のペン座標のセット
        LineL( SubScreenA, tx0, ty0, tx1, ty1, RGB(31,0,0) );		//線を引く
        tx0 = tx1;				//今のペン座標を退避
        ty0 = ty1;				//今のペン座標を退避
        tflg = 1;				//ペンタッチ有りフラグセット
      }
	
      if( (recvText[2]&KEY_A)!=0 ){	//相手がAボタンを押していたので画面クリアする
        ClearBGL( SubScreenA,   RGB(31,31,31) );
      }
      else if( (recvText[3]&0x4)!=0 ){	//相手がXボタンを押していたので画面クリアする
        ClearBGL( SubScreenA,   RGB(31,31,31) );
      }
    }
    else{
      swiWaitForVBlank(); //このwaitが無いと、相手が切断したときこっちがずっこける
    }
  }
  //少し間をおく
  for( i=0; i<50; i++ ){	swiWaitForVBlank();	}
}

受信側

受信側は少しだけ複雑です。
 recvd_len = getRecvData( sockNum, recvText, 4, 0, 40000L );
getRecvData()で相手側の送信データを取得します。これは自作関数です。40000μs間受信待ちしてデータが無ければデータを取得せずに戻ってきます。戻り値は取得データ量(バイト)です。とりあえず、一対一通信なのでブロッキングのまま単純に受信待ちしているだけです(下記プログラム参照)。
受信処理ですが、線を引くというようなメイン処理が入らない限り、swiWaitForVBlank();を入れています。これは相手が通信をやめたときにwaitを入れないで受信しに行くと挙動がおかしくなってしまうからです。他は受信データに合わせて線を引いたり、各処理をしているだけです。

//**************************************************
// 受信チェックありの受信処理
// socket, *buf, len, flags は、recv(int socket, void *buf, size_t len, int flags);
// us は、受信チェックの待ち時間、単位はμsec
//**************************************************
ssize_t getRecvData( int socket, void *buf, size_t len, int flags, suseconds_t us )
{
ssize_t	recvd_len = 0;
int		ret;
fd_set	fds;
struct	timeval tv;

  FD_ZERO( &fds );	  //ファイルディスクリプタの識別子初期化
  FD_SET( socket, &fds ); //socketのファイルディスクリプタ識別子に1をセット
  tv.tv_sec = 0;
  tv.tv_usec = us;

  //ポートの監視、(受信のみ監視、他はNULL)
  ret = select( (int)socket+1, &fds, NULL, NULL, &tv );
  if( ret!=0 ){
    recvd_len = recv( socket, buf, len, flags );
  }
  return( recvd_len );
}

こんな感じです。上の通信プログラムの場合、ペンタッチしている限りずっとデータを送り続けるので、処理が重くなっています。ここらへんは仕様を考えれば、もっと軽快な処理ができるのではないでしょうか。
 ということで、今日は遅いので、明日にでも、サンプルソースをアップしたいと思います。

本当にやりたいことリスト

(ブログの終わりにやりたいことを書いておきたいと思います)

  • 求職活動・・・このブログで興味を持った人一声かけてください。m(_ _)m
  • Androidプログラム
  • Web系のプログラム