RXマイコン、C++、HTTPサーバーの実装(ソケット版)

先日、ping が通るようになったネット・スタックだが、その先が中々進ま
ない。

苦労して、デバッグをした結果、ようやく、動作するようになった。
・ルネサスの、「r_socket_rx」にバグがあった。
※アドレス構造体にポートを設定する部分は、ソケットの仕様では、ネット
エンディアン(ビッグエンディアン)で行うのだが、それが逆だった。
・「r_t4_rx」のチェックサム計算ソースに問題があった。
※このアセンブラソースは、ルネサスの統合環境向けのソースコードで、
「gcc」の場合、アセンブルは通るが、そのままでは正しく動作しないよ
うだ。(これが判るまで、非常に苦労した)

 .file	"cksum_rx_little.s"
    .section    .text.ck
    .global     __cksum
__cksum:    ; function: _cksum
;uint16 _cksum(uchar *data, uint16 nbytes, uint16 sum0);
    and     #0ffffh, r2      ;arg2 uint16
    and	    #0ffffh, r3      ;arg3 uint16

上記のように、少し修正した。

次に、ソケット関連だが、ソースコードを見ると、ノンブロックモードが
用意されているようだが、実際はこのモードはまともに動作しない事が判
った。(とりあえず、ブロックモードで行っている)
ソケットのモジュールでは、BSDソケットとの互換を意識して、関数名
や、構造体を同じにしているが、これが、オリジナル(POSIX)のソケット
関係と当るので、それに準じた、名称に変更した。

これらを修正し、以前に実装した、Arduino 系のプログラムをソケット系に
修正を加え、http_server クラスを新規にコミットした。

また、元のネットスタック関係をデバッグ中、色々問題がある部分が多く、
それらに修正を加えた、なので、オリジナルソースとは違うものになってい
る。
・ソースの色々な部分で、「extern」を使い、変数の型や、関数の型を宣言
しているが、一つのソースで共有すべきなので、新たに、「global.h、
global.c、config_tcpudp.h」を作成した。
※まだ、みるに絶えない部分は沢山あるが、とりあえず・・・

ネットスタック全体は以下のような構成になっている。

ip_adrs.hpp
dhcp_client.hpp
net_tools.hpp
net_core.hpp
socket.hpp
http_server.hpp
r_tcpip_private.[hc]
r_config/r_t4_rx_config.h
r_config/r_socket_rx_config.h
r_t4_rx/src/config_tcpudp.[hc]
r_t4_rx/T4_src/dhcp.[hc]
r_t4_rx/T4_src/ether.[hc]
r_t4_rx/T4_src/global.[hc]
r_t4_rx/T4_src/igmp.[hc]
r_t4_rx/T4_src/ip.[hc]
r_t4_rx/T4_src/r_t4_itcpip.h
r_t4_rx/T4_src/t4define.h
r_t4_rx/T4_src/tcp.[hc]
r_t4_rx/T4_src/tcp_api.c
r_t4_rx/T4_src/type.h
r_t4_rx/T4_src/udp.[hc]
r_t4_rx/T4_src/checksum/rx/cksum_rx_little.s

インサーネットのハードウェアーの定義は以下のようにする。


    typedef device::ETHERC0 ETHERC;      // Ethernet Controller
    typedef device::EDMAC0 EDMAC;        // Ethernet DMA Controller
    typedef chip::phy_base<ETHERC> PHY;  // Ethernet PHY
    typedef device::ether_io<ETHERC, EDMAC, PHY> ETHER_IO;
    ETHER_IO    ether_;

    typedef net::net_core<ETHER_IO> NET_CORE;
    NET_CORE    net_(ether_);

    typedef net::http_server<ETHER_IO, SDC> HTTP;
    HTTP        http_(ether_, sdc_);

※PHY 層デバイスは、GR-KAEDE に使っている、Microchip LAN8720 用だが、
PHY 層デバイスは共通部分が多いので、そのまま使える、他のデバイス用に
カスタムする場合、「phy_base.hpp」を参考にして別のデバイス用を作成す
る。
※「SDC」は、SDカードの操作を行うクラス。(「main.cpp」参照)
※他に、ルネサスのネットスタックとの仕様を合わせるCの関数を定義する。
(ソースコード「main.cpp」を参照)

メインプログラムからHTTPサーバーを使う場合、以下のようにすれば良
い。
※「/」ルートページのレンダリング定義は、サンプルでは動的なプログラム
で行う。(C++ではラムダ式が使えるので簡潔に書ける)

    {  // Ethernet の開始
        ether_.set_intr_task(lan_inthdr);
        uint8_t intr_level = 4;
        ether_.start(intr_level);

        static uint8_t mac[6] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
        net_.start(mac);
    }

    {  // HTTP サーバーの設定
        http_.start("GR-KAEDE_net HTTP Server");

        // ルート・ページ設定
        http_.set_link("/", "", [=](void) {
            time_t t = get_time();
            struct tm *m = localtime(&t);
            HTTP::http_format("%s %s %d %02d:%02d:%02d  %4d
\n") % get_wday(m->tm_wday) % get_mon(m->tm_mon) % static_cast(m->tm_mday) % static_cast(m->tm_hour) % static_cast(m->tm_min) % static_cast(m->tm_sec) % static_cast(m->tm_year + 1900); http_.tag_hr(500, 3); } ); } uint32_t cnt = 0; while(1) { // 100Hz (10ms interval) cmt_.sync(); sdc_.service(); net_.service(); bool l = net_.check_link(); if(l) { http_.service(); } device::PORTC::PDR.B0 = 1; // output LED port device::PORTC::PODR.B0 = (cnt < 10) ? 0 : 1; ++cnt; if(cnt >= 50) cnt = 0; // 0.5 sec }

GR-KAEDE_net プロジェクト