/*
 *  packet.c -- パケットの処理
 *
 *  revision history:
 *     0.0: Jun.  8, 1996 by Dai ISHIJIMA (bsdfiler.c)
 *     0.1: Jul. 27, 1996
 *     0.2: Aug. 10, 1996
 */

#include <stdio.h>
#include <sys/types.h>
#include <time.h>
#include "bsdfiler.h"

#ifdef EBUG
/* -DEBUG オプションつきでコンパイルしたときは、送受信データをダンプする */
#define SEND 'S'
#define RECV 'R'
#define NDUMP 16
#define dumpchar(ch) (((' ' <= (ch)) && ((ch) <= '~')) ? (ch) : '.')


/* デバッグのためにパケットをダンプする */
debugdump(int mode, unsigned char ch)
{
    static int dumppos = 0;
    static int getput = EOS;
    static unsigned char asciidump[NDUMP];
    int n;
    
    if ((getput != mode) || (dumppos >= NDUMP)) {
	for (n = dumppos; n < NDUMP; n++) {
	    fprintf(stderr, "   ");
	}
	fprintf(stderr, "  ");
	for (n = 0; n < dumppos; n++) {
	    putc(dumpchar(asciidump[n]), stderr);
	}
	if (mode == SEND) {
	    fprintf(stderr, "\nSEND:");
	}
	else {
	    fprintf(stderr, "\nRECV:");
	}
	dumppos = 0;
    }
    getput = mode;
    fprintf(stderr, " %02x", ch);
    asciidump[dumppos] = ch;
    ++dumppos;
}
#endif /* -DEBUG */


/* 1バイト受信 */
int recvbyte(int fd)
{
    time_t t;
    int ch;

    t = time(NULL);
    while ((ch = ttygetc(fd)) < 0) {
	if (time(NULL) - t > TIMEOUT) {
	    return(-1);
	}
    }
#ifdef EBUG
    debugdump(RECV, ch);
#endif
    return(ch);
}


/* 1バイト送信 */
int sendbyte(int fd, int ch)
{
#ifdef EBUG
    debugdump(SEND, ch);
#endif
    ttyputc(fd, ch);
}


/* パケットを受信して buf に格納する。パケットの長さを返す */
int recvpacket(int fd, unsigned char *buf)
{
    int len;
    int esc;
    unsigned short crc;
    unsigned short pcrc;
    int ch;

    while ((ch = recvbyte(fd)) != SYN) {
	;
    }
    while ((ch = recvbyte(fd)) == SYN) {
	;
    }
    if (ch != DLE) {
	fprintf(stderr, "received character (%02x) is not DLE\n", ch);
    }
    if ((ch = recvbyte(fd)) != STX) {
	fprintf(stderr, "received character (%02x) is not STX\n", ch);
    }
    if ((ch = recvbyte(fd)) != SOH) {
	fprintf(stderr, "received character (%02x) is not SOH\n", ch);
    }
    crc = crc16c(0, ch, YES);
    esc = NO;
    len = 0;
    while (YES) {
	ch = recvbyte(fd);
	if (ch < 0) {
	    break;
	}
	if ((ch == DLE) && (esc == NO)) {
	    esc = YES;
	}
	else {
	    buf[len] = ch;
	    ++len;
	    crc = crc16c(crc, ch, YES);
	    if ((ch == ETX) && (esc == YES)) {
		/* DLE ETX のシーケンスを受信したらループを抜ける */
		--len;
		break;
	    }
	    esc = NO;
	}
    }
    pcrc = recvbyte(fd);
    pcrc += 256 * recvbyte(fd);
    if (crc != pcrc) {
	fprintf(stderr, "crc error, %04x != %04x\n", crc, pcrc);
	len = -len;
    }
    return(len);
}


/* 長さ len のパケットを送信する */
void sendpacket(int fd, int len, unsigned char *buf)
{
    unsigned short crc;
    int i;

    sendbyte(fd, SYN);
    sendbyte(fd, SYN);
    sendbyte(fd, SYN);
    sendbyte(fd, DLE);
    sendbyte(fd, STX);
    sendbyte(fd, SOH);
    crc = crc16c(0, SOH, YES);
    for (i = 0; i < len; i++) {
	if (buf[i] == DLE) {
	    sendbyte(fd, DLE);
	}
	sendbyte(fd, buf[i]);
	crc = crc16c(crc, buf[i], YES);
    }
    sendbyte(fd, DLE);
    sendbyte(fd, ETX);
    crc = crc16c(crc, ETX, YES);
    sendbyte(fd, crc % 256);
    sendbyte(fd, crc / 256);
}


/* パケット buf の ofs 位置に unsigned char をセットする */
int setbyte(unsigned char *buf, int ofs, unsigned char n)
{
    buf[ofs] = n;
    return(ofs + 1);
}


/* パケット buf の ofs 位置から short int を取り出す */
unsigned short getshort(unsigned char *buf, int ofs)
{
    return(buf[ofs] + buf[ofs + 1] * 256);
}


/* パケット buf の ofs 位置に short int をセットする */
int setshort(unsigned char *buf, int ofs, unsigned short n)
{
    buf[ofs] = n % 256;
    buf[ofs + 1] = n / 256;
    return(ofs + 2);
}


/* パケット buf の ofs 位置から long int を取り出す */
unsigned long getlong(unsigned char *buf, int ofs)
{
    return((((unsigned long)buf[ofs + 3] * 256 + buf[ofs + 2]) * 256
	    + buf[ofs + 1]) * 256 + buf[ofs]);
}


/* パケット buf の ofs 位置に long int をセットする */
int setlong(unsigned char *buf, int ofs, unsigned long n)
{
    buf[ofs]     = n % 256; n /= 256;
    buf[ofs + 1] = n % 256; n /= 256;
    buf[ofs + 2] = n % 256; n /= 256;
    buf[ofs + 3] = n % 256;
    return(ofs + 4);
}


/* パケット buf の ofs 位置から文字列を取り出し、その長さを返す */
int getmesg(unsigned char *buf, int ofs, char *msg)
{
    int i;
    int len;

    len = getshort(buf, ofs);
    for (i = 0; i < len; i++) {
	msg[i] = buf[ofs + i + 2];
    }
    msg[i] = EOS;
    return(len);
}


/* パケット buf の pos から len 分をゼロクリアする */
int clrparm(char *buf, int pos, int len)
{
    int i;

    for (i = 0; i < len; i++) {
	buf[pos] = 0;
	++pos;
    }
    return(pos);
}


/* パケット buf の pos から長さ len のパラメータをセットする */
int setparm(char *buf, int pos, int len, char *parm)
{
    int i;

    for (i = 0; i < len; i++) {
	buf[pos] = parm[i];
	++pos;
    }
    return(pos);
}


/* パケット buf の pos から長さ len の文字列をセットする */
int setmesg(char *buf, int pos, int len, char *msg)
{
    pos = setshort(buf, pos, len);
    return(setparm(buf, pos, len, msg));
}
