Top Page [◀◀]  2   3   4   5   6   7   8   9   ... [▶▶Last Page

M3S-T4-Tinyについて

初めての投稿です。

M3S-T4-Tinyで以下を実装された方はいらっしゃいますか?

---------------------------------------------------------------------------------------------------------

1)接続先のMACアドレスを取得する。

2)pingクライアント。

---------------------------------------------------------------------------------------------------------

1)はソースコードを見て次のコードで取得できるようになりました(時々取れない時もある)。

bool get_macaddr(UB *ipaddr, UB **mac_addr)
{
    bool res = false;
    int i;
    _ARP_ENTRY *ae;

    ae = _ether_arp_tbl[0];
    for(i=0; i<_ip_tblcnt[0]; i++, ae++){
        if(!memcmp(ipaddr, ae->ae_pra, sizeof(ae->ae_pra))){
            *mac_addr = (UB *)&ae->ae_hwa;
            res = true;
            break;
        }
    }
    return res;
}

  • fukueさん

    シェルティさんがネットワークに詳しいんですけれども、そろそろ顔を出してくれるかな??

  • In reply to Kirin:

    Kirinさん

    フォローありがとうございます。

    1)MACアドレスの取得に時々失敗する件は時間のある時にもう少し調べててみます。

    2)pingコマンドに関しては必要なら「サードパーティ製」を検討しろということかもしれませんネ。

  • In reply to fukue:

    fukue さん

    すみません、出張続きでチェックが出来ていませんでした。
    ping要求の実装がそこそこ難易度が高そうなので、
    サードパーティ製のTCP/IPの検討もした方が良いと思いました。
    以下それぞれ実装方法を検討してみました。

    まずは材料を揃えます。
    TCP/IPの最新版をダウンロードしてください。

    http://japan.renesas.com/mw/t4
    →関連FITモジュール
     →組み込み用TCP/IPモジュール
      →C source
       →ダウンロードボタン
        →My Renesasログイン
         →同意するボタン
          →ダウンロード&解凍
    →an_r20an0051jj0203_rx_t4_connectivity
     →FITModules
      →r_t4_rx_v2.03.zip
       →解凍
    →\r_t4_rx_v2.03
     →r_t4_rx\make_lib
      →make_lib.zip
       解凍
    →\make_lib\T4_src
     →TCP/IPのソースコード一式が格納されています
    →\make_lib\T4_Library
     →TCP/IPのライブラリの生成環境一式が格納されています
      →\make_lib\T4_Library\cubesuite\rx_ether\rx_ether.mtpjをCS+で読み込んでビルドすると、
       以下フォルダにライブラリが生成されます
       \make_lib\T4_Library\cubesuite\rx_ether\T4_Library_rxv1_ether_little\DefaultBuild

    次にソースコードを改造していきます。

    > 1)接続先のMACアドレスを取得する。

    ポイントは「data_link_buf_ptr」データポインタです。
    このデータポインタはEthernet層から受信データがTCP/IPに入力される度に
    ether.c の123行目で更新されます。
    宛先のMACアドレスは「data_link_buf_ptr」からオフセット+6のところから
    6バイト格納されています。
    TCPの接続相手のMACアドレスが知りたい場合、tcp.c 1022行目の_TCPS_LISTENのところで、
    data_link_buf_ptr+6を参照してMACアドレスをアプリケーション層の変数にコピーすると良いと思います。
    UDPの接続相手のMACアドレスが知りたい場合、udp.c 372行目のif文の中で、
    data_link_buf_ptr+6を参照してMACアドレスをアプリケーション層の変数にコピーすると良いと思います。

    > 2)pingクライアント。

    こちらはちょっと難儀です。私もまだ実現したことはないです。
    まずtcp.c の1781行目あたりからICMPエコー応答のパケットを作りだしているコードが
    あるのでこれを活用してICMPエコー要求のパケットを作り出して送信するAPIを作成します。
    Windowsの実装だと1秒毎に4回送信しています。APIはリクエストを発行し、
    10ms周期で呼び出される_process_tcpip()の中で1秒毎にICMPエコー要求を
    出すような実装になると思います。

    次に要求に呼応して応答が返ってきます。
    受信パケットは必ず ether.c の88行目のlan_read()から入ってきます。
    lan_read()の戻り値がデータ長なのですが、有効なデータ長の場合、115行目の
    以下チェックを通過します。
     ether.c の115行目:else if ((len > 1514) || (len < 60))

    この後に、先ほど送信したICMPエコー要求のパケットに対する応答かどうかを
    確認して、ユーザアプリにコールバックするような実装になると思います。

    少し時間に余裕ができましたら私も実装して試してみたいと思います。

    以上です

  • In reply to シェルティ:

    シェルティ さん、

    御教示有難うございます。

    1)MACアドレス取得

    ライブラリに手を付けるは気が引けたので以下のコードを接続した時に呼ぶようにしました。

    -----------------------------------------------------------------------------------------

    extern _ETH_HDR *data_link_buf_ptr;                         // tcp.c

    bool get_macaddr(UB mac_dst[], UB mac_src[])

    {

       bool res = false;

       if(!memcmp(mac_dst, data_link_buf_ptr->eh_dst, sizeof(data_link_buf_ptr->eh_dst))){

           memcpy(mac_src, data_link_buf_ptr->eh_src, sizeof(data_link_buf_ptr->eh_src));

           res = true;

       }

       return res;

    }

    ----------------------------------------------------------------------------------------

    サーバー及びクライアントが同じセグメントにある場合は接続先のMACアドレスが取得できました。

    ただ、ルータを間に入れるとルーターのMACアドレスが入るようです。

    2)pingコマンド

    面白そうなので時間があるときにご教示の方法にトライしてみたいと思います。

  • In reply to fukue:

    fukueさん

    コード確認しました。この内容で問題ないと思います。トライいただきありがとうございます。
    少し懸念が残るのは、ブロードキャストパケットが頻繁に行き交うネットワークだと、
    data_link_buf_ptrの先がどんどん受信データで更新されていってしまうので、
    get_macaddr()からは、falseしか返ってこないのではないか、というところです。

    通信相手のMACアドレスをもれなく入手したい場合は、
    _process_tcpip()の中、ether.c でlan_read()でパケットを吸い上げているところで
    1パケットずつget_macaddr()を実行し、trueが返ってきたら
    ユーザアプリにコールバックする実装が確実と思います。

    (確かにライブラリに手を付けるのは気が引けてしまいますね)

    >> ただ、ルータを間に入れるとルーターのMACアドレスが入るようです。

    これはおっしゃる通りですね。
    ルータの先の実通信相手のMACアドレスを入手しようとすると、
    [Ethernetヘッダ(14byte)][IPヘッダ(20byte)][TCPヘッダ(20byte)][ペイロード(max1460byte)]、または
    [Ethernetヘッダ(14byte)][IPヘッダ(20byte)][UDPヘッダ(8byte)][ペイロード(max1472byte)]の
    ペイロード部分にMACアドレスを詰め込んで通信相手に渡す必要がありますね。

    以上です

  • In reply to シェルティ:

    シェルティ さん、もう少し教えてください。

    MACアドレス取得で想定しているのはローカルエリアネットワークで最大の接続数が分かっている場合を想定しています。

    私が最初に作成したのはARPテーブルから接続先IPアドレスでマッチングしたMACアドレスを取得するというものですが、

    例えば、最大接続数が64個の場合に

    ------------------------------------------------------------------------------------------------------------------

    const UH _ip_tblcnt[] = { 65 };                  // CH毎のARPテーブルキャッシュエントリ数+1

    ------------------------------------------------------------------------------------------------------------------

    とすれば良いように思いますが、いかがでしょうか?

    >ペイロード部分にMACアドレスを詰め込んで通信相手に渡す必要がありますね。

    確かにそうですね、勉強不足でした。

  • In reply to fukue:

    fukue さん

    > とすれば良いように思いますが、いかがでしょうか?

    はい、良いと思います。
    ip_tblcnt[]はソースコードを見ると10分経つと自動で消えるところが
    注意事項として有りそうです。

    あと、fukueさんの使い方だと当てはまりませんが、
    ip_tblcnt[]で定義した数より、実際にネットワークに繋がっている端末の数が多い場合は、
    ip_tblcnt[]の溢れが想定されます。このときはip_tblcnt[]の添え字の小さい配列から
    順に上書きされてARPテーブルの中身が消えてARPパケットの送受信が発生する実装に
    なっていました。これもARPに関する注意事項ですね。

    ip_tblcnt[]に1を設定しているのにたくさんの端末が繋がったネットワークに接続すると、
    通信相手が変わる度に毎回ARPパケットのやり取りが発生する、といった動きになりますね。

    以上です

  • In reply to シェルティ:

    シェルティ さん、解析していただきありがとうございます。

    >10分経つと自動で消えるところが注意事項として有りそうです。

    は想定していませんでしたが、接続時に取得しておけばよさそうですネ。

    この方法で継続してテストしてみます。

  • In reply to fukue:

    ずいぶん時間が過ぎてしまいましたが、

    シェルティさんのヒントを参考に「pingクライアント」について実装してみました。

    [実装に当たっての方針]

    1)現時点でT4最新のVer1.08を使用する

    2)改造箇所を少なくするため複数回処理はアプリ側で行う

    [ソース]

    --------------------------------------------------------------------------------

    【r_t4_itcpip.h】

    /* ICMP APIs */

    typedef struct t_icmp_header

    {   // _ICMP_HDR と同じにする

       UB type;        /* type of message */

       UB code;        /* code (additional info. depend on type) */

       UH chksum;      /* checksum of ICMP header+data   */

       UH id;          /* message id */

       UH seq;         /* sequence number */

    } T_ICMP_HEADER;

    typedef struct t_icmp_ccep

    {

       ER(*callback)(VP data, T_ICMP_HEADER *hdr , INT len);   /* Callback routine */

       IPaddr ipaddr;  /* source address */

       IPaddr dstaddr; /* destination address */

       UB type;        /* type of message */

       UB code;        /* code (additional info. depend on type) */

       UH id;          /* message id */

       UH seq;         /* sequence number */

       UB *data;       /* message */

       INT len;        /* message length */

       UW timestamp;   /* time stamp */

       H status;

       ER result;

    } T_ICMP_CCEP;

    ER icmp_snd_dat(IPaddr ipaddr, IPaddr dstaddr, T_ICMP_HEADER *picmph, VP data, INT len);

    【tcp_api.c】

    // ICMP Request flag

    bool icmp_stat = false;

    // ICMP Packet Send

    extern T_ICMP_CCEP icmp_ccep;

    ER icmp_snd_dat(IPaddr ipaddr, IPaddr dstaddr, T_ICMP_HEADER *picmph, VP data, INT len)

    {

       memcpy(icmp_ccep.ipaddr, ipaddr, sizeof(IPaddr));

       memcpy(icmp_ccep.dstaddr, dstaddr, sizeof(IPaddr));

       icmp_ccep.type = picmph->type;

       icmp_ccep.code = picmph->code;

       icmp_ccep.id = picmph->id;

       icmp_ccep.seq = picmph->seq;

       icmp_ccep.data = (uchar *)data;

       icmp_ccep.len = len;

       icmp_stat = true;

       return E_OK;

    }

    【tcp.h】

    void _icmp_api(void);

    【tcp.c】

    // 22行目に追加

               _icmp_api();

    // 838行目に追加

                   if (picmph->type != _ICMP_ECHO_REQ)

                   {

                       if(icmp_ccep.callback){

                           len = _ch_info_tbl->_p_rcv_buf.len - _ICMP_HLEN - _IP_HLEN_MIN;

                           icmp_ccep.callback(picmp->data, (T_ICMP_HEADER *)picmph, len);

                           _ch_info_tbl->flag &= ~(_TCBF_PEND_ICMP | _TCBF_SND_ICMP);

                           rcv_buff_release(_ch_info_tbl->_ch_num);

                           _ch_info_tbl->_p_rcv_buf.len = 0;

                           break;

                       }

                       else{

                           report_error(_ch_info_tbl->_ch_num, RE_ICMP_HEADER1, data_link_buf_ptr);

                           goto _err_proc_rcv;

                       }

                   }

    // 最終行に追記

    void _icmp_api(void)

    {

       uint16  sum;

       _ICMP_HDR *picmph_s;

       if(icmp_stat && (_ch_info_tbl->flag&_TCBF_SND_ICMP)==0){

           icmp_stat = false;

           picmph_s = (_ICMP_HDR *)(_tx_hdr.ihdr.tip.thdr.icmph);

           picmph_s->type = icmp_ccep.type;

           picmph_s->code = icmp_ccep.code;

           picmph_s->chksum = 0;

           picmph_s->id = icmp_ccep.id;

           picmph_s->seq = icmp_ccep.seq;

           sum = _cksum((uchar *)picmph_s, _ICMP_HLEN, 0);

           sum = ~hs2net(sum);

           sum = _cksum(icmp_ccep.data, icmp_ccep.len, sum);

           picmph_s->chksum = hs2net(sum);

           _tx_hdr.hlen = _ICMP_HLEN;

           _tx_hdr.ihdr.tip.iph.ip_proto_num = _IPH_ICMP;

           _cpy_ipaddr(_tx_hdr.ihdr.tip.iph.ip_dst, icmp_ccep.dstaddr);

           _cpy_ipaddr(_tx_hdr.ihdr.tip.iph.ip_src, icmp_ccep.ipaddr);

           _ip_snd(icmp_ccep.data, icmp_ccep.len);

       }

    }

    【Apli】

    int ping_command(int argc, char *argv[])

    {

    ・・・

       if(ShellSetupNumber == 0){

    ・・・

           icmp_ccep.callback = ping_callback;

           icmp_ccep.timestamp = get_system_time();

           icmp_ccep.status = STS_WAIT_FOR_RESPONCE;

           icmp_ccep.result = E_OK;

           ++icmph.seq;

           ercd = icmp_snd_dat(tcpudp_env[0].ipaddr, dstaddr, &icmph, (VP)ping_msg, sizeof(ping_msg));

           if(ercd){

               icmp_ccep.callback = NULL;

               print("icmp send error.\r\n");

               return 0;

           }

           ++ ShellSetupNumber;

       }

       else{

    ・・・

           if(lap_time > tmout){

               if(icmp_ccep.status != STS_PRINTED_RESULT)

                   print_ping(icmp_ccep.len, byte4_to_long(icmp_ccep.dstaddr), icmp_ccep.seq, lap_time/10, true);

               icmp_ccep.status = STS_WAIT_FOR_RESPONCE;

               if(--count > 0){

                   icmp_ccep.timestamp = get_system_time();

                   icmp_ccep.status = STS_WAIT_FOR_RESPONCE;

                   icmp_ccep.result = E_OK;

                   ++icmph.seq;

                   ercd = icmp_snd_dat(tcpudp_env[0].ipaddr, icmp_ccep.dstaddr, &icmph, (VP)ping_msg, sizeof(ping_msg));

                   if(ercd){

                       icmp_ccep.callback = NULL;

                       print("icmp send error.\r\n");

                       ShellSetupNumber = 0;

                   }

               }

               else{

                   icmp_ccep.callback = NULL;

                   ShellSetupNumber = 0;

               }

           }

           else{

               if(icmp_ccep.status == STS_RECEVED_REPLAY){

                   ++icmp_ccep.status;

                   print_ping(icmp_ccep.len, byte4_to_long(icmp_ccep.dstaddr), icmp_ccep.seq, lap_time/10, icmp_ccep.result);

               }

           }

       }

    }

    static ER ping_callback(VP data, T_ICMP_HEADER *hdr , INT len)

    {

       if(hdr->seq == icmp_ccep.seq){

           icmp_ccep.status = STS_RECEVED_REPLAY;

           if(len!=icmp_ccep.len

                || memcmp((char *)data, (char *)icmp_ccep.data, icmp_ccep.len)!=0){

               icmp_ccep.result = -1;

           }

           else{

               icmp_ccep.result = E_OK;

           }

       }

       return E_OK;

    }

    --------------------------------------------------------------------------------

    [結果]

    1)初回はARPテーブルに宛先が無い為、ARP要求だけになる

    2)ICMP管理構造体の使い方がいまいち

  • In reply to fukue:

    fukueさん

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

    pingコマンド実装されたのですね、感激しました。
    私は実装試みると言いながら実行せず、
    有言実行のfukueさんの書かれたコードをさっそく
    コピペしようと企んでいる悪い人です。

    このTCP/IPはセミナーが開催されていたりして、
    セミナー講師の方がTCP/IPのコードを書いているとのことで、
    若干繋がりがあったりします。このスレッドについて連絡をしておきました。
    http://japan.renesas.com/support/seminar/system_seminar/ethernet_koza/tcp_ip_protocol_course/index.jsp

    fukueさんが挙げている改善点1)については、ARP送信処理のあとに
    ICMP送信フラグが消えないように手当してあげれば直る気がします。

    あとは、(他のTCP/IP関連APIも全部そうなのですが)API発行から
    実行されるまで、10msで周期起動している割り込み関数が実行されるまでの
    最大10msの幅で待ち時間が生じているところが改善点ですね。
    (ノンブロッキングコールをうまく活用しないと転送速度が出せない)
    [結果]のtimeが6ms~9msかかっている個所がうまく作り込みが出来れば
    全部1ms以内に完了できると考えています。
    これは講師の方が、API実行時にソフトウェア割り込みを起動してそこから
    TCP/IPを呼び出せば直ると思う、将来バージョンで直したい、と仰っていました。

    いずれにしても講師の方が直してくれるのを期待してみましょう。

    以上です

  • In reply to シェルティ:

    元々、pingコマンドがほしかった理由は

    1)昔、双方で疎通テストを行う必要性がたまにあった(HUB等の不良)。

    2)これまでのプログラミングではサーバーからファイルをダウンロードする前に存在を確認するようにしている。

    です。したがって、疎通の確認が出来れば良いと思っています。

    >全部1ms以内に完了できると考えています。

    スバラシイですね。

    ただ、

    CPUの負荷率を考えてアプリケーションとのバランス、使用目的などで設定できると良いと思います。今後、将来バージョンでNagleアルゴリズム等の機能が実装されるとうれしいですネ。

    また、先の提示したソースに記載漏れがありました。

    --------------------------------------------------------------------------------

    【tcp.c】

    // 106行目に追加

    extern T_ICMP_CCEP icmp_ccep;

    extern bool icmp_stat;

    【Apli】

    // 初期値の設定

    T_ICMP_CCEP icmp_ccep = {

       NULL,

       { 0, 0, 0, 0 },

       { 0, 0, 0, 0 },

       0,

       0,

       0,

       0,

       NULL,

       0,

       0

    };

    static T_ICMP_HEADER icmph = {

       8, 0, 0, 0x0001, 0

    };

    --------------------------------------------------------------------------------

    利用いただければ幸いです。

  • In reply to fukue:

    はじめまして、fukueさん。
    nnoriと申します。
    (もうずいぶん前の投稿なので、通じることを祈っております。)

    私も、この度ping実装を依頼されております。
    当初の最新はVer1.08とのことでしたが、現在Ver2.08となっております。

    大きな変更はないかと思いますが、
    実際上記の投稿内容でコード実装しようとすると、
    なかなか「***行目」というところが、
    Ver2.08ではどこ?となってしまい、理解できない状況でございます。

    何か良きアドバイスを頂けると助かります。
  • In reply to nnori:

    nnoriさん、初めましてfukueです。

    >(もうずいぶん前の投稿なので、通じることを祈っております。)
    申し訳けありませんが、私はすでに現役を外れて随分経ちます。

    アドバイスという事であれば、具体的にどの部分でエラーになるのかを提示されたほうが良いと思います。
    エラーの状態が分かればどなたかからのアドバイスがいただけると思います。

    以前に私も「シェルティ」からアドバイスを頂きました。
  • In reply to fukue:

    fukueさん

    replyありがとうございます。

    ①_icmp_api();について
     どこで実行すべきか、迷っています。

    ②_ch_info_tbl->flagの_TCBF_SND_ICMPについて
     ICMPのエコーリプライでは(元々ある機能)、_TCBF_SND_ICMPフラグOn/Offにより、
     リプライを送信するかしないか判断しています。

     この度のICMPエコーリクエストの送信は、
     そのフラグの代わりにicmp_statを使用しているかと認識しました。

     そこで、【tcp.c】838行目に追加の内容に、
     _ch_info_tbl->flag &= ~(_TCBF_PEND_ICMP | _TCBF_SND_ICMP);とありますが、
     このリクエスト送信過程で、_TCBF_PEND_ICMP や_TCBF_SND_ICMPが
     Onとなるタイミングはありますでしょうか?

    (直接的な質問となってしまい、申し訳ございません。)
  • In reply to nnori:

    nnoriさん

    ゴメンナサイ、
    ①の実行場所について(// 22行目に追加)は間違ってました。
    void _process_tcpip(void)関数の頭あたりで226行目でした。
    _proc_api();
    _proc_rcv();
    _proc_snd();
    <----
    関数自体はtcp.cの最後に追記しました。

    ②確かに追加したicmp_statフラグでリクエストを送信するようにしています。
    > Onとなるタイミングはありますでしょうか?
    もう記憶が定かでありませんが、
    1)_icmp_api();でリクエストを送信
    2)受信したICMPパケットの処理でリクエストでない場合はコールバックで内容をチェックして
    バッファをクリアするというものだったと思います。flagのクリア処理はこのバッファクリア
    と同等の処理だったと思います。

    もしできれば、
    同じバージョン(ver1.08)で動作確認をされてから最新バージョンへ移行されたほうが確実かもしれません。

Top Page [◀◀]  2   3   4   5   6   7   8   9   ... [▶▶Last Page