/*!
  \file
  \brief パケット処理のターゲット側

  \author Satofumi KAMIMURA

  $Id: packetHandleTarget.c 286 2008-10-20 09:40:22Z satofumi $
*/

#include "packetHandleTarget.h"
//#include "structTables.h"
#include "nodeAccess.h"
#include "transferCtrl.h"
#include "tRunCtrl.h"


int packetRecvHandler(runCtrl_t *run) {
  enum {
    WaitStartByte,
    WaitHeaderRecv,
    WaitPacketRecv,
    RecvCompleted,
    InvalidPacket,

    RecvPacketSize = 512,
  };
  static int state = InvalidPacket;
  static unsigned char recv_buffer[RecvPacketSize];
  static int require_size = 0;
  static int filled = 0;
  static int type = 0;
  static int packet_length = 0;
  int n;

  // !!! 処理の開始から return まで、1[msec] の割り込みを禁止すべきな気がする

  while (1) {
    if (state == InvalidPacket) {
      // 受信情報の初期化
      state = WaitStartByte;
      require_size = NODE_ACCESS_PACKET_HEADER_SIZE;
      recv_buffer[0] = 0x00;
      filled = removeInvalidPacketHeader((unsigned char*)recv_buffer, filled);
    }

    // 受信処理
    filled = removeInvalidPacketHeader(recv_buffer, filled);

    // V コマンドへの応答
    if ((state == WaitStartByte) && (trans_size() >= 2)) {
      unsigned char command[2] = { '\0', '\0' };
      trans_copy(command, 2);
      if ((command[0] == 'V') &&
	  ((command[1] == '\n') || (command[1] == '\r'))) {
	// バージョン情報を返す
	trans_recv(command, 2);
	trans_send((unsigned char *)V_COMMAND_REPLY, sizeof(V_COMMAND_REPLY));
      }
    }

    if (trans_size() < require_size) {
      return 0;
    }
    n = trans_recv(&recv_buffer[filled], require_size);
    filled += n;
    require_size -= n;

    filled = removeInvalidPacketHeader(recv_buffer, filled);

    if (state == WaitStartByte) {
      // スタートバイト待ち
      if ((filled >= 3) && (checkFirstTag(recv_buffer) >= 0)) {
	state = WaitHeaderRecv;
      }
    }

    if (state == WaitHeaderRecv) {
      // ヘッダのチェックサム確認
      if (checkHeaderFormat(recv_buffer) < 0) {
	state = InvalidPacket;
      } else {
	// ヘッダからパケット情報を取得
	packet_length = getPacketLength(recv_buffer);
	require_size += packet_length - NODE_ACCESS_PACKET_HEADER_SIZE;
	state = WaitPacketRecv;
	type = getPacketType(recv_buffer);
      }
      continue;
    }

    if (state == WaitPacketRecv) {
      if (checkPacketFormat(recv_buffer, packet_length) < 0) {
	state = InvalidPacket;
      } else {
	state = RecvCompleted;
      }
    }

    if (state == RecvCompleted) {
      if (type == PACKET_WRITE_REQUEST) {
	// 書き込みパケットへの応答
	writeFromPacketData(recv_buffer, (unsigned char *)run);
	packet_length =
	  createWriteResponsePacket(recv_buffer, (unsigned char *)run);

      } else if (type == PACKET_READ_REQUEST) {
	// 読み出しパケットへの応答
	packet_length =
	  createReadResponsePacket(recv_buffer, (unsigned char *)run);
      } else {
	packet_length = 0;
      }
      trans_send(recv_buffer, packet_length);
      state = InvalidPacket;
      filled = 0;
      return 1;
    }
  }
}
