こんにちは、ルネサスマイコン(RXマイコン中心ですが)でTCP/IP関連をいろいろ実験しておりますシェルティと申します。
TCP/IPですが、複雑怪奇な仕様であり、スクラッチ開発となると相当な難易度ですね。
実験/研究レベルならスクラッチ開発もありかもしれませんが、量産製品に適用となると、
第一にネットワーク関連ソフトを組み込みマイコン向けに製品化しているソフトウェアハウス製のものがおすすめです。
例えば、図研エルミック殿やデータテクノロジー殿、ユビキタス殿などの組み込み用TCP/IPが有名です。
ルネサス製でも組み込み用TCP/IP M3S-T4-Tinyというのが有償製品として提供されています。(SH2A用の無償ダウンロードもあるようです)
http://japan.renesas.com/mw/t4
第二に組み込み用OSに内包されているTCP/IP機能を使うのも良いです。
(ここでいう組み込み用OSはリアルタイムOSではなく、組み込み用Linuxを指します)
第三にuIPやlwIP等のオープンソース系のコードを頑張って量産製品に適用する道です。
第四にスクラッチ開発でTCP/IPを手作りする道です。
第三・第四の道は技術力に自信が有る場合におすすめですね。
安く仕上げられるというメリットも捨てがたいと思います。
-------
さて、uIPで大きいデータ転送に弱い件ですが、uIPのTCP処理の実装に問題があります。
lwIPでも私が調査した限り同様の問題を含んでいます。
組み込み用TCP/IP M3S-T4-TinyもRXマイコン用パッケージにて、最近ソースコードが公開されたので中の実装を確認したところ、
uIPやlwIPよりはマシですが、もう一段の改善が必要といったところです。
各TCP/IPを比較すると以下の通りです。
uIP or lwIP : TCPの送信アルゴリズムが貧弱。データ送信1回につき1個のACKが戻ってくることを期待している。
多くの一般的なTCP/IPはTCPデータ受信時は2個データを受信する or 1個データ受信し200ms経過後タイムアウトしACKを返す実装になっている。
その結果、毎回タイムアウトが発生し1秒に5回のデータ転送しか実現出来ない。
組み込み用TCP/IP M3S-T4-Tiny : TCPの送信アルゴリズムが少し貧弱。データ送信は2個セットでACKが戻ってくることを期待している。
その結果ACKがすぐ戻ってくるネットワーク環境(LAN)においては転送速度に問題は発生しないが、
ACKがすぐに戻ってこないネットワーク環境(WAN)においては転送速度がACKが返ってくる時間に律速する。
ACKが返ってくるまで200msかかる(東京-北米西海岸等)通信をする場合は、uIP or lwIPと変わらない程度の通信速度に落ちる。
※ローカル環境ではSH7216@200MHz で、TCP送受信が60Mbps程度出せることを確認しました。(RX62N@100MHz では30Mbps程度確認)
-----
これは組み込み用TCP/IPが多くの場合、RAM容量に制限の多いマイコンでの動作を期待しているため、
送信用/受信用のバッファを多く持たないことに起因します。
TCPの規格上、お互いに受信用のバッファサイズ(受信ウィンドウと呼ばれます)を常にTCPヘッダの特定16bitエリア(0xffff=最大64KB)に載せて
通知し合っているわけですが、上述したTCP/IPたちはここにTCPパケット1個分(=1460バイト)の容量を設定しているのです。
#組み込み用TCP/IP M3S-T4-Tinyではここが可変になっていて柔軟にチューニングが効くようにはなっています。
その上、送信アルゴリズムも上述した通り貧弱ですのでいずれにしても大きなデータ通信には向きません。
長くなりました。
結論ですが、量産製品にTCP/IP機能を付ける目的であれば、有償のTCP/IP製品をお求めになるのが良いかと思います。
とにかくまず実験して感触を掴んでみたい/通信速度が気になる/LANでしか通信しない、ということであれば、
SH2A用の組み込み用TCP/IP M3S-T4-Tinyを使って実験されるのが良いかと思います。
ただ、ソフトは無償ダウンロードがありますが、SH7216の評価ボードとE10Aエミュレータが必要となり、ちょっと実験してみるのには敷居が高そうですね。
(TCP/IP処理部分はSH7670でも動作するでしょうけれど、サンプル全体がSH7216用に作られているため、
Etherドライバ付近とボード周りの設定プログラム、スタートアップ等を調整してあげる必要はありそうです)
もちろん、せっかくuIPをSH7670に移植されたのですから、大きなデータ通信については目をつむり、そのまま使用し続ける案も十分に有りと思います。
以上です。
すみません、少し書き漏れました。
一般的なTCP送信アルゴリズムは、「通信相手の受信ウィンドウサイズに空きがあればACKが返ってこなくてもお構いなしに送信する」です。
このように実装するためには、通信相手の受信ウィンドウサイズの最大値(0xffff=64KB)の容量の送信バッファが必要です。
しかも、通信相手が複数同時に居る場合は通信相手の数分だけ64KBの送信バッファが要ります。もちろん受信ウィンドウも要ります。
従って、多くの(オープンソース系)組み込み用TCP/IPは多くのマイコンで動作させることを優先し、
バッファサイズを制限し通信速度を犠牲にしたのだと思います。
組み込みソフトを専業でやっているソフトウェアハウスのTCP/IPの場合、この辺りが柔軟に設定できるものがあると聞きますので
本格的に量産製品を作られる場合は一度ソフトウェアハウスに相談してみるのが良いかと思います。
IKUZOさん
こんにちは、シェルティです。
もうFTPの移植が完了したのですね、素晴らしいです。すごいですね。
通信速度も400KByte/secと十分実用に適用出来る速度ですね。
注意としてはT4は送信アルゴリズムが弱いため、ACKが返ってくるのが
遅い環境だと送信も合わせて遅くなる点です。
これは近いうちに直すと開発者から聞きましたが現在の最新版(V.2.00)では遅いままですね。
以下ご質問いただいた内容について回答です。
■ご質問①の回答:画像添付の方法
画像添付については「USE RICH FORMATTING」というリンクを押して
画像添付のアイコンをクリックしたら出来ました。
■ご質問②の回答:TIME_WAIT状態
以前別のスレッドで別の方から似たご質問が有りまして
そこで実施した回答が参考になると思います。
http://japan.renesasrulz.com/cafe_rene/f/69/p/2059/8911.aspx#8911
■ご質問③の回答:H8/300のライブラリ
作ってみます。 T4の最新版はソースコードが付いてて、RXマイコン用のライブラリビルド環境(HEW)も
付いているので、H8/300用に新規でビルド環境を起こして
Toolchainの設定を見ながら真似して設定してあげれば出来ると思います。
が、データの受け渡し方法が良い方法が無い気がしますね。
もしデータの受け渡し方法が見つからなければ、RXマイコン用のライブラリビルド環境を
H8/300用に改造する方法を説明したいと思います。
以上です
シェルティ さん
いつもお世話になっております、以前の投稿記事を拝見しました、_tcp_2mslはできるならそのままで、通信端点をRAMが許す限り多くすれば最大の転送速度になるということで納得しました
「T4の最新版はソースコードが付いてて」これはまたすばらしい
時間ができしだい、これもやりたいと思います、
新規開発ではRXになると思うのですが、H8が残留している基板もありまして
今回はt4で解決できたので、シェルティ さんに感謝しています。
ありがとうございました。
H8/300でT4ライブラリが作れるか、試してみました。結果OKでした。
以下手順です。
①T4ライブラリの最新版パッケージをダウンロード
RXファミリ 組み込み用TCP/IP M3S-T4-Tiny: 導入ガイドFirmware Integration TechnologyR20AN0051JJ0200
②T4ライブラリの最新版パッケージの中身のFITモジュールを解凍
\an_r20an0051jj0200_rx_t4_connectivity\FITModules\r_t4_rx_v2.00.zip
③FITモジュールの中のビルド環境を解凍
\r_t4_rx_v2.00\r_t4_rx\make_lib\make_lib.zip
④\make_lib\T4_Library\hew\T4_Library.hws でHEWを起動する
⑤画面左プロジェクトツリーの「T4_Library」で右クリックして、「プロジェクトの挿入」⇒「新規プロジェクト」を選択しOKボタン
⑥プロジェクトタイプを「Library」選択しプロジェクト名「T4_Library_h8300h_advance」とし、CPU種別に「H8S, H8/300」を選択
ツールチェインに「Hitachi H8S, H8/300 Standard」を選択し、OKボタン
⑦CPUシリーズに「H8/300H」を選択し「次へ」ボタン ※IKUZOさんのお持ちの環境に合わせてください
⑧動作モードに「Advanced」を選択し「完了」ボタン ※IKUZOさんのお持ちの環境に合わせてください
⑨以下ソースコードをプロジェクトツリーの「T4_Library_h8300h_advance」にドラッグアンドドロップ
\make_lib\T4_src
ether.c, ip.c, T4_Version.c, tcp.c, tcp_api.c, udp.c
⑩ビルド→H8S, H8/300 Standard Toolchainのコンパイラタブのオプション項目「インクルードファイルディレクトリ」でインクルードパスを以下追加
相対パス: Project directory
サブディレクトリ: ..\..\..\T4_src
⑪ビルド→H8S, H8/300 Standard Toolchainのコンパイラタブのオプション項目「マクロ定義」でマクロを以下追加
_TCP, _UDP, _TCP_DACK, _ETHER, _MULTI, _TEST_LIBRARY, _ICMP, far, _far
⑫T4_Version.c にH8/300H用のプリデファインマクロの切り分けが無いので以下を151行目に追加
#elif defined (__H8__) && defined(__300HA__)#define __TARGET_CPU__ "H8/300H Advanced mode"#define __COMPILER_VER__ __RENESAS_VERSION__
⑬チェックサム演算コードがRXマイコン用にアセンブラ化されていますが、H8/300用のコードは無いので、C言語で書いたコードを登録
※次投稿でコードを貼りつけます
これでビルドが通りました。お試しください。
r_t4_itcpip.h の冒頭にT4の対応マイコン表が書いてありますね。
ここに書いてある対応マイコンであれば上記と同等の手順でライブラリ生成環境が作れそうです。
#include <type.h>
uint16 _cksum(uchar *data, uint16 nbytes, uint16 sum0){ uint32 sum; uint16 *p_word, word, nwords;
if (nbytes == 0) { sum = sum0; } else { if (((uint32)data) & 0x1) { sum0 = ((sum0 >> 8) & 0x00ff) | (sum0 << 8);
p_word = (uint16 *)(data + 1); /* half word alignment */ nwords = (nbytes - 1) >> 1;
for (sum = sum0; nwords > 0; nwords--) sum += *p_word++;
/* if nbytes odd, add one byte of zero */ if (nbytes & 0x1) { word = 0; } else { /* add last byte */ word = net2hs(*p_word); word = word & 0xff00; /* clear lower 8bits */ } /* add first byte */ p_word = (uint16 *)(data - 1); word |= (net2hs(*p_word) & 0x00ff); /* clear upper 8 bits */ sum += hs2net(word);
sum = (sum >> 16) + (sum & 0xffff); /* add in carry */ sum = (sum >> 16) + (sum & 0xffff); /* maybe one more */ sum = ((sum >> 8) & 0x00ff) | (sum << 8); } else { p_word = (uint16 *)data; nwords = nbytes >> 1;
/* if nbytes odd, fill zero */ if (nbytes & 0x1) { word = net2hs(*p_word); word = (word >> 8) << 8; /* clear lower 8bits */ sum += hs2net(word); } sum = (sum >> 16) + (sum & 0xffff); /* add in carry */ sum = (sum >> 16) + (sum & 0xffff); /* maybe one more */ } }
sum = ~net2hs(sum);
return ((uint16)sum);}
いつもお世話になっています。
M3S-T4-Tiny でtelnetのサンプルなどはご存じないでしょうか?
telnetサンプルはないと思います。
telnetサーバ側でしょうか? クライアント側でしょうか?いずれもT4ライブラリのAPI(サーバ⇒tcp_acp_cep()、クライアント⇒tcp_con_cep())を使えばユーザアプリで実装できると思います。
サンプルで付属しているエコーサーバの待ち受けポートを23番に変更して、tcp_rcv_dat()で受信したデータをtcp_snd_dat()でオウム返ししているところを、受信データ解析して受信データに応じて処理してレスポンスをtcp_snd_dat()で送ることでtelnetサーバ的な動作を実現することはできると思います。
シェルティさん
いつもありがとうございます、
「tcp_snd_dat()でオウム返ししているところを、受信データ解析して受信データに応じて処理」ということでやってみます。
R20AN0314JJ0100サンプルでhttpもやりたいのですがhttpとDNSが関係しているのですがhttpのみ取り出して
もうしわけありませんマニュアルを読む前ですが、
R_httpd();とhttp_callbackだけを手当てしてやればよいのでしょうか?DNSも含めないといけないのでしょうか?
FTPの場合はR_ftp_srv_open();があったのですが、httpは無いようなので。
FTPは調子が良いです。
R_httpd();とhttp_callbackを手当てしてやってみると、
void R_httpd(void)でcase HTTPD_CLOSED:の
if(ercd != E_WBLK){でwhile (1);にはまります
なにが足りないのかな?
そこだけ違うCPUに抜き出してやっているので
マニュアル等は詳しいものはありませんでした。
もしかしたら、リアルタイムOS用のブロッキングコール用のソース?
ちょっと調べてみます
とりあえず、while (1);をreturn;にしてやりました、
下記回答します。
> R_httpd();とhttp_callbackだけを手当てしてやればよいのでしょうか?DNSも含めないといけないのでしょうか?
手当はもう少し必要です。DNSは不要です。
手当①:config_tcpudp.c の手当てconfig_tcpudp.c のTCP通信端点設定(tcp_ccep構造体)とTCP受付口(tcp_crep構造体)を見直しましょう。R20AN0314JJ0100のサンプルはRXマイコンの各種ボード用にWebサーバ、FTPサーバ、DNSクライアント、DHCPクライアントを実装したものですね。https://www.renesas.com/ja-jp/software/D6000403.html⇒RX65Nの発売に合わせて更新されたようです。
上記サンプルだと以下のようになっています。それぞれ1行1IDとなります。
通信端点IDは各APIの第1引数に、受付口IDはtcp_acp_cep()の第2引数に指定します。通信端点IDはシステム上複数動作しているアプリを識別するための番号、受付口IDはtcp_acp_cep()で待ち受けるポート番号を識別するための番号ですね。ゼロになっているところは未実装の設定フィールドです。例外として通信端点の1個目のメンバーでEtherのチャネル番号を指定できるようです。
たとえば、下記設定のシステムでtcp_acp_cep(5, 5, ...); と指定すると、21番ポートで待ち受けて、接続が完了するとftp_callback()が呼び出される、という寸法ですね。
T_TCP_CREP tcp_crep[] ={ { 0x0000, { 0, 21 }}, /* 受付口ID=1 */ { 0x0000, { 0, 20 }}, /* 受付口ID=2 */ { 0x0000, { 0, 21 }}, /* 受付口ID=3 */ { 0x0000, { 0, 20 }}, /* 受付口ID=4 */ { 0x0000, { 0, 21 }}, /* 受付口ID=5 */ { 0x0000, { 0, 20 }}, /* 受付口ID=6 */ { 0x0000, { 0, 80 }}, /* 受付口ID=7 */ { 0x0000, { 0, 80 }}, /* 受付口ID=8 */ { 0x0000, { 0, 80 }}, /* 受付口ID=9 */ { 0x0000, { 0, 80 }}, /* 受付口ID=10 */}
T_TCP_CCEP tcp_ccep[] ={ { 0, 0, 0, 0, 128, ftp_callback }, /* 通信端点ID=1 */ { 0, 0, 0, 0, 1460, ftp_data_callback }, /* 通信端点ID=2 */ { 0, 0, 0, 0, 128, ftp_callback }, /* 通信端点ID=3 */ { 0, 0, 0, 0, 1460, ftp_data_callback }, /* 通信端点ID=4 */ { 0, 0, 0, 0, 128, ftp_callback }, /* 通信端点ID=5 */ { 0, 0, 0, 0, 1460, ftp_data_callback }, /* 通信端点ID=6 */ { 0, 0, 0, 0, 1460, http_callback }, /* 通信端点ID=7 */ { 0, 0, 0, 0, 1460, http_callback }, /* 通信端点ID=8 */ { 0, 0, 0, 0, 1460, http_callback }, /* 通信端点ID=9 */ { 0, 0, 0, 0, 1460, http_callback }, /* 通信端点ID=10 */}
手当②:FTPサーバとWebサーバのコンフィグの手当て次にFTPサーバとWebサーバのコンフィグの手当てをします。コンフィグファイルは、r_t4_http_server_rx_config.h、r_t4_ftp_server_rx_config.hです。それぞれHTTP_START_TCP_CEP、FTP_START_TCP_CEPというのがあります。デフォルトだとどちらも"0"になっています。HTTP_START_TCP_CEPを6、FTP_START_TCP_CEPを0とすると良いでしょう。(通信端点は1からスタートなのに、FTPサーバとWebサーバの設定は0からスタート、混乱してしまいます)
> if(ercd != E_WBLK){でwhile (1);にはまりますなにが足りないのかな?
おそらくですが、FTPサーバとWebサーバとで同じ通信端点に対しtcp_acp_cep()を発行してしまい、E_QOVRが戻ってきているものと思われます。上記調整で解消するのではないでしょうか。
> もしかしたら、リアルタイムOS用のブロッキングコール用のソース?
これは今のところ関係ないと思います。
> とりあえず、while (1);をreturn;にしてやりました、
この対処だとウェブサーバは動作しないと思います。
助かりました、以下のように
const T_TCP_CCEP tcp_ccep[] =
{
//1.属性 ,
//2.送信ウィンドウの先頭アドレス,
//3.送信ウィンドウのサイズ,
//4.受信ウィンドウの先頭アドレス,
//5.受信ウィンドウのサイズ,
//6.コールバックルーチンアドレス(関数名)
// コールバック機能を使用しない場合には、NULL(=0)を設定
{ 0, 0, 0, 0, 128, ftp_callback },//ID=1 ->FTP_START_TCP_CEP 0
{ 0, 0, 0, 0, 1460, ftp_data_callback },//ID=2
{ 0, 0, 0, 0, 128, ftp_callback },//ID=3
{ 0, 0, 0, 0, 1460, ftp_data_callback },//ID=4
{ 0, 0, 0, 0, 128, ftp_callback },//ID=5
{ 0, 0, 0, 0, 1460, ftp_data_callback },//ID=6
{ 0, 0, 0, 0, 1460, http_callback },//ID=7 ->HTTP_START_TCP_CEP 6
{ 0, 0, 0, 0, 1460, http_callback },//ID=8
{ 0, 0, 0, 0, 1460, http_callback },//ID=9
{ 0, 0, 0, 0, 1460, http_callback },//ID=10
{ 0, 0, 0, 0, 128, t4_callback },//ID=11 ->TELNET_START_TCP_CEP 10
{ 0, 0, 0, 0, 128, t4_callback },//ID=12
{ 0, 0, 0, 0, 128, t4_callback },//ID=13
};
このようにしましたら、FTP、HTTP、TELNETで支障なくcallback を呼び出すことができました
引き続きやってみます。
お世話になります
t4_callback内のTFN_TCP_ACP_CEP:は確立済みと思いまして、tcp_snd_dat(cepid,をやってtelnetターミナル画面には文字が表示されます、その後case TFN_TCP_SND_DAT:からlen=(int)tcp_rcv_dat(を実行しますと、E_QOVR 、E_WBLK、E_WBLK等で受信に失敗します、アドバイスいただけませんか?
tcp_snd_dat(cepid,をやってtelnetターミナル画面には文字が表示されます、そこをbreak;しますとE_QOVR は出ません、後E_WBLKノンブロッキングコール受付ですがこれは何を意味するのか?
E_WBLK len=-83 E_WBLK len=-83 これは正常なt4_callbackでもこれを返すようです、正常であればデータ数を返すとなっていますがtelnetの画面はエコーしているのですが、tcp_rcv_datの返り値はE_WBLKです、送信の数値を見るとercdはrercd=1です、ということは返り値で判断せずrercdでデータ数を判断できるということのように理解したほうが良さそうです。
t4_callbackですが受信から始めないといけないみたいで、最初に、tcp_snd_dat(をやってしまいますとその後telnet応答しなくなります
tcp_rcv_datを先にしますと(telnetタミナル送信から)しますとその後やり取りができるようです、telnetの場合先にtcp_snd_datをやりたいのでこれをどうするか思案中です。
シェルティです、こんにちは。
> t4_callback内のTFN_TCP_ACP_CEP:は確立済みと思いまして、> tcp_snd_dat(cepid,をやってtelnetターミナル画面には文字が表示されます、> その後case TFN_TCP_SND_DAT:からlen=(int)tcp_rcv_dat(を実行しますと、> E_QOVR 、E_WBLK、E_WBLK等で受信に失敗します、アドバイスいただけませんか?
→続きのレスで解決しておられますね。 ご推察の通り、tcp_snd_dat()の後にbreak;が必要です。 1回のコールバックで発行できるAPIは通信端点毎に1個だけです。 なぜならば、このTCP/IPは同一通信端点に対しリクエストを キューイングできないからです。
> tcp_snd_dat(cepid,をやってtelnetターミナル画面には文字が表示されます、> そこをbreak;しますとE_QOVR は出ません、後E_WBLKノンブロッキングコール受付ですがこれは何を意味するのか?
→E_WBLKは「ノンブロッキングコールを受け付けた」という意味です。
> E_WBLK len=-83 E_WBLK len=-83 これは正常なt4_callbackでもこれを返すようです、> 正常であればデータ数を返すとなっていますがtelnetの画面はエコーしているのですが、> tcp_rcv_datの返り値はE_WBLKです、送信の数値を見るとercdはrercd=1です、> ということは返り値で判断せずrercdでデータ数を判断できるということのように理解したほうが良さそうです。
→ノンブロッキングコールの場合コールバック関数の第3引数のポインタの先に受信APIの実行結果(受信データ長)が入っています。 APIをノンブロッキングコールした瞬間はデータ受信はしておらず、先に説明した通り、 「ノンブロッキングコールを受け付けた」という意味のエラーコードE_WBLKが戻ってくるわけですね。 少し注意が要るのが、TCP/IPはストリーム型通信といってストリームの終わりはアプリが判断しないと いけないことです。これはTCP/IPに10バイト送れと命令してもTCP/IPや通信経路上の通信機器がその場の都合で データを分割することがあるためです。このため、アプリは希望するデータ長、または、使用するプロトコルで 規定された終了コードが来るまで受信データをバッファリングし、受信終了条件を満たすかどうかを 受信コールバック毎に判定する必要があります。 > t4_callbackですが受信から始めないといけないみたいで、最初に、> tcp_snd_dat(をやってしまいますとその後telnet応答しなくなります> tcp_rcv_datを先にしますと(telnetタミナル送信から)しますとその後やり取りができるようです、> telnetの場合先にtcp_snd_datをやりたいのでこれをどうするか思案中です。
→t4_callback()内に以下switch-caseをbreak;付きで用意しましょう。 これでmain()や他の通信端点と非同期に延々と通信を行う循環機構が完成します。 この骨組みを維持すればあとは送信データを加工したり、受信データに応じた処理をしたり、 自由に作れます。 TFN_TCP_ACP_CEP: tcp_snd_dat(...); break; TFN_TCP_SND_DAT: tcp_rcv_dat(...); break; TFN_TCP_RCV_DAT: tcp_cls_cep(...); break; TFN_TCP_CLS_CEP: tcp_acp_cep(...); break;
接続完了コールバック(TFN_TCP_ACP_CEP)→送信(tcp_snd_dat)→ 送信完了コールバック(TFN_TCP_SND_DAT)→受信(tcp_rcv_dat)→ 受信完了コールバック(TFN_TCP_RCV_DAT)→切断(tcp_cls_cep)→ 切断完了コールバック(TFN_TCP_CLS_CEP)→接続待ち(tcp_acp_cep)→ <繰り返し>
先に述べた受信のバッファリングは今後手当していってください。 ウェブサーバのコードがこのあたりのバッファリングをどのようにしているか 参考にできると思います。 以上です
いつもお世話になります
いろいろやりました、一つのことが課題でして
tcp_snd_datと tcp_rcv_datはcallbackの中で使用可能ということで
このことはtcp_snd_datのすぐ後にtcp_rcv_datする
tcp_rcv_datのすぐ後にtcp_snd_datということで良くわかります
tcp_snd_datで1Byte送信これを続けさまに発信するなどうまくいきます
tcp_rcv_datの場合は相手方がデータが入らない場合は無理です
ということでcallbackの中で全てを処理すれば
telnetは即可能であると感じています
ただtelnetを構成する場合、
現在使用しているインタープリタに結合させたいと思っています
telnetから入力したコマンドラインをインタープリタに送信して
インタープリタから出力される文字列をtelnetに出力したいと思います
この場合callback外の箇所からtelnet送信を起動しないといけません
uIPの場合ですと、パケットがなくてもcallbackが常に一定間隔で呼ばれており
その呼ばれたタイミングでデータがある場合はtelnetに出力できます
t4ですとcallbackイベントがないと飛んできません
外部からtelnet出力を起動できますでしょうか?
インタープリタをcallback中に作りこめばできることはわかりますが、
そうなるとソフト作成が大変なことになるので
アドバイスでもいただけましたら、幸いです。
httpサーバーの方は画面が一応出ました、ファイルリストがブラウザーに表示されました、とりあえずご報告まで。