質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.48%

H8/3067を使用したパケット送受信処理について

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 1,576

score 39

「H8マイコンによるネットワーク・プログラミング」(技術評論社)に記載してある
「4.4 ARP」のリストex4_2.cのコードについての質問です。

前提条件として、使用しているマイコンはH8/3067、パケット送受信のインターフェースはRTL8019AS、
使用している言語はC言語です。

今回動作させようとしているプログラムは、マイコンからPCにARPリクエストを送信し、
PCからARPリプライが返って来た時に、ARPリプライからPCのMACアドレスを取得し、
マイコン基板のLCDに表示させるものです。
本に記載されているコードは、ex4_2.cのように、global_vabiables.hに定義されたグローバル変数packetを、
ARPリクエストを行う関数(ARP_request)、パケットの受信を行う関数(packet_receive)に渡しています。
ここで、ARP_request、packet_receive関数に渡す引数を、main関数内でローカルに定義したsend_ch、rcv_chを
引数として渡すようコードを変更すると、ARPリプライが返ってこなくなります。
ARP_requestでは、引数にパケット送信のデータを格納、packet_receive内では引数に受信データを格納しているだけ
なので、引数をグローバル変数にする必要はなさそうに見えますが、ローカル変数に変えると予想通りの動作をしなくなる
理由が分からず困っています。
分かる方おられましたら、御回答お願い致します。

/* global_variables.h */
unsigned char src_IP[4]; /* 送信元IPアドレス */
unsigned char src_MAC[6]; /* 送信元MACアドレス */
unsigned char dst_IP[4]; /* 宛先IPアドレス */
unsigned char dst_MAC[6]; /* 宛先MACアドレス */
unsigned char packet[256]; /* 受信パケットのデータ */
/* ex4_2.c(本に記載してあるコード) */
#include "H8_register.h" /* H8/3067のレジスタ */
#include "RTL8019AS_register.h" /* RTL8019ASのレジスタ */
#include "packet_definition.h" /* パケットの定義 */
#include "global_variables.h" /* グローバル変数の定義 */
#include "H8_register_function.h" /* H8/3067のレジスタの設定 */
#include "delay_function.h" /* 時間待ちの関数 */
#include "LCD_function.h" /* SC1602Bの関数 */
#include "NIC_function.h" /* RTL8019ASの関数 */
#include "matrix_key_function.h" /* マトリクス・キーの関数 */
#include "utility_function.h" /* そのほかの関数 */
#include "ARP_function.h" /* ARPの関数 */

void main(void)
{
   unsigned short i;
   unsigned char packet_type;
   char str_IP[16];
   char str_MAC[13];
   ARP_PACKET *arp_packet;

   H8_register_init(); /* H8/3067のレジスタの設定 */
   LCD_init(); /* SC1602Bの初期化 */
   NIC_init(); /* RTL8019ASの初期化 */

   /* 送信元IPアドレスの設定 */
   src_IP[0] = 192;
   src_IP[1] = 168;
   src_IP[2] = 0;
   src_IP[3] = 100 + (P2DR & 0x07); /* ディップ・スイッチによって送信元IPアドレスを設定する */

   /* 宛先IPアドレスの設定 */
   dst_IP[0] = 192;
   dst_IP[1] = 168;
   dst_IP[2] = 0;
   dst_IP[3] = 2;

   LCD_clear(); /* 表示クリア */

   LCD_control(0x80); /* カーソルを0行目の先頭に移動する */
   IP_to_str(dst_IP, str_IP); /* dst_IPをstr_IP(文字列)に変換する */
   LCD_print(str_IP); /* 液晶ディスプレイにstr_IPを表示する */

   delay_ms(2000); /* 2000ms(2秒)の時間待ち */

   ARP_request(packet); /* ARPリクエスト */

   packet_type = 0; /* packet_typeを0にする */
   do
   {
      if (packet_receive(packet) != 1) /* パケットを受信したとき */
      {
         arp_packet = (ARP_PACKET *)packet; /* packetをARP_PACKET構造体に当てはめる */
         if ((arp_packet -> eth_ethernet_type == 0x0806) && 
             /* ARPのパケットのとき */
             (IP_compare(arp_packet -> arp_dst_IP, src_IP) == 0) && 
             /* パケットに記述されている宛先IPアドレスが送信元IPアドレスに一致したとき */
             (arp_packet -> arp_operation == 2)
             /* ARPリプライのとき */
            )
         {
            for (i = 0; i < 6; i++)
            {
               dst_MAC[i] = arp_packet -> arp_src_MAC[i];
               /* パケットに記述されている送信元MACアドレスをdst_MACに格納する */
            }
            packet_type = 'a'; /* packet_typeを'a'にする */
         }
      }
   } while (packet_type != 'a'); /* packet_typeが'a'になるまで待つ */

   LCD_control(0xC0); /* カーソルを1行目の先頭に移動する */
   MAC_to_str(dst_MAC, str_MAC); /* dst_MACをstr_MAC(文字列)に変換する */
   LCD_print(str_MAC); /* 液晶ディスプレイにstr_MACを表示する */

   while (1) /* 無限ループ */
   {
      /* 何もしない */
   }
}
/* ex4_2.c(ARP_request、packet_receiveの引数をローカル変数に変えたもの。ヘッダーは本と同一。このコードでは動かない。) */

void main(void)
{
   unsigned char send_ch[256];
   unsigned char rcv_ch[256];
   unsigned short i;
   unsigned char packet_type;
   char str_IP[16];
   char str_MAC[13];
   ARP_PACKET *arp_packet;

   H8_register_init(); /* H8/3067のレジスタの設定 */
   LCD_init(); /* SC1602Bの初期化 */
   NIC_init(); /* RTL8019ASの初期化 */

   /* 送信元IPアドレスの設定 */
   src_IP[0] = 192;
   src_IP[1] = 168;
   src_IP[2] = 0;
   src_IP[3] = 100 + (P2DR & 0x07); /* ディップ・スイッチによって送信元IPアドレスを設定する */

   /* 宛先IPアドレスの設定 */
   dst_IP[0] = 192;
   dst_IP[1] = 168;
   dst_IP[2] = 0;
   dst_IP[3] = 2;

   LCD_clear(); /* 表示クリア */

   LCD_control(0x80); /* カーソルを0行目の先頭に移動する */
   IP_to_str(dst_IP, str_IP); /* dst_IPをstr_IP(文字列)に変換する */
   LCD_print(str_IP); /* 液晶ディスプレイにstr_IPを表示する */

   delay_ms(2000); /* 2000ms(2秒)の時間待ち */

   ARP_request(send_ch); /* ARPリクエスト(引数をローカル変数に変更) */

   packet_type = 0; /* packet_typeを0にする */
   do
   {
      if (packet_receive(rcv_ch) != 1) /* パケットを受信したとき(引数をローカル変数に変更) */
      {
         arp_packet = (ARP_PACKET *)rcv_ch; /* rcv_chをARP_PACKET構造体に当てはめる(ローカル変数に変更) */
         if ((arp_packet -> eth_ethernet_type == 0x0806) && 
             /* ARPのパケットのとき */
             (IP_compare(arp_packet -> arp_dst_IP, src_IP) == 0) && 
             /* パケットに記述されている宛先IPアドレスが送信元IPアドレスに一致したとき */
             (arp_packet -> arp_operation == 2)
             /* ARPリプライのとき */
            )
         {
            for (i = 0; i < 6; i++)
            {
               dst_MAC[i] = arp_packet -> arp_src_MAC[i];
               /* パケットに記述されている送信元MACアドレスをdst_MACに格納する */
            }
            packet_type = 'a'; /* packet_typeを'a'にする */
         }
      }
   } while (packet_type != 'a'); /* packet_typeが'a'になるまで待つ */

   LCD_control(0xC0); /* カーソルを1行目の先頭に移動する */
   MAC_to_str(dst_MAC, str_MAC); /* dst_MACをstr_MAC(文字列)に変換する */
   LCD_print(str_MAC); /* 液晶ディスプレイにstr_MACを表示する */

   while (1) /* 無限ループ */
   {
      /* 何もしない */
   }
}
/* NIC_function.h(packet_receive以外の関数は記載を省略) */
unsigned char packet_receive(unsigned char *packet)
{
   unsigned short i;
   unsigned short size;
   unsigned char data;
   unsigned char size_H, size_L;
   unsigned char boundary_page, start_page, current_page;
   unsigned char header[4];

   NIC_write(CR, 0x22); /* レジスタ・ページ0 */
   boundary_page = NIC_read(BNRY); /* BNRYを読み取る */
   NIC_write(CR, 0x62); /* レジスタ・ページ1 */
   current_page = NIC_read(CURR); /* CURRを読み取る */

   if (current_page < boundary_page)
   {
      current_page += (0x60 - 0x46); /* 受信バッファがリング・バッファであることを考慮する */
   }
   if (current_page == boundary_page + 1) /* 受信パケットの判定 */
   {
      return 1; /* 受信パケットなし */
   }

   start_page = boundary_page + 1; /* 受信パケットの開始ページ */
   if (start_page == 0x60)
   {
      start_page = 0x46; /* 受信バッファがリング・バッファであることを考慮する */
   }

   NIC_write(CR, 0x22); /* レジスタ・ページ0 */
   NIC_write(RBCR0, 4); /* フレーム管理ヘッダのサイズ(下位バイト) */
   NIC_write(RBCR1, 0); /* フレーム管理ヘッダのサイズ(上位バイト) */
   NIC_write(RSAR0, 0x00); /* フレーム管理ヘッダの先頭アドレス(下位バイト) */
   NIC_write(RSAR1, start_page); /* フレーム管理ヘッダの先頭アドレス(上位バイト) */
   NIC_write(CR, 0x0A); /* リモートDMA読み取りを許可する */
   for (i = 0; i < 4; i++)
   {
      header[i] = NIC_read(RDMAP); /* フレーム管理ヘッダを読み取る */
   }
   do
   {
      data = NIC_read(ISR); /* ISRを読み取る */
   } while ((data & 0x40) == 0x00); /* リモートDMAが停止するのを待つ */

   NIC_write(CR, 0x22); /* レジスタ・ページ0 */
   size_L = header[2]; /* 受信パケットのサイズ(下位バイト) */
   size_H = header[3]; /* 受信パケットのサイズ(上位バイト) */
   size = ((unsigned short)size_H << 8) + (unsigned short)size_L; /* 受信パケットのサイズ */
   NIC_write(RBCR0, size_L); /* 受信パケットのサイズ(下位バイト) */
   NIC_write(RBCR1, size_H); /* 受信パケットのサイズ(上位バイト) */
   NIC_write(RSAR0, 0x00); /* 受信パケットの先頭アドレス(下位バイト) */
   NIC_write(RSAR1, start_page); /* 受信パケットの先頭アドレス(上位バイト) */
   NIC_write(CR, 0x0A); /* リモートDMA読み取りを許可する */
   for (i = 0; i < 4; i++)
   {
      NIC_read(RDMAP); /* ダミー・データを読み取る */
   }
   for (i = 0; i < (size - 4); i++)
   {
      packet[i] = NIC_read(RDMAP); /* 受信バッファからパケットのデータを読み取る */

      if (i >= 256) /* パケットのサイズが256byteよりも大きいとき */
      {
         NIC_read(RDMAP); /* ダミー・データを読み取る */
      }
   }
   do
   {
      data = NIC_read(ISR); /* ISRを読み取る */
   } while ((data & 0x40) == 0x00); /* リモートDMAが停止するのを待つ */

   NIC_write(CR, 0x22); /* レジスタ・ページ0 */
   boundary_page = current_page - 1;
   if (boundary_page >= 0x60)
   {
      boundary_page -= (0x60 - 0x46); /* 受信バッファがリング・バッファであることを考慮する */
   }
   NIC_write(BNRY, boundary_page); /* BNRYを更新する */

   return 0;
}
/* ARP_function.h(ARP_request以外の関数は記載を省略) */
void ARP_request(unsigned char *packet)
{
   unsigned short i;
   ARP_PACKET *arp_packet;

   arp_packet = (ARP_PACKET *)packet; /* packetをARP_PACKET構造体に当てはめる */

   for (i = 0; i < 6; i++)
   {
      arp_packet -> eth_dst_MAC[i] = 0xFF; /* ブロードキャスト・アドレス */
   }
   for (i = 0; i < 6; i++)
   {
      arp_packet -> eth_src_MAC[i] = src_MAC[i]; /* 送信元MACアドレス */
   }
   arp_packet -> eth_ethernet_type = 0x0806; /* 上位プロトコルの種類(ARP) */
   arp_packet -> arp_hardware_type = 0x0001; /* ネットワークの物理媒体の種類(イーサネット) */
   arp_packet -> arp_protocol_type = 0x0800; /* 上位プロトコルの種類(IP) */
   arp_packet -> arp_hardware_length = 6; /* ネットワークの物理媒体のアドレス長(MACアドレス) */
   arp_packet -> arp_protocol_length = 4; /* 上位プロトコルのアドレス長(IPv4) */
   arp_packet -> arp_operation = 1; /* ARPの動作(ARPリクエスト) */
   for (i = 0; i < 6; i++)
   {
      arp_packet -> arp_src_MAC[i] = src_MAC[i]; /* 送信元MACアドレス */
   }
   for (i = 0; i < 4; i++)
   {
      arp_packet -> arp_src_IP[i] = src_IP[i]; /* 送信元IPアドレス */
   }
   for (i = 0; i < 6; i++)
   {
      arp_packet -> arp_dst_MAC[i] = 0x00; /* 宛先MACアドレス */
   }
   for (i = 0; i < 4; i++)
   {
      arp_packet -> arp_dst_IP[i] = dst_IP[i]; /* 宛先IPアドレス */
   }

   packet_send(packet, 60); /* パケットのサイズを60byteに指定して送信する */
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+3

TOMO6181さん、

ローカル変数宣言が main関数内で

void main(void)
{
   unsigned char send_ch[256];
   unsigned char rcv_ch[256];


としているので、スタックからメモリを確保しようとしていますが、スタックサイズは足りていますか?

とりあえず、以下のように、staticをつけて、動作するか、確認してみてください。

   static unsigned char send_ch[256];
   static unsigned char rcv_ch[256];

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/17 01:05

    仰られるようにローカル変数にstaticを付けたら動作しました。
    スタックサイズのことを完全に失念していました。
    H8/3067のスタック領域にデータを確保する十分なサイズがなかったようです。
    staticを付けたローカル変数はスタック領域ではなく、データ領域にデータが確保されるから
    動作したのですね。
    御回答ありがとうございました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.48%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る