/* * jerm.c - terminal emulator * Copyright (C) 2000, 2001, 2002, 2003, 2004 candy * $Id: jerm.c,v 1.25 2007/08/09 09:04:43 candy Exp candy $ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __CYGWIN__ #include "getaddrinfo.c" #endif #ifdef USE_LIBWRAP #include #include int allow_severity = LOG_INFO; /* for connection logging */ int deny_severity = LOG_WARNING; /* for connection logging */ static int use_libwrap = 0; /* use libwrap or not. 0 = no, nonzero = yes */ #endif #define PORT 8086 #define PI 3.1415926535897932 static char *myname; enum parity_t { P_NONE, P_EVEN, P_ODD, }; enum flow_t { F_NONE, F_HARD, F_X, }; static int speed = B9600; /* B38400 - B75 */ static enum parity_t parity = P_NONE; static int data_bit = CS8; static int stop_bit = 1; static enum flow_t flow_control = F_NONE; static int hex_mode; /* hex dump モード */ static int pipe_mode; /* シリアルに垂流し */ static int is_server = 0; /* server モード */ static int quit_flag; /* 行末変換のプリミティブ */ enum rn_conv_t { RN_DROP, /* 捨てる */ RN_MAP_CR, /* CR に変換 */ RN_MAP_LF, /* LF に変換 */ RN_MAP_CRLF, /* CR LF に変換 */ RN_CONV_SIZE }; /* rn_conv_t に対応する変換値 */ static char *RN_OUTPUT[RN_CONV_SIZE] = { "", "\r", "\n", "\r\n", }; /* rn_conv_t に対応するオプション文字 */ static char RN_STR[RN_CONV_SIZE + 1] = "xrnt"; /* 行末変換テーブル rn_map[] のインデクス */ enum rn_index_t { RN_RECV_CR, /* リモートから CR 受信した */ RN_RECV_LF, /* リモートから LF 受信した */ RN_SEND_CR, /* ローカルから CR 受信した */ RN_SEND_LF, /* ローカルから LF 受信した */ RN_INDEX_SIZE }; static enum rn_conv_t rn_map[RN_INDEX_SIZE] = { RN_MAP_CR, RN_MAP_LF, RN_MAP_CR, RN_MAP_LF, }; /* * select on 2 file descriptors. */ static int sel2(fd_set *m, int f1, int f2) { int maxfd = f1 > f2 ? f1 : f2; FD_ZERO(m); FD_SET(f1, m); FD_SET(f2, m); errno = 0; return select(maxfd + 1, m, NULL, NULL, NULL); }/* sel2 */ /* * host:port に TCP 接続。 * ソケットを返す。 */ static int conn(const char *host, int port, int family) { int so = -1; int err; char servname[16]; struct addrinfo hints, *res; memset(&hints, 0, sizeof(hints)); hints.ai_family = family; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = 0; sprintf(servname, "%d", port); err = getaddrinfo(host, servname, &hints, &res); if (err == 0) { if (res != NULL) { so = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (so >= 0) { int err = connect(so, res->ai_addr, res->ai_addrlen); if (err < 0) { perror("connect"); close(so); so = -1; } } else perror("socket"); freeaddrinfo(res); } else fprintf(stderr, "getaddrinfo: no address\n"); } else perror("gethostbyname"); return so; }/* conn */ /* * ソケットに size_ バイト送信。 */ static int so_write(int so, const void *buf, size_t size_) { int err = 0; int size = size_; const char *mv = buf; while (err == 0 && size >= 1) { int wrote = write(so, mv, size); if (wrote >= size) { size -= wrote; mv += wrote; } else err = -1; }/* while */ if (err == 0) err = size_; return err; }/* so_write */ /* * */ static struct termios tio_save; static int ti_fd; /* * 死ぬ前にターミナルの状態を戻す。 */ static void restore_local_terminal(void) { tcsetattr(ti_fd, TCSANOW, &tio_save); }/* restore_local_terminal */ /* * ターミナルの状態を保存。 */ static int save_local_terminal(int fd) { int err = tcgetattr(fd, &tio_save); if (err < 0) { perror("tcgetattr"); } else { ti_fd = fd; atexit(restore_local_terminal); } return err; }/* save_local_terminal */ /* * cfmakeraw() by blogger323 * */ #ifdef __CYGWIN__ /* [ */ /* Workaround for Cygwin, which is missing cfmakeraw */ /* Pasted from man page; added in serial.c arbitrarily */ void cfmakeraw(struct termios *termios_p) { termios_p->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP |INLCR|IGNCR|ICRNL|IXON); termios_p->c_oflag &= ~OPOST; termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); termios_p->c_cflag &= ~(CSIZE|PARENB); termios_p->c_cflag |= CS8; }/* cfmakeraw */ #endif /* ] */ /* * ターミナルを raw モードにする。 */ static int make_local_raw(int fd) { int err = 0; if (isatty(fd)) { err = save_local_terminal(fd); if (err == 0) { struct termios tio; if ((err = tcgetattr(fd, &tio)) < 0) perror("tcgetattr"); else { cfmakeraw(&tio); if ((err = tcsetattr(fd, TCSANOW, &tio)) < 0) perror("tcsetattr"); } } } return err; }/* make_local_raw */ /* * 改行 */ static char *NL = "\r\n"; /* * -r rnRN * 行末の変換オプション * r: リモートから受信した CR をローカルに表示する時何に変換するか * n: リモートから受信した NL をローカルに表示する時何に変換するか * R: ローカルから受信した CR をリモートに送信する時何に変換するか * N: ローカルから受信した NL をリモートに送信する時何に変換するか * それぞれ一桁の文字で表す。 * x = 受信した文字を捨てる。 * r = CR に変換する。 * n = LF に変換する。 * t = CR LF に変換する。 * - = 変換無し。 */ static int parse_rn_char(int c, int dflt) { int ret = dflt; switch (c) { case 'x': ret = RN_DROP; break; case 'r': ret = RN_MAP_CR; break; case 'n': ret = RN_MAP_LF; break; case 't': ret = RN_MAP_CRLF; break; }/* switch */ return ret; }/* parse_rn_char */ static int set_rn_opt(const char *rnopt) { int err = -1; int len = strlen(rnopt); int rn[RN_INDEX_SIZE]; if (len == RN_INDEX_SIZE) { if ((rn[RN_RECV_CR] = parse_rn_char(rnopt[RN_RECV_CR], -1)) != -1 && (rn[RN_RECV_LF] = parse_rn_char(rnopt[RN_RECV_LF], -1)) != -1 && (rn[RN_SEND_CR] = parse_rn_char(rnopt[RN_SEND_CR], -1)) != -1 && (rn[RN_SEND_LF] = parse_rn_char(rnopt[RN_SEND_LF], -1)) != -1) { memcpy(rn_map, rn, sizeof(rn_map)); err = 0; } } return err; }/* set_rn_opt */ static char * print_rn_opt(char *buf, int size) { char *ret = NULL; if (size >= RN_INDEX_SIZE + 1) { buf[RN_RECV_CR] = RN_STR[rn_map[RN_RECV_CR]]; buf[RN_RECV_LF] = RN_STR[rn_map[RN_RECV_LF]]; buf[RN_SEND_CR] = RN_STR[rn_map[RN_SEND_CR]]; buf[RN_SEND_LF] = RN_STR[rn_map[RN_SEND_LF]]; buf[RN_INDEX_SIZE] = '\0'; ret = buf; } return ret; }/* print_rn_opt */ /* $BB.EY?tCM(B $B$H(B Bxxx$BDj5ACM(B $B$NBP1~I=(B */ static struct speed_map { int num; speed_t speed; } speed_map[] = { { 0, B0 }, { 50, B50 }, { 75, B75 }, { 110, B110 }, { 134, B134 }, { 150, B150 }, { 200, B200 }, { 300, B300 }, { 600, B600 }, { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 }, { 4800, B4800 }, { 9600, B9600 }, { 19200, B19200 }, { 38400, B38400 }, { 57600, B57600 }, { 115200, B115200 }, }; /* * $BB.EY?tCM(B $B$+$i(B Bxxx$BDj5ACM$KJQ49(B * $B$@$a$J$i$=$N$^$^(B */ static int speed_to_num(speed_t speed) { int i = sizeof(speed_map)/sizeof(speed_map[0]); while(i--) if( speed_map[i].speed == speed) return speed_map[i].num; return speed; }/* speed_to_num */ /* * Bxxx$BDj5ACM(B $B$+$i(B $BB.EY?tCM(B $BDj5ACM$KJQ49(B * $B$@$a$J$i$=$N$^$^(B */ static speed_t num_to_speed(int num) { int i = sizeof(speed_map)/sizeof(speed_map[0]); while(i--) if( speed_map[i].num == num) return speed_map[i].speed; return num; }/* num_to_speed */ /* * ターミナルの状態を表示。 * stty -a みたいなやつ。 */ static void print_status(const struct termios *tio) { int cs; char *csstr = "?"; speed_t ispeed = cfgetispeed(tio); speed_t ospeed = cfgetospeed(tio); fprintf(stderr, " ispeed %d", speed_to_num(ispeed)); fprintf(stderr, " ospeed %d", speed_to_num(ospeed)); fprintf(stderr, "%s", NL); fprintf(stderr, " %cIGNBRK", (tio->c_iflag & IGNBRK) ? '+' : '-'); fprintf(stderr, " %cBRKINT", (tio->c_iflag & BRKINT) ? '+' : '-'); fprintf(stderr, " %cIGNPAR", (tio->c_iflag & IGNPAR) ? '+' : '-'); fprintf(stderr, " %cPARMRK", (tio->c_iflag & PARMRK) ? '+' : '-'); fprintf(stderr, " %cINPCK", (tio->c_iflag & INPCK) ? '+' : '-'); fprintf(stderr, " %cISTRIP", (tio->c_iflag & ISTRIP) ? '+' : '-'); fprintf(stderr, " %cINLCR", (tio->c_iflag & INLCR) ? '+' : '-'); fprintf(stderr, " %cIGNCR", (tio->c_iflag & IGNCR) ? '+' : '-'); fprintf(stderr, " %cICRNL", (tio->c_iflag & ICRNL) ? '+' : '-'); fprintf(stderr, " %cIXON", (tio->c_iflag & IXON) ? '+' : '-'); fprintf(stderr, " %cIXOFF", (tio->c_iflag & IXOFF) ? '+' : '-'); fprintf(stderr, " %cIXANY", (tio->c_iflag & IXANY) ? '+' : '-'); fprintf(stderr, " %cIMAXBEL", (tio->c_iflag & IMAXBEL) ? '+' : '-'); fprintf(stderr, "%s", NL); fprintf(stderr, " %cOPOST", (tio->c_oflag & OPOST) ? '+' : '-'); fprintf(stderr, " %cONLCR", (tio->c_oflag & ONLCR) ? '+' : '-'); #ifdef OXTABS fprintf(stderr, " %cOXTABS", (tio->c_oflag & OXTABS) ? '+' : '-'); #endif #if defined(TABDLY) && defined(XTABS) /* linux */ fprintf(stderr, " %cTABDLY", (tio->c_oflag & TABDLY) == XTABS ? '+' : '-'); #endif #ifdef ONOEOT fprintf(stderr, " %cONOEOT", (tio->c_oflag & ONOEOT) ? '+' : '-'); #endif fprintf(stderr, "%s", NL); cs = tio->c_cflag & CSIZE; switch (cs) { case CS5: csstr = "5"; break; case CS6: csstr = "6"; break; case CS7: csstr = "7"; break; case CS8: csstr = "8"; break; default: csstr = "?"; break; }/* switch */ fprintf(stderr, " cs%s", csstr); fprintf(stderr, " %cCSTOPB", (tio->c_cflag & CSTOPB) ? '+' : '-'); fprintf(stderr, " %cCREAD", (tio->c_cflag & CREAD) ? '+' : '-'); fprintf(stderr, " %cPARENB", (tio->c_cflag & PARENB) ? '+' : '-'); fprintf(stderr, " %cPARODD", (tio->c_cflag & PARODD) ? '+' : '-'); fprintf(stderr, " %cHUPCL", (tio->c_cflag & HUPCL) ? '+' : '-'); fprintf(stderr, " %cCLOCAL", (tio->c_cflag & CLOCAL) ? '+' : '-'); #ifdef CCTS_OFLOW fprintf(stderr, " %cCCTS_OFLOW", (tio->c_cflag & CCTS_OFLOW) ? '+' : '-'); #endif fprintf(stderr, " %cCRTSCTS", (tio->c_cflag & CRTSCTS) ? '+' : '-'); #ifdef CRTS_IFLOW fprintf(stderr, " %cCRTS_IFLOW", (tio->c_cflag & CRTS_IFLOW) ? '+' : '-'); #endif #ifdef MDMBUF fprintf(stderr, " %cMDMBUF", (tio->c_cflag & MDMBUF) ? '+' : '-'); #endif fprintf(stderr, " %cECHOKE", (tio->c_lflag & ECHOKE) ? '+' : '-'); fprintf(stderr, " %cECHOE", (tio->c_lflag & ECHOE) ? '+' : '-'); fprintf(stderr, " %cECHO", (tio->c_lflag & ECHO) ? '+' : '-'); fprintf(stderr, " %cECHONL", (tio->c_lflag & ECHONL) ? '+' : '-'); #ifdef ECHOPRT fprintf(stderr, " %cECHOPRT", (tio->c_lflag & ECHOPRT) ? '+' : '-'); #endif fprintf(stderr, " %cECHOCTL", (tio->c_lflag & ECHOCTL) ? '+' : '-'); fprintf(stderr, " %cISIG", (tio->c_lflag & ISIG) ? '+' : '-'); fprintf(stderr, " %cICANON", (tio->c_lflag & ICANON) ? '+' : '-'); #ifdef ALTWERASE fprintf(stderr, " %cALTWERASE", (tio->c_lflag & ALTWERASE) ? '+' : '-'); #endif fprintf(stderr, " %cIEXTEN", (tio->c_lflag & IEXTEN) ? '+' : '-'); fprintf(stderr, "%s", NL); #ifdef EXTPROC fprintf(stderr, " %cEXTPROC", (tio->c_lflag & EXTPROC) ? '+' : '-'); #endif fprintf(stderr, " %cTOSTOP", (tio->c_lflag & TOSTOP) ? '+' : '-'); fprintf(stderr, " %cFLUSHO", (tio->c_lflag & FLUSHO) ? '+' : '-'); #ifdef NOKERNINFO fprintf(stderr, " %cNOKERNINFO", (tio->c_lflag & NOKERNINFO) ? '+' : '-'); #endif #ifdef PENDIN fprintf(stderr, " %cPENDIN", (tio->c_lflag & PENDIN) ? '+' : '-'); #endif fprintf(stderr, " %cNOFLSH", (tio->c_lflag & NOFLSH) ? '+' : '-'); fprintf(stderr, "%s", NL); fflush(stderr); }/* print_status */ /* * グローバル変数を参照して、ターミナルの状態 * (speed, parity, data bits 等)を設定する。 */ static void set_status(struct termios *tio) { cfsetispeed(tio, speed); cfsetospeed(tio, speed); tio->c_cflag = (tio->c_cflag & ~CSIZE) | data_bit; if (stop_bit == 1) tio->c_cflag &= ~CSTOPB; else if (stop_bit == 2) tio->c_cflag |= CSTOPB; switch (parity) { case P_NONE: tio->c_cflag &= ~PARENB; break; case P_EVEN: tio->c_cflag = (tio->c_cflag | PARENB) & ~PARODD; break; case P_ODD: tio->c_cflag = tio->c_cflag | PARENB | PARODD; break; }/* switch */ switch (flow_control) { case F_NONE: tio->c_cflag &= ~CRTSCTS; tio->c_iflag &= ~(IXON | IXOFF); break; case F_HARD: tio->c_cflag |= CRTSCTS; tio->c_iflag &= ~(IXON | IXOFF); break; case F_X: tio->c_cflag &= ~CRTSCTS; tio->c_iflag |= (IXON | IXOFF); break; }/* switch */ }/* set_status */ /* * 指定されたファイルハンドルのターミナル状態を表示。 */ static int print_fdstatus(int fd) { int err = -1; struct termios tio; if (tcgetattr(fd, &tio) < 0) perror("tcgetattr"); else { print_status(&tio); err = 0; } return err; }/* print_fdstatus */ /* * 指定されたファイルハンドルのターミナルの状態を初期化する。 * raw モードにして、CLOCAL を設定する。 */ static int fd_init(int fd) { struct termios tio; int err = -1; if (tcgetattr(fd, &tio) < 0) perror("tcgetattr"); else { cfmakeraw(&tio); tio.c_cflag |= CLOCAL; /* do not send SIGHUP to me! */ if (tcsetattr(fd, TCSANOW, &tio) < 0) perror("tcsetattr"); else err = 0; } return err; }/* fd_init */ /* * 指定されたファイルハンドルについて、 * グローバル変数を参照して、ターミナルの状態 * (speed, parity, data bits 等)を設定する。 */ static int set_fdstatus(int fd) { struct termios tio; int err = -1; if (tcgetattr(fd, &tio) < 0) perror("tcgetattr"); else { set_status(&tio); if (tcsetattr(fd, TCSANOW, &tio) < 0) perror("tcsetattr"); else err = 0; } return err; }/* set_fdstatus */ /* * */ static int chardump(const void *buf_, size_t size) { const unsigned char *buf = buf_; int i; printf(" |"); for (i = 0; i < size; i++) { if (buf[i] >= ' ' && buf[i] < 0x7f) printf("%c", buf[i]); else printf("."); }/* for */ printf("%s", NL); fflush(stdout); return 0; }/* chardump */ static unsigned char hex_buf[16]; static int hex_count; static int hexdump_start(void) { fprintf(stderr, "[HEX MODE]%s", NL); hex_count = 0; return 0; }/* hexdump_start */ static int hexdump_stop(void) { if (hex_count > 0) chardump(hex_buf, hex_count); fprintf(stderr, "[NORMAL MODE]%s", NL); return 0; }/* hexdump_stop */ /* * */ static int hexdump(const void *buf_, size_t size) { const unsigned char *buf = buf_; int i; for (i = 0; i < size; i++) { printf("%02x ", buf[i]); hex_buf[hex_count++] = buf[i]; if (hex_count == sizeof(hex_buf)) { chardump(hex_buf, hex_count); hex_count = 0; } }/* for */ return 0; }/* hexdump */ #ifdef JUPITER /* [ */ /* * JUPITER GPS (rockwell binary mode) decoder */ static int rockwell_mode; static int jdebug; struct jm1000_t { unsigned short stime[2]; unsigned short seq; unsigned short sseq; unsigned short navval; unsigned short navtype; unsigned short nmeas; unsigned short polar; unsigned short gweek; unsigned short sweek[2]; unsigned short nsweek[2]; unsigned short utcday; unsigned short utcmon; unsigned short utcyear; unsigned short utchour; unsigned short utcmin; unsigned short utcsec; unsigned short utcnsec[2]; unsigned short latitude[2]; unsigned short longitude[2]; unsigned short height[2]; unsigned short gsep; unsigned short speed[2]; unsigned short course; unsigned short mvar; unsigned short climb; unsigned short map; unsigned short herr[2]; unsigned short verr[2]; unsigned short terr[2]; unsigned short hverr; unsigned short bias[2]; unsigned short biassd[2]; unsigned short drift[2]; unsigned short driftsd[2]; unsigned short dsum; }; struct jm1002_t { unsigned short stime[2]; unsigned short seq; unsigned short sseq; unsigned short gweek; unsigned short sweek[2]; unsigned short nsweek[2]; struct { unsigned short flag; unsigned short sate_prn; unsigned short c_no; } ch_summary[12]; unsigned short dsum; }; struct jm1003_t { unsigned short stime[2]; unsigned short seq; unsigned short gdop; unsigned short pdop; unsigned short hdop; unsigned short vdop; unsigned short tdop; unsigned short num_vis; struct { unsigned short sate_prn; unsigned short sate_azimuth; unsigned short sate_elevation; } vis_sate[12]; unsigned short dsum; }; struct jm1011_t { unsigned short stime[2]; unsigned short seq; unsigned char num_ch[10]; unsigned char sw_ver[10]; unsigned char sw_date[10]; unsigned char opt_list[10]; unsigned char reserve[10]; unsigned short dsum; }; struct jm1012_t { unsigned short stime[2]; unsigned short seq; unsigned short flags; unsigned short cold_timeout; unsigned short dgps_timeout; short ele_mask; unsigned short candi1; unsigned short candi2; unsigned short solval; unsigned short nsate; unsigned short min_hor[2]; unsigned short min_ver[2]; unsigned short platform; unsigned short dsum; }; struct jm1108_t { unsigned short stime[2]; unsigned short seq; unsigned short reserved[5]; unsigned short sweek[2]; short offs; unsigned short offns[2]; unsigned short flags; unsigned short dsum; }; struct jm1135_t { unsigned short stime[2]; unsigned short seq; unsigned short id_prn; unsigned short dsum; }; static time_t get_gpsweek(int utc_of_week) { time_t ret = 0; int err; struct timeval tv; err = gettimeofday(&tv, NULL); if (err == 0) { time_t t0 = tv.tv_sec; struct tm tm = *gmtime(&t0); int sec_of_week = tm.tm_wday * 86400 + tm.tm_hour * 3600 + tm.tm_min * 60 + tm.tm_sec; /*int diff = utc_of_week - sec_of_week;*/ ret = tv.tv_sec - sec_of_week; } else perror("gettimeofday"); return ret; }/* get_gpsweek */ static int get_now(int utc_of_week) { time_t gps0 = get_gpsweek(utc_of_week); time_t t = gps0 + utc_of_week; return t; }/* get_now */ #define UDI(v_) (((unsigned long)(v_)[1] << 16) | (v_)[0]) #define DI(v_) (((long)(v_)[1] << 16) | (v_)[0]) static int print_C(const void *buf, int size, FILE *fp) { const unsigned char *p = buf; int i; for (i = 0; i < size; i++) { if (p[i] >= ' ' && p[i] < 0x7f) fprintf(fp, "%c", p[i]); else fprintf(fp, "\\x%02x", p[i]); } return 0; }/* print_C */ static void rad_to_deg(double rad, int *deg, int *min, int *sec, int *usec) { double d = rad * 180.0 / PI; *deg = floor(d); d = (d - floor(d)) * 60; *min = floor(d); d = (d - floor(d)) * 60; *sec = floor(d); *usec = (d - floor(d)) * 1000000; }/* rad_to_deg */ static void gm_to_local(int *Y, int *m, int *d, int *H, int *M, int *S) { struct tm tm; time_t t; tm.tm_year = *Y - 1900; tm.tm_mon = *m - 1; tm.tm_mday = *d; tm.tm_hour = *H; tm.tm_min = *M; tm.tm_sec = *S; tm.tm_isdst = 0; t = timegm(&tm); tm = *localtime(&t); *Y = tm.tm_year + 1900; *m = tm.tm_mon + 1; *d = tm.tm_mday; *H = tm.tm_hour; *M = tm.tm_min; *S = tm.tm_sec; } #define A 6378137.0 /* 赤道半径 m */ #define F 298.257222101 /* 扁平率の逆数=1/((A-B)/A) */ #define B 6356752.31414035584785210687 /* 極半径=A-A/F */ static void xymove(double nt, double et, double *delta_n, double *delta_e) { static double nt0, et0; double cos_nt, sin_nt, r1, r2; double rdn, rde; if (nt0 == 0) { nt0 = nt; et0 = et; } cos_nt = cos(nt); sin_nt = sin(nt); r1 = sqrt(A * A * cos_nt * cos_nt + B * B * sin_nt * sin_nt); /* 北緯 nt の地球半径 */ r2 = A * cos_nt; /* 北緯 nt の円の半径 */ rdn = (nt - nt0); /* 北緯変位 [rad] */ rde = (et - et0); /* 東経変位 [rad] */ *delta_n = r1 * rdn; /* 北変位[m] */ *delta_e = r2 * rde; /* 東変位[m] */ } static int decode(unsigned short *dt, int count) { int id = dt[1]; /*int dlen = dt[2];*/ struct jm1000_t *jm1000; struct jm1002_t *jm1002; struct jm1003_t *jm1003; struct jm1011_t *jm1011; struct jm1012_t *jm1012; struct jm1108_t *jm1108; struct jm1135_t *jm1135; int latdeg, latmin, latsec, latusec; int longdeg, longmin, longsec, longusec; int Y, m, d, H, M, S; double dx, dy; switch (id) { case 1000: jm1000 = (struct jm1000_t *)&dt[5]; rad_to_deg(DI(jm1000->latitude) * 1e-8, &latdeg, &latmin, &latsec, &latusec); rad_to_deg(DI(jm1000->longitude) * 1e-8, &longdeg, &longmin, &longsec, &longusec); Y = jm1000->utcyear; m = jm1000->utcmon; d = jm1000->utcday; H = jm1000->utchour; M = jm1000->utcmin; S = jm1000->utcsec; gm_to_local(&Y, &m, &d, &H, &M, &S); xymove(DI(jm1000->latitude) * 1e-8, DI(jm1000->longitude) * 1e-8, &dx, &dy); printf("%04d/%02d/%02d %02d:%02d:%02d %d%02d%02d.%06d %d%02d%02d.%06d %.2f %d %c %5.1f %7.3f %7.3f\r\n", Y, m, d, H, M, S, latdeg, latmin, latsec, latusec, longdeg, longmin, longsec, longusec, DI(jm1000->height) / 100.0, jm1000->map, ((jm1000->navval & 0x4) ? 'V' : 'A'), UDI(jm1000->speed) * 1e-2 * 3.6, dx * 1e-3, dy * 1e-3 ); break; case 1002: jm1002 = (struct jm1002_t *)&dt[5]; printf("%d", jm1002->seq); { int i; for (i = 0; i < 12; i++) { printf(" %d %d", jm1002->ch_summary[i].sate_prn, jm1002->ch_summary[i].c_no); } printf("\r\n"); } break; case 1003: jm1003 = (struct jm1003_t *)&dt[5]; printf("%d", jm1003->seq); printf(" G%d P%d H%d V%d T%d N%d", jm1003->gdop, jm1003->pdop, jm1003->hdop, jm1003->vdop, jm1003->tdop, jm1003->num_vis); { int i; for (i = 0; i < 12; i++) { printf(" %d", jm1003->vis_sate[i].sate_prn); } printf("\r\n"); } break; case 1011: jm1011 = (struct jm1011_t *)&dt[5]; printf("num_ch=["); print_C(jm1011->num_ch, 10, stdout); printf("] sw_ver=["); print_C(jm1011->sw_ver, 10, stdout); printf("] sw_date=["); print_C(jm1011->sw_date, 10, stdout); printf("] opt_list=["); print_C(jm1011->opt_list, 10, stdout); printf("]\r\n"); break; case 1012: jm1012 = (struct jm1012_t *)&dt[5]; printf("flag=%04x ele_mask=%.3f nsate=%d platform=%d\r\n", jm1012->flags, jm1012->ele_mask * 1e-3, jm1012->nsate, jm1012->platform); break; case 1108: jm1108 = (struct jm1108_t *)&dt[5]; { time_t t = get_now(UDI(jm1108->sweek)); struct tm tm = *localtime(&t); printf("%d wsec %lu GtoU %d.%09ld A/V=%d GPS/UTC=%d %04d/%02d/%02d %02d:%02d:%02d\r\n", jm1108->seq, UDI(jm1108->sweek), jm1108->offs, UDI(jm1108->offns), jm1108->flags & 1, jm1108->flags & 2, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec ); } break; case 1135: jm1135 = (struct jm1135_t *)&dt[5]; printf("%d %d %d\r\n", jm1135->seq, jm1135->id_prn & 0xff, jm1135->id_prn >> 8); break; default: printf("ndata=%d\r\n", dt[2]); { int i; for (i = 0; i < dt[2]; i++) { printf(" %d=%04x", 6 + i, dt[5 + i]); } printf("\r\n"); } break; }/* switch */ return 0; }/* decode */ #define WORD_MAX 300 static unsigned short bdata[WORD_MAX]; static int rockwell2(int ch) { static int stat; static int soh_del; static int message_id; static int data_word_count; static int dcl0_qran; static int header_checksum; static int wc; static int sum; int err = 0; switch (stat) { case 0: bdata[0] = ch; if (ch == 0x81ff) { soh_del = ch; if (jdebug) fprintf(stderr, "soh_del = %04x\r\n", ch); stat++; printf(":"); fflush(stdout); } else { if (jdebug) fprintf(stderr, "not soh_del : %04x\r\n", ch); err = -1; } break; case 1: bdata[1] = ch; message_id = ch; if (jdebug) fprintf(stderr, "message_id = %04x (%d)\r\n", ch, ch); printf("%d ", ch); fflush(stdout); stat++; break; case 2: bdata[2] = ch; data_word_count = ch; if (jdebug) fprintf(stderr, "data_word_count = %04x\r\n", ch); if (data_word_count >= WORD_MAX) { fprintf(stderr, "data_word_count %d >= %d\r\n", data_word_count, WORD_MAX); err = -1; } stat++; break; case 3: bdata[3] = ch; dcl0_qran = ch; if (jdebug) fprintf(stderr, "dcl0_qran = %04x\r\n", ch); stat++; break; case 4: bdata[4] = ch; header_checksum = ch; wc = 0; stat++; sum = (-(0x81ff + message_id + data_word_count + dcl0_qran)) & 0xffff; if (jdebug) fprintf(stderr, "header_checksum = %04x calc = %04x\r\n", ch, sum); if (sum != header_checksum) { fprintf(stderr, "checksum error: header = %04x, calc = %04x\r\n", header_checksum, sum); err = -1; } sum = 0; break; case 5: if (5 + wc < WORD_MAX) bdata[5 + wc] = ch; if (wc < data_word_count) { if (jdebug) fprintf(stderr, " %d=%04x", wc + 6, ch); sum = (sum + ch) & 0xffff; } else { sum = -sum & 0xffff; if (jdebug) fprintf(stderr, "\r\n"); if (jdebug) fprintf(stderr, " data sum = %04x, calc = %04x\r\n", ch, sum); if (sum != ch) { fprintf(stderr, "checksum error: data sum = %04x, calc = %04x\r\n", ch, sum); err = -1; } else { if (5 + wc < WORD_MAX) { decode(bdata, 5 + wc + 1); } } stat = 0; } wc++; break; }/* switch */ if (err < 0) stat = 0; return err; }/* rockwell2 */ static int rockwell(const void *buf_, size_t size) { const unsigned char *buf = buf_; static int stat, lo_ch = EOF; int i = 0, ch; int err; for (i = 0; i < size; i++) { /* fprintf(stderr, " %02x\r\n", buf[i]); */ switch (stat) { case 0: if (buf[i] == 0xff) stat = 1; break; case 1: if (buf[i] == 0x81) { stat = 2; lo_ch = EOF; err = rockwell2(0x81ff); } else if (buf[i] == 0xff) stat = 1; else stat = 0; break; case 2: if (lo_ch == EOF) lo_ch = buf[i]; else { ch = lo_ch | (buf[i] << 8); lo_ch = EOF; err = rockwell2(ch); if (err < 0) stat = 0; } break; } } return 0; }/* rockwell */ #endif /* ] */ /* * リモートからデータが送られて来た処理。 */ static int read_remote(int localfd, int remotefd, FILE *log) { unsigned char lbuf[80]; int err = read(remotefd, lbuf, sizeof(lbuf)); if (err < 0) perror("remote read"); else if (err == 0) { fprintf(stderr, "remote closed"); err = -1; } else { if (log != NULL) { fwrite(lbuf, 1, err, log); fflush(log); } if (is_server) { if (so_write(localfd, lbuf, err) == err) err = 0; else perror("so_write"); } else if (pipe_mode) { if (fwrite(lbuf, 1, err, stdout) == err) err = 0; else perror("so_write"); } else if (hex_mode) err = hexdump(lbuf, err); #ifdef JUPITER else if (rockwell_mode) err = rockwell(lbuf, err); #endif else { int i = 0, n = err; err = 0; while (err == 0 && i < n) { switch (lbuf[i]) { case '\n': if (fputs(RN_OUTPUT[rn_map[RN_RECV_LF]], stdout) == EOF) err = -1; break; case '\r': if (fputs(RN_OUTPUT[rn_map[RN_RECV_CR]], stdout) == EOF) err = -1; break; default: if (fputc(lbuf[i], stdout) == EOF) err = -1; }/* switch */ i++; }/* while */ } fflush(stdout); } return err; }/* read_remote */ /* * */ static char * read_line(char *buf, int size, int fd) { int idx = 0, err = 0, done = 0, ch = EOF; char *ret = NULL, lbuf[1]; while (!done && (err = read(fd, lbuf, 1) > 0)) { int i; ch = (unsigned char)lbuf[0]; switch (ch) { case '[' - '@': fprintf(stderr, "%s", NL); done = 1; break; case 'M' - '@': case 'J' - '@': if (idx < size) buf[idx] = '\0'; fprintf(stderr, "%s", NL); done = 1; break; case 'H' - '@': if (idx >= 1) { fprintf(stderr, "\b \b"); idx--; } break; case 'U' - '@': for (i = 0; i < idx; i++) fprintf(stderr, "\b \b"); idx = 0; break; default: if (iscntrl(ch)) fprintf(stderr, "\a"); else { if (idx + 1 < size) { /* keep 1 for '\0' */ buf[idx++] = ch; fprintf(stderr, "%c", ch); } else fprintf(stderr, "\a"); } break; }/* switch */ }/* while */ if (err > 0) { if (ch != '[' - '@') ret = buf; } return ret; }/* read_line */ /* * */ static int put_file(const char *name, int fd) { int err = -1; FILE *fp = fopen(name, "r"); if (fp == NULL) fprintf(stderr, "%s: %s%s", name, strerror(errno), NL); else { int xx; char lbuf[256]; err = 0; while (err == 0 && (xx = fread(lbuf, 1, sizeof(lbuf), fp)) > 0) { if (write(fd, lbuf, xx) != xx) { fprintf(stderr, "%s: %s%s", name, strerror(errno), NL); err = -1; } }/* while */ fclose(fp); } return err; }/* put_file */ /* * エスケープ (改行・チルダ) の後に cmd が入力された処理。 * return * 0: ok (エスケープ続く) * 1: ok (エスケープ終る) * -1: error (エスケープ終る) */ static int do_escape(int cmd, int localfd, int remotefd) { int err = 0; char obuf[2]; switch (cmd) { case '?': fprintf(stderr, "[COMMANDS]%s", NL); fprintf(stderr, "[~?]\thelp%s", NL); fprintf(stderr, "[~.]\tquit%s", NL); fprintf(stderr, "[~~]\tsend '~'%s", NL); fprintf(stderr, "[~#]\tsend break%s", NL); fprintf(stderr, "[~x]\ttoggle hex mode%s", NL); fprintf(stderr, "[~r rnRN]\tset crlf map mode%s", NL); fprintf(stderr, "[~>flie]\tput file%s", NL); break; case '.': quit_flag = 1; /* プログラム終了 */ break; case '>': { char lbuf[256]; fprintf(stderr, "put file>"); if (read_line(lbuf, sizeof(lbuf), localfd) != NULL) { put_file(lbuf, remotefd); } } break; case '~': err = 1; if (so_write(remotefd, "~", 1) != 1) { perror("write remote"); err = -1; } break; case '#': if (tcsendbreak(remotefd, 0) < 0) { perror("tcsendbreak"); err = -1; } break; case 'x': hex_mode = !hex_mode; if (hex_mode) hexdump_start(); else hexdump_stop(); break; case 'r': { char lbuf[8], map[8]; print_rn_opt(map, sizeof(map)); fprintf(stderr, "crlf map: x=drop, r=CR, n=LF, t=CRLF%s", NL); fprintf(stderr, "crlf map: option order = {recv CR, recv NL, send CR, send LF}%s", NL); fprintf(stderr, "crlf map: current option=%s, input new option=", map); if (read_line(lbuf, sizeof(lbuf), localfd) != NULL) { if (set_rn_opt(lbuf) < 0) fprintf(stderr, "%s: wrong format. ignored%s", lbuf, NL); } } break; default: err = 1; obuf[0] = '~'; obuf[1] = cmd; if (so_write(remotefd, obuf, 2) != 2) { perror("write remote"); err = -1; } break; }/* switch */ return err; }/* do_escape */ /* * キーボードから入力があった処理。 */ static int read_local(int localfd, int remotefd, FILE *log) { static int lastch = '\n'; unsigned char lbuf[1]; int err = read(localfd, lbuf, sizeof(lbuf)); if (err < 0) perror("local read"); else if (err == 0) { fprintf(stderr, "local closed\n"); err = -1; } else { if (is_server || pipe_mode) { if (so_write(remotefd, lbuf, err) == err) err = 0; else perror("so_write"); } else if ((lastch == '\n' || lastch == '\r') && lbuf[0] == '~') { err = read(localfd, lbuf, sizeof(lbuf)); if (err < 0) perror("local read"); else if (err == 0) { fprintf(stderr, "local closed\n"); err = -1; } else { err = do_escape(lbuf[0], localfd, remotefd); if (err != 0) lastch = lbuf[0]; if (err == 1) err = 0; } } else { char *obuf = lbuf; int n = err; switch (lbuf[0]) { case '\r': obuf = RN_OUTPUT[rn_map[RN_SEND_CR]]; n = strlen(obuf); break; case '\n': obuf = RN_OUTPUT[rn_map[RN_SEND_LF]]; n = strlen(obuf); break; }/* switch */ err = so_write(remotefd, obuf, n); if (err < 0) { perror("write remote"); } else err = 0; lastch = lbuf[0]; } } return err; }/* read_local */ /* * メインループ */ static int fnain(int localfd, int remotefd, FILE *log) { int err = 0; if (pipe_mode) set_fdstatus(localfd); quit_flag = 0; while (quit_flag == 0 && err == 0) { fd_set fds; err = sel2(&fds, localfd, remotefd); if (err == -1) perror("select"); else if (err == 0) { /* timeout */ } else { if (FD_ISSET(remotefd, &fds)) { err = read_remote(localfd, remotefd, log); } if (FD_ISSET(localfd, &fds)) { err = read_local(localfd, remotefd, log); } } }/* while */ return err; }/* fnain */ /* * シリアルポートじゃなくて、 * host:port に TCP で接続して通信する。 * telnet(1) みたいな奴。 */ static int oain(const char *host, int port, int family, FILE *log) { int err = -1; int so = conn(host, port, family); if (so >= 0) { if (make_local_raw(0) == 0) err = fnain(0, so, log); close(so); } return err; }/* oain */ /* * ファイル名 dev を通してシリアル通信を行う。 */ static int nain(int localfd, const char *dev, FILE *log) { int err = -1; int remotefd = open(dev, O_RDWR); if (remotefd < 0) perror(dev); else { if (make_local_raw(localfd) == 0 && fd_init(remotefd) == 0 && set_fdstatus(remotefd) == 0) { if (!is_server) print_fdstatus(remotefd); err = fnain(localfd, remotefd, log); } close(remotefd); } return err; }/* nain */ static int server(const char *dev, int port, int family, FILE *log) { int err; char servname[16]; struct addrinfo hints, *res; is_server = 1; memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_PASSIVE; hints.ai_family = family; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = 0; sprintf(servname, "%d", port); err = getaddrinfo(NULL, servname, &hints, &res); if (err == 0) { if (res != NULL) { int so = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (so >= 0) { int on = 1; setsockopt(so, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)); if (bind(so, res->ai_addr, res->ai_addrlen) == 0) { if (listen(so, 5) == 0) { while (1) { int len = res->ai_addrlen; int newso = accept(so, res->ai_addr, &len); err = 0; #ifdef USE_LIBWRAP /*[*/ if (use_libwrap) { char hostname[NI_MAXHOST]; struct request_info accessreq; memset(hostname, 0x00, sizeof(hostname)); err = getnameinfo(res->ai_addr, len, hostname, sizeof(hostname), NULL, 0, NI_NUMERICHOST); if (err == 0) { request_init(&accessreq, RQ_DAEMON, "jerm", RQ_CLIENT_ADDR, hostname, NULL); if (!hosts_access(&accessreq)) err = -1; } else { fprintf(stderr, "getnameinfo: %s\n", gai_strerror(err)); if (err == EAI_SYSTEM) fprintf(stderr, "getnameinfo: %s\n", strerror(errno)); } } #endif /*]*/ if (err == 0) err = nain(newso, dev, log); close(newso); }/* while */ } else fprintf(stderr, "listen: %s\n", strerror(errno)); } else fprintf(stderr, "bind: %d: %s\n", port, strerror(errno)); } else fprintf(stderr, "socket: %s\n", strerror(errno)); freeaddrinfo(res); } else fprintf(stderr, "getaddrinfo: no address\n"); } else { fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err)); if (err == EAI_SYSTEM) fprintf(stderr, "getaddrinfo: %s\n", strerror(errno)); } return err; }/* server */ static char *copyright = "Jerminal v0.8096 Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007 candy"; /* * */ static char *usage_msg = "usage1: %s [optinos] device\n" "\t-b speed\tspeed\n" "\t-p [none|even|odd]\tparity\n" "\t-d [7|8]\tdata bits\n" "\t-s [1|2|1.5]\tstop bit\n" "\t-f [none|x|hard]\tflow control\n" "\t-F\tSet FUCK MODE for TA-100KR/RA SYSTEMS CORP.\n" "usage2: %s [-46i][-P port] [options] host\n" "\tclient mode.\n" "\t-i\tinit stdin/out by device options (pipe mode)\n" "common optinos:\n" "\t-l file\tlog file\n" "\t-z\ttruncate log file\n" "\t-x\tstart in hex dump mode\n" "\t-r cccc\tset CR LF mapping. (default = rnrn)\n" "\t\tc = {x=drop, r=CR, n=LF, t=CRLF}\n" "\t\toption order = {recv CR, recv NL, send CR, send LF}\n" #ifdef JUPITER "\t-j\trockwell binary data mode\n" #endif "usage3: %s -D [-46T][-P port][-z][-l file] device\n" "\tserver mode.\n" #ifdef USE_LIBWRAP "\t-T\tuse libwrap(3)\n" #endif ; /* * */ int main(int argc, char *argv[]) { int ex = 1, ch, show_usage = 0; int port = PORT, truncate_log = 0; int family = AF_INET; /* AF_UNSPEC; */ char *logfile = NULL; int daemon = 0; myname = argv[0]; while ((ch = getopt(argc, argv, "46b:d:Df:Fijl:p:P:r:s:TVxz")) != EOF) { switch (ch) { int x; default: case 'V': show_usage = 1; break; case '4': family = AF_INET; break; case '6': #ifdef AF_INET6 family = AF_INET6; #else fprintf(stderr, "%s: WARNING: IPv6 is not supported, ignored.\n", myname); #endif break; case 'b': x = strtol(optarg, NULL, 10); speed = num_to_speed(x); break; case 'd': x = strtol(optarg, NULL, 10); switch (x) { case 8: data_bit = CS8; break; case 7: data_bit = CS7; break; default: show_usage = 1; break; }/* switch */ break; case 'D': daemon++; break; #ifdef USE_LIBWRAP case 'T': use_libwrap = 1; break; #endif case 'f': switch (optarg[0]) { case 'n': flow_control = F_NONE; break; case 'x': flow_control = F_X; break; case 'h': flow_control = F_HARD; break; default: show_usage = 1; break; }/* switch */ break; case 'F': /* TA-100 用 */ speed = B9600; data_bit = CS8; stop_bit = 1; parity = P_EVEN; flow_control = F_HARD; rn_map[RN_SEND_CR] = RN_MAP_CRLF; break; case 'i': pipe_mode = 1; break; case 'j': #ifdef JUPITER rockwell_mode = 1; #else fprintf(stderr, "Error: -j not available. compile with '-DJUPITER'\n"); #endif break; case 'l': logfile = optarg; break; case 'p': switch (optarg[0]) { case 'n': parity = P_NONE; break; case 'e': parity = P_EVEN; break; case 'o': parity = P_ODD; break; default: show_usage = 1; break; }/* switch */ break; case 'P': port = strtol(optarg, NULL, 0); break; case 'r': if (set_rn_opt(optarg) < 0) { fprintf(stderr, "%s: %s: wrong format\n", myname, optarg); show_usage++; } break; case 's': if (strcmp(optarg, "1") == 0) stop_bit = 1; else if (strcmp(optarg, "2") == 0) stop_bit = 2; else if (strcmp(optarg, "1.5") == 0) stop_bit = 3; else show_usage = 1; break; case 'x': hex_mode = 1; break; case 'z': truncate_log = 1; break; }/* switch */ }/* while */ if (argc - optind != 1) show_usage++; if (show_usage) { fprintf(stderr, "%s\n", copyright); fprintf(stderr, usage_msg, myname, myname, myname); } else { int err = 0; FILE *logfp = NULL; if (logfile != NULL) { logfp = fopen(logfile, (truncate_log ? "w" : "a")); if (logfp == NULL) { perror(logfile); err = -1; } } if (err == 0) { if (hex_mode) hexdump_start(); if (daemon) server(argv[optind], port, family, logfp); else { char *target = argv[optind]; fprintf(stderr, "%s\n", copyright); fprintf(stderr, "Type \"Ctrl-M ~ .\" to exit.\n"); if (*target == '/') nain(0, argv[optind], logfp); else oain(argv[optind], port, family, logfp); } ex = 0; } } return ex; }/* main */