Arduinoと有線LANで通信する(ENC28J60 2)

前回は、ENC28J60チップを使って、Raspberryがサーバー、 Arduinoがクライアントの動作を試してみました。
そこで、今回はRaspberryがクライアント、Arduinoがサーバーの動作を試してみます。

【Arduino側】

Arduino側のスケッチは以下の通りです。
クライアントから受信した文字列を大文字に変換して送り返す単純なものです。
DHCPでのIPアドレス取得で失敗することがあるので、IPアドレスが取得できるまでリトライしています。

/*
 * ENC28J60 Ethernet Module TcpServer example.
 */

#include <UIPEthernet.h>

EthernetServer server = EthernetServer(9876);

void EthernetBegin() {
  uint8_t mac[6] = {0x00,0x01,0x02,0x03,0x04,0x05};

  while(1) {
    Serial.print("begin....");
    int Ret = Ethernet.begin(mac);
    Serial.print(Ret);
    Serial.print("...");
    if (Ret) {
      Serial.println("ok....");
      Serial.print("localIP: ");
      Serial.println(Ethernet.localIP());
      Serial.print("subnetMask: ");
      Serial.println(Ethernet.subnetMask());
      Serial.print("gatewayIP: ");
      Serial.println(Ethernet.gatewayIP());
      Serial.print("dnsServerIP: ");
      Serial.println(Ethernet.dnsServerIP());
      break;
    } // end if
    Serial.println("faild....");
    delay(1000);
  } // end while
}

void setup()
{
  Serial.begin(9600);
  EthernetBegin();
  server.begin();
  Serial.println("Server Start");
}

void loop()
{
  size_t size;
 
  if (EthernetClient client = server.available()) {
    while((size = client.available()) > 0) {
      size = client.available();
      Serial.print("Receive size=");
      Serial.print(size);
      Serial.print(" Receive=[");
      uint8_t* rmsg = (uint8_t*)malloc(size);
      char* smsg = (char*)malloc(size);
      memset(smsg,0,sizeof(smsg));
      size = client.read(rmsg,size);
      Serial.write(rmsg,size);
      for (int i=0; i< size; i++){
       if(isalpha(rmsg[i])) {
         smsg[i] = toupper(rmsg[i]);
       } else {
         smsg[i] = rmsg[i];
       }
      }
      free(rmsg);
      Serial.println("]");
      client.write(smsg,size);
      free(smsg);
    } // end while
    client.stop();
  }
}

このスケッチを実行するとArduinoのシリアルモニターに以下が表示されます。



なお、IPアドレスを固定にする場合は、以下の様にIPアドレスを指定します。


#include <UIPEthernet.h>

EthernetServer server = EthernetServer(9876);

void EthernetBegin() {
  uint8_t mac[6] = {0x00,0x01,0x02,0x03,0x04,0x05};

  while(1) {
    Serial.print("begin....");
    IPAddress myIP(192,168,111,50);
    int Ret = Ethernet.begin(mac,myIP);
    Serial.print(Ret);
    Serial.print("...");
    if (Ret) {
      Serial.println("ok....");
      Serial.print("localIP: ");
      Serial.println(Ethernet.localIP());
      Serial.print("subnetMask: ");
      Serial.println(Ethernet.subnetMask());
      Serial.print("gatewayIP: ");
      Serial.println(Ethernet.gatewayIP());
      Serial.print("dnsServerIP: ");
      Serial.println(Ethernet.dnsServerIP());
      break;
    }
    Serial.println("faild....");
    delay(1000);
  } // end while
}

  {後略}

【Raspberry側】

以下のコード(client.c)をコンパイルして実行します。
サーバー側が止まっているなどで、Connectできないときはリトライします。
コンパイルは単純に「cc client.c」で、実行は「./a.out」です。

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <time.h>
#include <limits.h>

int retryTotal=0;

#define PORT 9876 //サーバープログラムとポート番号を合わせてください

int connect2(struct sockaddr_in * dstAddr, int dstAddrLen) {
  int dstSocket;
  int retry = 0;
  int retryMax = 10;
  time_t start_time, end_time;
  double dtime;

  while (1) {
    //ソケットの生成
    dstSocket = socket(AF_INET, SOCK_STREAM, 0);
 
    //接続
    write(1,"Connecting...",13);
    time( &start_time );
    if (connect(dstSocket, (struct sockaddr *)dstAddr, dstAddrLen) == 0) return(dstSocket);
    time( &end_time );
    dtime=difftime( end_time, start_time );
    retry++;
    printf("接続できませんでした retry=%d difftime=%f\n",retry,dtime);
    retryTotal++;
    close(dstSocket);
    if (retry > retryMax) return(-1);
    sleep(10);
  }
}

int main(int argc, char **argv){
  // IP アドレス,ソケット,sockaddr_in 構造体
  char destination[32];
  int dstSocket;
  struct sockaddr_in dstAddr;

  //struct sockaddr_in addr;
  struct hostent *hp;
  char  buf[1024];
  int number = 0;
  int numrcv;
  int retry = 0;
  int loopMax;
  int loopCnt;

  time_t start_time=0, end_time;
  double dtime;

  loopMax=INT_MAX;
  if (argc == 2) {
    loopMax=atoi(argv[1]);
  }
  // 相手先アドレスの入力と送る文字の入力
  printf("サーバーマシンのIPは?:");
  scanf("%s", destination);
 
  //sockaddr_in 構造体のセット
  bzero((char *)&dstAddr, sizeof(dstAddr));
  dstAddr.sin_family = AF_INET;
  dstAddr.sin_port = htons(PORT);
 
  hp = gethostbyname(destination);
  bcopy(hp->h_addr, &dstAddr.sin_addr, hp->h_length);

  for(loopCnt=0;loopCnt<loopMax;loopCnt++) {
//  while (0) {
    dstSocket = connect2(&dstAddr, sizeof(dstAddr));
    printf("dstSocket=%d\n",dstSocket);
    if (dstSocket < 0) {
      printf("%s に接続できませんでした\n",destination);
      return(-1);
    }
    printf("%s に接続しました\n",destination);
    if (start_time == 0) time( &start_time );
 
    memset(buf,0,sizeof(buf));
    sprintf(buf,"data from raspberry %05d",number);
    number++;
    printf("Send=[%s]",buf);
    //パケットの送信
    write(dstSocket, buf, strlen(buf));
    //パケットの受信
    memset(buf,0,sizeof(buf));
    numrcv = read(dstSocket, buf, 1024);
    printf("→Recv=[%s]\n",buf);
    close(dstSocket);
    sleep(5);
  } // end for
  time( &end_time );
  dtime=difftime( end_time, start_time );
  printf("loop=%d difftime=%f[sec] %f[min] retry=%d\n",loopMax,dtime,dtime/60,retryTotal);
  return(0);
}

実行するとサーバーのIPアドレスを聞いてきますので、ArduinoのIPアドレスを入力します。




Raspberryから送った「data from raspberry」の文字が「DATA FROM RASPBERRY」となって返ってきます。



Arduino側は以下の様に表示されます。



Raspberryがサーバー、 Arduinoがクライアントの動作と、
Raspberryがクライアント、Arduinoがサーバーの動作を試しましたが、
どちらがどちらが高速に動作するかパフォーマンスを比較してみます。

続く...