ソケットAPIモジュールによるUDP通信について

PU:RX62N(Starter kit)
開発環境:CS+ for CC V3.01.00

はじめまして。
M3S-T4-Tinyを用いたサンプルプログラムをベース始めました。
試験をしながら作ったSW類やタイマー、LCDの表示等の確認を済ませたシンプルなソフトは完了しました。
次にソケットAPIを使ってUDP通信を行う予定です。ドキュメント r20an0296jj0122_rx_t4.pdfを読みつつ作業中です。
an_r20an0296jj0122_rx_t4_connectivityを解凍し、中のソースを流用してみました

とりあえずmain関数内でUDPを用いて一回だけ相手に送信を行いたいと思っています。

r_socket_rx_config.hはそのままで
#define     MAX_UDP_CCEP            4
#define     MAX_TCP_CCEP            4
となっています。


下記の通り記述してみたのですが、

 int sock,ercd;
  struct sockaddr_in addr;

  R_SOCKET_Init();

 sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); // 4が返ってきます

  addr.sin_family = AF_INET;  
  addr.sin_port = htons(14001);  //自待ち受けポート
  addr.sin_addr.s_addr = INADDR_ANY; 

 if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
 {
  closesocket(sock);
  return SOCKET_ERROR;
 }
 //bindは問題できているようです  

 addr.sin_family = AF_INET;
  addr.sin_port = htons(14000);   //相手先ポート 14000 
  addr.sin_addr.s_addr = 0x0A00A8C0;//相手先IP 192.168.0.10

  ercd =sendto(sock, "HELLO", 5, 0, (struct sockaddr *)&addr, sizeof(addr)); //送信されない
 //-17が返ってきます

最後のsendto関数で-17が返ってきて送信されていないようです。
sendto関数の中でなにが起きているのか?と調べてステップで追いかけると
 ercd = udp_snd_dat(cepid, (T_IPV4EP*)&sockets[sock].dstaddr,
       (VP)(buffer), length, sockets[sock].tmout);
という最後のudp_snd_dat関数の処理で-17が返ってきているようです。
-17というのはパラメータエラーのようですが原因がわかりません。

使用方法等が間違っているのでしょうか?
ご存知の方がいらっしゃいましたらご教示願います。

Parents
  • redcrowさん

    その後調子はいかがでしょう。

    ↓ シェルティさんが来てくれれば、もう大丈夫です!

  • redcrowさん

    RXマイコンEther関連でいろいろと実験しております、シェルティと申します。

    以下2点チェックしてみてください。

    (1)addr.sin_addr.s_addr には、0x0A00A8C0 ではなく、0xc0a8000a を指定するとよいです。

    (2)config_tcpudp.c の tcp_ccep[] を4個、udp_ccep[] を4個用意しているか確認してみてください。

      以下の設定でTCPのソケットが4個、UDPのソケットが4個、固定で用意されます。

      TCPは1個目のメンバーがLANポート番号設定、5個目のメンバーが受信ウィンドウサイズの設定、6個目のメンバーがコールバック関数の設定です。それ以外は未実装です。

      UDPは1個目のメンバーがLANポート番号設定、2個目の構造体の2個目のメンバーがUDP受信ポート番号、3個目のメンバーがコールバックルーチン関数の設定です。

    T_TCP_CCEP tcp_ccep[4] =

    {

       { 0, 0, 0, 0, 1460, 0 },

       { 0, 0, 0, 0, 1460, 0 },

       { 0, 0, 0, 0, 1460, 0 },

       { 0, 0, 0, 0, 1460, 0 },

    };

    T_UDP_CCEP udp_ccep[4] =

    {

       { 0, { 0, 1365 }, 0 },

       { 0, { 0, 1366 }, 0 },

       { 0, { 0, 1367 }, 0 },

       { 0, { 0, 1365 }, 0 },

    };

    TCP/IPのソースコードを確認しました。udp_snd_dat()が-17を返すのは、以下条件です。

    (1)第一引数のcepidが0以下または、udp_ccep[]の個数を超えたとき

    (2)第四引数のlenが0より小さいとき

    (3)第五引数のtmoutがTMO_POL(0)のとき

    (4)udp_snd_dat()がudp_ccep[]の3個目のメンバーで指定したコールバック関数内から呼ばれ、第五引数のtmoutがTMO_NBLK(-2)以外のとき

    コードを見る限りどれも問題なしのように思えます。デバッガで各引数の中身を確認してみてはどうでしょうか。

    (1)はsockが4、中のコードを追いかけるとcepid = sock + 1 - MAX_TCP_CCEPとなってcepidが1、第一引数は1となり問題なし

    (2)は即値の5がそのまま第四引数にはいり問題なし

    (3)はsockets[sock].tmoutがTMO_FEVRで初期化されて、第五引数にはいり問題なし

    (4)はコールバックのメカニズムはおそらく使用されていないと思いますので問題なし

    ---

    あとはルネサスのTCP/IPのサンプルソフトにソケットAPIの使用例がありますのでそれが参考になるかもしれません。

    japan.renesas.com/.../m3s_t4_tiny_fit.jsp

    →TCP/IPサンプルプログラム

     →ダウンロード&解凍

    解凍データ

    \an_r20an0312jj0100_rx_t4_connectivity\workspace\sample\rx64m_rsk_socket_e2

       \src\udp_blocking_sample\echo_srv.c

    以上です

  • お返事が遅くなりました。

    シェルティ 様 大ヒントありがとうございます!

    tcpudp_get_ramsize()とtcpudp_open()を R_SOCKET_Init();の後に使用してみたところ、

    sendtoを呼び出しても-17ではなく5が戻ってきました。

    成功しているようです。

    ただ、待ち受けにしているPCでフリーソフトでUDP通信状況を見ているのですが受信したことにはなっていないようです。

    これについては別途調査しないとだめですが、1段階進めることができました。

    他の皆様も初歩的な質問にお付き合いいただきありがとうございました。

  • redcrowさん

    シェルティです。

    一歩前進とのことでよかったです。

    sendto()が5を返してきたということは、5バイト送れた、という意味になりますね。

    PC側でまだ受信できていないということなので以下確認してみてください。

    (1)UDPを受信するPCでwiresharkというパケットキャプチャツールを動かして、

     パケットレベルで受信できているかどうかを調べる

    (2)UDP 14000番ポートがPC側で正しく待ち状態になっているかを調べる

     Windowsの場合コマンドプロンプトで「netstat -a」とすると、接続中/接続待ち状態のTCPポートや

     通信待ち状態中のUDPポートが一覧で出力されます。

    以上です

  • まだ調べきれてないのですが、現状報告です。

    明日以降まだ自分でも調べてみるつもりです。

    (2)「netstat -a」についてやってみました

    沢山の一覧の中に

    UDP         0.0.0.0:14000          *:*

    が含まれていますので大丈夫かなと思います。

    試しにPC-PC間でこのソフト同士のテキストのやりとりをやってもできました。

    一方、(1)wiresharkについては元々常時起動して使っていたのですがパケットがPC-基板間を直結させてもwiresharkでは拾えていないようです。基板から本当に出てる?っていう感じです。

    受信処理である/***************************************/間の部分をコメントアウトしてループして送信してみました。

    毎回=sendtoを呼ぶ度に5が戻り、試験的に送信を高速に繰り返す予定でいました。

    まだちゃんと熟読していないので処理が足りないのかも知れません。

    あと2点気になるのが、

    ①受信処理を生かすとR_SOCKET_Init関数を呼んだあとに戻ってこなくなります。

    ブレークすると以下のエラーもでます。

    今はとりあえずは送信のみなので使わなくてもいいですが、後々困りそうです。

    ブレーク・イベントを設定できませんでした。

    [エラーの直接原因]

    MCUのスリープモード中で内部クロックが停止状態です。(E1813204)

    ②T_UDP_CCEP の中身はポート14000で使うとしてもこのままでいいものなのでしょうか?

    T_UDP_CCEP udp_ccep[4] =

    {

      { 0, { 0, 1365 }, 0 },

      { 0, { 0, 1366 }, 0 },

      { 0, { 0, 1367 }, 0 },

      { 0, { 0, 1365 }, 0 },

    };

    以下は試行錯誤の結果の現状です

    static UW tcpudp_work[2500];

    while(1)

    {

    int sock,ercd;

    struct sockaddr_in addr;

    struct sockaddr     clientaddr;

    int                 clientlen;

    char buf[1000];

    char rcv_buf[1000];

    W    size;

    R_SOCKET_Init();

    /* 使用するワーク領域のサイズの算出 */  

        size = tcpudp_get_ramsize(); //6784が戻ります

          if(size/4 > sizeof(tcpudp_work))

    {  

    return;  

           }  

    ercd = tcpudp_open(tcpudp_work);

    if (ercd != E_OK)

    {

    return;  

    }

    sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); //4が戻ります

    if(SOCKET_ERROR == sock) /* There is no free socket */

    {

    continue;

    }

    addr.sin_family = AF_INET; //マニュアル通り?

    addr.sin_port = htons(14001); //自待ち受けポート

    addr.sin_addr.s_addr =  htonl(INADDR_ANY);

    if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)

    {

    closesocket(sock);

    return SOCKET_ERROR;

    }

    addr.sin_family = AF_INET;

    addr.sin_port =  htons(14000);  //相手先ポート 14000つもり

    addr.sin_addr.s_addr = htonl(0xc0a8000a); //相手先IP 192.168.0.10 のつもり

    /***************************************/

    ercd = recvfrom(sock, (void *)rcv_buf, 1000, 0,&clientaddr, &clientlen );

    if (ercd > 0)

    {

    ercd = sendto(sock,(const void *)rcv_buf, ercd, 0,&clientaddr, &clientlen);

    }

    /***************************************/

    ercd =sendto(sock, "HELLO", 5, 0, (struct sockaddr *)&addr, sizeof(addr));

    //5が戻ります

    tcpudp_close();

    closesocket(sock);

    }

  • redcrowさん

    シェルティです。

    >①受信処理を生かすとR_SOCKET_Init関数を呼んだあとに戻ってこなくなります。

    tcpudp_open()を追加いただいたのですが、lan_open()も必要でした。

    お手数ですがtcpudp_open()の前にlan_open()を呼び出して現象が変わるかご確認いただけますか?

    lan_open()はRXマイコンのEtherコントローラを初期化していく関数です。

    tcpudp_open()はTCP/IP処理に必要なソフトウェア制御用変数の束を初期化する関数です。

    >②T_UDP_CCEP の中身はポート14000で使うとしてもこのままでいいものなのでしょうか?

    OKです。udp_ccep[]の設定値は、udp_rcv_dat()で受信するときのポート番号を設定するものです。

    redcrowさんのプログラムだとbind()で14001が入力され、udp_ccep[]に格納され、

    14001番ポートでUDP受信待ちの設定ができているかと思います。

    以上です

  • シェルティ様

    お忙しい中アドバイスありがとうございます。

    R_SOCKET_Init後にlan_open()を追加してみました。

    ルネサスのecho_sev.cでも確かに使用していますね。

    デバッグでは0が戻ります。これ自体は成功しているようですね。

    昨日のソースコードですと

    ブレークした時以外、DUPREXとSPEED LEDが消灯していることに気づきました。

    ループの度にlan_open、tcpudp_open、closeを繰り返すものではないのかな?と思い、

    echo_sev.cを参考にwhileの前にR_SOCKET_Init、lan_open()、

    またtcpudp_get_ramsize、tcpudp_openもwhileの前に移動してみました。

    while内ではsoclet→bind→sendtoという流れのループになりました。

    これだとDUPREXとSPEED LEDはちゃんと点灯しました。

    ①sendtoは変わらず5が戻ってきて成功しているようですが、今だパケットは確認できず・・・です。

    ※PC-基板間をLANケーブルで直結し、wiresharkで確認しています。

    ②また、recvfromを生かすとやはりR_SOCKET_Initを呼んだあとに前述の通りステップが進まず、戻ってこなくなります。
    →その後解決しました。ほかの方のサンプルソースで試験したりしているうちに治った時があり、比べてみると「char rcv_buf[1000];」の部分でした。
    これをchar rcv_buf[2048];としたところR_SOCKET_Initで行方不明にならないようになりました。別に2048である必要はないのでしょうけど、足りなかったのかも知れません。
    修正後はrecvfromは-1が戻ってきました。明日以降また調査を続けるつもりです。

    ③lan_open()のおかげかpingで192.168.0.3で応答するようになりました。繋がってはいるようですね
    telnetで192.168.0.3、ポート14001は応答なし、nmapでのポート開放の検出はしませんでした。

  • redcrowさん

    シェルティです。少し間があいてしまいました。ごめんなさい。

    pingが通ったとのことで少しずつ進んでいますね。

    バシッと解決策を提示したいところなのですが、すみません。

    こちらでも少しRX62Nのスタータキットの実機をひっぱり出してきて似た実験をしてみようと思います。

    pingが通ったけれどアプリの通信ができないというときは、

    よくある落とし穴として以下ありますので再度ご確認ください。

    ①スタックが足りていない

     →リンカの設定でスタック情報出力する、としてCallwalkerというツールでスタック情報を読み込むと

      スタックサイズが見れて便利です。

     →スタックの設定は、/r_config/r_bsp_config.h の #pragma stacksize si で設定されてます。

      デフォルト設定だとユーザスタックは使わない設定になっていて、割り込みスタックのみ使っていることに注意です。

    ②tcpudp_open()に渡しているワーク領域が破壊されている

     そもそもワーク領域が足りていないこともありますので、再度tcpudp_get_ramsize()の戻り値も確認してください。

    ③割り込みが動いてない

     M3S-T4-Tinyは、t4_driver.c に実装されているtimer_interrupt()とlan_inthdr()内で呼び出される

     _process_tcpip()が処理本体です。

     main()から呼び出されたAPI(udp_snd_dat()など)は10ms周期で呼び出される

     timer_interrupt()内の_process_tcpip()で受付処理されます。

     ここにブレークポイントをはり、10ms毎に呼び出されているか確認してみてください。

     pingが動作するということは、すくなくともpingのパケット受信時にlan_inthdr()は呼び出されているはずなので、

     これも念のためブレークポイントをはってpingを送った時にブレークするか確認してみてください。

     (pingを送らなくてもPCなどから定常的に出力されるブロードキャストパケットを受信しても割り込み発生しますので

      ここだけ少しご留意ください)

    以上です

  • シェルティ様

    いつもお忙しい中アドバイスありがとうございます。

    ②tcpudp_get_ramsize()は6784(0x1a80)と返ってきます。

    コード上では

    tcpudp_work[2500];

    ercd = tcpudp_open(tcpudp_work); //ercd=0が戻ります

    として使っています。

    ③t4_driver.cファイルの下記関数が割り込みで呼ばれているようです。

    何度でもブレークしてくれます。

    #pragma interrupt ( timer_interrupt( vect = _VECT( _CMT0_CMI0 ) ) )

    void timer_interrupt(void)

    {

    if (tcpip_flag == 1)

    {

    _process_tcpip();

    tcpudp_time_cnt++;

    }

    /* for wait function */

    if (wait_timer < 0xFFFF)

    {

    wait_timer++;

    }

    }

    lan_inthdrについてもLANケーブルを抜けばブレークしませんが、普段はブレークするようです。

    ③やこの関数で更にcallしている「process_tcpip」はF11でステップしても飛ばされるようですね

    an_r20an0312jj0100_rx_t4_connectivity内に含まれていた

    tcp.cに入っている関数のようですが、T4_Library_rx600_ether_little.libをプロジェクトに入れているので大丈夫だと思っています

    ① スタックですが、#pragma stacksize si=0x400となっています。特に気にしていなかったのでそのままでした。

    callwalkerについては存在も知りませんでした。

    起動してみてもよくわからず・・・ちょっと勉強してみます。

  • redcrow さん

    こんにちは、シェルティです。

    RX62N のスタータキットのボードで実験してみました。以下手順でソケットAPIを動かすことができました。

    もしよろしければ試してみてください。

     

    ■使用したソフトウェア
    http://japan.renesas.com/products/tools/middleware/c_communication/a_tcpip/tcpip_t4/sub/m3s_t4_tiny_fit.jsp
    (1)TCP/IPサンプルプログラム
     an_r20an0312jj0100_rx_t4_connectivity.zip
    (2)ソケットAPIモジュール
     an_r20an0296jj0122_rx_t4_connectivity.zip

    http://japan.renesas.com/products/tools/ide/downloads.jsp#
    (3)統合開発環境 e² studio 4.1.0.018 インストーラ (オフライン用)
    (4)【無償評価版】RXファミリ用C/C++コンパイラパッケージ V2 (統合開発環境なし)

    ■事前準備
    (1)使用したソフトウェア(3)(4)をPCにインストールしておく

    ■動作確認手順:TCP/IP(T4)のサンプルソフトそのままの状態で動作確認
    (1)使用したソフトウェア(1)を解凍
    (2)\an_r20an0312jj0100_rx_t4_connectivity\workspace\sample\rx62n_rsk\echo_srv_udp_blocking\echo_srv_udp_blocking.hwp
     を、e2 studioでコンバートする
     コンバート手順①:
      ファイル→インポート→一般→HEWプロジェクト→HEWプロジェクトにチェック→参照ボタンで、
      上記echo_srv_udp_blocking.hwpを指定
     コンバート手順②:
      HEWプロジェクトのインポート→ターゲットの選択で、「R5F562N8BxBG」を選択する
     コンバート手順③:
      終了ボタン
    (3)先ずはソケットAPI無しで動作確認する
    (4)プロジェクト→すべてをプロジェクトをビルド<エラーなし確認>
    (5)実行→デバッグの構成→Renesas GDB Hardware→echo_srv_udp_nonblocking Debugを選択→デバッグボタンを押す
     <E1エミュレータ/LANケーブルを正しくボードに接続しておく。電源はE1エミュレータから供給される>
    (6)デバッグウィンドウのRestartを押す<プログラムが実行状態になりmain()でブレーク>
    (7)実行→再開ボタンを押す<プログラムが実行状態になる>
    (8)PCから ping 192.168.0.3 を実行し動作確認
    (9)SocketDebugger等のUDP送信可能なツールで、192.168.0.3の1365番ポート宛てにデータ送信し、
     エコーバックされることを確認する

    ■動作確認手順:TCP/IP(T4)のサンプルソフトにソケットAPIを載せる
    (1)使用したソフトウェア(2)を解凍
    (2)\an_r20an0296jj0122_rx_t4_connectivity\FITModules\r_socket_rx_v1.22.zip を解凍
    (3)解凍後の「r_config」「r_socket_rx」を以下にコピー
     \an_r20an0312jj0100_rx_t4_connectivity\workspace\sample\rx62n_rsk\src
    (4)コピーしたフォルダ「r_config」「r_socket_rx」を選択状態にして、
     e2 studioのプロジェクトエクスプローラのツリーの、src にドラッグ&ドロップ
    (5)ファイルおよびフォルダーにリンクを選択状態にして、OKボタン
    (6)ソケットAPI用のサンプルコードをコピー
     \an_r20an0312jj0100_rx_t4_connectivity\workspace\sample\rx64m_rsk_socket_e2\src
      main.c ファイルと、udp_blocking_sample フォルダ を、以下に上書きコピー
     \an_r20an0312jj0100_rx_t4_connectivity\workspace\sample\rx62n_rsk\src\t4
    (7)インクルードパスを追加する
     プロジェクトエクスプローラで、echo_srv_udp_blockingを右クリックしてプロパティ
     →C/C++ビルド→設定→Compiler→ソース→インクルードファイルディレクトリ
     →ファイルに+マークが付いたアイコン→ワークスペース で「r_config」「r_socket_rx」
      フォルダをを選択
    (8)ビルドすると、"No such file or directory"のエラーが出るので修正する
     r_socket_config.h -> r_socket_rx_config.h
     r_socket_if.h -> r_socket_rx_if.h
    (9)ビルドしてエラーなしを確認
    (10)「動作確認手順:TCP/IP(T4)のサンプルソフトそのままの状態で動作確認」の手順(5)~(9)で
      再度動作確認。

    ■動作確認手順:TCP/IP(T4)のサンプルソフト(echo_srv.c)をエコーバックではなく、自発的なUDP送信に変更する
    echo_srv.c を以下のように改造する。192.168.0.100 のUDP1365番ポートに対しUDPデータを送信し続けます。


    void echo_srv(void)
    {
     SOCKET             sck;
     struct sockaddr_in  serveraddr;
     struct sockaddr_in  clientaddr;
     int                 clientlen;
     ER                  ercd;
     UB                  snd_buf[BUFF_SIZE] = {0xaa};
     UB                  cnt;
     UB                  cnt2;

     while (1)
     {
      for(cnt=0; cnt<MAX_UDP_CCEP; cnt++)
      {
       sck = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
       if(SOCKET_ERROR == sck) /* There is no free socket */
       {
        continue;
       }
       serveraddr.sin_family      = AF_INET;
       serveraddr.sin_addr.s_addr = htonl(socket_info[cnt].ipaddr);
       serveraddr.sin_port        = (unsigned short)socket_info[cnt].portno;

       clientaddr.sin_family      = AF_INET;
       clientaddr.sin_addr.s_addr = 0xc0a80064;
       clientaddr.sin_port        = 1365;

       ercd = bind(sck, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
       if (ercd < 0)
       {
        goto exit;
       }

       for(cnt2 = 0; cnt2<10; cnt2++)
       {
    # if 0
        ercd = recvfrom(sck, (void *)rcv_buf, BUFF_SIZE, 0, &clientaddr, &clientlen );
        if (ercd <= 0)
        {
         break;
        }
    #endif
        ercd = sendto(sck,(const void *)snd_buf, 10, 0, (struct sockaddr*)&clientaddr, sizeof(clientaddr));
        if (ercd < 0)
        {
         break;
        }
       }
    exit:
       closesocket(sck);
      }
     }
    }

    以上です

    RE: ソケットAPIモジュールによるUDP通信について

  • シェルティ様

    大がかりな対応ありがとうございます。

    今週は出張でほとんど着手できていません・・・

    ちなみに初心かえって、改めてサンプルコードを組みなおしてみたところ

    an_r20an0312jj0100_rx_t4_connectivity\an_r20an0312jj0100_rx_t4_connectivity\workspace\sample\rx62n_rsk\echo_srv_udp_blocking

    で届いたテキストをそのまま返すという、pingも返す、動作は確認できました。

    理想は自発的に送信できることなので戻り次第さっそく試してみます。

  • ようやく戻ってきて試してみました。

    結果として無事にUDPで送信することができました!

    主な原因をまとめると

    APIだけで一通りこなせると思いこんでいて

    lan_open

    tcpudp_get_ramsize

    tcpudp_open

    の処理が抜けていた。

    教えてもらうまで気づきませんでした。

    ダウンロードした複数のFIT、lib、サンプルの整理が行き届かずおそらく組み合わせが悪い状態となっていた。

    →必要最小限にサンプルソース、各種インクルードを組み合わせ、作り直すことでこちらも解決

    ということろでしょうか。

    これでようやく通信の試行錯誤が始められそうです。

    長い間ありがとうございました。

Reply
  • ようやく戻ってきて試してみました。

    結果として無事にUDPで送信することができました!

    主な原因をまとめると

    APIだけで一通りこなせると思いこんでいて

    lan_open

    tcpudp_get_ramsize

    tcpudp_open

    の処理が抜けていた。

    教えてもらうまで気づきませんでした。

    ダウンロードした複数のFIT、lib、サンプルの整理が行き届かずおそらく組み合わせが悪い状態となっていた。

    →必要最小限にサンプルソース、各種インクルードを組み合わせ、作り直すことでこちらも解決

    ということろでしょうか。

    これでようやく通信の試行錯誤が始められそうです。

    長い間ありがとうございました。

Children
No Data