2015年12月13日日曜日

Ether ShieldのW5100をSTM8Sから動かしてみる (3)UDP受信

W5100を動かしてみるトライはそれなりに苦心しまして、ようやくUDPが動きました.判ってしまえばW5100を動かすのは意外に簡単でした.

当初はSocketが全然判らないので、PCやLinuxのSocketプログラムについての書籍はチラチラと読みました.Socketのあらましについて理解できたところで、W5100をUDPで動かすぶんにはsocketの知識はあまり必要ではありませんでした.W5100のdatasheetに解説されている手続きどおりにダラーッとcodingすりゃUDPぐらいなら動ごかせそうです.というかそれで動いた.

以下は、windowsが送信したUDP packetを、W5100が受信する動作を実現するものです.
ソースコードの入ったLinuxのフォルダをzipにしてこちらに置きました.
http://yahoo.jp/box/uamBA5
この情報であなたが損害を受けてもわたしは責任を負いません.

【ハードウエア】
・W5100は、arduinoのEternet shield V5を使用.Ethernet shieldの詳細はこちらを参照.
・CPUは、STM8Sを使用.UARTでPCに接続する.
・STM8S---W5100はSPIで接続する.SPI信号はこの4本です.
【開発ツール】
・開発マシンはLinux.
・STM8Sのクロスコンパイラとして、Linux上で動くsdccを使う.sdccインストールはこちらを参照.
・STM8S FLASH焼きは、Linux上で動くstm8flashを使う.

【デバッグ環境】
・家庭内LANを使う.(もちろん有線LAN)
・windows7のipsendwinからUDP packetを送信する.
・W5100で同packetを受信する.
・W5100のUDP受信データを、UART経由でwindowsマシンへ送る.
・windowsはtera termでUARTデータを受信し表示する.
・想定どおりに表示されたらよかよか

-----
【W5100の感想】
W5100はハードウエアだけでTCP,UDP,PPPOEなどのプロトコルを処理してくれます.
なので、CPUを搭載してません.
なので、SPI越しのSTM8Sから見えるW5100は、純粋にレジスタとして見えます.
CPUの処理負担が少ないので8bit CPUでも大丈夫です.
W5100にはSocketが0-3の4つ内蔵されているので、同時に4つの送受信ができます.

W5100のレジスタは、
・W5100のIPやMACアドレスを収蔵するための、0~30H番地までのレジスタ群と、
・Socket0-3の相手IPなどを収蔵するための、レジスタ群があります.
    400H~  Socket0
    500H~  Socket1
    600H~  Socket2
    700H~  Socket3

W5100の送受信バッファは、
    送信バッファ 4000~5FFFH  (8kBYTE)
    受信バッファ 6000~7FFFH  (8kBYTE)
と在りますが.これらを4つのSocketで分けあって使うのでアドレッシングは要注意です.

W5100の送受信バッファはSocket0~順に割り振られますが、各Socketに割り当てるサイズを1k, 2k, 4k, 8kBYTEからセレクトできます.なので、この割り当てサイズによって、各Socketのバッファの先頭アドレスが変動します.地道に計算するしかありませんが、わたしはめんどくさいので、全部等しく2kBYTEに割り振って、次のように決め打ちしました.
    4000H Socket 0 TX buffer (2kBYTE)
    4800H Socket 1 TX buffer (2kBYTE)
    5000H Socket 2 TX buffer (2kBYTE)
    5800H Socket 3 TX buffer (2kBYTE)
    6000H Socket 0 RX buffer (2kBYTE)
    6800H Socket 1 RX buffer (2kBYTE)
    7000H Socket 2 RX buffer (2kBYTE)
    7800H Socket 3 RX buffer (2kBYTE)

W5100の送受信バッファのアドレッシングにはもう一つ要注意があります.
USBでは、どんなに小さいサイズのpacketでも、1つのpacketを受信したらFIFOがそれで満杯になってしまい、あまりにも矢継ぎ早にpacket送信するとFIFOが便秘になります.
一方で、W5100の送受信バッファの特徴はこうです(W5100のというよりもEthernetコントローラ全般に同様と思います)
    1) リングバッファである
    2) ひたすらpacketをバッファにブタ積みしつづける
    3) ゆえにリングバッファのポインタがある
バッファ領域を踏み外すと隣のSocketを踏み荒らしてしまうので、リングバッファと成すためにアドレッシングにケアが必要です.

【ソースコード】
ソースコードのzipを解凍するといろいろなファイルが出てきます.
・stm8s_xxxx.x というファイルは、ST社が提供するSTM8S用のライブラリ
・usrlib-spi-w5100.x というファイルは、SPIでW5100のレジスタを読み書きするサブルーチン
・usrlib-uart.x というファイルは、STM8SがPCとUARTで通信するサブルーチン

以上はW5100とはあまり関係の無いファイルです.

W5100とモロに関係のあるのは、
  w5100.h
  w5100.c
  main.c
です.

(w5100.h)
・w5100.hの上の方では、W5100のレジスタ関係の定義をやっています.
・最後の方にはレジスタアクセスサブルーチンを宣言しています.setXXX()とgetXXX()はそれぞれがXXXというレジスタに書くか(set)、読むか(get)です.SOCKET sにはソケット番号0~3を代入します.main.cでs=0に決めています.

(w5100.c)
・ひたすら、setXXXとgetXXXを機械的に書いています.一部しか動作確認してないのでバグってるかもしれない.

(main.c)
ここは重要箇所です.

まず、レジスタの初期設定ですが、たったのこれだけと云ってよいでしょう.ここでsetXX()はレジスタXXに値を書くだけのルーチン.getXX()はレジスタから値を読むルーチン.ゆえに大したことはやっていない.
雰囲気的には、こんなかんじ.
 1) レジスタにIPやMACをセットし、UDPモードにセットし、GO!するのみ
 2) データ到着はポーリングまたは割り込みで気付く
 3) データはリングバッファで出し入れする
  // common registers
  setMR(0x80);    // (0) w5100 reset
  ip[0] = 192; ip[1] = 168; ip[2] = 1; ip[3] = 1;
  setGAR( ip );   // (1-4) gateway address
  ip[0] = 255;ip[1] = 255;ip[2] = 255;ip[3] = 0;
  setSUBR( ip );  // (5-8) subnet address
  ip[0]=0x00; ip[1]=0x08; ip[2]=0xDC; ip[3]=0x00; ip[4]=0x00;
  ip[5]=0x4F;
  setSHAR( ip );  // (9-e)  MAC address
  ip[0] = 192; ip[1] = 168; ip[2] = 1; ip[3] = 100;
  setSIPR( ip );  // (f-12)  IP address
  setIR(0);       // (15) no interrupt
  setIMR(0);      // (16) no interrupt
  setRMSR(0x55);  // (1A) read buf 2kB each
  setTMSR(0x55);  // (1B) send buf 2kB each
  
  // set socket registers for UDP
  setSn_MR(s,Sn_MR_UDP);  // (400)  UDP mode
  setSn_IR(s,0);          // (402) no interrupt
  ip[0]=0x30; ip[1]=0x39; //  PORT number 12345-->0x3039
  setSn_PORT(s,ip);       // (404-405)
  setSn_CR(s,Sn_CR_OPEN); // (401)  socket open command
  r=getSn_SR(s);          // (403) status
  while(r!=SOCK_UDP){}    // wait to be UDP

初期設定のキモの部分は①~⑤くらいかと思います.
①IPを192.168.1.100に設定していますが、これがW5100の自機IP(任意)です.
②MACを00:08:DC:00:00:4Fに設定していますが、これがW5100の自機MACアドレス(任意)です.MACアドレスは好き勝手に名乗れないはずですから、このように好き勝手に決めてしまって良いはずがありませんが、好き勝手に設定しちゃいます.LAN内に同じMACの機器が在る確率は少ないだろう.
③W5100のSocket0はport番号0x3039=12345であんぐりと口を開けて待ちます.
④UDPモードに設定
⑤socket0をオープン

次に、STM8Sのmain loopで、UDP受信データをポーリングする部分です.今回は割り込みは使いませんでした.UDP受信データを受信バッファから取り出してUARTへ表示しています.
  if(getSn_RX_RSR(s)!=0)  //  w5100 UDP data polling
 {
   // RX buffer addressing
   size = getSn_RX_RSR(s) & bMUSK; //  RX data size
   offset = getSn_RX_RD(s) & bMUSK; //  buffer pointer
   adrs = bRX(s)+offset; 

   // display UDP data
     中略
   for(i=8;i<size;i++)
    {
      adrs = bRXA(s,bRX(s)+offset+i); 
      r = w51RD(adrs); 
      sprintf(UARTstrTX,"%c", r<32?32:r);
      SerialPutString(UARTstrTX);
    }

   adrs = getSn_RX_RD(s)+size; //  update RX buffer pointer
   setSn_RX_RD(s,adrs); 

   setSn_CR(s,Sn_CR_RECV);   //  UDP recieving mode
 }

⑥受信データがあるとこのレジスタが非ゼロになります
⑦受信データサイズを得て、上位桁無視のため2kB(0x7FF)でANDしておきます
⑧受信バッファのポインタです.これも上位桁を無視します
⑨bRX(s)は受信バッファ先頭アドレスなので、ポインタ値を加算してリアルアドレスを得ます
⑩リアルアドレスを++したら、リングバッファを意識したアドレス補正計算をしないと他のSocketバッファにはみ出してしまいます.はみ出し防止計算がbRXA()です
⑪w51RD()はW5100から1バイト読みます
⑫次のpacket受信準備のため、受信バッファポインタを進めます
⑬進めた受信バッファポインタを書き込みます  (ここはなぜか手動なんですね)
⑭次のpacket受信準備のため、RECIEVEコマンドをW5100に与えます

以上、UDPの受信動作を実現するためのW5100の操作でした.TCPだと再送処理とかで2倍ぐらい複雑になりますが、UDPは送りっぱなしなんで意外と簡単です.

【動かし方】
sdcc及びstm8flashがインストールされたLinuxマシンで、
 make
すればコンパイルが完了します.
LinuxマシンのUSBに、ST-LINX/V2を接続し、SWIMでSTM8Sを接続し、
 make flash
すればFLASHを焼けます.
このへんの詳細はこちらです.

STM8SのUARTをwindowsマシンに接続し、teratermでシリアル接続します.

W5100のEthernetに家庭内LANを接続します.

windowsマシンでipsendwinを起動.
ipsendwinを以下のように設定.
ipsendwinの送信ボタンを押す.
←192.168.1.100
←ターゲットポート12345
←お好みでどうぞ
すると、teraterm画面に、W5100が受信したUDPデータがこのように表示されます.
[w5100 recv reg] BYTE=102 0066 offset=1e bufadrs=601e
[UDP recv headder] IP 192.168.1.3 PORT 12345 data size 94 BYTEs
@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
next offset 4884
3行目の文字列は、ipsendwinでお好みで設定したPAYLOADデータです.

以上で、UDP packetの送出→W5100で受信→STM8S→teraterm端末 まで通りました.

#192.168.1.100は家庭内LANのルータに明示的に登録しないとダメなのかと思っておりましたが、やってみたところそのような手順は不要でした.いきなり繋いだだけでLANに192.168.1.100が存在しています.

2へ  4へ

かしこ


=== STMのアフィリエイト始めました ===
STM32のwelcome-kitです
        
試用レポはいずれまた...

6 件のコメント:

  1. トロージャンを拾ってしまいました。(今流行の分らしいです)
    ブラウザから乗っ取り身代金の脅迫が・・ネットを切って別のPCで方策を検討影響は2日ほど有りました。
    有名どころの対策では一向に駆除できず。
    avira_free_antivirus_jp.exe dmw.exe TR/BitCoinMiner.Gen の報告
    NSD_3D_22.5.2_SYMTB_PROMO_4_MRFTT_13682-JP-JP.exe Trojan.Gen.2 の報告
    カスペル君は試さず以下無反応
    McAfeeSetup-AutoLogin.exe
    avast

    C:\Users\troj3\AppData\Local\Temp\msupdate71\dmw.exe 
    ↑これがトロージャン
    消しても消しても再生します。
    dds.com
    ComboFix.exe
    Defogger.exe
    rkill.com
    4つを連続して通すと消えてくれ、(プログラム追跡型検知?)
    \msupdate71 そのものもイリュージョンでした。
    ノートン君が2つのファイルを報告 これを処理して、終結しました。

    返信削除
    返信
    1. vvvとかいうウイルス?が流行中だそうですね.ウイルス駆除は一つのソフトだと察知できなかったりといろいろあるようです・

      わたしの興味は、ウイルスに感染したexeファイルを無毒化することって出来ないのかなぁ、ということです.現状のウイルス駆除はexeファイル丸ごと削除のようですからそれだとなんかまいちではないかと.

      削除
    2. https://www.microsoft.com/ja-jp/security/pc-security/mse.aspx
      いちおうMSのこれをやってますけど、どれだけ効くのか?

      削除
    3. https://www.virustotal.com/
      個別のファイルのウイルスチェックはこれを使っております.

      削除
  2. ウイルスに感染したexeファイル は見つけられれば、削除できます。
    問題は悪さをする感染したファイルと別にそれを作るソフト郡があることです。
    作り出し行程をトレースしてその元を削除すると良いんですが、いつ作動し始めるか判らないのが怖い点です。

    返信削除
  3. 暗号化ファイル システム (EFS) の証明書
    と言うのに出くわす。
    立ち上げたら出て証明書にパスワードを付けて保存するらしい。
    そもそも頼んでいないのに、移動先が暗号化圧縮ホルダであったらしい。
    http://07.net/EFS/

    返信削除