2015年12月17日木曜日

Ether ShieldのW5100をSTM8Sから動かしてみる (4)UDP全二重

ソケットって、全二重(full duplex)で動くんでしょうか?という素朴な疑問を抱いています.

Linuxやwindowsのsocket()recv()send()を利用するぶんには、APIから見たら全二重っぽく見えるのはもちろんそうでしょうが、回路としてのソケットは半二重なんだけどソフトで全二重に見せかけているのかなぁなどという疑問.
 (A)単一ソケットで送受信できるならソケットは全二重
 (B)ソケット0を送信専用、ソケット1を受信専用に設定せないかんならソケットは非全二重
ちなみにEthernet cableは全二重構造になっているらしい.10M/100Mの信号はcableを全二重で利用しているらしい.1000Mでもそうなのかは知らない.

それでW5100のソケットを弄ってみたら、
ソケットというものは、回路として全二重で動くみたいだ
というのが結論です.なかなか便利に作ってあるもんですね.

----
以下、ソースコードについて.(エラー処理とか一切やってません)

W5100はTCP,UDPなどのプロトコル処理をお任せでやってくれるので、ユーザー(CPU)がやる仕事は次の3つでだいたい事足ります.
 1)レジスタを初期設定する
 2)受信処理をする (受信バッファから読む)
 3)送信処理をする (送信バッファへ積む)
下記を見るとわかるように、送受信バッファのアクセス以外には、W5100の取り扱いに関与する操作としてはポインタ計算+αぐらいしかやっていませんので楽チン.

1)レジスタに初期設定をする
上半分が自機のIPやMACの設定.(割り込みは使ってない)
ここでは、自機IPを 192.168.1.100 ポート12345 に仮決めしてあります.
下半分がソケット0の設定で、相手のIPやPORTを設定.(ソケット1,2,3は放置プレイ)
ここでは、パケットの送り先を 192.168.1.5 ポート12345 に仮決めしてあります.
(上半分)
  // common registers
  // gateway address
  ip[0] = 192; ip[1] = 168; ip[2] = 1; ip[3] = 1;
  setGAR( ip );   // (1-4)
  // subnet address
  ip[0] = 255;ip[1] = 255;ip[2] = 255;ip[3] = 0;
  setSUBR( ip );  // (5-8)
  // MAC address   自機のMAC
  ip[0]=0x00; ip[1]=0x08; ip[2]=0xDC; ip[3]=0x00; ip[4]=0x00;
  ip[5]=0x4F;
  setSHAR( ip );  // (9-e)
  // IP address  自機のIPアドレス
  ip[0] = 192; ip[1] = 168; ip[2] = 1; ip[3] = 100;
  setSIPR( ip );  // (f-12)
  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 0 registers for UDP   UDPモード
  setSn_MR(s,Sn_MR_UDP);  // (400) UDP mode
  setSn_IR(s,0);          // (402) no interrupt
  // source PORT number 12345-->0x3039  自機PORT番号
  ip[0]=0x30; ip[1]=0x39;
  setSn_PORT(s,ip);       // (404-405)
  // destination IP  相手のIPアドレス
  ip[0] = 192; ip[1] = 168; ip[2] = 1; ip[3] = 5;
  setSn_DIPR(s,ip);
  // destination PORT number 12345-->0x3039  相手のPORT番号
  ip[0]=0x30; ip[1]=0x39;
  setSn_DPORT(s,ip);
  // open socket 0   ソケットOPEN
  setSn_CR(s,Sn_CR_OPEN); // (401) socket open command
  while(getSn_SR(s)!=SOCK_UDP){}    // wait UDP
  sprintf(UARTstrTX,"=====W5100 Socket#%d UDP start=====\r\n", s);

2)ソケット0の受信処理をする (受信バッファから読む)
void UDP_recv(void)
{
  r=getSn_RX_RSR(s);  UDP受信データバイト数を示すレジスタを読む

  if(r!=0) UDP受信データ在りなら以下を実行
    {
      // 受信バッファポインタを計算する
      size = getSn_RX_RSR(s) & bMUSK; // RX data size
      offset = getSn_RX_RD(s) & bMUSK; // buffer pointer
      adrs = bRX(s)+offset;

        中略      
      for(i=8;i<size;i++)  受信バッファを読んでUARTに出力する
        {
          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;  受信バッファポインタを進める
      setSn_RX_RD(s,adrs);

      setSn_CR(s,Sn_CR_RECV);  W5100の受信動作をkickoff
    }
}

3)送信処理をする (送信バッファへ積む)
STM8Sのタイマ3割り込みで1秒毎に送信するようにkickされるようになっていまして、SOCKET_SEND_DATA_EXIST=1にセットされます.(タイマ3割り込みルーチン内で送信するのはSPIバスが不具合になるのでやめました)
void UDP_send(void){
  if(SOCKET_SEND_DATA_EXIST==1)  送信データがあれば以下を実行
    {
      freeb = getSn_TX_FSR(s); 送信バッファの空き
      sr = getSn_SR(s);  UDPモードかどうかをチェック
      if(freeb>=100 && sr==SOCK_UDP) 送信バッファの空きチェック
    {
        // 送信バッファポインタを計算する
        offset = getSn_TX_WR(s) & bMUSK; // TX buffer pointer

        // なんでもよいが送信データを用意する
        sprintf(UARTstrTX,"TIM3 int %04d   free%04x SR%02x 
          offset%04x\r\n",
                tim3cnt,
                freeb,
                sr,
                offset);
        size = strlen(UARTstrTX);

        for(i=0;i<size;i++){ 送信バッファへコピる
          adrs = bTXA(s,bTX(s)+offset+i);
          w51WR(adrs,UARTstrTX[i]);
        }

        adrs = getSn_TX_WR(s)+size; 送信バッファポインタを進める
        setSn_TX_WR(s,adrs);

        setSn_CR(s,Sn_CR_SEND);  送信コマンド
        while(getSn_CR(s)!=0){} // wait send ending
      }
      SOCKET_SEND_DATA_EXIST=0;
    }
}


ハードウエア
連載3回目ではこのようにSPIを接続しましたが、
今回からはSTM8SがW5100をリセットできるようにRESET線を一本追加しました.
STM8S 24pin PE6 → W5100 59pin RESET

使い方
(2)UDPパケット受信
本機を家庭内LANに接続し、外部から本機192.168.1.100 ポート12345に向けてUDPモードで送信すると、本機が受信した内容をUARTに出力します.packet発生にはipsendwinでも使ってください.
(3)UDPパケット送信
本機は1秒ごとにUDPpacketを送信します.宛先は、192.168.1.5 ポート12345です.192.168.1.5マシンでpacket monitor toolで観測すりゃUDP packetが毎秒来てるのがわかります.
←この写真はEther未接続だorz

Linuxのsdccでコンパイルするソースフォルダはここです.エラー処理とか一切してません.
コンパイル方法などは連載3を参照のこと.
このソースによりリーダーやメンバーが捕えられ、或いは殺されても当局は一切関知しないのでそのつもりで.

3へ   5へ

かしこ

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

7 件のコメント:

  1. かしこい応用、500円台の音波歯ブラシ半年ほど同じ単4電池使っても周波数もパワーも余り落ちてきません。
    しかし換えブラシとの嵌め合いがツイストロック(バヨネット本来は銃剣)の所が回転微動摩耗で細くなり一気に緩んでしまいました。
    値段からこんな物と思って、取り替え中を見てみますとスマホバイブレータとSWが入っていまして、すばらしいアイデアです。
    以前日本鉋に同じ事をしてみたらすばらしく切れました。(取り付けが不細工でした)
    今度はこの歯ブラシを取り付けてみようと思っています。

    返信削除
    返信
    1. 画像です
      http://blog-imgs-86.fc2.com/y/o/k/yokirimaru/sDSCF9102.jpg
      http://blog-imgs-86.fc2.com/y/o/k/yokirimaru/sDSCF9105.jpg

      削除
    2. ケータイの振動モータでしょうか? さもなくば結構貧弱?

      削除
    3. PRO SONIC 1 を見つけて 買ってしまいました。380円
      内容はほとんど同じ、(バイブロモータ)
      ボデーの肩の所が少し太く、太めのブラシが山切りカット、
      PRO SONIC 2 の極細は歯茎に突き刺さるので此方を試してみます。

      削除
  2. あきれた対応
    http://www.dell.com/support/article/jp/ja/jpbsd1/SLN2419

    「"バッテリーをバッテリを長持ちさせる"意味は2つ有ります。
    1, ACに繋がず モバイル用途で長く使用する。
    2, ACに繋いだまま、停電時のバックアップに使い、長い期間バッテリーの活性状態を保つ。
    ですが、御社の方針は1,のみにしか対応していません。
    Dell Command | Power Manager
    ユーザーガイドの内容も同じです。
    2の用途では 高度な充電に近く見えますが、全く内容は適切ではありません。(ピークシフトが電力事情考慮であるなら消費が少ないので問題有りません)
    一番対応してほしいのは、任意の充電開始容量 と 任意の充電停止容量を設定できるだけでよいのです。
    このようにしますと最低容量(例えば50%)最高容量(例えば80%)の間を保ち、自然放電で規定最低容量より下がったら充電、規定最高容量で充電停止としたいのです。
    これですと充放電サイクル数が減り、過放電(導電チャネルの消失)、過充電(電極の金属析出応力破壊)もなくなります。(バッテリーの交換が少なくなって御社は儲からないかも知れませんが)。
    容量と充電電圧には密接な関係(履歴的電圧変化もあります)が御社の技術で問題なく解決できると考えています。
    それではよろしくお願いします。」

    ここにフィードバックを書いて送ろうとしたら、
    キャプチャーコードの入力 視覚と聴き取り共に違う内容で記入しても弾かれてしまいます。
    きっと聞きたくないのでしょうか?

    返信削除
    返信
    1. Li-ionの非満充電と非空っぽの間を往復できたらいいですね.

      削除
    2. 今日はちゃんと文字と音声が一致していて、フイードバックできました。何でだろ?
      それとフォルダのアクセス権ワケワカメだったのが適切なアドバイスを戴いて解決しました。
      http://answers.microsoft.com/ja-jp/windows/forum/windows_7-security/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%84/517e3316-eded-462e-af9a-60e87b4db69c?msgId=090b25c3-f1b3-4f5b-afbf-0c9c1a112303

      削除